|
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