|
18 | 18 | */
|
19 | 19 | package org.elasticsearch.repositories.url;
|
20 | 20 |
|
21 |
| -import com.sun.net.httpserver.HttpExchange; |
22 |
| -import com.sun.net.httpserver.HttpHandler; |
23 |
| -import com.sun.net.httpserver.HttpServer; |
| 21 | +import org.elasticsearch.test.fixture.AbstractHttpFixture; |
24 | 22 | import org.elasticsearch.common.SuppressForbidden;
|
25 |
| -import org.elasticsearch.mocksocket.MockHttpServer; |
26 | 23 | import org.elasticsearch.rest.RestStatus;
|
27 | 24 |
|
28 | 25 | import java.io.IOException;
|
29 |
| -import java.lang.management.ManagementFactory; |
30 |
| -import java.net.Inet6Address; |
31 |
| -import java.net.InetAddress; |
32 |
| -import java.net.InetSocketAddress; |
33 |
| -import java.net.SocketAddress; |
34 |
| -import java.nio.charset.StandardCharsets; |
35 | 26 | import java.nio.file.Files;
|
36 | 27 | import java.nio.file.Path;
|
37 | 28 | import java.nio.file.Paths;
|
38 |
| -import java.nio.file.StandardCopyOption; |
| 29 | +import java.util.HashMap; |
39 | 30 | import java.util.Map;
|
40 |
| -import java.util.Objects; |
41 |
| - |
42 |
| -import static java.nio.charset.StandardCharsets.UTF_8; |
43 |
| -import static java.util.Collections.emptyMap; |
44 |
| -import static java.util.Collections.singleton; |
45 |
| -import static java.util.Collections.singletonMap; |
46 | 31 |
|
47 | 32 | /**
|
48 | 33 | * This {@link URLFixture} exposes a filesystem directory over HTTP. It is used in repository-url
|
49 | 34 | * integration tests to expose a directory created by a regular FS repository.
|
50 | 35 | */
|
51 |
| -public class URLFixture { |
| 36 | +public class URLFixture extends AbstractHttpFixture { |
| 37 | + |
| 38 | + private final Path repositoryDir; |
| 39 | + |
| 40 | + /** |
| 41 | + * Creates a {@link URLFixture} |
| 42 | + */ |
| 43 | + private URLFixture(final String workingDir, final String repositoryDir) { |
| 44 | + super(workingDir); |
| 45 | + this.repositoryDir = dir(repositoryDir); |
| 46 | + } |
52 | 47 |
|
53 | 48 | public static void main(String[] args) throws Exception {
|
54 | 49 | if (args == null || args.length != 2) {
|
55 | 50 | throw new IllegalArgumentException("URLFixture <working directory> <repository directory>");
|
56 | 51 | }
|
57 | 52 |
|
58 |
| - final InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); |
59 |
| - final HttpServer httpServer = MockHttpServer.createHttp(socketAddress, 0); |
60 |
| - |
61 |
| - try { |
62 |
| - final Path workingDirectory = dir(args[0]); |
63 |
| - /// Writes the PID of the current Java process in a `pid` file located in the working directory |
64 |
| - writeFile(workingDirectory, "pid", ManagementFactory.getRuntimeMXBean().getName().split("@")[0]); |
65 |
| - |
66 |
| - final String addressAndPort = addressToString(httpServer.getAddress()); |
67 |
| - // Writes the address and port of the http server in a `ports` file located in the working directory |
68 |
| - writeFile(workingDirectory, "ports", addressAndPort); |
69 |
| - |
70 |
| - // Exposes the repository over HTTP |
71 |
| - httpServer.createContext("/", new ResponseHandler(dir(args[1]))); |
72 |
| - httpServer.start(); |
73 |
| - |
74 |
| - // Wait to be killed |
75 |
| - Thread.sleep(Long.MAX_VALUE); |
76 |
| - |
77 |
| - } finally { |
78 |
| - httpServer.stop(0); |
79 |
| - } |
80 |
| - } |
81 |
| - |
82 |
| - @SuppressForbidden(reason = "Paths#get is fine - we don't have environment here") |
83 |
| - private static Path dir(final String dir) { |
84 |
| - return Paths.get(dir); |
85 |
| - } |
86 |
| - |
87 |
| - private static void writeFile(final Path dir, final String fileName, final String content) throws IOException { |
88 |
| - final Path tempPidFile = Files.createTempFile(dir, null, null); |
89 |
| - Files.write(tempPidFile, singleton(content)); |
90 |
| - Files.move(tempPidFile, dir.resolve(fileName), StandardCopyOption.ATOMIC_MOVE); |
| 53 | + final URLFixture fixture = new URLFixture(args[0], args[1]); |
| 54 | + fixture.listen(); |
91 | 55 | }
|
92 | 56 |
|
93 |
| - private static String addressToString(final SocketAddress address) { |
94 |
| - final InetSocketAddress inetSocketAddress = (InetSocketAddress) address; |
95 |
| - if (inetSocketAddress.getAddress() instanceof Inet6Address) { |
96 |
| - return "[" + inetSocketAddress.getHostString() + "]:" + inetSocketAddress.getPort(); |
97 |
| - } else { |
98 |
| - return inetSocketAddress.getHostString() + ":" + inetSocketAddress.getPort(); |
99 |
| - } |
100 |
| - } |
101 |
| - |
102 |
| - static class ResponseHandler implements HttpHandler { |
103 |
| - |
104 |
| - private final Path repositoryDir; |
105 |
| - |
106 |
| - ResponseHandler(final Path repositoryDir) { |
107 |
| - this.repositoryDir = repositoryDir; |
108 |
| - } |
109 |
| - |
110 |
| - @Override |
111 |
| - public void handle(HttpExchange exchange) throws IOException { |
112 |
| - Response response; |
113 |
| - |
114 |
| - final String userAgent = exchange.getRequestHeaders().getFirst("User-Agent"); |
115 |
| - if (userAgent != null && userAgent.startsWith("Apache Ant")) { |
116 |
| - // This is a request made by the AntFixture, just reply "OK" |
117 |
| - response = new Response(RestStatus.OK, emptyMap(), "text/plain; charset=utf-8", "OK".getBytes(UTF_8)); |
118 |
| - |
119 |
| - } else if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) { |
120 |
| - String path = exchange.getRequestURI().toString(); |
121 |
| - if (path.length() > 0 && path.charAt(0) == '/') { |
122 |
| - path = path.substring(1); |
123 |
| - } |
| 57 | + @Override |
| 58 | + protected AbstractHttpFixture.Response handle(final Request request) throws IOException { |
| 59 | + if ("GET".equalsIgnoreCase(request.getMethod())) { |
| 60 | + String path = request.getPath(); |
| 61 | + if (path.length() > 0 && path.charAt(0) == '/') { |
| 62 | + path = path.substring(1); |
| 63 | + } |
124 | 64 |
|
125 |
| - Path normalizedRepositoryDir = repositoryDir.normalize(); |
126 |
| - Path normalizedPath = normalizedRepositoryDir.resolve(path).normalize(); |
| 65 | + Path normalizedRepositoryDir = repositoryDir.normalize(); |
| 66 | + Path normalizedPath = normalizedRepositoryDir.resolve(path).normalize(); |
127 | 67 |
|
128 |
| - if (normalizedPath.startsWith(normalizedRepositoryDir)) { |
129 |
| - if (Files.exists(normalizedPath) && Files.isReadable(normalizedPath) && Files.isRegularFile(normalizedPath)) { |
130 |
| - byte[] content = Files.readAllBytes(normalizedPath); |
131 |
| - Map<String, String> headers = singletonMap("Content-Length", String.valueOf(content.length)); |
132 |
| - response = new Response(RestStatus.OK, headers, "application/octet-stream", content); |
133 |
| - } else { |
134 |
| - response = new Response(RestStatus.NOT_FOUND, emptyMap(), "text/plain; charset=utf-8", new byte[0]); |
135 |
| - } |
| 68 | + if (normalizedPath.startsWith(normalizedRepositoryDir)) { |
| 69 | + if (Files.exists(normalizedPath) && Files.isReadable(normalizedPath) && Files.isRegularFile(normalizedPath)) { |
| 70 | + byte[] content = Files.readAllBytes(normalizedPath); |
| 71 | + final Map<String, String> headers = new HashMap<>(contentType("application/octet-stream")); |
| 72 | + headers.put("Content-Length", String.valueOf(content.length)); |
| 73 | + return new Response(RestStatus.OK.getStatus(), headers, content); |
136 | 74 | } else {
|
137 |
| - response = new Response(RestStatus.FORBIDDEN, emptyMap(), "text/plain; charset=utf-8", new byte[0]); |
| 75 | + return new Response(RestStatus.NOT_FOUND.getStatus(), TEXT_PLAIN_CONTENT_TYPE, EMPTY_BYTE); |
138 | 76 | }
|
139 | 77 | } else {
|
140 |
| - response = new Response(RestStatus.INTERNAL_SERVER_ERROR, emptyMap(), "text/plain; charset=utf-8", |
141 |
| - "Unsupported HTTP method".getBytes(StandardCharsets.UTF_8)); |
| 78 | + return new Response(RestStatus.FORBIDDEN.getStatus(), TEXT_PLAIN_CONTENT_TYPE, EMPTY_BYTE); |
142 | 79 | }
|
143 |
| - exchange.sendResponseHeaders(response.status.getStatus(), response.body.length); |
144 |
| - if (response.body.length > 0) { |
145 |
| - exchange.getResponseBody().write(response.body); |
146 |
| - } |
147 |
| - exchange.close(); |
148 | 80 | }
|
| 81 | + return null; |
149 | 82 | }
|
150 | 83 |
|
151 |
| - /** |
152 |
| - * Represents a HTTP Response. |
153 |
| - */ |
154 |
| - static class Response { |
155 |
| - |
156 |
| - final RestStatus status; |
157 |
| - final Map<String, String> headers; |
158 |
| - final String contentType; |
159 |
| - final byte[] body; |
160 |
| - |
161 |
| - Response(final RestStatus status, final Map<String, String> headers, final String contentType, final byte[] body) { |
162 |
| - this.status = Objects.requireNonNull(status); |
163 |
| - this.headers = Objects.requireNonNull(headers); |
164 |
| - this.contentType = Objects.requireNonNull(contentType); |
165 |
| - this.body = Objects.requireNonNull(body); |
166 |
| - } |
| 84 | + @SuppressForbidden(reason = "Paths#get is fine - we don't have environment here") |
| 85 | + private static Path dir(final String dir) { |
| 86 | + return Paths.get(dir); |
167 | 87 | }
|
168 | 88 | }
|
0 commit comments