You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by sh...@apache.org on 2026/08/18 12:49:04 UTC

(cloudstack) 05/20: Validate URL before obtaining remote size

This is an automated email from the ASF dual-hosted git repository.

shwstppr pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit bbd37271c6211e54947fb807e61eb6f1aeab42ae
Author: Pearl Dsilva <pe...@gmail.com>
AuthorDate: Tue Jul 14 10:24:32 2026 -0400

    Validate URL before obtaining remote size
---
 .../com/cloud/template/TemplateManagerImpl.java    | 15 ++++--
 .../cloud/template/TemplateManagerImplTest.java    | 55 ++++++++++++++++++++++
 2 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index 49b056e8813..ee0b2ff1321 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -349,6 +349,15 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
         return adapter;
     }
 
+    private long validateUrlAndGetSecondaryStorageUsage(TemplateAdapter adapter, String format, String url, boolean isDirectDownload) {
+        boolean isHypervisorTemplateAdapter = adapter instanceof HypervisorTemplateAdapter && !isDirectDownload;
+        if (isHypervisorTemplateAdapter) {
+            UriUtils.validateUrl(format, url, !TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), isDirectDownload);
+        }
+        return isHypervisorTemplateAdapter ?
+                UriUtils.getRemoteSize(url, StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+    }
+
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "Creating ISO")
     public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException {
@@ -358,8 +367,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
         // Secondary storage resource count is not incremented for BareMetalTemplateAdapter
         // Note: checking the file size before registering will require the Management Server host to have access to the Internet and a DNS server
         // If it does not, UriUtils.getRemoteSize will return 0L.
-        long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
-                UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+        long secondaryStorageUsage = validateUrlAndGetSecondaryStorageUsage(adapter, ImageFormat.ISO.getFileExtension(), cmd.getUrl(), cmd.isDirectDownload());
 
         try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
              CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
@@ -398,8 +406,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
         TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
         Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
 
-        long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
-                UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+        long secondaryStorageUsage = validateUrlAndGetSecondaryStorageUsage(adapter, cmd.getFormat(), cmd.getUrl(), cmd.isDirectDownload());
 
         try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
              CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
diff --git a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
index 7893d28d9ca..353a4393700 100755
--- a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
+++ b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
@@ -51,11 +51,14 @@ import com.cloud.user.ResourceLimitService;
 import com.cloud.user.User;
 import com.cloud.user.UserData;
 import com.cloud.user.UserVO;
+import com.cloud.utils.UriUtils;
 import com.cloud.utils.concurrency.NamedThreadFactory;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.dao.VMInstanceDao;
 import junit.framework.TestCase;
+
+import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
 import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
 import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
 import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
@@ -86,6 +89,7 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.Spy;
 import org.mockito.invocation.InvocationOnMock;
@@ -583,6 +587,57 @@ public class TemplateManagerImplTest extends TestCase {
         Mockito.verify(dataStoreManager, Mockito.times(0)).getImageStoreWithFreeCapacity(Mockito.anyLong());
     }
 
+    private HypervisorTemplateAdapter mockHypervisorTemplateAdapter() {
+        HypervisorTemplateAdapter adapter = Mockito.mock(HypervisorTemplateAdapter.class);
+        when(adapter.getName()).thenReturn(TemplateAdapter.TemplateAdapterType.Hypervisor.getName());
+        templateManager.setTemplateAdapters(new ArrayList<>(List.of(adapter)));
+        return adapter;
+    }
+
+    @Test
+    public void testRegisterTemplateValidatesUrlBeforeProbingSize() {
+        RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);
+        when(cmd.getTemplateTag()).thenReturn(null);
+        when(cmd.isRoutingType()).thenReturn(null);
+        when(cmd.getUrl()).thenReturn("http://10.0.0.5/template.qcow2");
+        when(cmd.getFormat()).thenReturn("QCOW2");
+        when(cmd.getHypervisor()).thenReturn(Hypervisor.HypervisorType.KVM.toString());
+        when(cmd.isDirectDownload()).thenReturn(false);
+        when(cmd.getEntityOwnerId()).thenReturn(1L);
+        when(_accountMgr.getAccount(1L)).thenReturn(Mockito.mock(Account.class));
+
+        mockHypervisorTemplateAdapter();
+
+        try (MockedStatic<UriUtils> uriUtilsMock = Mockito.mockStatic(UriUtils.class)) {
+            uriUtilsMock.when(() -> UriUtils.validateUrl(any(), any(), Mockito.anyBoolean(), Mockito.anyBoolean()))
+                    .thenThrow(new IllegalArgumentException("Illegal host specified in URL."));
+
+            Assert.assertThrows(IllegalArgumentException.class, () -> templateManager.registerTemplate(cmd));
+
+            uriUtilsMock.verify(() -> UriUtils.getRemoteSize(any(), any()), Mockito.never());
+        }
+    }
+
+    @Test
+    public void testRegisterIsoValidatesUrlBeforeProbingSize() throws Exception {
+        RegisterIsoCmd cmd = Mockito.mock(RegisterIsoCmd.class);
+        when(cmd.getUrl()).thenReturn("http://10.0.0.5/image.iso");
+        when(cmd.isDirectDownload()).thenReturn(false);
+        when(cmd.getEntityOwnerId()).thenReturn(1L);
+        when(_accountMgr.getAccount(1L)).thenReturn(Mockito.mock(Account.class));
+
+        mockHypervisorTemplateAdapter();
+
+        try (MockedStatic<UriUtils> uriUtilsMock = Mockito.mockStatic(UriUtils.class)) {
+            uriUtilsMock.when(() -> UriUtils.validateUrl(any(), any(), Mockito.anyBoolean(), Mockito.anyBoolean()))
+                    .thenThrow(new IllegalArgumentException("Illegal host specified in URL."));
+
+            Assert.assertThrows(IllegalArgumentException.class, () -> templateManager.registerIso(cmd));
+
+            uriUtilsMock.verify(() -> UriUtils.getRemoteSize(any(), any()), Mockito.never());
+        }
+    }
+
     @Test
     public void testRegisterTemplateWithTemplateType() {
         RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);