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