file:
as first 5 symbols,
104 | * then cut any path after jar!..
105 | *
106 | * @param resourceFolderPath
107 | * @return jar path
108 | */
109 | private String substringJarPath(String resourceFolderPath) {
110 | return resourceFolderPath.substring(5, resourceFolderPath.indexOf("!"));
111 | }
112 |
113 | private NameMapper pathKeeper() {
114 | return new NameMapper() {
115 | @Override
116 | public String map(String name) {
117 | return path + "/" + name;
118 | }
119 | };
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/main/java/io/sterodium/extensions/client/upload/ResourcePackagingException.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.upload;
2 |
3 | /**
4 | * @author Alexey Nikolaenko alexey@tcherezov.com
5 | * Date: 25/09/2015
6 | */
7 | class ResourcePackagingException extends RuntimeException {
8 |
9 | public ResourcePackagingException(String message) {
10 | super(message);
11 | }
12 |
13 | public ResourcePackagingException(Throwable cause) {
14 | super(cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/main/java/io/sterodium/extensions/client/upload/ResourceUploadException.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.upload;
2 |
3 | /**
4 | * @author Alexey Nikolaenko alexey@tcherezov.com
5 | * Date: 25/09/2015
6 | */
7 | class ResourceUploadException extends RuntimeException {
8 | public ResourceUploadException(int code, String message) {
9 | super(String.format("Resource upload returned status %d with message: %s", code, message));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/main/java/io/sterodium/extensions/client/upload/ResourceUploadRequest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.upload;
2 |
3 | import com.google.common.base.Throwables;
4 |
5 | import org.apache.http.Consts;
6 | import org.apache.http.HttpHost;
7 | import org.apache.http.HttpStatus;
8 | import org.apache.http.client.methods.CloseableHttpResponse;
9 | import org.apache.http.client.methods.HttpPost;
10 | import org.apache.http.entity.InputStreamEntity;
11 | import org.apache.http.impl.client.CloseableHttpClient;
12 | import org.apache.http.impl.client.HttpClients;
13 | import org.apache.http.protocol.HTTP;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import org.zeroturnaround.zip.commons.IOUtils;
17 |
18 | import java.io.File;
19 | import java.io.FileInputStream;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 |
23 | /**
24 | * @author Alexey Nikolaenko alexey@tcherezov.com
25 | * Date: 25/09/2015
26 | */
27 | public class ResourceUploadRequest {
28 |
29 | private static final Logger LOGGER = LoggerFactory
30 | .getLogger(ResourceUploadRequest.class);
31 |
32 | public static final String FILE_UPLOAD_EXTENSION_PATH = "/grid/admin/HubRequestsProxyingServlet/session/%s/FileUploadServlet";
33 |
34 | private final HttpHost httpHost;
35 | private final String sessionId;
36 |
37 | public ResourceUploadRequest(String host, int port, String sessionId) {
38 | this.httpHost = new HttpHost(host, port);
39 | this.sessionId = sessionId;
40 | }
41 |
42 | public String upload(String resourcesPath) {
43 | LOGGER.debug("Uploading resources from path:" + resourcesPath);
44 |
45 | File zip = addResourcesToZip(resourcesPath);
46 |
47 | CloseableHttpClient httpClient = HttpClients.createDefault();
48 |
49 | HttpPost request = new HttpPost(String.format(FILE_UPLOAD_EXTENSION_PATH, sessionId));
50 | request.setHeader(HTTP.CONTENT_TYPE, "application/octet-stream");
51 | request.setHeader(HTTP.CONTENT_ENCODING, Consts.ISO_8859_1.name());
52 | try {
53 | FileInputStream fileInputStream = new FileInputStream(zip);
54 | InputStreamEntity entity = new InputStreamEntity(fileInputStream);
55 | request.setEntity(entity);
56 | CloseableHttpResponse execute = httpClient.execute(httpHost, request);
57 |
58 | int statusCode = execute.getStatusLine().getStatusCode();
59 | String content = contentAsString(execute);
60 |
61 | if (HttpStatus.SC_OK == statusCode) {
62 | return content;
63 | } else {
64 | throw new ResourceUploadException(statusCode, content);
65 | }
66 | } catch (IOException e) {
67 | throw Throwables.propagate(e);
68 | }
69 | }
70 |
71 | private String contentAsString(CloseableHttpResponse execute) throws IOException {
72 | InputStream response = execute.getEntity().getContent();
73 | return IOUtils.toString(response, "utf-8");
74 | }
75 |
76 | protected File addResourcesToZip(String resourcesPath) {
77 | ResourceFolder resourceFolder = new ResourceFolder(resourcesPath);
78 | return resourceFolder.toZip();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/java/io/sterodium/extensions/client/BaseRequestTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client;
2 |
3 | import org.seleniumhq.jetty9.server.Server;
4 | import org.seleniumhq.jetty9.servlet.ServletContextHandler;
5 | import org.seleniumhq.jetty9.servlet.ServletHolder;
6 |
7 | import javax.servlet.ServletException;
8 | import javax.servlet.http.HttpServlet;
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.io.IOException;
12 |
13 | /**
14 | * @author Alexey Nikolaenko alexey@tcherezov.com
15 | * Date: 30/09/2015
16 | */
17 | public abstract class BaseRequestTest {
18 |
19 | public static final String PATH = "/grid/admin/%s/session/%s/%s/%s";
20 |
21 | protected Server startServerForServlet(HttpServlet servlet, String path) throws Exception {
22 | Server server = new Server(0);
23 |
24 | ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
25 | context.setContextPath("/");
26 | server.setHandler(context);
27 |
28 | context.addServlet(new ServletHolder(servlet), path);
29 | server.start();
30 |
31 | return server;
32 | }
33 |
34 | public static class StubServlet extends HttpServlet {
35 |
36 | private Function function;
37 |
38 | public void setFunction(Function function) {
39 | this.function = function;
40 | }
41 |
42 | @Override
43 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
44 | function.apply(req, resp);
45 | }
46 |
47 | @Override
48 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
49 | function.apply(req, resp);
50 | }
51 | }
52 |
53 | protected interface Function {
54 | void apply(HttpServletRequest req, HttpServletResponse resp);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/java/io/sterodium/extensions/client/download/FileDownloadRequestTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.download;
2 |
3 | import io.sterodium.extensions.client.BaseRequestTest;
4 | import io.sterodium.extensions.hub.proxy.HubRequestsProxyingServlet;
5 | import io.sterodium.extensions.node.download.FileDownloadServlet;
6 | import org.apache.commons.io.FileUtils;
7 | import org.apache.commons.io.IOUtils;
8 | import org.junit.After;
9 | import org.junit.Before;
10 | import org.junit.Test;
11 | import org.junit.runner.RunWith;
12 | import org.mockito.Mock;
13 | import org.mockito.invocation.InvocationOnMock;
14 | import org.mockito.runners.MockitoJUnitRunner;
15 | import org.mockito.stubbing.Answer;
16 | import org.seleniumhq.jetty9.server.AbstractNetworkConnector;
17 | import org.seleniumhq.jetty9.server.Server;
18 |
19 | import javax.servlet.ServletOutputStream;
20 | import javax.servlet.http.HttpServletRequest;
21 | import javax.servlet.http.HttpServletResponse;
22 | import java.io.File;
23 | import java.io.FileInputStream;
24 | import java.io.IOException;
25 | import java.nio.charset.StandardCharsets;
26 | import java.util.Base64;
27 |
28 | import static org.hamcrest.CoreMatchers.containsString;
29 | import static org.hamcrest.CoreMatchers.is;
30 | import static org.hamcrest.MatcherAssert.assertThat;
31 | import static org.junit.Assert.assertTrue;
32 | import static org.mockito.Mockito.any;
33 | import static org.mockito.Mockito.doAnswer;
34 | import static org.mockito.Mockito.times;
35 | import static org.mockito.Mockito.verify;
36 |
37 | /**
38 | * @author Alexey Nikolaenko alexey@tcherezov.com
39 | * Date: 30/09/2015
40 | */
41 | @RunWith(MockitoJUnitRunner.class)
42 | public class FileDownloadRequestTest extends BaseRequestTest {
43 |
44 | private static final String SESSION_ID = "sessionId";
45 | private static final String EXPECTED_CONTENT = "expected content";
46 |
47 | @Mock
48 | Function responseHandleFunction;
49 |
50 | private File fileToGet;
51 | private Server server;
52 | private int port;
53 | private String extensionPath;
54 |
55 | @Before
56 | public void setUp() throws Exception {
57 | StubServlet stubServlet = new StubServlet();
58 | stubServlet.setFunction(responseHandleFunction);
59 |
60 | fileToGet = File.createTempFile("test filename with spaces", ".txt");
61 | FileUtils.write(fileToGet, EXPECTED_CONTENT, StandardCharsets.UTF_8);
62 |
63 | extensionPath = String.format(PATH, HubRequestsProxyingServlet.class.getSimpleName(), SESSION_ID, FileDownloadServlet.class.getSimpleName(), "*");
64 | server = startServerForServlet(stubServlet, extensionPath);
65 | port = ((AbstractNetworkConnector) server.getConnectors()[0]).getLocalPort();
66 | }
67 |
68 | @After
69 | public void tearDown() throws Exception {
70 | server.stop();
71 | assertTrue(fileToGet.delete());
72 | }
73 |
74 | @Test
75 | public void pathTemplateShouldHaveProperServletNames() {
76 | String resultPath = String.format(FileDownloadRequest.FILE_DOWNLOAD_EXTENSION_PATH, SESSION_ID, "*");
77 | assertThat(resultPath, is(extensionPath));
78 | }
79 |
80 | @Test
81 | public void testDownload() throws IOException {
82 | doAnswer(verifyRequestContent())
83 | .when(responseHandleFunction)
84 | .apply(any(HttpServletRequest.class), any(HttpServletResponse.class));
85 |
86 | FileDownloadRequest fileDownloadRequest = new FileDownloadRequest("localhost", port, SESSION_ID);
87 | File downloadedFile = fileDownloadRequest.download(fileToGet.getAbsolutePath());
88 |
89 | try (FileInputStream fileInputStream = new FileInputStream(downloadedFile)) {
90 | String s = IOUtils.toString(fileInputStream, StandardCharsets.UTF_8);
91 | assertThat(s, is(EXPECTED_CONTENT));
92 | }
93 | verify(responseHandleFunction, times(1)).apply(any(HttpServletRequest.class), any(HttpServletResponse.class));
94 | }
95 |
96 | private Answer verifyRequestContent() {
97 | return new Answer() {
98 | @Override
99 | public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
100 | HttpServletRequest req = (HttpServletRequest) invocationOnMock.getArguments()[0];
101 | HttpServletResponse resp = (HttpServletResponse) invocationOnMock.getArguments()[1];
102 |
103 | String pathInfo = req.getRequestURI().substring(req.getServletPath().length() + 1);
104 | pathInfo = new String(Base64.getUrlDecoder().decode(pathInfo.getBytes()));
105 |
106 | assertThat(pathInfo, containsString(fileToGet.getAbsolutePath()));
107 |
108 | try (
109 |
110 | FileInputStream fileInputStream = new FileInputStream(new File(pathInfo));
111 | ServletOutputStream outputStream = resp.getOutputStream()) {
112 | IOUtils.copy(fileInputStream, outputStream);
113 | }
114 | return null;
115 | }
116 | };
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/java/io/sterodium/extensions/client/upload/ResourceFolderTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.upload;
2 |
3 | import com.google.common.io.Files;
4 | import org.junit.Test;
5 | import org.zeroturnaround.zip.ZipUtil;
6 |
7 | import java.io.File;
8 |
9 | import static org.junit.Assert.assertTrue;
10 |
11 | /**
12 | * @author Alexey Nikolaenko alexey@tcherezov.com
13 | * Date: 08/10/2015
14 | */
15 | public class ResourceFolderTest {
16 |
17 | @Test
18 | public void shouldZipLocalResources() {
19 | ResourceFolder uploadFolder = new ResourceFolder("upload");
20 | File file = uploadFolder.toZip();
21 |
22 | File tempDir = Files.createTempDir();
23 | ZipUtil.unpack(file, tempDir);
24 |
25 | verifyFilesInZip(tempDir,
26 | "upload",
27 | "upload/first.txt",
28 | "upload/directory",
29 | "upload/directory/second.txt",
30 | "upload/directory/dir",
31 | "upload/directory/dir/third.txt");
32 | }
33 |
34 | @Test
35 | public void shouldZipExternalResources_FlatFolderCase() {
36 | ResourceFolder uploadFolder = new ResourceFolder("flat");
37 | File file = uploadFolder.toZip();
38 |
39 | File tempDir = Files.createTempDir();
40 | ZipUtil.unpack(file, tempDir);
41 |
42 | verifyFilesInZip(tempDir,
43 | "flat",
44 | "flat/flat1.txt",
45 | "flat/flat2.txt",
46 | "flat/flat3.txt");
47 | }
48 |
49 | @Test
50 | public void shouldZipExternalResources_HierarchicalFolderCase() {
51 | ResourceFolder uploadFolder = new ResourceFolder("hierarchy");
52 | File file = uploadFolder.toZip();
53 |
54 | File tempDir = Files.createTempDir();
55 | ZipUtil.unpack(file, tempDir);
56 |
57 | verifyFilesInZip(tempDir,
58 | "hierarchy/level0.txt",
59 | "hierarchy/level1",
60 | "hierarchy/level1/level1.txt",
61 | "hierarchy/level1/level2",
62 | "hierarchy/level1/level2/level2.txt",
63 | "hierarchy/level1.1/level1.1.txt",
64 | "hierarchy/level1.1/level2.2",
65 | "hierarchy/level1.1/level2.2/level2.2.txt");
66 | }
67 |
68 | private void verifyFilesInZip(File dir, String... paths) {
69 | for (String path : paths) {
70 | assertTrue(String.format("File %s not exists in dir: %s", path, dir.getAbsolutePath()),
71 | new File(dir, path).exists());
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/java/io/sterodium/extensions/client/upload/ResourceUploadRequestTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.client.upload;
2 |
3 | import com.google.common.io.Files;
4 | import io.sterodium.extensions.client.BaseRequestTest;
5 | import io.sterodium.extensions.hub.proxy.HubRequestsProxyingServlet;
6 | import io.sterodium.extensions.node.upload.FileUploadServlet;
7 | import org.apache.commons.io.FileUtils;
8 | import org.apache.commons.io.IOUtils;
9 | import org.junit.After;
10 | import org.junit.Before;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 | import org.mockito.Mock;
14 | import org.mockito.invocation.InvocationOnMock;
15 | import org.mockito.runners.MockitoJUnitRunner;
16 | import org.mockito.stubbing.Answer;
17 | import org.seleniumhq.jetty9.server.AbstractNetworkConnector;
18 | import org.seleniumhq.jetty9.server.Server;
19 | import org.zeroturnaround.zip.ZipUtil;
20 |
21 | import javax.servlet.ServletInputStream;
22 | import javax.servlet.http.HttpServletRequest;
23 | import javax.servlet.http.HttpServletResponse;
24 | import java.io.File;
25 | import java.io.FileOutputStream;
26 | import java.io.OutputStream;
27 | import java.nio.charset.Charset;
28 |
29 | import static org.hamcrest.CoreMatchers.containsString;
30 | import static org.hamcrest.CoreMatchers.is;
31 | import static org.hamcrest.CoreMatchers.startsWith;
32 | import static org.hamcrest.MatcherAssert.assertThat;
33 | import static org.junit.Assert.assertTrue;
34 | import static org.mockito.Mockito.any;
35 | import static org.mockito.Mockito.doAnswer;
36 | import static org.mockito.Mockito.times;
37 | import static org.mockito.Mockito.verify;
38 |
39 | /**
40 | * @author Alexey Nikolaenko alexey@tcherezov.com
41 | * Date: 28/09/2015
42 | *
43 | * Test verifies that ResoureUploadRequest makes proper upload request with zipped resource folder.
44 | * As result it should return contents of response as String.
45 | */
46 | @RunWith(MockitoJUnitRunner.class)
47 | public class ResourceUploadRequestTest extends BaseRequestTest {
48 |
49 |
50 | private static final String EXPECTED_RETURN_FOLDER = "C:/Expected/Folder/";
51 | private static final String SESSION_ID = "sessionId";
52 |
53 | @Mock
54 | Function responseHandleFunction;
55 |
56 | private Server server;
57 | private int port;
58 | private String extensionPath;
59 |
60 | @Before
61 | public void setUp() throws Exception {
62 | StubServlet stubServlet = new StubServlet();
63 | stubServlet.setFunction(responseHandleFunction);
64 |
65 | extensionPath = String.format(PATH, HubRequestsProxyingServlet.class.getSimpleName(), SESSION_ID, FileUploadServlet.class.getSimpleName(), "*");
66 | server = startServerForServlet(stubServlet, extensionPath);
67 | port = ((AbstractNetworkConnector) server.getConnectors()[0]).getLocalPort();
68 | }
69 |
70 | @After
71 | public void tearDown() throws Exception {
72 | server.stop();
73 | }
74 |
75 | @Test
76 | public void pathTemplateShouldHaveProperServletNames() {
77 | String resultPath = String.format(ResourceUploadRequest.FILE_UPLOAD_EXTENSION_PATH, SESSION_ID);
78 | assertThat(extensionPath, startsWith(resultPath));
79 | }
80 |
81 | @Test
82 | public void verifyUploadedContentHasProperStructureAndCanBeUnzipped() {
83 | doAnswer(verifyRequestContent())
84 | .when(responseHandleFunction)
85 | .apply(any(HttpServletRequest.class), any(HttpServletResponse.class));
86 |
87 | ResourceUploadRequest resourceUploadRequest = new ResourceUploadRequest("localhost", port, SESSION_ID);
88 | String responseWithPath = resourceUploadRequest.upload("files_for_upload");
89 |
90 | verify(responseHandleFunction, times(1)).apply(any(HttpServletRequest.class), any(HttpServletResponse.class));
91 | assertThat(responseWithPath, is(EXPECTED_RETURN_FOLDER));
92 | }
93 |
94 | private Answer verifyRequestContent() {
95 | return new Answer() {
96 | @Override
97 | public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
98 | HttpServletRequest req = (HttpServletRequest) invocationOnMock.getArguments()[0];
99 | HttpServletResponse resp = (HttpServletResponse) invocationOnMock.getArguments()[1];
100 |
101 | File tempFile = File.createTempFile("temp_resources", ".zip");
102 | try (ServletInputStream inputStream = req.getInputStream();
103 | OutputStream outputStream = new FileOutputStream(tempFile)) {
104 | IOUtils.copy(inputStream, outputStream);
105 | }
106 | File tempDir = Files.createTempDir();
107 | ZipUtil.unpack(tempFile, tempDir);
108 |
109 | File firstTxtFile = new File(tempDir, "files_for_upload/first.txt");
110 | File secondTxtFile = new File(tempDir, "files_for_upload/directory/second.txt");
111 |
112 | assertTrue(firstTxtFile.exists());
113 | assertTrue(secondTxtFile.exists());
114 |
115 | //verify content
116 | String firstFileContent = Files.toString(firstTxtFile, Charset.defaultCharset());
117 | assertThat(firstFileContent, containsString("content1"));
118 | String secondFileContent = Files.toString(secondTxtFile, Charset.defaultCharset());
119 | assertThat(secondFileContent, containsString("content2"));
120 |
121 | //clean temp directories
122 | FileUtils.deleteDirectory(tempDir);
123 | assertTrue("Failed to delete uploaded zip", tempFile.delete());
124 |
125 |
126 | //form response
127 | resp.getWriter().write(EXPECTED_RETURN_FOLDER);
128 | return null;
129 | }
130 | };
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/resources/files_for_upload/directory/second.txt:
--------------------------------------------------------------------------------
1 | content2
2 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/resources/files_for_upload/first.txt:
--------------------------------------------------------------------------------
1 | content1
2 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/resources/upload/directory/dir/third.txt:
--------------------------------------------------------------------------------
1 | third file
2 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/resources/upload/directory/second.txt:
--------------------------------------------------------------------------------
1 | second file
2 |
--------------------------------------------------------------------------------
/extension-clients/file-extension-client/src/test/resources/upload/first.txt:
--------------------------------------------------------------------------------
1 | first file
2 |
--------------------------------------------------------------------------------
/extension-clients/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 | * Deletes file by providing it's path in GET request.
17 | */
18 | public class FileDeleteServlet extends HttpServlet {
19 |
20 | private static final Logger LOGGER = Logger.getLogger(FileDeleteServlet.class.getName());
21 |
22 | @Override
23 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
24 | String pathInfo = req.getRequestURI().substring(req.getServletPath().length() + 1);
25 | pathInfo = new String(Base64.getUrlDecoder().decode(pathInfo.getBytes()));
26 | LOGGER.info("Request for file delete received with path: " + pathInfo);
27 |
28 | File file = new File(pathInfo);
29 | if (!fileExistsAndNotDirectory(file, resp)) {
30 | return;
31 | }
32 |
33 | file.delete();
34 | }
35 |
36 | private boolean fileExistsAndNotDirectory(File requestedFile, HttpServletResponse resp) throws IOException {
37 | if (!requestedFile.exists()) {
38 | LOGGER.info("Requested file doesn't exist: " + requestedFile.getAbsolutePath());
39 | sendError(resp, "Requested file doesn't exist.");
40 | return false;
41 | }
42 | if (requestedFile.isDirectory()) {
43 | LOGGER.info("Requested file is directory: " + requestedFile.getAbsolutePath());
44 | sendError(resp, "Requested file is directory.");
45 | return false;
46 | }
47 | if (!requestedFile.canRead()) {
48 | LOGGER.info("Requested file cannot bet read: " + requestedFile.getAbsolutePath());
49 | sendError(resp, "Requested file can be read.");
50 | return false;
51 | }
52 | return true;
53 | }
54 |
55 | private void sendError(HttpServletResponse resp, String msg) throws IOException {
56 | resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
57 | resp.getWriter().write(msg);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/main/java/io/sterodium/extensions/node/download/FileDownloadServlet.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node.download;
2 |
3 | import com.google.common.net.HttpHeaders;
4 | import com.google.common.net.MediaType;
5 | import org.apache.commons.io.IOUtils;
6 |
7 | import javax.servlet.ServletException;
8 | import javax.servlet.ServletOutputStream;
9 | import javax.servlet.http.HttpServlet;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.File;
13 | import java.io.FileInputStream;
14 | import java.io.IOException;
15 | import java.nio.file.Files;
16 | import java.util.Base64;
17 | import java.util.logging.Logger;
18 |
19 | /**
20 | * @author Alexey Nikolaenko alexey@tcherezov.com
21 | * Date: 22/09/2015
22 | *
23 | * Allows to download file by providing it's path in GET request.
24 | */
25 | public class FileDownloadServlet extends HttpServlet {
26 |
27 | private static final Logger LOGGER = Logger.getLogger(FileDownloadServlet.class.getName());
28 |
29 | @Override
30 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
31 | String pathInfo = req.getRequestURI().substring(req.getServletPath().length() + 1);
32 | pathInfo = new String(Base64.getUrlDecoder().decode(pathInfo.getBytes()));
33 | LOGGER.info("Request for file download received with path: " + pathInfo);
34 |
35 | File file = new File(pathInfo);
36 | if (!fileExistsAndNotDirectory(file, resp)) {
37 | return;
38 | }
39 |
40 | String contentType = identifyFileContentType(file);
41 | resp.setContentType(contentType);
42 | resp.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
43 |
44 | try (
45 | FileInputStream fileInputStream = new FileInputStream(file);
46 | ServletOutputStream outputStream = resp.getOutputStream()) {
47 | IOUtils.copy(fileInputStream, outputStream);
48 | }
49 | }
50 |
51 | private String identifyFileContentType(File file) throws IOException {
52 | String contentType = Files.probeContentType(file.toPath());
53 | return contentType != null ? contentType : MediaType.OCTET_STREAM.toString();
54 | }
55 |
56 | private boolean fileExistsAndNotDirectory(File requestedFile, HttpServletResponse resp) throws IOException {
57 | if (!requestedFile.exists()) {
58 | LOGGER.info("Requested file doesn't exist: " + requestedFile.getAbsolutePath());
59 | sendError(resp, "Requested file doesn't exist.");
60 | return false;
61 | }
62 | if (requestedFile.isDirectory()) {
63 | LOGGER.info("Requested file is directory: " + requestedFile.getAbsolutePath());
64 | sendError(resp, "Requested file is directory.");
65 | return false;
66 | }
67 | if (!requestedFile.canRead()) {
68 | LOGGER.info("Requested file cannot bet read: " + requestedFile.getAbsolutePath());
69 | sendError(resp, "Requested file can be read.");
70 | return false;
71 | }
72 | return true;
73 | }
74 |
75 | private void sendError(HttpServletResponse resp, String msg) throws IOException {
76 | resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
77 | resp.getWriter().write(msg);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/main/java/io/sterodium/extensions/node/upload/FileUploadServlet.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node.upload;
2 |
3 | import com.google.common.io.Files;
4 | import com.google.common.net.MediaType;
5 | import org.apache.commons.io.IOUtils;
6 |
7 | import javax.servlet.ServletException;
8 | import javax.servlet.ServletInputStream;
9 | import javax.servlet.http.HttpServlet;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.File;
13 | import java.io.FileOutputStream;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.io.OutputStream;
17 | import java.io.PrintWriter;
18 | import java.util.Enumeration;
19 | import java.util.logging.Logger;
20 | import java.util.zip.ZipEntry;
21 | import java.util.zip.ZipFile;
22 |
23 | /**
24 | * @author Alexey Nikolaenko alexey@tcherezov.com
25 | * Date: 22/09/2015
26 | *
27 | * Allows to upload zip archive with resources.
28 | * Zip contents will be stored in temporary folder,
29 | * absolute path will be returned in response body.
30 | */
31 | public class FileUploadServlet extends HttpServlet {
32 |
33 | private static final Logger LOGGER = Logger.getLogger(FileUploadServlet.class.getName());
34 |
35 | @Override
36 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
37 | LOGGER.info(String.format("Request Content-Type: %s, Content-Length:%d", req.getContentType(), req.getContentLength()));
38 |
39 | if (!MediaType.OCTET_STREAM.toString().equals(req.getContentType())) {
40 | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Content type " + req.getContentType() + " is not supported");
41 | return;
42 | }
43 |
44 | LOGGER.info("Creating temporary file");
45 | File tempFile = File.createTempFile("selenium_node", ".zip");
46 | try (ServletInputStream inputStream = req.getInputStream();
47 | OutputStream outputStream = new FileOutputStream(tempFile)) {
48 | LOGGER.info("Copying request input stream to file");
49 | IOUtils.copy(inputStream, outputStream);
50 | }
51 |
52 | LOGGER.info("Unzipping zip archive");
53 | File imagesBaseDir = unZip(tempFile);
54 | if (!tempFile.delete()) {
55 | throw new IOException("Unable to delete file: " + tempFile);
56 | }
57 |
58 | LOGGER.info("Writing directory to response");
59 | PrintWriter writer = resp.getWriter();
60 | writer.write(imagesBaseDir.getAbsolutePath());
61 | }
62 |
63 | private static File unZip(final File zippedFile) throws IOException {
64 | File outputFolder = Files.createTempDir();
65 | try (ZipFile zipFile = new ZipFile(zippedFile)) {
66 | final Enumeration extends ZipEntry> entries = zipFile.entries();
67 | while (entries.hasMoreElements()) {
68 | final ZipEntry entry = entries.nextElement();
69 | final File entryDestination = new File(outputFolder, entry.getName());
70 | if (entry.isDirectory()) {
71 | //noinspection ResultOfMethodCallIgnored
72 | entryDestination.mkdirs();
73 | } else {
74 | //noinspection ResultOfMethodCallIgnored
75 | entryDestination.getParentFile().mkdirs();
76 | final InputStream in = zipFile.getInputStream(entry);
77 | final OutputStream out = new FileOutputStream(entryDestination);
78 | IOUtils.copy(in, out);
79 | IOUtils.closeQuietly(in);
80 | out.close();
81 | }
82 | }
83 | }
84 | return outputFolder;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/test/java/io/sterodium/extensions/node/BaseServletTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node;
2 |
3 | import org.apache.commons.io.IOUtils;
4 | import org.seleniumhq.jetty9.server.Server;
5 | import org.seleniumhq.jetty9.servlet.ServletContextHandler;
6 | import org.seleniumhq.jetty9.servlet.ServletHolder;
7 |
8 | import javax.servlet.http.HttpServlet;
9 | import java.io.File;
10 | import java.io.FileOutputStream;
11 | import java.io.IOException;
12 | import java.nio.charset.StandardCharsets;
13 | import java.util.zip.ZipEntry;
14 | import java.util.zip.ZipOutputStream;
15 |
16 | import static org.hamcrest.CoreMatchers.is;
17 | import static org.junit.Assert.assertThat;
18 |
19 | /**
20 | * @author Alexey Nikolaenko alexey@tcherezov.com
21 | * Date: 24/09/2015
22 | */
23 | public abstract class BaseServletTest {
24 |
25 | public static final String ZIP_FILE_NAME = "test_entry.txt";
26 |
27 | protected Server startServerForServlet(HttpServlet servlet, String path) throws Exception {
28 | Server server = new Server(0);
29 |
30 | ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
31 | context.setContextPath("/");
32 | server.setHandler(context);
33 |
34 | context.addServlet(new ServletHolder(servlet), path);
35 | server.start();
36 |
37 | return server;
38 | }
39 |
40 | protected File createZipArchiveWithTextFile() throws IOException {
41 | final File zipArchive = File.createTempFile("temp_zip_", ".zip");
42 | try (
43 | final ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipArchive))) {
44 | ZipEntry e = new ZipEntry(ZIP_FILE_NAME);
45 | out.putNextEntry(e);
46 | IOUtils.write("test data", out, StandardCharsets.UTF_8);
47 | out.closeEntry();
48 | }
49 | return zipArchive;
50 | }
51 |
52 | protected void deleteIfExists(File... files) {
53 | for (File file : files) {
54 | if (file != null && file.exists()) {
55 | assertThat("Couldn't clean file after tests", file.delete(), is(true));
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/test/java/io/sterodium/extensions/node/delete/FileDeleteServletTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node.delete;
2 |
3 | import io.sterodium.extensions.node.BaseServletTest;
4 | import org.apache.commons.io.FileUtils;
5 | import org.apache.http.HttpHost;
6 | import org.apache.http.client.methods.CloseableHttpResponse;
7 | import org.apache.http.client.methods.HttpGet;
8 | import org.apache.http.impl.client.CloseableHttpClient;
9 | import org.apache.http.impl.client.HttpClients;
10 | import org.junit.After;
11 | import org.junit.Before;
12 | import org.junit.Test;
13 | import org.seleniumhq.jetty9.server.AbstractNetworkConnector;
14 | import org.seleniumhq.jetty9.server.Server;
15 |
16 | import java.io.File;
17 | import java.io.IOException;
18 | import java.net.URLEncoder;
19 | import java.nio.charset.StandardCharsets;
20 | import java.util.Base64;
21 |
22 | import static org.hamcrest.CoreMatchers.is;
23 | import static org.hamcrest.MatcherAssert.assertThat;
24 |
25 | /**
26 | * @author Sameer Jethvani (s.jethvani@gmail.com)
27 | * Date: 22/06/2017
28 | */
29 | public class FileDeleteServletTest extends BaseServletTest {
30 |
31 | private Server filedeleteServer;
32 | private HttpHost serverHost;
33 |
34 | @Before
35 | public void setUp() throws Exception {
36 | filedeleteServer = startServerForServlet(new FileDeleteServlet(), "/" + FileDeleteServlet.class.getSimpleName() + "/*");
37 | serverHost = new HttpHost("localhost", ((AbstractNetworkConnector) filedeleteServer.getConnectors()[0]).getLocalPort());
38 | }
39 |
40 | @After
41 | public void tearDown() throws Exception {
42 | filedeleteServer.stop();
43 | }
44 |
45 | @Test
46 | public void getShouldDeleteFile() throws IOException {
47 | File fileTobeDeleted = File.createTempFile("testDeleteFile", ".txt");
48 | FileUtils.write(fileTobeDeleted, "file_to_be_deleted_content", StandardCharsets.UTF_8);
49 |
50 | CloseableHttpClient httpClient = HttpClients.createDefault();
51 |
52 | String encode = Base64.getUrlEncoder().encodeToString(fileTobeDeleted.getAbsolutePath().getBytes(StandardCharsets.UTF_8));
53 | HttpGet httpGet = new HttpGet("/FileDeleteServlet/" + encode);
54 |
55 | CloseableHttpResponse execute = httpClient.execute(serverHost, httpGet);
56 |
57 | //check file got deleted
58 | //Assert.assertFalse(fileTobeDeleted.getAbsolutePath()+" File should have been deleted ",fileTobeDeleted.exists());
59 | assertThat(fileTobeDeleted+" File should have been deleted . It should not exist at this point",fileTobeDeleted.exists(), is(false));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/test/java/io/sterodium/extensions/node/download/FileDownloadServletTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node.download;
2 |
3 | import io.sterodium.extensions.node.BaseServletTest;
4 | import com.google.common.io.Files;
5 | import com.google.common.net.HttpHeaders;
6 | import org.apache.commons.io.FileUtils;
7 | import org.apache.commons.io.IOUtils;
8 | import org.apache.http.Header;
9 | import org.apache.http.HttpHost;
10 | import org.apache.http.HttpStatus;
11 | import org.apache.http.client.methods.CloseableHttpResponse;
12 | import org.apache.http.client.methods.HttpGet;
13 | import org.apache.http.impl.client.CloseableHttpClient;
14 | import org.apache.http.impl.client.HttpClients;
15 | import org.junit.After;
16 | import org.junit.Before;
17 | import org.junit.Test;
18 | import org.seleniumhq.jetty9.server.AbstractNetworkConnector;
19 | import org.seleniumhq.jetty9.server.Server;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.nio.charset.StandardCharsets;
25 | import java.util.Base64;
26 |
27 | import static junit.framework.TestCase.assertTrue;
28 | import static org.hamcrest.CoreMatchers.containsString;
29 | import static org.hamcrest.CoreMatchers.is;
30 | import static org.hamcrest.MatcherAssert.assertThat;
31 |
32 | /**
33 | * @author Alexey Nikolaenko alexey@tcherezov.com
34 | * Date: 30/09/2015
35 | */
36 | public class FileDownloadServletTest extends BaseServletTest {
37 |
38 | private Server fileUploadServer;
39 | private HttpHost serverHost;
40 |
41 | @Before
42 | public void setUp() throws Exception {
43 | fileUploadServer = startServerForServlet(new FileDownloadServlet(), "/" + FileDownloadServlet.class.getSimpleName() + "/*");
44 | serverHost = new HttpHost("localhost", ((AbstractNetworkConnector) fileUploadServer.getConnectors()[0]).getLocalPort());
45 | }
46 |
47 | @After
48 | public void tearDown() throws Exception {
49 | fileUploadServer.stop();
50 | }
51 |
52 | @Test
53 | public void getShouldReturnFileContentsWithNameInHeader() throws IOException {
54 | File fileToGet = File.createTempFile("test filename with spaces", ".txt");
55 | FileUtils.write(fileToGet, "expected_content", StandardCharsets.UTF_8);
56 |
57 | CloseableHttpClient httpClient = HttpClients.createDefault();
58 |
59 | String encode = Base64.getUrlEncoder().encodeToString(fileToGet.getAbsolutePath().getBytes(StandardCharsets.UTF_8));
60 | HttpGet httpGet = new HttpGet("/FileDownloadServlet/" + encode);
61 |
62 | CloseableHttpResponse execute = httpClient.execute(serverHost, httpGet);
63 |
64 | //check contents are properly sent
65 | try (
66 | InputStream content = execute.getEntity().getContent()) {
67 | String s = IOUtils.toString(content, StandardCharsets.UTF_8);
68 | assertThat(s, is("expected_content"));
69 | }
70 |
71 | //check file name is available from header
72 | Header contentDispositionHeader = execute.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION);
73 | assertThat(contentDispositionHeader.getValue(), containsString("filename=" + fileToGet.getName()));
74 | //check file is not locked by anything
75 | assertTrue(fileToGet.delete());
76 | }
77 |
78 | @Test
79 | public void getShouldReturnBadRequestWhenFileNotExists() throws IOException {
80 | CloseableHttpClient httpClient = HttpClients.createDefault();
81 |
82 | String encode = Base64.getUrlEncoder().encodeToString("/some/location/".getBytes(StandardCharsets.UTF_8));
83 | HttpGet httpGet = new HttpGet("/FileDownloadServlet/" + encode);
84 |
85 | CloseableHttpResponse execute = httpClient.execute(serverHost, httpGet);
86 |
87 | int statusCode = execute.getStatusLine().getStatusCode();
88 | assertThat(statusCode, is(HttpStatus.SC_BAD_REQUEST));
89 |
90 | //check error message is set
91 | try (
92 | InputStream content = execute.getEntity().getContent()) {
93 | String s = IOUtils.toString(content, StandardCharsets.UTF_8);
94 | assertThat(s, is("Requested file doesn't exist."));
95 | }
96 | }
97 |
98 | @Test
99 | public void getShouldReturnBadRequestWhenFileIsDirectory() throws IOException {
100 | File directory = Files.createTempDir();
101 | CloseableHttpClient httpClient = HttpClients.createDefault();
102 |
103 | String encode = Base64.getUrlEncoder().encodeToString(directory.getAbsolutePath().getBytes(StandardCharsets.UTF_8));
104 | HttpGet httpGet = new HttpGet("/FileDownloadServlet/" + encode);
105 |
106 | CloseableHttpResponse execute = httpClient.execute(serverHost, httpGet);
107 |
108 | int statusCode = execute.getStatusLine().getStatusCode();
109 | assertThat(statusCode, is(HttpStatus.SC_BAD_REQUEST));
110 |
111 | //check error message is set
112 | try (
113 | InputStream content = execute.getEntity().getContent()) {
114 | String s = IOUtils.toString(content, StandardCharsets.UTF_8);
115 | assertThat(s, is("Requested file is directory."));
116 | }
117 | //check file is not locked by anything
118 | assertTrue(directory.delete());
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/node-extensions/file-extension/src/test/java/io/sterodium/extensions/node/upload/FileUploadServletTest.java:
--------------------------------------------------------------------------------
1 | package io.sterodium.extensions.node.upload;
2 |
3 |
4 | import io.sterodium.extensions.node.BaseServletTest;
5 | import com.google.common.net.HttpHeaders;
6 | import com.google.common.net.MediaType;
7 | import org.apache.commons.io.IOUtils;
8 | import org.apache.http.StatusLine;
9 | import org.apache.http.client.methods.CloseableHttpResponse;
10 | import org.apache.http.client.methods.HttpPost;
11 | import org.apache.http.entity.InputStreamEntity;
12 | import org.apache.http.impl.client.CloseableHttpClient;
13 | import org.apache.http.impl.client.HttpClients;
14 | import org.junit.After;
15 | import org.junit.Before;
16 | import org.junit.Test;
17 | import org.seleniumhq.jetty9.server.AbstractNetworkConnector;
18 | import org.seleniumhq.jetty9.server.Server;
19 |
20 | import java.io.File;
21 | import java.io.FileInputStream;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.nio.charset.StandardCharsets;
25 |
26 | import static org.hamcrest.CoreMatchers.equalTo;
27 | import static org.hamcrest.CoreMatchers.is;
28 | import static org.junit.Assert.assertThat;
29 |
30 | /**
31 | * @author Alexey Nikolaenko alexey@tcherezov.com
32 | * Date: 24/09/2015
33 | */
34 | public class FileUploadServletTest extends BaseServletTest {
35 |
36 | private int port;
37 | private File zipArchive;
38 | private Server fileUploadServer;
39 | private File unzippedFile;
40 | private File unzippedArchive;
41 |
42 | @Before
43 | public void setUp() throws Exception {
44 | fileUploadServer = startServerForServlet(new FileUploadServlet(), "/" + FileUploadServlet.class.getSimpleName() + "/*");
45 | port = ((AbstractNetworkConnector) fileUploadServer.getConnectors()[0]).getLocalPort();
46 |
47 | zipArchive = createZipArchiveWithTextFile();
48 | }
49 |
50 | @Test
51 | public void testDoPost() throws IOException {
52 | CloseableHttpClient httpClient = HttpClients.createDefault();
53 |
54 | HttpPost httpPost = new HttpPost("http://localhost:" + port + "/FileUploadServlet/");
55 | httpPost.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.OCTET_STREAM.toString());
56 |
57 | FileInputStream fileInputStream = new FileInputStream(zipArchive);
58 | InputStreamEntity entity = new InputStreamEntity(fileInputStream);
59 | httpPost.setEntity(entity);
60 |
61 | CloseableHttpResponse execute = httpClient.execute(httpPost);
62 |
63 | StatusLine statusLine = execute.getStatusLine();
64 | assertThat(statusLine.getStatusCode(), equalTo(200));
65 |
66 | try (
67 | InputStream content = execute.getEntity().getContent()) {
68 | String directory = IOUtils.toString(content, StandardCharsets.UTF_8);
69 | unzippedArchive = new File(directory);
70 | unzippedFile = new File(directory + "/" + ZIP_FILE_NAME);
71 | }
72 |
73 | assertThat(unzippedFile.exists(), is(true));
74 |
75 | try (FileInputStream unzippedFileStream = new FileInputStream(unzippedFile)) {
76 | String contents = IOUtils.toString(unzippedFileStream, StandardCharsets.UTF_8);
77 | assertThat(contents, is("test data"));
78 | }
79 | }
80 |
81 | @After
82 | public void tearDown() throws Exception {
83 | deleteIfExists(unzippedFile, unzippedArchive, zipArchive);
84 | fileUploadServer.stop();
85 | }
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/node-extensions/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |