|
28 | 28 | import com.google.api.services.dns.model.Project;
|
29 | 29 | import com.google.api.services.dns.model.Quota;
|
30 | 30 | import com.google.api.services.dns.model.ResourceRecordSet;
|
| 31 | +import com.google.cloud.AuthCredentials; |
31 | 32 | import com.google.cloud.dns.DnsOptions;
|
32 | 33 | import com.google.common.annotations.VisibleForTesting;
|
33 | 34 | import com.google.common.base.Joiner;
|
|
38 | 39 | import com.google.common.collect.Lists;
|
39 | 40 | import com.google.common.collect.Sets;
|
40 | 41 | import com.google.common.io.ByteStreams;
|
41 |
| - |
42 | 42 | import com.sun.net.httpserver.Headers;
|
43 | 43 | import com.sun.net.httpserver.HttpExchange;
|
44 | 44 | import com.sun.net.httpserver.HttpHandler;
|
@@ -282,18 +282,13 @@ private String toJson(String message) throws IOException {
|
282 | 282 | private class RequestHandler implements HttpHandler {
|
283 | 283 |
|
284 | 284 | private Response pickHandler(HttpExchange exchange, CallRegex regex) {
|
285 |
| - URI relative = null; |
286 |
| - try { |
287 |
| - relative = BASE_CONTEXT.relativize(new URI(exchange.getRequestURI().getRawPath())); |
288 |
| - } catch (URISyntaxException e) { |
289 |
| - return Error.INTERNAL_ERROR.response("Parsing URI failed."); |
290 |
| - } |
| 285 | + URI relative = BASE_CONTEXT.relativize(exchange.getRequestURI()); |
291 | 286 | String path = relative.getPath();
|
292 | 287 | String[] tokens = path.split("/");
|
293 | 288 | String projectId = tokens.length > 0 ? tokens[0] : null;
|
294 | 289 | String zoneName = tokens.length > 2 ? tokens[2] : null;
|
295 | 290 | String changeId = tokens.length > 4 ? tokens[4] : null;
|
296 |
| - String query = exchange.getRequestURI().getQuery(); |
| 291 | + String query = relative.getQuery(); |
297 | 292 | switch (regex) {
|
298 | 293 | case CHANGE_GET:
|
299 | 294 | return getChange(projectId, zoneName, changeId, query);
|
@@ -324,7 +319,7 @@ private Response pickHandler(HttpExchange exchange, CallRegex regex) {
|
324 | 319 | case BATCH:
|
325 | 320 | try {
|
326 | 321 | return handleBatch(exchange);
|
327 |
| - } catch (IOException ex) { |
| 322 | + } catch (IOException | URISyntaxException ex) { |
328 | 323 | return Error.BAD_REQUEST.response(ex.getMessage());
|
329 | 324 | }
|
330 | 325 | default:
|
@@ -352,58 +347,75 @@ public void handle(HttpExchange exchange) throws IOException {
|
352 | 347 | requestMethod, exchange.getRequestURI())));
|
353 | 348 | }
|
354 | 349 |
|
355 |
| - private Response handleBatch(final HttpExchange exchange) throws IOException { |
| 350 | + private Response handleBatch(final HttpExchange exchange) throws IOException, |
| 351 | + URISyntaxException { |
356 | 352 | String contentType = exchange.getRequestHeaders().getFirst("Content-type");
|
357 | 353 | if (contentType != null) {
|
358 |
| - int port = server.getAddress().getPort(); |
359 | 354 | HttpMediaType httpMediaType = new HttpMediaType(contentType);
|
360 | 355 | String boundary = httpMediaType.getParameter("boundary");
|
361 | 356 | MultipartStream multipartStream =
|
362 | 357 | new MultipartStream(exchange.getRequestBody(), boundary.getBytes(), 1024, null);
|
363 | 358 | ByteArrayOutputStream out = new ByteArrayOutputStream();
|
364 | 359 | byte[] bytes = new byte[1024];
|
365 |
| - multipartStream.skipPreamble(); |
366 |
| - while (multipartStream.readBoundary()) { |
367 |
| - Socket socket = new Socket("localhost", port); |
368 |
| - OutputStream socketOutput = socket.getOutputStream(); |
369 |
| - ByteArrayOutputStream section = new ByteArrayOutputStream(); |
370 |
| - multipartStream.readBodyData(section); |
| 360 | + boolean nextPart = multipartStream.skipPreamble(); |
| 361 | + while (nextPart) { |
371 | 362 | String line;
|
372 | 363 | String contentId = null;
|
373 |
| - Scanner scanner = new Scanner(new String(section.toByteArray())); |
| 364 | + String headers = multipartStream.readHeaders(); |
| 365 | + Scanner scanner = new Scanner(headers); |
374 | 366 | while (scanner.hasNextLine()) {
|
375 | 367 | line = scanner.nextLine();
|
376 |
| - if(line.isEmpty()) { |
377 |
| - break; |
378 |
| - } else if (line.toLowerCase().startsWith("content-id")) { |
| 368 | + if (line.toLowerCase().startsWith("content-id")) { |
379 | 369 | contentId = line.split(":")[1].trim();
|
380 | 370 | }
|
381 | 371 | }
|
382 |
| - String requestLine = scanner.nextLine(); |
383 |
| - socketOutput.write((requestLine + " \r\n").getBytes()); |
384 |
| - socketOutput.write("Connection: close \r\n".getBytes()); |
385 |
| - while(scanner.hasNextLine()) { |
386 |
| - line = scanner.nextLine(); |
387 |
| - socketOutput.write(line.getBytes()); |
388 |
| - if (!line.isEmpty()) { |
389 |
| - socketOutput.write(" \r\n".getBytes()); |
390 |
| - } else { |
391 |
| - socketOutput.write("\r\n".getBytes()); |
| 372 | + // TODO: remove and write directly to socket once api client provides a complete |
| 373 | + // location line (e.g. GET /aaa/bbb HTTP/1.0) |
| 374 | + // and uses a request path for location instead of a complete URL. |
| 375 | + ByteArrayOutputStream bouts = new ByteArrayOutputStream(); |
| 376 | + multipartStream.readBodyData(bouts); |
| 377 | + byte[] contentBytes = bouts.toByteArray(); |
| 378 | + int indexOfCr = -1; |
| 379 | + for (int i = 0; i < contentBytes.length; i++) { |
| 380 | + if (contentBytes[i] == '\r') { |
| 381 | + indexOfCr = i; |
| 382 | + break; |
392 | 383 | }
|
393 | 384 | }
|
| 385 | + Socket socket = new Socket("127.0.0.1", server.getAddress().getPort()); |
| 386 | + OutputStream socketOutput = socket.getOutputStream(); |
| 387 | + InputStream socketInput = socket.getInputStream(); |
| 388 | + //multipartStream.readBodyData(socketOutput); |
| 389 | + if (indexOfCr < 0) { |
| 390 | + socketOutput.write(contentBytes); |
| 391 | + } else { |
| 392 | + String[] requestLine = |
| 393 | + new String(contentBytes, 0, indexOfCr, StandardCharsets.UTF_8).split(" "); |
| 394 | + socketOutput.write(requestLine[0].getBytes()); |
| 395 | + socketOutput.write(' '); |
| 396 | + URI uri = new URI(requestLine[1]); |
| 397 | + socketOutput.write(uri.getRawPath().getBytes()); |
| 398 | + if (uri.getRawQuery() != null) { |
| 399 | + socketOutput.write('?'); |
| 400 | + socketOutput.write(uri.getRawQuery().getBytes()); |
| 401 | + } |
| 402 | + if (uri.getRawFragment() != null) { |
| 403 | + socketOutput.write('#'); |
| 404 | + socketOutput.write(uri.getRawFragment().getBytes()); |
| 405 | + } |
| 406 | + socketOutput.write(" HTTP/1.0".getBytes()); |
| 407 | + socketOutput.write(contentBytes, indexOfCr, contentBytes.length - indexOfCr); |
| 408 | + } |
394 | 409 | socketOutput.flush();
|
395 |
| - InputStream in = socket.getInputStream(); |
396 |
| - int length; |
397 | 410 | out.write(RESPONSE_SEPARATOR.getBytes());
|
398 |
| - out.write("Content-Type: application/http \r\n".getBytes()); |
399 |
| - out.write(("Content-ID: " + contentId + " \r\n\r\n").getBytes()); |
400 |
| - try { |
401 |
| - while ((length = in.read(bytes)) != -1) { |
402 |
| - out.write(bytes, 0, length); |
403 |
| - } |
404 |
| - } catch (IOException ex) { |
405 |
| - // this handles connection reset error |
| 411 | + out.write("Content-Type: application/http\r\n".getBytes()); |
| 412 | + out.write(("Content-ID: " + contentId + "\r\n\r\n").getBytes()); |
| 413 | + int length; |
| 414 | + while ((length = socketInput.read(bytes)) != -1) { |
| 415 | + out.write(bytes, 0, length); |
406 | 416 | }
|
| 417 | + socket.close(); |
| 418 | + nextPart = multipartStream.skipPreamble(); |
407 | 419 | }
|
408 | 420 | out.write(RESPONSE_END.getBytes());
|
409 | 421 | writeBatchResponse(exchange, out);
|
@@ -483,7 +495,11 @@ public static LocalDnsHelper create(Long delay) {
|
483 | 495 | * Returns a {@link DnsOptions} instance that sets the host to use the mock server.
|
484 | 496 | */
|
485 | 497 | public DnsOptions options() {
|
486 |
| - return DnsOptions.builder().projectId(PROJECT_ID).host("http://localhost:" + port).build(); |
| 498 | + return DnsOptions.builder() |
| 499 | + .projectId(PROJECT_ID) |
| 500 | + .host("http://localhost:" + port) |
| 501 | + .authCredentials(AuthCredentials.noAuth()) |
| 502 | + .build(); |
487 | 503 | }
|
488 | 504 |
|
489 | 505 | /**
|
|
0 commit comments