1 /* |
1 /* |
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
267 if (Arrays.compare(clientPreface, bytes) != 0) { |
267 if (Arrays.compare(clientPreface, bytes) != 0) { |
268 throw new IOException("Invalid preface: " + new String(bytes, 0, len)); |
268 throw new IOException("Invalid preface: " + new String(bytes, 0, len)); |
269 } |
269 } |
270 } |
270 } |
271 |
271 |
272 String doUpgrade() throws IOException { |
272 Http1InitialRequest doUpgrade() throws IOException { |
273 String upgrade = readHttp1Request(); |
273 Http1InitialRequest upgrade = readHttp1Request(); |
274 String h2c = getHeader(upgrade, "Upgrade"); |
274 String h2c = getHeader(upgrade.headers, "Upgrade"); |
275 if (h2c == null || !h2c.equals("h2c")) { |
275 if (h2c == null || !h2c.equals("h2c")) { |
276 System.err.println("Server:HEADERS: " + upgrade); |
276 System.err.println("Server:HEADERS: " + upgrade); |
277 throw new IOException("Bad upgrade 1 " + h2c); |
277 throw new IOException("Bad upgrade 1 " + h2c); |
278 } |
278 } |
279 |
279 |
460 } |
460 } |
461 } |
461 } |
462 |
462 |
463 // First stream (1) comes from a plaintext HTTP/1.1 request |
463 // First stream (1) comes from a plaintext HTTP/1.1 request |
464 @SuppressWarnings({"rawtypes","unchecked"}) |
464 @SuppressWarnings({"rawtypes","unchecked"}) |
465 void createPrimordialStream(String request) throws IOException { |
465 void createPrimordialStream(Http1InitialRequest request) throws IOException { |
466 HttpHeadersImpl headers = new HttpHeadersImpl(); |
466 HttpHeadersImpl headers = new HttpHeadersImpl(); |
467 String requestLine = getRequestLine(request); |
467 String requestLine = getRequestLine(request.headers); |
468 String[] tokens = requestLine.split(" "); |
468 String[] tokens = requestLine.split(" "); |
469 if (!tokens[2].equals("HTTP/1.1")) { |
469 if (!tokens[2].equals("HTTP/1.1")) { |
470 throw new IOException("bad request line"); |
470 throw new IOException("bad request line"); |
471 } |
471 } |
472 URI uri = null; |
472 URI uri = null; |
473 try { |
473 try { |
474 uri = new URI(tokens[1]); |
474 uri = new URI(tokens[1]); |
475 } catch (URISyntaxException e) { |
475 } catch (URISyntaxException e) { |
476 throw new IOException(e); |
476 throw new IOException(e); |
477 } |
477 } |
478 String host = getHeader(request, "Host"); |
478 String host = getHeader(request.headers, "Host"); |
479 if (host == null) { |
479 if (host == null) { |
480 throw new IOException("missing Host"); |
480 throw new IOException("missing Host"); |
481 } |
481 } |
482 |
482 |
483 headers.setHeader(":method", tokens[0]); |
483 headers.setHeader(":method", tokens[0]); |
484 headers.setHeader(":scheme", "http"); // always in this case |
484 headers.setHeader(":scheme", "http"); // always in this case |
485 headers.setHeader(":authority", host); |
485 headers.setHeader(":authority", host); |
486 headers.setHeader(":path", uri.getPath()); |
486 headers.setHeader(":path", uri.getPath()); |
487 Queue q = new Queue(sentinel); |
487 Queue q = new Queue(sentinel); |
488 String body = getRequestBody(request); |
488 byte[] body = getRequestBody(request); |
489 addHeaders(getHeaders(request), headers); |
489 addHeaders(getHeaders(request.headers), headers); |
490 headers.setHeader("Content-length", Integer.toString(body.length())); |
490 headers.setHeader("Content-length", Integer.toString(body.length)); |
491 |
491 |
492 addRequestBodyToQueue(body, q); |
492 addRequestBodyToQueue(body, q); |
493 streams.put(1, q); |
493 streams.put(1, q); |
494 exec.submit(() -> { |
494 exec.submit(() -> { |
495 handleRequest(headers, q, 1, true /*complete request has been read*/); |
495 handleRequest(headers, q, 1, true /*complete request has been read*/); |
883 } |
883 } |
884 |
884 |
885 final static String CRLF = "\r\n"; |
885 final static String CRLF = "\r\n"; |
886 final static String CRLFCRLF = "\r\n\r\n"; |
886 final static String CRLFCRLF = "\r\n\r\n"; |
887 |
887 |
888 String readHttp1Request() throws IOException { |
888 static class Http1InitialRequest { |
|
889 final String headers; |
|
890 final byte[] body; |
|
891 Http1InitialRequest(String headers, byte[] body) { |
|
892 this.headers = headers; |
|
893 this.body = body.clone(); |
|
894 } |
|
895 } |
|
896 |
|
897 Http1InitialRequest readHttp1Request() throws IOException { |
889 String headers = readUntil(CRLF + CRLF); |
898 String headers = readUntil(CRLF + CRLF); |
890 int clen = getContentLength(headers); |
899 int clen = getContentLength(headers); |
891 String te = getHeader(headers, "Transfer-encoding"); |
900 String te = getHeader(headers, "Transfer-encoding"); |
892 byte[] buf = new byte[0]; |
901 byte[] buf = new byte[0]; |
893 try { |
902 try { |
897 is.readNBytes(buf, 0, clen); |
906 is.readNBytes(buf, 0, clen); |
898 } else if ("chunked".equalsIgnoreCase(te)) { |
907 } else if ("chunked".equalsIgnoreCase(te)) { |
899 // HTTP/1.1 chunked data, read it |
908 // HTTP/1.1 chunked data, read it |
900 buf = readChunkedInputStream(is); |
909 buf = readChunkedInputStream(is); |
901 } |
910 } |
902 String body = new String(buf, StandardCharsets.US_ASCII); |
911 return new Http1InitialRequest(headers, buf); |
903 return headers + body; |
|
904 } catch (IOException e) { |
912 } catch (IOException e) { |
905 System.err.println("TestServer: headers read: [ " + headers + " ]"); |
913 System.err.println("TestServer: headers read: [ " + headers + " ]"); |
906 throw e; |
914 throw e; |
907 } |
915 } |
908 } |
916 } |
941 final static ByteBuffer[] bbarray = new ByteBuffer[0]; |
949 final static ByteBuffer[] bbarray = new ByteBuffer[0]; |
942 |
950 |
943 // wrapper around a BlockingQueue that throws an exception when it's closed |
951 // wrapper around a BlockingQueue that throws an exception when it's closed |
944 // Each stream has one of these |
952 // Each stream has one of these |
945 |
953 |
946 String getRequestBody(String request) { |
954 byte[] getRequestBody(Http1InitialRequest request) { |
947 int bodystart = request.indexOf(CRLF+CRLF); |
955 return request.body; |
948 String body; |
|
949 if (bodystart == -1) |
|
950 body = ""; |
|
951 else |
|
952 body = request.substring(bodystart+4); |
|
953 return body; |
|
954 } |
956 } |
955 |
957 |
956 @SuppressWarnings({"rawtypes","unchecked"}) |
958 @SuppressWarnings({"rawtypes","unchecked"}) |
957 void addRequestBodyToQueue(String body, Queue q) throws IOException { |
959 void addRequestBodyToQueue(byte[] body, Queue q) throws IOException { |
958 ByteBuffer buf = ByteBuffer.wrap(body.getBytes(StandardCharsets.US_ASCII)); |
960 ByteBuffer buf = ByteBuffer.wrap(body); |
959 DataFrame df = new DataFrame(1, DataFrame.END_STREAM, buf); |
961 DataFrame df = new DataFrame(1, DataFrame.END_STREAM, buf); |
960 // only used for primordial stream |
962 // only used for primordial stream |
961 q.put(df); |
963 q.put(df); |
962 } |
964 } |
963 |
965 |