36 import java.nio.ByteBuffer; |
36 import java.nio.ByteBuffer; |
37 import java.nio.charset.StandardCharsets; |
37 import java.nio.charset.StandardCharsets; |
38 import java.util.*; |
38 import java.util.*; |
39 import java.util.concurrent.ExecutorService; |
39 import java.util.concurrent.ExecutorService; |
40 import java.util.function.Consumer; |
40 import java.util.function.Consumer; |
41 import jdk.incubator.http.internal.common.ByteBufferReference; |
|
42 import jdk.incubator.http.internal.common.HttpHeadersImpl; |
41 import jdk.incubator.http.internal.common.HttpHeadersImpl; |
43 import jdk.incubator.http.internal.frame.DataFrame; |
42 import jdk.incubator.http.internal.frame.DataFrame; |
44 import jdk.incubator.http.internal.frame.FramesDecoder; |
43 import jdk.incubator.http.internal.frame.FramesDecoder; |
45 import jdk.incubator.http.internal.frame.FramesEncoder; |
44 import jdk.incubator.http.internal.frame.FramesEncoder; |
46 import jdk.incubator.http.internal.frame.GoAwayFrame; |
45 import jdk.incubator.http.internal.frame.GoAwayFrame; |
192 // simulate header of Settings Frame |
191 // simulate header of Settings Frame |
193 ByteBuffer bb0 = ByteBuffer.wrap( |
192 ByteBuffer bb0 = ByteBuffer.wrap( |
194 new byte[] {0, 0, (byte)payload.length, 4, 0, 0, 0, 0, 0}); |
193 new byte[] {0, 0, (byte)payload.length, 4, 0, 0, 0, 0, 0}); |
195 List<Http2Frame> frames = new ArrayList<>(); |
194 List<Http2Frame> frames = new ArrayList<>(); |
196 FramesDecoder reader = new FramesDecoder(frames::add); |
195 FramesDecoder reader = new FramesDecoder(frames::add); |
197 reader.decode(ByteBufferReference.of(bb0)); |
196 reader.decode(bb0); |
198 reader.decode(ByteBufferReference.of(bb1)); |
197 reader.decode(bb1); |
199 if (frames.size()!=1) |
198 if (frames.size()!=1) |
200 throw new IOException("Expected 1 frame got "+frames.size()) ; |
199 throw new IOException("Expected 1 frame got "+frames.size()) ; |
201 Http2Frame frame = frames.get(0); |
200 Http2Frame frame = frames.get(0); |
202 if (!(frame instanceof SettingsFrame)) |
201 if (!(frame instanceof SettingsFrame)) |
203 throw new IOException("Expected SettingsFrame"); |
202 throw new IOException("Expected SettingsFrame"); |
233 exec.submit(this::readLoop); |
232 exec.submit(this::readLoop); |
234 exec.submit(this::writeLoop); |
233 exec.submit(this::writeLoop); |
235 } |
234 } |
236 |
235 |
237 private void writeFrame(Http2Frame frame) throws IOException { |
236 private void writeFrame(Http2Frame frame) throws IOException { |
238 ByteBufferReference[] refs = new FramesEncoder().encodeFrame(frame); |
237 List<ByteBuffer> bufs = new FramesEncoder().encodeFrame(frame); |
239 //System.err.println("TestServer: Writing frame " + frame.toString()); |
238 //System.err.println("TestServer: Writing frame " + frame.toString()); |
240 int c = 0; |
239 int c = 0; |
241 for (ByteBufferReference ref : refs) { |
240 for (ByteBuffer buf : bufs) { |
242 ByteBuffer buf = ref.get(); |
|
243 byte[] ba = buf.array(); |
241 byte[] ba = buf.array(); |
244 int start = buf.arrayOffset() + buf.position(); |
242 int start = buf.arrayOffset() + buf.position(); |
245 c += buf.remaining(); |
243 c += buf.remaining(); |
246 os.write(ba, start, buf.remaining()); |
244 os.write(ba, start, buf.remaining()); |
247 |
245 |
304 DecodingCallback cb = (name, value) -> { |
302 DecodingCallback cb = (name, value) -> { |
305 headers.addHeader(name.toString(), value.toString()); |
303 headers.addHeader(name.toString(), value.toString()); |
306 }; |
304 }; |
307 |
305 |
308 for (HeaderFrame frame : frames) { |
306 for (HeaderFrame frame : frames) { |
309 ByteBufferReference[] buffers = frame.getHeaderBlock(); |
307 List<ByteBuffer> buffers = frame.getHeaderBlock(); |
310 for (ByteBufferReference buffer : buffers) { |
308 for (ByteBuffer buffer : buffers) { |
311 hpackIn.decode(buffer.get(), false, cb); |
309 hpackIn.decode(buffer, false, cb); |
312 } |
310 } |
313 } |
311 } |
314 hpackIn.decode(EMPTY_BUFFER, true, cb); |
312 hpackIn.decode(EMPTY_BUFFER, true, cb); |
315 return headers; |
313 return headers; |
316 } |
314 } |
593 } |
591 } |
594 } |
592 } |
595 |
593 |
596 private void handlePush(OutgoingPushPromise op) throws IOException { |
594 private void handlePush(OutgoingPushPromise op) throws IOException { |
597 int promisedStreamid = nextPushStreamId; |
595 int promisedStreamid = nextPushStreamId; |
598 PushPromiseFrame pp = new PushPromiseFrame(op.parentStream, HeaderFrame.END_HEADERS, promisedStreamid, encodeHeaders(op.headers), 0); |
596 PushPromiseFrame pp = new PushPromiseFrame(op.parentStream, |
|
597 HeaderFrame.END_HEADERS, |
|
598 promisedStreamid, |
|
599 encodeHeaders(op.headers), |
|
600 0); |
599 pushStreams.add(promisedStreamid); |
601 pushStreams.add(promisedStreamid); |
600 nextPushStreamId += 2; |
602 nextPushStreamId += 2; |
601 pp.streamid(op.parentStream); |
603 pp.streamid(op.parentStream); |
602 writeFrame(pp); |
604 writeFrame(pp); |
603 final InputStream ii = op.is; |
605 final InputStream ii = op.is; |
651 int n = is.readNBytes(rest, 0, len); |
653 int n = is.readNBytes(rest, 0, len); |
652 if (n != len) |
654 if (n != len) |
653 throw new IOException("Error reading frame"); |
655 throw new IOException("Error reading frame"); |
654 List<Http2Frame> frames = new ArrayList<>(); |
656 List<Http2Frame> frames = new ArrayList<>(); |
655 FramesDecoder reader = new FramesDecoder(frames::add); |
657 FramesDecoder reader = new FramesDecoder(frames::add); |
656 reader.decode(ByteBufferReference.of(ByteBuffer.wrap(buf))); |
658 reader.decode(ByteBuffer.wrap(buf)); |
657 reader.decode(ByteBufferReference.of(ByteBuffer.wrap(rest))); |
659 reader.decode(ByteBuffer.wrap(rest)); |
658 if (frames.size()!=1) |
660 if (frames.size()!=1) |
659 throw new IOException("Expected 1 frame got "+frames.size()) ; |
661 throw new IOException("Expected 1 frame got "+frames.size()) ; |
660 |
662 |
661 return frames.get(0); |
663 return frames.get(0); |
662 } |
664 } |
789 } |
791 } |
790 |
792 |
791 @SuppressWarnings({"rawtypes","unchecked"}) |
793 @SuppressWarnings({"rawtypes","unchecked"}) |
792 void addRequestBodyToQueue(String body, Queue q) throws IOException { |
794 void addRequestBodyToQueue(String body, Queue q) throws IOException { |
793 ByteBuffer buf = ByteBuffer.wrap(body.getBytes(StandardCharsets.US_ASCII)); |
795 ByteBuffer buf = ByteBuffer.wrap(body.getBytes(StandardCharsets.US_ASCII)); |
794 DataFrame df = new DataFrame(1, DataFrame.END_STREAM, ByteBufferReference.of(buf)); |
796 DataFrame df = new DataFrame(1, DataFrame.END_STREAM, buf); |
795 // only used for primordial stream |
797 // only used for primordial stream |
796 q.put(df); |
798 q.put(df); |
797 } |
799 } |
798 |
800 |
799 // window updates done in main reader thread because they may |
801 // window updates done in main reader thread because they may |