| // | |
| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| // | |
| package com.cloud.utils; | |
| import static org.junit.Assert.assertArrayEquals; | |
| import static org.junit.Assert.assertFalse; | |
| import static org.junit.Assert.assertNotNull; | |
| import static org.junit.Assert.assertNull; | |
| import static org.junit.Assert.assertTrue; | |
| import static org.mockito.ArgumentMatchers.any; | |
| import static org.mockito.ArgumentMatchers.anyInt; | |
| import static org.mockito.ArgumentMatchers.anyString; | |
| import static org.mockito.ArgumentMatchers.contains; | |
| import static org.mockito.ArgumentMatchers.eq; | |
| import static org.mockito.Mockito.atLeastOnce; | |
| import static org.mockito.Mockito.verify; | |
| import static org.mockito.Mockito.when; | |
| import java.io.ByteArrayInputStream; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.net.HttpURLConnection; | |
| import java.net.URL; | |
| import java.net.URLConnection; | |
| import java.net.URLStreamHandler; | |
| import java.nio.file.Files; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| import javax.servlet.http.Cookie; | |
| import javax.servlet.http.HttpSession; | |
| import org.apache.logging.log4j.Logger; | |
| import org.junit.BeforeClass; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.mockito.Mock; | |
| import org.mockito.junit.MockitoJUnitRunner; | |
| import org.springframework.mock.web.MockHttpSession; | |
| @RunWith(MockitoJUnitRunner.class) | |
| public class HttpUtilsTest { | |
| // Use a custom protocol (e.g., "mockhttp") for testing. | |
| private static FakeURLStreamHandler fakeHandler; | |
| @Mock | |
| private Logger logger; | |
| @Mock | |
| private HttpURLConnection httpConn; | |
| @Test | |
| public void findCookieTest() { | |
| Cookie[] cookies = null; | |
| String cookieName = null; | |
| // null test | |
| assertNull(HttpUtils.findCookie(cookies, cookieName)); | |
| cookieName = ""; | |
| assertNull(HttpUtils.findCookie(cookies, cookieName)); | |
| // value test | |
| cookieName = "daakuBandar"; | |
| cookies = new Cookie[]{new Cookie(cookieName, "someValue")}; | |
| assertNull(HttpUtils.findCookie(cookies, "aalasiLangur")); | |
| assertNotNull(HttpUtils.findCookie(cookies, cookieName)); | |
| } | |
| @Test | |
| public void validateSessionKeyTest() { | |
| HttpSession session = null; | |
| Map<String, Object[]> params = null; | |
| String sessionKeyString = null; | |
| Cookie[] cookies = null; | |
| final String sessionKeyValue = "randomUniqueSessionID"; | |
| // session and sessionKeyString null test | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| sessionKeyString = "sessionkey"; | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param and cookie null test | |
| session = new MockHttpSession(); | |
| final String sessionId = session.getId(); | |
| session.setAttribute(sessionKeyString, sessionKeyValue); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param null, cookies not null test (JSESSIONID is null) | |
| params = null; | |
| cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)}; | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param null, cookies not null test (JSESSIONID is not null and matches) | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0"); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param null, cookies not null test (JSESSIONID is not null but mismatches) | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| cookies[1] = new Cookie("JSESSIONID", "node0xxxxxxxxxxxxx.node0"); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param not null, cookies null test | |
| params = new HashMap<String, Object[]>(); | |
| params.put(sessionKeyString, new String[]{"randomString"}); | |
| cookies = null; | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| params.put(sessionKeyString, new String[]{sessionKeyValue}); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // both param and cookies not null test (JSESSIONID is null) | |
| params = new HashMap<String, Object[]>(); | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| params.put(sessionKeyString, new String[]{"incorrectValue"}); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| params.put(sessionKeyString, new String[]{sessionKeyValue}); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // both param and cookies not null test (JSESSIONID is not null but mismatches) | |
| params = new HashMap<String, Object[]>(); | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| cookies[1] = new Cookie("JSESSIONID", "node0xxxxxxxxxxxxx.node0"); | |
| params.put(sessionKeyString, new String[]{"incorrectValue"}); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| params.put(sessionKeyString, new String[]{sessionKeyValue}); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // both param and cookies not null test (JSESSIONID is not null amd matches) | |
| params = new HashMap<String, Object[]>(); | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0"); | |
| params.put(sessionKeyString, new String[]{"incorrectValue"}); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| params.put(sessionKeyString, new String[]{sessionKeyValue}); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| // param not null, cookies null test (JSESSIONID is not null amd matches) | |
| params = new HashMap<String, Object[]>(); | |
| cookies = new Cookie[1]; | |
| cookies[0] = new Cookie("JSESSIONID", sessionId + ".node0"); | |
| params.put(sessionKeyString, new String[]{"incorrectValue"}); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly)); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter)); | |
| params.put(sessionKeyString, new String[]{sessionKeyValue}); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly)); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter)); | |
| // param not null (correct), cookies not null test (correct) | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, sessionKeyValue); | |
| cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0"); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly)); | |
| assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter)); | |
| // param not null (correct), cookies not null test (wrong) | |
| cookies = new Cookie[2]; | |
| cookies[0] = new Cookie(sessionKeyString, "incorrectValue"); | |
| cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0"); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter)); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly)); | |
| assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter)); | |
| } | |
| private static class FakeURLStreamHandler extends URLStreamHandler { | |
| private HttpURLConnection connection; | |
| public void setHttpURLConnection(HttpURLConnection connection) { | |
| this.connection = connection; | |
| } | |
| @Override | |
| protected URLConnection openConnection(URL u) { | |
| return connection; | |
| } | |
| } | |
| // Register our custom URLStreamHandlerFactory once for the tests. | |
| @BeforeClass | |
| public static void setUpOnce() { | |
| fakeHandler = new FakeURLStreamHandler(); | |
| try { | |
| URL.setURLStreamHandlerFactory(protocol -> { | |
| if ("mockhttp".equals(protocol)) { | |
| return fakeHandler; | |
| } | |
| return null; | |
| }); | |
| } catch (Error e) { | |
| // The factory can only be set once. In case it is already set, ignore. | |
| } | |
| } | |
| @Test | |
| public void testSuccessfulDownload_withContentLength() throws Exception { | |
| String fileURL = "mockhttp://example.com/file.txt"; | |
| File tempFile = File.createTempFile("downloadTest", ".tmp"); | |
| tempFile.deleteOnExit(); | |
| byte[] fileData = "Hello World".getBytes(); | |
| ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData); | |
| when(httpConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); | |
| when(httpConn.getContentLength()).thenReturn(fileData.length); | |
| when(httpConn.getInputStream()).thenReturn(inputStream); | |
| fakeHandler.setHttpURLConnection(httpConn); | |
| boolean result = HttpUtils.downloadFileWithProgress(fileURL, tempFile.getAbsolutePath(), logger); | |
| assertTrue(result); | |
| verify(logger, atLeastOnce()).debug(anyString(), anyInt(), eq(fileURL)); | |
| verify(logger).info("File {} downloaded successfully using {}.", fileURL, tempFile.getAbsolutePath()); | |
| byte[] actualData = Files.readAllBytes(tempFile.toPath()); | |
| assertArrayEquals(fileData, actualData); | |
| } | |
| @Test | |
| public void testSuccessfulDownload_negativeContentLength() throws Exception { | |
| String fileURL = "mockhttp://example.com/file.txt"; | |
| File tempFile = File.createTempFile("downloadTest", ".tmp"); | |
| tempFile.deleteOnExit(); | |
| byte[] fileData = "Hello World".getBytes(); | |
| ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData); | |
| when(httpConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); | |
| // Simulate missing content length | |
| when(httpConn.getContentLength()).thenReturn(-1); | |
| when(httpConn.getInputStream()).thenReturn(inputStream); | |
| fakeHandler.setHttpURLConnection(httpConn); | |
| boolean result = HttpUtils.downloadFileWithProgress(fileURL, tempFile.getAbsolutePath(), logger); | |
| assertTrue(result); | |
| verify(logger).warn("Content length not provided for {}, progress updates may not be accurate", fileURL); | |
| verify(logger).info("File {} downloaded successfully using {}.", fileURL, tempFile.getAbsolutePath()); | |
| byte[] actualData = Files.readAllBytes(tempFile.toPath()); | |
| assertArrayEquals(fileData, actualData); | |
| } | |
| @Test | |
| public void testDownloadFile_nonOKResponse() throws Exception { | |
| String fileURL = "mockhttp://example.com/file.txt"; | |
| String savePath = "dummyPath"; | |
| when(httpConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NOT_FOUND); | |
| fakeHandler.setHttpURLConnection(httpConn); | |
| boolean result = HttpUtils.downloadFileWithProgress(fileURL, savePath, logger); | |
| assertFalse(result); | |
| verify(logger).error("No file to download {}. Server replied with code: {}", fileURL, HttpURLConnection.HTTP_NOT_FOUND); | |
| } | |
| @Test | |
| public void testDownloadFile_exceptionDuringDownload() throws Exception { | |
| String fileURL = "mockhttp://example.com/file.txt"; | |
| String savePath = "dummyPath"; | |
| when(httpConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); | |
| when(httpConn.getContentLength()).thenReturn(100); | |
| // Simulate an IOException when trying to get the InputStream | |
| when(httpConn.getInputStream()).thenThrow(new IOException("Connection error")); | |
| fakeHandler.setHttpURLConnection(httpConn); | |
| boolean result = HttpUtils.downloadFileWithProgress(fileURL, savePath, logger); | |
| assertFalse(result); | |
| verify(logger).error(contains("Failed to download {} due to: {}"), eq(fileURL), eq("Connection error"), any(IOException.class)); | |
| } | |
| } |