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