1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package io.netty.handler.codec.http2;
16
17 import io.netty.buffer.ByteBuf;
18 import io.netty.channel.ChannelHandlerContext;
19 import io.netty.handler.codec.http.HttpHeaderNames;
20 import io.netty.handler.codec.http.HttpStatusClass;
21 import io.netty.handler.codec.http.HttpUtil;
22 import io.netty.handler.codec.http2.Http2Connection.Endpoint;
23 import io.netty.util.internal.logging.InternalLogger;
24 import io.netty.util.internal.logging.InternalLoggerFactory;
25
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map.Entry;
29
30 import static io.netty.handler.codec.http.HttpStatusClass.INFORMATIONAL;
31 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT;
32 import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
33 import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
34 import static io.netty.handler.codec.http2.Http2Error.STREAM_CLOSED;
35 import static io.netty.handler.codec.http2.Http2Exception.connectionError;
36 import static io.netty.handler.codec.http2.Http2Exception.streamError;
37 import static io.netty.handler.codec.http2.Http2PromisedRequestVerifier.ALWAYS_VERIFY;
38 import static io.netty.handler.codec.http2.Http2Stream.State.CLOSED;
39 import static io.netty.handler.codec.http2.Http2Stream.State.HALF_CLOSED_REMOTE;
40 import static io.netty.util.internal.ObjectUtil.checkNotNull;
41 import static java.lang.Integer.MAX_VALUE;
42 import static java.lang.Math.min;
43
44
45
46
47
48
49
50
51
52
53 public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
54 private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultHttp2ConnectionDecoder.class);
55 private Http2FrameListener internalFrameListener = new PrefaceFrameListener();
56 private final Http2Connection connection;
57 private Http2LifecycleManager lifecycleManager;
58 private final Http2ConnectionEncoder encoder;
59 private final Http2FrameReader frameReader;
60 private Http2FrameListener listener;
61 private final Http2PromisedRequestVerifier requestVerifier;
62 private final Http2SettingsReceivedConsumer settingsReceivedConsumer;
63 private final boolean autoAckPing;
64 private final Http2Connection.PropertyKey contentLengthKey;
65 private final boolean validateHeaders;
66
67 public DefaultHttp2ConnectionDecoder(Http2Connection connection,
68 Http2ConnectionEncoder encoder,
69 Http2FrameReader frameReader) {
70 this(connection, encoder, frameReader, ALWAYS_VERIFY);
71 }
72
73 public DefaultHttp2ConnectionDecoder(Http2Connection connection,
74 Http2ConnectionEncoder encoder,
75 Http2FrameReader frameReader,
76 Http2PromisedRequestVerifier requestVerifier) {
77 this(connection, encoder, frameReader, requestVerifier, true);
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public DefaultHttp2ConnectionDecoder(Http2Connection connection,
93 Http2ConnectionEncoder encoder,
94 Http2FrameReader frameReader,
95 Http2PromisedRequestVerifier requestVerifier,
96 boolean autoAckSettings) {
97 this(connection, encoder, frameReader, requestVerifier, autoAckSettings, true);
98 }
99
100 @Deprecated
101 public DefaultHttp2ConnectionDecoder(Http2Connection connection,
102 Http2ConnectionEncoder encoder,
103 Http2FrameReader frameReader,
104 Http2PromisedRequestVerifier requestVerifier,
105 boolean autoAckSettings,
106 boolean autoAckPing) {
107 this(connection, encoder, frameReader, requestVerifier, autoAckSettings, autoAckPing, true);
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 public DefaultHttp2ConnectionDecoder(Http2Connection connection,
126 Http2ConnectionEncoder encoder,
127 Http2FrameReader frameReader,
128 Http2PromisedRequestVerifier requestVerifier,
129 boolean autoAckSettings,
130 boolean autoAckPing,
131 boolean validateHeaders) {
132 this.validateHeaders = validateHeaders;
133 this.autoAckPing = autoAckPing;
134 if (autoAckSettings) {
135 settingsReceivedConsumer = null;
136 } else {
137 if (!(encoder instanceof Http2SettingsReceivedConsumer)) {
138 throw new IllegalArgumentException("disabling autoAckSettings requires the encoder to be a " +
139 Http2SettingsReceivedConsumer.class);
140 }
141 settingsReceivedConsumer = (Http2SettingsReceivedConsumer) encoder;
142 }
143 this.connection = checkNotNull(connection, "connection");
144 contentLengthKey = this.connection.newKey();
145 this.frameReader = checkNotNull(frameReader, "frameReader");
146 this.encoder = checkNotNull(encoder, "encoder");
147 this.requestVerifier = checkNotNull(requestVerifier, "requestVerifier");
148 if (connection.local().flowController() == null) {
149 connection.local().flowController(new DefaultHttp2LocalFlowController(connection));
150 }
151 connection.local().flowController().frameWriter(encoder.frameWriter());
152 }
153
154 @Override
155 public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
156 this.lifecycleManager = checkNotNull(lifecycleManager, "lifecycleManager");
157 }
158
159 @Override
160 public Http2Connection connection() {
161 return connection;
162 }
163
164 @Override
165 public final Http2LocalFlowController flowController() {
166 return connection.local().flowController();
167 }
168
169 @Override
170 public void frameListener(Http2FrameListener listener) {
171 this.listener = checkNotNull(listener, "listener");
172 }
173
174 @Override
175 public Http2FrameListener frameListener() {
176 return listener;
177 }
178
179 @Override
180 public boolean prefaceReceived() {
181 return FrameReadListener.class == internalFrameListener.getClass();
182 }
183
184 @Override
185 public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception {
186 frameReader.readFrame(ctx, in, internalFrameListener);
187 }
188
189 @Override
190 public Http2Settings localSettings() {
191 Http2Settings settings = new Http2Settings();
192 Http2FrameReader.Configuration config = frameReader.configuration();
193 Http2HeadersDecoder.Configuration headersConfig = config.headersConfiguration();
194 Http2FrameSizePolicy frameSizePolicy = config.frameSizePolicy();
195 settings.initialWindowSize(flowController().initialWindowSize());
196 settings.maxConcurrentStreams(connection.remote().maxActiveStreams());
197 settings.headerTableSize(headersConfig.maxHeaderTableSize());
198 settings.maxFrameSize(frameSizePolicy.maxFrameSize());
199 settings.maxHeaderListSize(headersConfig.maxHeaderListSize());
200 if (!connection.isServer()) {
201
202 settings.pushEnabled(connection.local().allowPushTo());
203 }
204 return settings;
205 }
206
207 @Override
208 public void close() {
209 frameReader.close();
210 }
211
212
213
214
215
216
217
218
219 protected long calculateMaxHeaderListSizeGoAway(long maxHeaderListSize) {
220 return Http2CodecUtil.calculateMaxHeaderListSizeGoAway(maxHeaderListSize);
221 }
222
223 private int unconsumedBytes(Http2Stream stream) {
224 return flowController().unconsumedBytes(stream);
225 }
226
227 void onGoAwayRead0(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData)
228 throws Http2Exception {
229 listener.onGoAwayRead(ctx, lastStreamId, errorCode, debugData);
230 connection.goAwayReceived(lastStreamId, errorCode, debugData);
231 }
232
233
234 private void verifyContentLength(Http2Stream stream, int data, boolean isEnd) throws Http2Exception {
235 ContentLength contentLength = stream.getProperty(contentLengthKey);
236 if (contentLength != null) {
237 try {
238 contentLength.increaseReceivedBytes(connection.isServer(), stream.id(), data, isEnd);
239 } finally {
240 if (isEnd) {
241 stream.removeProperty(contentLengthKey);
242 }
243 }
244 }
245 }
246
247
248
249
250 private final class FrameReadListener implements Http2FrameListener {
251 @Override
252 public int onDataRead(final ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
253 boolean endOfStream) throws Http2Exception {
254 Http2Stream stream = connection.stream(streamId);
255 Http2LocalFlowController flowController = flowController();
256 int readable = data.readableBytes();
257 int bytesToReturn = readable + padding;
258
259 final boolean shouldIgnore;
260 try {
261 shouldIgnore = shouldIgnoreHeadersOrDataFrame(ctx, streamId, stream, endOfStream, "DATA");
262 } catch (Http2Exception e) {
263
264
265 flowController.receiveFlowControlledFrame(stream, data, padding, endOfStream);
266 flowController.consumeBytes(stream, bytesToReturn);
267 throw e;
268 } catch (Throwable t) {
269 throw connectionError(INTERNAL_ERROR, t, "Unhandled error on data stream id %d", streamId);
270 }
271
272 if (shouldIgnore) {
273
274
275 flowController.receiveFlowControlledFrame(stream, data, padding, endOfStream);
276 flowController.consumeBytes(stream, bytesToReturn);
277
278
279 verifyStreamMayHaveExisted(streamId, endOfStream, "DATA");
280
281
282 return bytesToReturn;
283 }
284 Http2Exception error = null;
285 switch (stream.state()) {
286 case OPEN:
287 case HALF_CLOSED_LOCAL:
288 break;
289 case HALF_CLOSED_REMOTE:
290 case CLOSED:
291 error = streamError(stream.id(), STREAM_CLOSED, "Stream %d in unexpected state: %s",
292 stream.id(), stream.state());
293 break;
294 default:
295 error = streamError(stream.id(), PROTOCOL_ERROR,
296 "Stream %d in unexpected state: %s", stream.id(), stream.state());
297 break;
298 }
299
300 int unconsumedBytes = unconsumedBytes(stream);
301 try {
302 flowController.receiveFlowControlledFrame(stream, data, padding, endOfStream);
303
304 unconsumedBytes = unconsumedBytes(stream);
305
306
307 if (error != null) {
308 throw error;
309 }
310
311 verifyContentLength(stream, readable, endOfStream);
312
313
314
315 bytesToReturn = listener.onDataRead(ctx, streamId, data, padding, endOfStream);
316
317 if (endOfStream) {
318 lifecycleManager.closeStreamRemote(stream, ctx.newSucceededFuture());
319 }
320
321 return bytesToReturn;
322 } catch (Http2Exception | RuntimeException e) {
323
324
325
326 int delta = unconsumedBytes - unconsumedBytes(stream);
327 bytesToReturn -= delta;
328 throw e;
329 } finally {
330
331 flowController.consumeBytes(stream, bytesToReturn);
332 }
333 }
334
335 @Override
336 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
337 boolean endOfStream) throws Http2Exception {
338 onHeadersRead(ctx, streamId, headers, 0, DEFAULT_PRIORITY_WEIGHT, false, padding, endOfStream);
339 }
340
341 @Override
342 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency,
343 short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {
344 Http2Stream stream = connection.stream(streamId);
345 boolean allowHalfClosedRemote = false;
346 boolean isTrailers = false;
347 if (stream == null && !connection.streamMayHaveExisted(streamId)) {
348 stream = connection.remote().createStream(streamId, endOfStream);
349
350 allowHalfClosedRemote = stream.state() == HALF_CLOSED_REMOTE;
351 } else if (stream != null) {
352 isTrailers = stream.isHeadersReceived();
353 }
354
355 if (shouldIgnoreHeadersOrDataFrame(ctx, streamId, stream, endOfStream, "HEADERS")) {
356 return;
357 }
358
359 boolean isInformational = !connection.isServer() &&
360 HttpStatusClass.valueOf(headers.status()) == INFORMATIONAL;
361 if ((isInformational || !endOfStream) && stream.isHeadersReceived() || stream.isTrailersReceived()) {
362 throw streamError(streamId, PROTOCOL_ERROR,
363 "Stream %d received too many headers EOS: %s state: %s",
364 streamId, endOfStream, stream.state());
365 }
366
367 switch (stream.state()) {
368 case RESERVED_REMOTE:
369 stream.open(endOfStream);
370 break;
371 case OPEN:
372 case HALF_CLOSED_LOCAL:
373
374 break;
375 case HALF_CLOSED_REMOTE:
376 if (!allowHalfClosedRemote) {
377 throw streamError(stream.id(), STREAM_CLOSED, "Stream %d in unexpected state: %s",
378 stream.id(), stream.state());
379 }
380 break;
381 case CLOSED:
382 throw streamError(stream.id(), STREAM_CLOSED, "Stream %d in unexpected state: %s",
383 stream.id(), stream.state());
384 default:
385
386 throw connectionError(PROTOCOL_ERROR, "Stream %d in unexpected state: %s", stream.id(),
387 stream.state());
388 }
389
390 if (!isTrailers) {
391
392 List<? extends CharSequence> contentLength = headers.getAll(HttpHeaderNames.CONTENT_LENGTH);
393 if (contentLength != null && !contentLength.isEmpty()) {
394 try {
395 long cLength = HttpUtil.normalizeAndGetContentLength(contentLength, false, true);
396 if (cLength != -1) {
397 headers.setLong(HttpHeaderNames.CONTENT_LENGTH, cLength);
398 stream.setProperty(contentLengthKey, new ContentLength(cLength));
399 }
400 } catch (IllegalArgumentException e) {
401 throw streamError(stream.id(), PROTOCOL_ERROR, e,
402 "Multiple content-length headers received");
403 }
404 }
405
406
407 } else if (validateHeaders && headers.size() > 0) {
408
409
410 for (Iterator<Entry<CharSequence, CharSequence>> iterator =
411 headers.iterator(); iterator.hasNext();) {
412 CharSequence name = iterator.next().getKey();
413 if (Http2Headers.PseudoHeaderName.hasPseudoHeaderFormat(name)) {
414 throw streamError(stream.id(), PROTOCOL_ERROR,
415 "Found invalid Pseudo-Header in trailers: %s", name);
416 }
417 }
418 }
419
420 stream.headersReceived(isInformational);
421 verifyContentLength(stream, 0, endOfStream);
422 encoder.flowController().updateDependencyTree(streamId, streamDependency, weight, exclusive);
423 listener.onHeadersRead(ctx, streamId, headers, streamDependency,
424 weight, exclusive, padding, endOfStream);
425
426 if (endOfStream) {
427 lifecycleManager.closeStreamRemote(stream, ctx.newSucceededFuture());
428 }
429 }
430
431 @Override
432 public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
433 boolean exclusive) throws Http2Exception {
434 encoder.flowController().updateDependencyTree(streamId, streamDependency, weight, exclusive);
435
436 listener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive);
437 }
438
439 @Override
440 public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
441 Http2Stream stream = connection.stream(streamId);
442 if (stream == null) {
443 verifyStreamMayHaveExisted(streamId, false, "RST_STREAM");
444 return;
445 }
446
447 switch(stream.state()) {
448 case IDLE:
449 throw connectionError(PROTOCOL_ERROR, "RST_STREAM received for IDLE stream %d", streamId);
450 case CLOSED:
451 return;
452 default:
453 break;
454 }
455
456 listener.onRstStreamRead(ctx, streamId, errorCode);
457
458 lifecycleManager.closeStream(stream, ctx.newSucceededFuture());
459 }
460
461 @Override
462 public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {
463
464 Http2Settings settings = encoder.pollSentSettings();
465
466 if (settings != null) {
467 applyLocalSettings(settings);
468 }
469
470 listener.onSettingsAckRead(ctx);
471 }
472
473
474
475
476
477
478 private void applyLocalSettings(Http2Settings settings) throws Http2Exception {
479 Boolean pushEnabled = settings.pushEnabled();
480 final Http2FrameReader.Configuration config = frameReader.configuration();
481 final Http2HeadersDecoder.Configuration headerConfig = config.headersConfiguration();
482 final Http2FrameSizePolicy frameSizePolicy = config.frameSizePolicy();
483 if (pushEnabled != null) {
484 if (connection.isServer()) {
485 throw connectionError(PROTOCOL_ERROR, "Server sending SETTINGS frame with ENABLE_PUSH specified");
486 }
487 connection.local().allowPushTo(pushEnabled);
488 }
489
490 Long maxConcurrentStreams = settings.maxConcurrentStreams();
491 if (maxConcurrentStreams != null) {
492 connection.remote().maxActiveStreams((int) min(maxConcurrentStreams, MAX_VALUE));
493 }
494
495 Long headerTableSize = settings.headerTableSize();
496 if (headerTableSize != null) {
497 headerConfig.maxHeaderTableSize(headerTableSize);
498 }
499
500 Long maxHeaderListSize = settings.maxHeaderListSize();
501 if (maxHeaderListSize != null) {
502 headerConfig.maxHeaderListSize(maxHeaderListSize, calculateMaxHeaderListSizeGoAway(maxHeaderListSize));
503 }
504
505 Integer maxFrameSize = settings.maxFrameSize();
506 if (maxFrameSize != null) {
507 frameSizePolicy.maxFrameSize(maxFrameSize);
508 }
509
510 Integer initialWindowSize = settings.initialWindowSize();
511 if (initialWindowSize != null) {
512 flowController().initialWindowSize(initialWindowSize);
513 }
514 }
515
516 @Override
517 public void onSettingsRead(final ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
518 if (settingsReceivedConsumer == null) {
519
520
521
522 encoder.writeSettingsAck(ctx, ctx.newPromise());
523
524 encoder.remoteSettings(settings);
525 } else {
526 settingsReceivedConsumer.consumeReceivedSettings(settings);
527 }
528
529 listener.onSettingsRead(ctx, settings);
530 }
531
532 @Override
533 public void onPingRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
534 if (autoAckPing) {
535
536 encoder.writePing(ctx, true, data, ctx.newPromise());
537 }
538 listener.onPingRead(ctx, data);
539 }
540
541 @Override
542 public void onPingAckRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
543 listener.onPingAckRead(ctx, data);
544 }
545
546 @Override
547 public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
548 Http2Headers headers, int padding) throws Http2Exception {
549
550 if (connection().isServer()) {
551 throw connectionError(PROTOCOL_ERROR, "A client cannot push.");
552 }
553
554 Http2Stream parentStream = connection.stream(streamId);
555
556 if (shouldIgnoreHeadersOrDataFrame(ctx, streamId, parentStream, false, "PUSH_PROMISE")) {
557 return;
558 }
559
560 switch (parentStream.state()) {
561 case OPEN:
562 case HALF_CLOSED_LOCAL:
563
564 break;
565 default:
566
567 throw connectionError(PROTOCOL_ERROR,
568 "Stream %d in unexpected state for receiving push promise: %s",
569 parentStream.id(), parentStream.state());
570 }
571
572 if (!requestVerifier.isAuthoritative(ctx, headers)) {
573 throw streamError(promisedStreamId, PROTOCOL_ERROR,
574 "Promised request on stream %d for promised stream %d is not authoritative",
575 streamId, promisedStreamId);
576 }
577 if (!requestVerifier.isCacheable(headers)) {
578 throw streamError(promisedStreamId, PROTOCOL_ERROR,
579 "Promised request on stream %d for promised stream %d is not known to be cacheable",
580 streamId, promisedStreamId);
581 }
582 if (!requestVerifier.isSafe(headers)) {
583 throw streamError(promisedStreamId, PROTOCOL_ERROR,
584 "Promised request on stream %d for promised stream %d is not known to be safe",
585 streamId, promisedStreamId);
586 }
587
588
589 connection.remote().reservePushStream(promisedStreamId, parentStream);
590
591 listener.onPushPromiseRead(ctx, streamId, promisedStreamId, headers, padding);
592 }
593
594 @Override
595 public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData)
596 throws Http2Exception {
597 onGoAwayRead0(ctx, lastStreamId, errorCode, debugData);
598 }
599
600 @Override
601 public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement)
602 throws Http2Exception {
603 Http2Stream stream = connection.stream(streamId);
604 if (stream == null || stream.state() == CLOSED || streamCreatedAfterGoAwaySent(streamId)) {
605
606 verifyStreamMayHaveExisted(streamId, false, "WINDOW_UPDATE");
607 return;
608 }
609
610
611 encoder.flowController().incrementWindowSize(stream, windowSizeIncrement);
612
613 listener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement);
614 }
615
616 @Override
617 public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
618 ByteBuf payload) throws Http2Exception {
619 Http2Stream stream = connection.stream(streamId);
620 if (stream == null) {
621 return;
622 }
623
624 listener.onUnknownFrame(ctx, frameType, streamId, flags, payload);
625 }
626
627
628
629
630
631 private boolean shouldIgnoreHeadersOrDataFrame(ChannelHandlerContext ctx, int streamId, Http2Stream stream,
632 boolean endOfStream, String frameName) throws Http2Exception {
633 if (stream == null) {
634 if (streamCreatedAfterGoAwaySent(streamId)) {
635 logger.info("{} ignoring {} frame for stream {}. Stream sent after GOAWAY sent",
636 ctx.channel(), frameName, streamId);
637 return true;
638 }
639
640
641
642 verifyStreamMayHaveExisted(streamId, endOfStream, frameName);
643
644
645
646
647 throw streamError(streamId, STREAM_CLOSED, "Received %s frame for an unknown stream %d",
648 frameName, streamId);
649 }
650 if (stream.isResetSent() || streamCreatedAfterGoAwaySent(streamId)) {
651
652
653
654
655
656 if (logger.isInfoEnabled()) {
657 logger.info("{} ignoring {} frame for stream {}", ctx.channel(), frameName,
658 stream.isResetSent() ? "RST_STREAM sent." :
659 "Stream created after GOAWAY sent. Last known stream by peer " +
660 connection.remote().lastStreamKnownByPeer());
661 }
662
663 return true;
664 }
665 return false;
666 }
667
668
669
670
671
672
673
674
675
676
677
678
679
680 private boolean streamCreatedAfterGoAwaySent(int streamId) {
681 Endpoint<?> remote = connection.remote();
682 return connection.goAwaySent() && remote.isValidStreamId(streamId) &&
683 streamId > remote.lastStreamKnownByPeer();
684 }
685
686 private void verifyStreamMayHaveExisted(int streamId, boolean endOfStream, String frameName)
687 throws Http2Exception {
688 if (!connection.streamMayHaveExisted(streamId)) {
689 throw connectionError(PROTOCOL_ERROR,
690 "Stream %d does not exist for inbound frame %s, endOfStream = %b",
691 streamId, frameName, endOfStream);
692 }
693 }
694 }
695
696 private final class PrefaceFrameListener implements Http2FrameListener {
697
698
699
700
701
702
703 private void verifyPrefaceReceived() throws Http2Exception {
704 if (!prefaceReceived()) {
705 throw connectionError(PROTOCOL_ERROR, "Received non-SETTINGS as first frame.");
706 }
707 }
708
709 @Override
710 public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, boolean endOfStream)
711 throws Http2Exception {
712 verifyPrefaceReceived();
713 return internalFrameListener.onDataRead(ctx, streamId, data, padding, endOfStream);
714 }
715
716 @Override
717 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
718 boolean endOfStream) throws Http2Exception {
719 verifyPrefaceReceived();
720 internalFrameListener.onHeadersRead(ctx, streamId, headers, padding, endOfStream);
721 }
722
723 @Override
724 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency,
725 short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {
726 verifyPrefaceReceived();
727 internalFrameListener.onHeadersRead(ctx, streamId, headers, streamDependency, weight,
728 exclusive, padding, endOfStream);
729 }
730
731 @Override
732 public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
733 boolean exclusive) throws Http2Exception {
734 verifyPrefaceReceived();
735 internalFrameListener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive);
736 }
737
738 @Override
739 public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
740 verifyPrefaceReceived();
741 internalFrameListener.onRstStreamRead(ctx, streamId, errorCode);
742 }
743
744 @Override
745 public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {
746 verifyPrefaceReceived();
747 internalFrameListener.onSettingsAckRead(ctx);
748 }
749
750 @Override
751 public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
752
753
754 if (!prefaceReceived()) {
755 internalFrameListener = new FrameReadListener();
756 }
757 internalFrameListener.onSettingsRead(ctx, settings);
758 }
759
760 @Override
761 public void onPingRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
762 verifyPrefaceReceived();
763 internalFrameListener.onPingRead(ctx, data);
764 }
765
766 @Override
767 public void onPingAckRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
768 verifyPrefaceReceived();
769 internalFrameListener.onPingAckRead(ctx, data);
770 }
771
772 @Override
773 public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
774 Http2Headers headers, int padding) throws Http2Exception {
775 verifyPrefaceReceived();
776 internalFrameListener.onPushPromiseRead(ctx, streamId, promisedStreamId, headers, padding);
777 }
778
779 @Override
780 public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData)
781 throws Http2Exception {
782 onGoAwayRead0(ctx, lastStreamId, errorCode, debugData);
783 }
784
785 @Override
786 public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement)
787 throws Http2Exception {
788 verifyPrefaceReceived();
789 internalFrameListener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement);
790 }
791
792 @Override
793 public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
794 ByteBuf payload) throws Http2Exception {
795 verifyPrefaceReceived();
796 internalFrameListener.onUnknownFrame(ctx, frameType, streamId, flags, payload);
797 }
798 }
799
800 private static final class ContentLength {
801 private final long expected;
802 private long seen;
803
804 ContentLength(long expected) {
805 this.expected = expected;
806 }
807
808 void increaseReceivedBytes(boolean server, int streamId, int bytes, boolean isEnd) throws Http2Exception {
809 seen += bytes;
810
811 if (seen < 0) {
812 throw streamError(streamId, PROTOCOL_ERROR,
813 "Received amount of data did overflow and so not match content-length header %d", expected);
814 }
815
816 if (seen > expected) {
817 throw streamError(streamId, PROTOCOL_ERROR,
818 "Received amount of data %d does not match content-length header %d", seen, expected);
819 }
820
821 if (isEnd) {
822 if (seen == 0 && !server) {
823
824 return;
825 }
826
827
828 if (expected > seen) {
829 throw streamError(streamId, PROTOCOL_ERROR,
830 "Received amount of data %d does not match content-length header %d", seen, expected);
831 }
832 }
833 }
834 }
835 }