|
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