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 e) {
400
401
402
403 int delta = unconsumedBytes - unconsumedBytes(stream);
404 bytesToReturn -= delta;
405 throw e;
406 } catch (RuntimeException e) {
407
408
409
410 int delta = unconsumedBytes - unconsumedBytes(stream);
411 bytesToReturn -= delta;
412 throw e;
413 } finally {
414
415 flowController.consumeBytes(stream, bytesToReturn);
416 }
417 }
418
419 @Override
420 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
421 boolean endOfStream) throws Http2Exception {
422 onHeadersRead(ctx, streamId, headers, 0, DEFAULT_PRIORITY_WEIGHT, false, padding, endOfStream);
423 }
424
425 @Override
426 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency,
427 short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {
428 Http2Stream stream = connection.stream(streamId);
429 boolean allowHalfClosedRemote = false;
430 boolean isTrailers = false;
431 if (stream == null && !connection.streamMayHaveExisted(streamId)) {
432 stream = connection.remote().createStream(streamId, endOfStream);
433
434 allowHalfClosedRemote = stream.state() == HALF_CLOSED_REMOTE;
435 } else if (stream != null) {
436 isTrailers = stream.isHeadersReceived();
437 }
438
439 if (shouldIgnoreHeadersOrDataFrame(ctx, streamId, stream, endOfStream, "HEADERS")) {
440 return;
441 }
442
443 boolean isInformational = !connection.isServer() &&
444 HttpStatusClass.valueOf(headers.status()) == INFORMATIONAL;
445 if ((isInformational || !endOfStream) && stream.isHeadersReceived() || stream.isTrailersReceived()) {
446 throw streamError(streamId, PROTOCOL_ERROR,
447 "Stream %d received too many headers EOS: %s state: %s",
448 streamId, endOfStream, stream.state());
449 }
450
451 switch (stream.state()) {
452 case RESERVED_REMOTE:
453 stream.open(endOfStream);
454 break;
455 case OPEN:
456 case HALF_CLOSED_LOCAL:
457
458 break;
459 case HALF_CLOSED_REMOTE:
460 if (!allowHalfClosedRemote) {
461 throw streamError(stream.id(), STREAM_CLOSED, "Stream %d in unexpected state: %s",
462 stream.id(), stream.state());
463 }
464 break;
465 case CLOSED:
466 throw streamError(stream.id(), STREAM_CLOSED, "Stream %d in unexpected state: %s",
467 stream.id(), stream.state());
468 default:
469
470 throw connectionError(PROTOCOL_ERROR, "Stream %d in unexpected state: %s", stream.id(),
471 stream.state());
472 }
473
474 if (!isTrailers) {
475 if (validateRequiredPseudoHeaders && !isInformational) {
476
477 validateRequiredPseudoHeaders(connection.isServer(), stream.id(), headers);
478 }
479
480 List<? extends CharSequence> contentLength = headers.getAll(HttpHeaderNames.CONTENT_LENGTH);
481 if (contentLength != null && !contentLength.isEmpty()) {
482 try {
483 long cLength = HttpUtil.normalizeAndGetContentLength(contentLength, false, true);
484 if (cLength != -1) {
485 headers.setLong(HttpHeaderNames.CONTENT_LENGTH, cLength);
486 stream.setProperty(contentLengthKey, new ContentLength(cLength));
487 }
488 } catch (IllegalArgumentException e) {
489 throw streamError(stream.id(), PROTOCOL_ERROR, e,
490 "Multiple content-length headers received");
491 }
492 }
493
494
495 } else if (validateHeaders && headers.size() > 0) {
496
497
498 for (Iterator<Entry<CharSequence, CharSequence>> iterator =
499 headers.iterator(); iterator.hasNext();) {
500 CharSequence name = iterator.next().getKey();
501 if (Http2Headers.PseudoHeaderName.hasPseudoHeaderFormat(name)) {
502 throw streamError(stream.id(), PROTOCOL_ERROR,
503 "Found invalid Pseudo-Header in trailers: %s", name);
504 }
505 }
506 }
507
508 stream.headersReceived(isInformational);
509 verifyContentLength(stream, 0, endOfStream);
510 encoder.flowController().updateDependencyTree(streamId, streamDependency, weight, exclusive);
511 listener.onHeadersRead(ctx, streamId, headers, streamDependency,
512 weight, exclusive, padding, endOfStream);
513
514 if (endOfStream) {
515 lifecycleManager.closeStreamRemote(stream, ctx.newSucceededFuture());
516 }
517 }
518
519 @Override
520 public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
521 boolean exclusive) throws Http2Exception {
522 encoder.flowController().updateDependencyTree(streamId, streamDependency, weight, exclusive);
523
524 listener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive);
525 }
526
527 @Override
528 public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
529 Http2Stream stream = connection.stream(streamId);
530 if (stream == null) {
531 verifyStreamMayHaveExisted(streamId, false, "RST_STREAM");
532 return;
533 }
534
535 switch(stream.state()) {
536 case IDLE:
537 throw connectionError(PROTOCOL_ERROR, "RST_STREAM received for IDLE stream %d", streamId);
538 case CLOSED:
539 return;
540 default:
541 break;
542 }
543
544 listener.onRstStreamRead(ctx, streamId, errorCode);
545
546 lifecycleManager.closeStream(stream, ctx.newSucceededFuture());
547 }
548
549 @Override
550 public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {
551
552 Http2Settings settings = encoder.pollSentSettings();
553
554 if (settings != null) {
555 applyLocalSettings(settings);
556 }
557
558 listener.onSettingsAckRead(ctx);
559 }
560
561
562
563
564
565
566 private void applyLocalSettings(Http2Settings settings) throws Http2Exception {
567 Boolean pushEnabled = settings.pushEnabled();
568 final Http2FrameReader.Configuration config = frameReader.configuration();
569 final Http2HeadersDecoder.Configuration headerConfig = config.headersConfiguration();
570 final Http2FrameSizePolicy frameSizePolicy = config.frameSizePolicy();
571 if (pushEnabled != null) {
572 if (connection.isServer()) {
573 throw connectionError(PROTOCOL_ERROR, "Server sending SETTINGS frame with ENABLE_PUSH specified");
574 }
575 connection.local().allowPushTo(pushEnabled);
576 }
577
578 Long maxConcurrentStreams = settings.maxConcurrentStreams();
579 if (maxConcurrentStreams != null) {
580 connection.remote().maxActiveStreams((int) min(maxConcurrentStreams, MAX_VALUE));
581 }
582
583 Long headerTableSize = settings.headerTableSize();
584 if (headerTableSize != null) {
585 headerConfig.maxHeaderTableSize(headerTableSize);
586 }
587
588 Long maxHeaderListSize = settings.maxHeaderListSize();
589 if (maxHeaderListSize != null) {
590 headerConfig.maxHeaderListSize(maxHeaderListSize, calculateMaxHeaderListSizeGoAway(maxHeaderListSize));
591 }
592
593 Integer maxFrameSize = settings.maxFrameSize();
594 if (maxFrameSize != null) {
595 frameSizePolicy.maxFrameSize(maxFrameSize);
596 }
597
598 Integer initialWindowSize = settings.initialWindowSize();
599 if (initialWindowSize != null) {
600 flowController().initialWindowSize(initialWindowSize);
601 }
602 }
603
604 @Override
605 public void onSettingsRead(final ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
606 if (settingsReceivedConsumer == null) {
607
608
609
610 encoder.writeSettingsAck(ctx, ctx.newPromise());
611
612 encoder.remoteSettings(settings);
613 } else {
614 settingsReceivedConsumer.consumeReceivedSettings(settings);
615 }
616
617 listener.onSettingsRead(ctx, settings);
618 }
619
620 @Override
621 public void onPingRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
622 if (autoAckPing) {
623
624 encoder.writePing(ctx, true, data, ctx.newPromise());
625 }
626 listener.onPingRead(ctx, data);
627 }
628
629 @Override
630 public void onPingAckRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
631 listener.onPingAckRead(ctx, data);
632 }
633
634 @Override
635 public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
636 Http2Headers headers, int padding) throws Http2Exception {
637
638 if (connection().isServer()) {
639 throw connectionError(PROTOCOL_ERROR, "A client cannot push.");
640 }
641
642 Http2Stream parentStream = connection.stream(streamId);
643
644 if (shouldIgnoreHeadersOrDataFrame(ctx, streamId, parentStream, false, "PUSH_PROMISE")) {
645 return;
646 }
647
648 switch (parentStream.state()) {
649 case OPEN:
650 case HALF_CLOSED_LOCAL:
651
652 break;
653 default:
654
655 throw connectionError(PROTOCOL_ERROR,
656 "Stream %d in unexpected state for receiving push promise: %s",
657 parentStream.id(), parentStream.state());
658 }
659
660 if (!requestVerifier.isAuthoritative(ctx, headers)) {
661 throw streamError(promisedStreamId, PROTOCOL_ERROR,
662 "Promised request on stream %d for promised stream %d is not authoritative",
663 streamId, promisedStreamId);
664 }
665 if (!requestVerifier.isCacheable(headers)) {
666 throw streamError(promisedStreamId, PROTOCOL_ERROR,
667 "Promised request on stream %d for promised stream %d is not known to be cacheable",
668 streamId, promisedStreamId);
669 }
670 if (!requestVerifier.isSafe(headers)) {
671 throw streamError(promisedStreamId, PROTOCOL_ERROR,
672 "Promised request on stream %d for promised stream %d is not known to be safe",
673 streamId, promisedStreamId);
674 }
675
676
677 connection.remote().reservePushStream(promisedStreamId, parentStream);
678
679 listener.onPushPromiseRead(ctx, streamId, promisedStreamId, headers, padding);
680 }
681
682 @Override
683 public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData)
684 throws Http2Exception {
685 onGoAwayRead0(ctx, lastStreamId, errorCode, debugData);
686 }
687
688 @Override
689 public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement)
690 throws Http2Exception {
691 Http2Stream stream = connection.stream(streamId);
692 if (stream == null || stream.state() == CLOSED || streamCreatedAfterGoAwaySent(streamId)) {
693
694 verifyStreamMayHaveExisted(streamId, false, "WINDOW_UPDATE");
695 return;
696 }
697
698
699 encoder.flowController().incrementWindowSize(stream, windowSizeIncrement);
700
701 listener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement);
702 }
703
704 @Override
705 public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
706 ByteBuf payload) throws Http2Exception {
707 Http2Stream stream = connection.stream(streamId);
708 if (stream == null) {
709 return;
710 }
711
712 listener.onUnknownFrame(ctx, frameType, streamId, flags, payload);
713 }
714
715
716
717
718
719 private boolean shouldIgnoreHeadersOrDataFrame(ChannelHandlerContext ctx, int streamId, Http2Stream stream,
720 boolean endOfStream, String frameName) throws Http2Exception {
721 if (stream == null) {
722 if (streamCreatedAfterGoAwaySent(streamId)) {
723 logger.info("{} ignoring {} frame for stream {}. Stream sent after GOAWAY sent",
724 ctx.channel(), frameName, streamId);
725 return true;
726 }
727
728
729
730 verifyStreamMayHaveExisted(streamId, endOfStream, frameName);
731
732
733
734
735 throw streamError(streamId, STREAM_CLOSED, "Received %s frame for an unknown stream %d",
736 frameName, streamId);
737 }
738 if (stream.isResetSent() || streamCreatedAfterGoAwaySent(streamId)) {
739
740
741
742
743
744 if (logger.isInfoEnabled()) {
745 logger.info("{} ignoring {} frame for stream {}", ctx.channel(), frameName,
746 stream.isResetSent() ? "RST_STREAM sent." :
747 "Stream created after GOAWAY sent. Last known stream by peer " +
748 connection.remote().lastStreamKnownByPeer());
749 }
750
751 return true;
752 }
753 return false;
754 }
755
756
757
758
759
760
761
762
763
764
765
766
767
768 private boolean streamCreatedAfterGoAwaySent(int streamId) {
769 Endpoint<?> remote = connection.remote();
770 return connection.goAwaySent() && remote.isValidStreamId(streamId) &&
771 streamId > remote.lastStreamKnownByPeer();
772 }
773
774 private void verifyStreamMayHaveExisted(int streamId, boolean endOfStream, String frameName)
775 throws Http2Exception {
776 if (!connection.streamMayHaveExisted(streamId)) {
777 throw connectionError(PROTOCOL_ERROR,
778 "Stream %d does not exist for inbound frame %s, endOfStream = %b",
779 streamId, frameName, endOfStream);
780 }
781 }
782 }
783
784 private final class PrefaceFrameListener implements Http2FrameListener {
785
786
787
788
789
790
791 private void verifyPrefaceReceived() throws Http2Exception {
792 if (!prefaceReceived()) {
793 throw connectionError(PROTOCOL_ERROR, "Received non-SETTINGS as first frame.");
794 }
795 }
796
797 @Override
798 public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, boolean endOfStream)
799 throws Http2Exception {
800 verifyPrefaceReceived();
801 return internalFrameListener.onDataRead(ctx, streamId, data, padding, endOfStream);
802 }
803
804 @Override
805 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
806 boolean endOfStream) throws Http2Exception {
807 verifyPrefaceReceived();
808 internalFrameListener.onHeadersRead(ctx, streamId, headers, padding, endOfStream);
809 }
810
811 @Override
812 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency,
813 short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {
814 verifyPrefaceReceived();
815 internalFrameListener.onHeadersRead(ctx, streamId, headers, streamDependency, weight,
816 exclusive, padding, endOfStream);
817 }
818
819 @Override
820 public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
821 boolean exclusive) throws Http2Exception {
822 verifyPrefaceReceived();
823 internalFrameListener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive);
824 }
825
826 @Override
827 public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
828 verifyPrefaceReceived();
829 internalFrameListener.onRstStreamRead(ctx, streamId, errorCode);
830 }
831
832 @Override
833 public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {
834 verifyPrefaceReceived();
835 internalFrameListener.onSettingsAckRead(ctx);
836 }
837
838 @Override
839 public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
840
841
842 if (!prefaceReceived()) {
843 internalFrameListener = new FrameReadListener();
844 }
845 internalFrameListener.onSettingsRead(ctx, settings);
846 }
847
848 @Override
849 public void onPingRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
850 verifyPrefaceReceived();
851 internalFrameListener.onPingRead(ctx, data);
852 }
853
854 @Override
855 public void onPingAckRead(ChannelHandlerContext ctx, long data) throws Http2Exception {
856 verifyPrefaceReceived();
857 internalFrameListener.onPingAckRead(ctx, data);
858 }
859
860 @Override
861 public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
862 Http2Headers headers, int padding) throws Http2Exception {
863 verifyPrefaceReceived();
864 internalFrameListener.onPushPromiseRead(ctx, streamId, promisedStreamId, headers, padding);
865 }
866
867 @Override
868 public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData)
869 throws Http2Exception {
870 onGoAwayRead0(ctx, lastStreamId, errorCode, debugData);
871 }
872
873 @Override
874 public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement)
875 throws Http2Exception {
876 verifyPrefaceReceived();
877 internalFrameListener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement);
878 }
879
880 @Override
881 public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
882 ByteBuf payload) throws Http2Exception {
883 verifyPrefaceReceived();
884 internalFrameListener.onUnknownFrame(ctx, frameType, streamId, flags, payload);
885 }
886 }
887
888 private static final class ContentLength {
889 private final long expected;
890 private long seen;
891
892 ContentLength(long expected) {
893 this.expected = expected;
894 }
895
896 void increaseReceivedBytes(boolean server, int streamId, int bytes, boolean isEnd) throws Http2Exception {
897 seen += bytes;
898
899 if (seen < 0) {
900 throw streamError(streamId, PROTOCOL_ERROR,
901 "Received amount of data did overflow and so not match content-length header %d", expected);
902 }
903
904 if (seen > expected) {
905 throw streamError(streamId, PROTOCOL_ERROR,
906 "Received amount of data %d does not match content-length header %d", seen, expected);
907 }
908
909 if (isEnd) {
910 if (seen == 0 && !server) {
911
912 return;
913 }
914
915
916 if (expected > seen) {
917 throw streamError(streamId, PROTOCOL_ERROR,
918 "Received amount of data %d does not match content-length header %d", seen, expected);
919 }
920 }
921 }
922 }
923 }