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