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);