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