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