| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -40,6 +40,11 @@ | |||
| 40 | 40 | </exclusion> | |
| 41 | 41 | </exclusions> | |
| 42 | 42 | </dependency> | |
| 43 | + <dependency> | ||
| 44 | + <groupId>commons-fileupload</groupId> | ||
| 45 | + <artifactId>commons-fileupload</artifactId> | ||
| 46 | + <version>1.3.1</version> | ||
| 47 | + </dependency> | ||
| 43 | 48 | <dependency> | |
| 44 | 49 | <groupId>${project.groupId}</groupId> | |
| 45 | 50 | <artifactId>gcloud-java-core</artifactId> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,6 +20,7 @@ | |||
| 20 | 20 | import static java.net.HttpURLConnection.HTTP_NO_CONTENT; | |
| 21 | 21 | import static java.net.HttpURLConnection.HTTP_OK; | |
| 22 | 22 | ||
| 23 | + import com.google.api.client.http.HttpMediaType; | ||
| 23 | 24 | import com.google.api.client.json.JsonFactory; | |
| 24 | 25 | import com.google.api.client.json.jackson.JacksonFactory; | |
| 25 | 26 | import com.google.api.services.dns.model.Change; | |
@@ -43,13 +44,16 @@ | |||
| 43 | 44 | import com.sun.net.httpserver.HttpHandler; | |
| 44 | 45 | import com.sun.net.httpserver.HttpServer; | |
| 45 | 46 | ||
| 47 | + import org.apache.commons.fileupload.MultipartStream; | ||
| 46 | 48 | import org.joda.time.format.ISODateTimeFormat; | |
| 47 | 49 | ||
| 50 | + import java.io.ByteArrayOutputStream; | ||
| 48 | 51 | import java.io.IOException; | |
| 49 | 52 | import java.io.InputStream; | |
| 50 | 53 | import java.io.OutputStream; | |
| 51 | 54 | import java.math.BigInteger; | |
| 52 | 55 | import java.net.InetSocketAddress; | |
| 56 | + import java.net.Socket; | ||
| 53 | 57 | import java.net.URI; | |
| 54 | 58 | import java.net.URISyntaxException; | |
| 55 | 59 | import java.nio.charset.StandardCharsets; | |
@@ -62,6 +66,7 @@ | |||
| 62 | 66 | import java.util.NavigableMap; | |
| 63 | 67 | import java.util.NavigableSet; | |
| 64 | 68 | import java.util.Random; | |
| 69 | + import java.util.Scanner; | ||
| 65 | 70 | import java.util.Set; | |
| 66 | 71 | import java.util.SortedMap; | |
| 67 | 72 | import java.util.TreeMap; | |
@@ -112,6 +117,9 @@ public class LocalDnsHelper { | |||
| 112 | 117 | private static final ScheduledExecutorService EXECUTORS = | |
| 113 | 118 | Executors.newScheduledThreadPool(2, Executors.defaultThreadFactory()); | |
| 114 | 119 | private static final String PROJECT_ID = "dummyprojectid"; | |
| 120 | + private static final String RESPONSE_BOUNDARY = "____THIS_IS_HELPERS_BOUNDARY____"; | ||
| 121 | + private static final String RESPONSE_SEPARATOR = "--" + RESPONSE_BOUNDARY + "\r\n"; | ||
| 122 | + private static final String RESPONSE_END = "--" + RESPONSE_BOUNDARY + "--\r\n\r\n"; | ||
| 115 | 123 | ||
| 116 | 124 | static { | |
| 117 | 125 | try { | |
@@ -138,7 +146,8 @@ private enum CallRegex { | |||
| 138 | 146 | ZONE_GET("GET", CONTEXT + "/[^/]+/managedZones/[^/]+"), | |
| 139 | 147 | ZONE_LIST("GET", CONTEXT + "/[^/]+/managedZones"), | |
| 140 | 148 | PROJECT_GET("GET", CONTEXT + "/[^/]+"), | |
| 141 | - RECORD_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/rrsets"); | ||
| 149 | + RECORD_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/rrsets"), | ||
| 150 | + BATCH("POST", "/batch"); | ||
| 142 | 151 | ||
| 143 | 152 | private final String method; | |
| 144 | 153 | private final String pathRegex; | |
@@ -273,13 +282,18 @@ private String toJson(String message) throws IOException { | |||
| 273 | 282 | private class RequestHandler implements HttpHandler { | |
| 274 | 283 | ||
| 275 | 284 | private Response pickHandler(HttpExchange exchange, CallRegex regex) { | |
| 276 | - URI relative = BASE_CONTEXT.relativize(exchange.getRequestURI()); | ||
| 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 | + } | ||
| 277 | 291 | String path = relative.getPath(); | |
| 278 | 292 | String[] tokens = path.split("/"); | |
| 279 | 293 | String projectId = tokens.length > 0 ? tokens[0] : null; | |
| 280 | 294 | String zoneName = tokens.length > 2 ? tokens[2] : null; | |
| 281 | 295 | String changeId = tokens.length > 4 ? tokens[4] : null; | |
| 282 | - String query = relative.getQuery(); | ||
| 296 | + String query = exchange.getRequestURI().getQuery(); | ||
| 283 | 297 | switch (regex) { | |
| 284 | 298 | case CHANGE_GET: | |
| 285 | 299 | return getChange(projectId, zoneName, changeId, query); | |
@@ -307,6 +321,12 @@ private Response pickHandler(HttpExchange exchange, CallRegex regex) { | |||
| 307 | 321 | } catch (IOException ex) { | |
| 308 | 322 | return Error.BAD_REQUEST.response(ex.getMessage()); | |
| 309 | 323 | } | |
| 324 | + case BATCH: | ||
| 325 | + try { | ||
| 326 | + return handleBatch(exchange); | ||
| 327 | + } catch (IOException ex) { | ||
| 328 | + return Error.BAD_REQUEST.response(ex.getMessage()); | ||
| 329 | + } | ||
| 310 | 330 | default: | |
| 311 | 331 | return Error.INTERNAL_ERROR.response("Operation without a handler."); | |
| 312 | 332 | } | |
@@ -319,7 +339,11 @@ public void handle(HttpExchange exchange) throws IOException { | |||
| 319 | 339 | for (CallRegex regex : CallRegex.values()) { | |
| 320 | 340 | if (requestMethod.equals(regex.method) && rawPath.matches(regex.pathRegex)) { | |
| 321 | 341 | Response response = pickHandler(exchange, regex); | |
| 322 | - writeResponse(exchange, response); | ||
| 342 | + if (response != null) { | ||
| 343 | + /* null response is returned by batch request, because it handles writing | ||
| 344 | + the response on its own */ | ||
| 345 | + writeResponse(exchange, response); | ||
| 346 | + } | ||
| 323 | 347 | return; | |
| 324 | 348 | } | |
| 325 | 349 | } | |
@@ -328,6 +352,67 @@ public void handle(HttpExchange exchange) throws IOException { | |||
| 328 | 352 | requestMethod, exchange.getRequestURI()))); | |
| 329 | 353 | } | |
| 330 | 354 | ||
| 355 | + private Response handleBatch(final HttpExchange exchange) throws IOException { | ||
| 356 | + String contentType = exchange.getRequestHeaders().getFirst("Content-type"); | ||
| 357 | + if (contentType != null) { | ||
| 358 | + int port = server.getAddress().getPort(); | ||
| 359 | + HttpMediaType httpMediaType = new HttpMediaType(contentType); | ||
| 360 | + String boundary = httpMediaType.getParameter("boundary"); | ||
| 361 | + MultipartStream multipartStream = | ||
| 362 | + new MultipartStream(exchange.getRequestBody(), boundary.getBytes(), 1024, null); | ||
| 363 | + ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
| 364 | + 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); | ||
| 371 | + String line; | ||
| 372 | + String contentId = null; | ||
| 373 | + Scanner scanner = new Scanner(new String(section.toByteArray())); | ||
| 374 | + while (scanner.hasNextLine()) { | ||
| 375 | + line = scanner.nextLine(); | ||
| 376 | + if(line.isEmpty()) { | ||
| 377 | + break; | ||
| 378 | + } else if (line.toLowerCase().startsWith("content-id")) { | ||
| 379 | + contentId = line.split(":")[1].trim(); | ||
| 380 | + } | ||
| 381 | + } | ||
| 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()); | ||
| 392 | + } | ||
| 393 | + } | ||
| 394 | + socketOutput.flush(); | ||
| 395 | + InputStream in = socket.getInputStream(); | ||
| 396 | + int length; | ||
| 397 | + 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 | ||
| 406 | + } | ||
| 407 | + } | ||
| 408 | + out.write(RESPONSE_END.getBytes()); | ||
| 409 | + writeBatchResponse(exchange, out); | ||
| 410 | + } else { | ||
| 411 | + return Error.BAD_REQUEST.response("Content-type header was not provided for batch."); | ||
| 412 | + } | ||
| 413 | + return null; | ||
| 414 | + } | ||
| 415 | + | ||
| 331 | 416 | /** | |
| 332 | 417 | * @throws IOException if the request cannot be parsed. | |
| 333 | 418 | */ | |
@@ -368,7 +453,8 @@ private LocalDnsHelper(long delay) { | |||
| 368 | 453 | try { | |
| 369 | 454 | server = HttpServer.create(new InetSocketAddress(0), 0); | |
| 370 | 455 | port = server.getAddress().getPort(); | |
| 371 | - server.createContext(CONTEXT, new RequestHandler()); | ||
| 456 | + server.setExecutor(Executors.newCachedThreadPool()); | ||
| 457 | + server.createContext("/", new RequestHandler()); | ||
| 372 | 458 | } catch (IOException e) { | |
| 373 | 459 | throw new RuntimeException("Could not bind the mock DNS server.", e); | |
| 374 | 460 | } | |
@@ -430,6 +516,20 @@ private static void writeResponse(HttpExchange exchange, Response response) { | |||
| 430 | 516 | } | |
| 431 | 517 | } | |
| 432 | 518 | ||
| 519 | + private static void writeBatchResponse(HttpExchange exchange, ByteArrayOutputStream output) { | ||
| 520 | + exchange.getResponseHeaders().set( | ||
| 521 | + "Content-type", "multipart/mixed; boundary=" + RESPONSE_BOUNDARY); | ||
| 522 | + try { | ||
| 523 | + exchange.getResponseHeaders().add("Connection", "close"); | ||
| 524 | + exchange.sendResponseHeaders(200, output.toByteArray().length); | ||
| 525 | + OutputStream responseBody = exchange.getResponseBody(); | ||
| 526 | + output.writeTo(responseBody); | ||
| 527 | + responseBody.close(); | ||
| 528 | + } catch (IOException e) { | ||
| 529 | + log.log(Level.WARNING, "IOException encountered when sending response.", e); | ||
| 530 | + } | ||
| 531 | + } | ||
| 532 | + | ||
| 433 | 533 | private static String decodeContent(Headers headers, InputStream inputStream) throws IOException { | |
| 434 | 534 | List<String> contentEncoding = headers.get("Content-encoding"); | |
| 435 | 535 | InputStream input = inputStream; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments