48 import java.net.Socket; |
48 import java.net.Socket; |
49 import java.net.URL; |
49 import java.net.URL; |
50 import java.security.MessageDigest; |
50 import java.security.MessageDigest; |
51 import java.security.NoSuchAlgorithmException; |
51 import java.security.NoSuchAlgorithmException; |
52 import java.time.Instant; |
52 import java.time.Instant; |
|
53 import java.util.ArrayList; |
53 import java.util.Arrays; |
54 import java.util.Arrays; |
54 import java.util.Base64; |
55 import java.util.Base64; |
55 import java.util.List; |
56 import java.util.List; |
56 import java.util.Objects; |
57 import java.util.Objects; |
57 import java.util.Random; |
58 import java.util.Random; |
|
59 import java.util.concurrent.CopyOnWriteArrayList; |
58 import java.util.stream.Collectors; |
60 import java.util.stream.Collectors; |
59 import javax.net.ssl.SSLContext; |
61 import javax.net.ssl.SSLContext; |
60 import sun.net.www.HeaderParser; |
62 import sun.net.www.HeaderParser; |
61 |
63 |
62 /** |
64 /** |
143 default: |
145 default: |
144 throw new InternalError("Unknown server type: " + authType); |
146 throw new InternalError("Unknown server type: " + authType); |
145 } |
147 } |
146 } |
148 } |
147 |
149 |
|
150 /** |
|
151 * The HttpServerFactory ensures that the local port used by an HttpServer |
|
152 * previously created by the current test/VM will not get reused by |
|
153 * a subsequent test in the same VM. This is to avoid having the |
|
154 * AuthCache reuse credentials from previous tests - which would |
|
155 * invalidate the assumptions made by the current test on when |
|
156 * the default authenticator should be called. |
|
157 */ |
|
158 private static final class HttpServerFactory { |
|
159 private static final int MAX = 10; |
|
160 private static final CopyOnWriteArrayList<String> addresses = |
|
161 new CopyOnWriteArrayList<>(); |
|
162 private static HttpServer newHttpServer(HttpProtocolType protocol) |
|
163 throws IOException { |
|
164 switch (protocol) { |
|
165 case HTTP: return HttpServer.create(); |
|
166 case HTTPS: return HttpsServer.create(); |
|
167 default: throw new InternalError("Unsupported protocol " + protocol); |
|
168 } |
|
169 } |
|
170 static <T extends HttpServer> T create(HttpProtocolType protocol) |
|
171 throws IOException { |
|
172 final int max = addresses.size() + MAX; |
|
173 final List<HttpServer> toClose = new ArrayList<>(); |
|
174 try { |
|
175 for (int i = 1; i <= max; i++) { |
|
176 HttpServer server = newHttpServer(protocol); |
|
177 server.bind(new InetSocketAddress("127.0.0.1", 0), 0); |
|
178 InetSocketAddress address = server.getAddress(); |
|
179 String key = address.toString(); |
|
180 if (addresses.addIfAbsent(key)) { |
|
181 System.out.println("Server bound to: " + key |
|
182 + " after " + i + " attempt(s)"); |
|
183 return (T) server; |
|
184 } |
|
185 System.out.println("warning: address " + key |
|
186 + " already used. Retrying bind."); |
|
187 // keep the port bound until we get a port that we haven't |
|
188 // used already |
|
189 toClose.add(server); |
|
190 } |
|
191 } finally { |
|
192 // if we had to retry, then close the servers we're not |
|
193 // going to use. |
|
194 for (HttpServer s : toClose) { |
|
195 try { s.stop(1); } catch (Exception x) { /* ignore */ } |
|
196 } |
|
197 } |
|
198 throw new IOException("Couldn't bind servers after " + max + " attempts: " |
|
199 + "addresses used before: " + addresses); |
|
200 } |
|
201 } |
|
202 |
148 static HttpServer createHttpServer(HttpProtocolType protocol) throws IOException { |
203 static HttpServer createHttpServer(HttpProtocolType protocol) throws IOException { |
149 switch (protocol) { |
204 switch (protocol) { |
150 case HTTP: return HttpServer.create(); |
205 case HTTP: return HttpServerFactory.create(protocol); |
151 case HTTPS: return configure(HttpsServer.create()); |
206 case HTTPS: return configure(HttpServerFactory.create(protocol)); |
152 default: throw new InternalError("Unsupported protocol " + protocol); |
207 default: throw new InternalError("Unsupported protocol " + protocol); |
153 } |
208 } |
154 } |
209 } |
155 |
210 |
156 static HttpsServer configure(HttpsServer server) throws IOException { |
211 static HttpsServer configure(HttpsServer server) throws IOException { |
191 HttpServer impl = createHttpServer(protocol); |
246 HttpServer impl = createHttpServer(protocol); |
192 final HTTPTestServer server = new HTTPTestServer(impl, null, delegate); |
247 final HTTPTestServer server = new HTTPTestServer(impl, null, delegate); |
193 final HttpHandler hh = server.createHandler(schemeType, auth, authType); |
248 final HttpHandler hh = server.createHandler(schemeType, auth, authType); |
194 HttpContext ctxt = impl.createContext(path, hh); |
249 HttpContext ctxt = impl.createContext(path, hh); |
195 server.configureAuthentication(ctxt, schemeType, auth, authType); |
250 server.configureAuthentication(ctxt, schemeType, auth, authType); |
196 impl.bind(new InetSocketAddress("127.0.0.1", 0), 0); |
|
197 impl.start(); |
251 impl.start(); |
198 return server; |
252 return server; |
199 } |
253 } |
200 |
254 |
201 public static HTTPTestServer createProxy(HttpProtocolType protocol, |
255 public static HTTPTestServer createProxy(HttpProtocolType protocol, |
213 ? new HttpsProxyTunnel(impl, null, delegate) |
267 ? new HttpsProxyTunnel(impl, null, delegate) |
214 : new HTTPTestServer(impl, null, delegate); |
268 : new HTTPTestServer(impl, null, delegate); |
215 final HttpHandler hh = server.createHandler(schemeType, auth, authType); |
269 final HttpHandler hh = server.createHandler(schemeType, auth, authType); |
216 HttpContext ctxt = impl.createContext(path, hh); |
270 HttpContext ctxt = impl.createContext(path, hh); |
217 server.configureAuthentication(ctxt, schemeType, auth, authType); |
271 server.configureAuthentication(ctxt, schemeType, auth, authType); |
218 |
|
219 impl.bind(new InetSocketAddress("127.0.0.1", 0), 0); |
|
220 impl.start(); |
272 impl.start(); |
221 |
273 |
222 return server; |
274 return server; |
223 } |
275 } |
224 |
276 |
251 InetSocketAddress redirectAddr = redirectTarget.getAddress(); |
303 InetSocketAddress redirectAddr = redirectTarget.getAddress(); |
252 URL locationURL = url(targetProtocol, redirectAddr, "/"); |
304 URL locationURL = url(targetProtocol, redirectAddr, "/"); |
253 final HttpHandler hh = redirectingServer.create300Handler(locationURL, |
305 final HttpHandler hh = redirectingServer.create300Handler(locationURL, |
254 HttpAuthType.SERVER, code300); |
306 HttpAuthType.SERVER, code300); |
255 impl.createContext("/", hh); |
307 impl.createContext("/", hh); |
256 impl.bind(new InetSocketAddress("127.0.0.1", 0), 0); |
|
257 impl.start(); |
308 impl.start(); |
258 return redirectingServer; |
309 return redirectingServer; |
259 } |
310 } |
260 |
311 |
261 public InetSocketAddress getAddress() { |
312 public InetSocketAddress getAddress() { |