ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/coyote/http2/Http2Parser.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/coyote/http2/Http2Parser.java
Status
scanned
Type
file
Name
Http2Parser.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
34547 (33.7 KB)
MD5
b0e9a3802a33225a6da303c4d55e6196
SHA1
ca4332970a0aa7f794eba4454e367aa029cb6e6c
SHA256
9665e7bd370f11634efd9c05f15faa04f485a1c4abe7ace5e6040ecfdd61bc14
SHA512

      
    
SHA1_git
2973311bcab3fd2264edcdabc439b3513c278c9b
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
Http2Parser.java | 33.7 KB |

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.coyote.http2; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import jakarta.servlet.http.WebConnection; import org.apache.coyote.ProtocolException; import org.apache.coyote.http2.HpackDecoder.HeaderEmitter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteBufferUtils; import org.apache.tomcat.util.http.parser.Priority; import org.apache.tomcat.util.res.StringManager; class Http2Parser { protected static final Log log = LogFactory.getLog(Http2Parser.class); protected static final StringManager sm = StringManager.getManager(Http2Parser.class); static final byte[] CLIENT_PREFACE_START = "PRI * HTTP/2.0 SM ".getBytes(StandardCharsets.ISO_8859_1); protected final String connectionId; protected final Input input; private final Output output; private final byte[] frameHeaderBuffer = new byte[9]; private volatile HpackDecoder hpackDecoder; private volatile ByteBuffer headerReadBuffer = ByteBuffer.allocate(Constants.DEFAULT_HEADER_READ_BUFFER_SIZE); private volatile int headersCurrentStream = -1; private volatile boolean headersEndStream = false; Http2Parser(String connectionId, Input input, Output output) { this.connectionId = connectionId; this.input = input; this.output = output; } /** * Read and process a single frame. The initial read is non-blocking to determine if a frame is present. Once the * start of a frame is read, the remainder will be read using blocking IO. * * @return <code>true</code> if a frame was read otherwise <code>false</code> * * @throws IOException If an IO error occurs while trying to read a frame */ boolean readFrame() throws Http2Exception, IOException { return readFrame(false, null); } protected boolean readFrame(boolean block, FrameType expected) throws IOException, Http2Exception { if (!input.fill(block, frameHeaderBuffer)) { return false; } int payloadSize = ByteUtil.getThreeBytes(frameHeaderBuffer, 0); int frameTypeId = ByteUtil.getOneByte(frameHeaderBuffer, 3); FrameType frameType = FrameType.valueOf(frameTypeId); int flags = ByteUtil.getOneByte(frameHeaderBuffer, 4); int streamId = ByteUtil.get31Bits(frameHeaderBuffer, 5); try { validateFrame(expected, frameType, streamId, flags, payloadSize); } catch (StreamException se) { swallowPayload(streamId, frameTypeId, payloadSize, false, null); throw se; } switch (frameType) { case DATA: readDataFrame(streamId, flags, payloadSize, null); break; case HEADERS: readHeadersFrame(streamId, flags, payloadSize, null); break; case PRIORITY: readPriorityFrame(streamId, null); break; case RST: readRstFrame(streamId, null); break; case SETTINGS: readSettingsFrame(flags, payloadSize, null); break; case PUSH_PROMISE: readPushPromiseFrame(streamId, flags, payloadSize, null); break; case PING: readPingFrame(flags, null); break; case GOAWAY: readGoawayFrame(payloadSize, null); break; case WINDOW_UPDATE: readWindowUpdateFrame(streamId, null); break; case CONTINUATION: readContinuationFrame(streamId, flags, payloadSize, null); break; case PRIORITY_UPDATE: readPriorityUpdateFrame(payloadSize, null); break; case UNKNOWN: readUnknownFrame(streamId, frameTypeId, flags, payloadSize, null); } return true; } protected void readDataFrame(int streamId, int flags, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { // Process the Stream int padLength = 0; boolean endOfStream = Flags.isEndOfStream(flags); int dataLength; if (Flags.hasPadding(flags)) { if (buffer == null) { byte[] b = new byte[1]; input.fill(true, b); padLength = b[0] & 0xFF; } else { padLength = buffer.get() & 0xFF; } if (padLength >= payloadSize) { throw new ConnectionException( sm.getString("http2Parser.processFrame.tooMuchPadding", connectionId, Integer.toString(streamId), Integer.toString(padLength), Integer.toString(payloadSize)), Http2Error.PROTOCOL_ERROR); } // +1 is for the padding length byte we just read above dataLength = payloadSize - (padLength + 1); } else { dataLength = payloadSize; } if (log.isTraceEnabled()) { String padding; if (Flags.hasPadding(flags)) { padding = Integer.toString(padLength); } else { padding = "none"; } log.trace(sm.getString("http2Parser.processFrameData.lengths", connectionId, Integer.toString(streamId), Integer.toString(dataLength), padding)); } ByteBuffer dest = output.startRequestBodyFrame(streamId, dataLength, endOfStream); if (dest == null) { swallowPayload(streamId, FrameType.DATA.getId(), dataLength, false, buffer); // Process padding before sending any notifications in case padding // is invalid. if (Flags.hasPadding(flags)) { swallowPayload(streamId, FrameType.DATA.getId(), padLength, true, buffer); } if (endOfStream) { output.receivedEndOfStream(streamId); } } else { synchronized (dest) { if (dest.remaining() < dataLength) { // Client has sent more data than permitted by Window size swallowPayload(streamId, FrameType.DATA.getId(), dataLength, false, buffer); if (Flags.hasPadding(flags)) { swallowPayload(streamId, FrameType.DATA.getId(), padLength, true, buffer); } throw new StreamException(sm.getString("http2Parser.processFrameData.window", connectionId), Http2Error.FLOW_CONTROL_ERROR, streamId); } if (buffer == null) { input.fill(true, dest, dataLength); } else { int oldLimit = buffer.limit(); buffer.limit(buffer.position() + dataLength); dest.put(buffer); buffer.limit(oldLimit); } // Process padding before sending any notifications in case // padding is invalid. if (Flags.hasPadding(flags)) { swallowPayload(streamId, FrameType.DATA.getId(), padLength, true, buffer); } if (endOfStream) { output.receivedEndOfStream(streamId); } output.endRequestBodyFrame(streamId, dataLength); } } } protected void readHeadersFrame(int streamId, int flags, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { headersEndStream = Flags.isEndOfStream(flags); if (hpackDecoder == null) { hpackDecoder = output.getHpackDecoder(); } try { hpackDecoder.setHeaderEmitter(output.headersStart(streamId, headersEndStream)); } catch (StreamException se) { swallowPayload(streamId, FrameType.HEADERS.getId(), payloadSize, false, buffer); throw se; } int padLength = 0; boolean padding = Flags.hasPadding(flags); boolean priority = Flags.hasPriority(flags); int optionalLen = 0; if (padding) { optionalLen = 1; } if (priority) { optionalLen += 5; } if (optionalLen > 0) { byte[] optional = new byte[optionalLen]; if (buffer == null) { input.fill(true, optional); } else { buffer.get(optional); } if (padding) { padLength = ByteUtil.getOneByte(optional, 0); if (padLength >= payloadSize) { throw new ConnectionException(sm.getString("http2Parser.processFrame.tooMuchPadding", connectionId, Integer.toString(streamId), Integer.toString(padLength), Integer.toString(payloadSize)), Http2Error.PROTOCOL_ERROR); } } // Ignore RFC 7450 priority data if present payloadSize -= optionalLen; payloadSize -= padLength; } readHeaderPayload(streamId, payloadSize, buffer); swallowPayload(streamId, FrameType.HEADERS.getId(), padLength, true, buffer); // Validate the headers so far hpackDecoder.getHeaderEmitter().validateHeaders(); if (Flags.isEndOfHeaders(flags)) { onHeadersComplete(streamId); } else { headersCurrentStream = streamId; } } protected void readPriorityFrame(int streamId, ByteBuffer buffer) throws IOException { // RFC 7450 priority frames are ignored. Still need to treat as overhead. try { swallowPayload(streamId, FrameType.PRIORITY.getId(), 5, false, buffer); } catch (ConnectionException ignore) { // Will never happen because swallowPayload() is called with isPadding set // to false } output.increaseOverheadCount(FrameType.PRIORITY); } protected void readRstFrame(int streamId, ByteBuffer buffer) throws Http2Exception, IOException { byte[] payload = new byte[4]; if (buffer == null) { input.fill(true, payload); } else { buffer.get(payload); } long errorCode = ByteUtil.getFourBytes(payload, 0); output.reset(streamId, errorCode); headersCurrentStream = -1; headersEndStream = false; } protected void readSettingsFrame(int flags, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { boolean ack = Flags.isAck(flags); if (payloadSize > 0 && ack) { throw new ConnectionException(sm.getString("http2Parser.processFrameSettings.ackWithNonZeroPayload"), Http2Error.FRAME_SIZE_ERROR); } if (payloadSize == 0 && !ack) { // Ensure empty SETTINGS frame increments the overhead count output.setting(null, 0); } else { // Process the settings byte[] setting = new byte[6]; for (int i = 0; i < payloadSize / 6; i++) { if (buffer == null) { input.fill(true, setting); } else { buffer.get(setting); } int id = ByteUtil.getTwoBytes(setting, 0); long value = ByteUtil.getFourBytes(setting, 2); Setting key = Setting.valueOf(id); if (key == Setting.UNKNOWN) { log.warn(sm.getString("connectionSettings.unknown", connectionId, Integer.toString(id), Long.toString(value))); } output.setting(key, value); } } output.settingsEnd(ack); } /** * This default server side implementation always throws an exception. If re-used for client side parsing, this * method should be overridden with an appropriate implementation. * * @param streamId The pushed stream * @param flags The flags set in the frame header * @param payloadSize The size of the payload in bytes * @param buffer The payload, if available * * @throws Http2Exception Always * @throws IOException May be thrown by sub-classes that parse this frame */ protected void readPushPromiseFrame(int streamId, int flags, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { throw new ConnectionException( sm.getString("http2Parser.processFramePushPromise", connectionId, Integer.valueOf(streamId)), Http2Error.PROTOCOL_ERROR); } protected void readPingFrame(int flags, ByteBuffer buffer) throws IOException { // Read the payload byte[] payload = new byte[8]; if (buffer == null) { input.fill(true, payload); } else { buffer.get(payload); } output.pingReceive(payload, Flags.isAck(flags)); } protected void readGoawayFrame(int payloadSize, ByteBuffer buffer) throws IOException { byte[] payload = new byte[payloadSize]; if (buffer == null) { input.fill(true, payload); } else { buffer.get(payload); } int lastStreamId = ByteUtil.get31Bits(payload, 0); long errorCode = ByteUtil.getFourBytes(payload, 4); String debugData = null; if (payloadSize > 8) { debugData = new String(payload, 8, payloadSize - 8, StandardCharsets.UTF_8); } output.goaway(lastStreamId, errorCode, debugData); } protected void readWindowUpdateFrame(int streamId, ByteBuffer buffer) throws Http2Exception, IOException { byte[] payload = new byte[4]; if (buffer == null) { input.fill(true, payload); } else { buffer.get(payload); } int windowSizeIncrement = ByteUtil.get31Bits(payload, 0); if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.processFrameWindowUpdate.debug", connectionId, Integer.toString(streamId), Integer.toString(windowSizeIncrement))); } // Validate the data if (windowSizeIncrement == 0) { if (streamId == 0) { throw new ConnectionException(sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement", connectionId, Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR); } else { throw new StreamException(sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement", connectionId, Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR, streamId); } } output.incrementWindowSize(streamId, windowSizeIncrement); } protected void readContinuationFrame(int streamId, int flags, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { if (headersCurrentStream == -1) { // No headers to continue throw new ConnectionException(sm.getString("http2Parser.processFrameContinuation.notExpected", connectionId, Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR); } boolean endOfHeaders = Flags.isEndOfHeaders(flags); // Used to detect abusive clients sending large numbers of small // continuation frames output.headersContinue(payloadSize, endOfHeaders); readHeaderPayload(streamId, payloadSize, buffer); // Validate the headers so far hpackDecoder.getHeaderEmitter().validateHeaders(); if (endOfHeaders) { headersCurrentStream = -1; onHeadersComplete(streamId); } } protected void readPriorityUpdateFrame(int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { // Identify prioritized stream ID byte[] payload = new byte[payloadSize]; if (buffer == null) { input.fill(true, payload); } else { buffer.get(payload); } int prioritizedStreamID = ByteUtil.get31Bits(payload, 0); if (prioritizedStreamID == 0) { throw new ConnectionException(sm.getString("http2Parser.processFramePriorityUpdate.streamZero"), Http2Error.PROTOCOL_ERROR); } ByteArrayInputStream bais = new ByteArrayInputStream(payload, 4, payloadSize - 4); Reader r = new BufferedReader(new InputStreamReader(bais, StandardCharsets.US_ASCII)); try { Priority p = Priority.parsePriority(r); if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.processFramePriorityUpdate.debug", connectionId, Integer.toString(prioritizedStreamID), Integer.toString(p.getUrgency()), Boolean.valueOf(p.getIncremental()))); } output.priorityUpdate(prioritizedStreamID, p); } catch (IllegalArgumentException iae) { // Priority frames with invalid priority field values should be ignored if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.processFramePriorityUpdate.invalid", connectionId, Integer.toString(prioritizedStreamID)), iae); } } } protected void readHeaderPayload(int streamId, int payloadSize, ByteBuffer buffer) throws Http2Exception, IOException { if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.processFrameHeaders.payload", connectionId, Integer.valueOf(streamId), Integer.valueOf(payloadSize))); } int remaining = payloadSize; while (remaining > 0) { if (headerReadBuffer.remaining() == 0) { // Buffer needs expansion int newSize; if (headerReadBuffer.capacity() < payloadSize) { // First step, expand to the current payload. That should // cover most cases. newSize = payloadSize; } else { // Header must be spread over multiple frames. Keep doubling // buffer size until the header can be read. newSize = headerReadBuffer.capacity() * 2; } headerReadBuffer = ByteBufferUtils.expand(headerReadBuffer, newSize); } int toRead = Math.min(headerReadBuffer.remaining(), remaining); // headerReadBuffer in write mode if (buffer == null) { input.fill(true, headerReadBuffer, toRead); } else { int oldLimit = buffer.limit(); buffer.limit(buffer.position() + toRead); headerReadBuffer.put(buffer); buffer.limit(oldLimit); } // switch to read mode headerReadBuffer.flip(); try { hpackDecoder.decode(headerReadBuffer); } catch (HpackException hpe) { throw new ConnectionException(sm.getString("http2Parser.processFrameHeaders.decodingFailed"), Http2Error.COMPRESSION_ERROR, hpe); } // switches to write mode headerReadBuffer.compact(); remaining -= toRead; if (hpackDecoder.isHeaderCountExceeded()) { StreamException headerException = new StreamException( sm.getString("http2Parser.headerLimitCount", connectionId, Integer.valueOf(streamId)), Http2Error.ENHANCE_YOUR_CALM, streamId); hpackDecoder.getHeaderEmitter().setHeaderException(headerException); } if (hpackDecoder.isHeaderSizeExceeded(headerReadBuffer.position())) { StreamException headerException = new StreamException( sm.getString("http2Parser.headerLimitSize", connectionId, Integer.valueOf(streamId)), Http2Error.ENHANCE_YOUR_CALM, streamId); hpackDecoder.getHeaderEmitter().setHeaderException(headerException); } if (hpackDecoder.isHeaderSwallowSizeExceeded(headerReadBuffer.position())) { throw new ConnectionException( sm.getString("http2Parser.headerLimitSize", connectionId, Integer.valueOf(streamId)), Http2Error.ENHANCE_YOUR_CALM); } } } protected void readUnknownFrame(int streamId, int frameTypeId, int flags, int payloadSize, ByteBuffer buffer) throws IOException { try { swallowPayload(streamId, frameTypeId, payloadSize, false, buffer); } catch (ConnectionException e) { // Will never happen because swallowPayload() is called with isPadding set // to false } finally { output.onSwallowedUnknownFrame(streamId, frameTypeId, flags, payloadSize); } } /** * Swallow some or all of the bytes from the payload of an HTTP/2 frame. * * @param streamId Stream being swallowed * @param frameTypeId Type of HTTP/2 frame for which the bytes will be swallowed * @param len Number of bytes to swallow * @param isPadding Are the bytes to be swallowed padding bytes? * @param byteBuffer Used with {@link Http2AsyncParser} to access the data that has already been read * * @throws IOException If an I/O error occurs reading additional bytes into the input buffer. * @throws ConnectionException If the swallowed bytes are expected to have a value of zero but do not */ protected void swallowPayload(int streamId, int frameTypeId, int len, boolean isPadding, ByteBuffer byteBuffer) throws IOException, ConnectionException { if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.swallow.debug", connectionId, Integer.toString(streamId), Integer.toString(len))); } try { if (len == 0) { return; } if (!isPadding && byteBuffer != null) { byteBuffer.position(byteBuffer.position() + len); } else { int read = 0; byte[] buffer = new byte[1024]; while (read < len) { int thisTime = Math.min(buffer.length, len - read); if (byteBuffer == null) { input.fill(true, buffer, 0, thisTime); } else { byteBuffer.get(buffer, 0, thisTime); } if (isPadding) { // Validate the padding is zero since receiving non-zero padding // is a strong indication of either a faulty client or a server // side bug. for (int i = 0; i < thisTime; i++) { if (buffer[i] != 0) { throw new ConnectionException(sm.getString("http2Parser.nonZeroPadding", connectionId, Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR); } } } read += thisTime; } } } finally { if (FrameType.DATA.getIdByte() == frameTypeId) { if (isPadding) { // Need to add 1 for the padding length bytes that was also // part of the payload. len += 1; } if (len > 0) { output.onSwallowedDataFramePayload(streamId, len); } } } } protected void onHeadersComplete(int streamId) throws Http2Exception { // Any left over data is a compression error if (headerReadBuffer.position() > 0) { throw new ConnectionException(sm.getString("http2Parser.processFrameHeaders.decodingDataLeft"), Http2Error.COMPRESSION_ERROR); } /* * Clear the reference to the stream in the HPack decoder now that the headers have been processed so that the * HPack decoder does not retain a reference to this stream. This aids GC. */ hpackDecoder.clearHeaderEmitter(); synchronized (output) { output.headersEnd(streamId, headersEndStream); if (headersEndStream) { headersEndStream = false; } } // Reset size for new request if the buffer was previously expanded if (headerReadBuffer.capacity() > Constants.DEFAULT_HEADER_READ_BUFFER_SIZE) { headerReadBuffer = ByteBuffer.allocate(Constants.DEFAULT_HEADER_READ_BUFFER_SIZE); } } /* * Implementation note: Validation applicable to all incoming frames should be implemented here. Frame type specific * validation should be performed in the appropriate readXxxFrame() method. For validation applicable to some but * not all frame types, use your judgement. */ protected void validateFrame(FrameType expected, FrameType frameType, int streamId, int flags, int payloadSize) throws Http2Exception { if (log.isTraceEnabled()) { log.trace(sm.getString("http2Parser.processFrame", connectionId, Integer.toString(streamId), frameType, Integer.toString(flags), Integer.toString(payloadSize))); } if (expected != null && frameType != expected) { throw new StreamException(sm.getString("http2Parser.processFrame.unexpectedType", expected, frameType), Http2Error.PROTOCOL_ERROR, streamId); } int maxFrameSize = input.getMaxFrameSize(); if (payloadSize > maxFrameSize) { throw new ConnectionException(sm.getString("http2Parser.payloadTooBig", Integer.toString(payloadSize), Integer.toString(maxFrameSize)), Http2Error.FRAME_SIZE_ERROR); } if (headersCurrentStream != -1) { if (headersCurrentStream != streamId) { throw new ConnectionException( sm.getString("http2Parser.headers.wrongStream", connectionId, Integer.toString(headersCurrentStream), Integer.toString(streamId)), Http2Error.COMPRESSION_ERROR); } if (frameType == FrameType.RST) { // NO-OP: RST is OK here } else if (frameType != FrameType.CONTINUATION) { throw new ConnectionException(sm.getString("http2Parser.headers.wrongFrameType", connectionId, Integer.toString(headersCurrentStream), frameType), Http2Error.COMPRESSION_ERROR); } } frameType.check(streamId, payloadSize); } /** * Read and validate the connection preface from input using blocking IO. * * @param webConnection The connection * @param stream The current stream */ void readConnectionPreface(WebConnection webConnection, Stream stream) throws Http2Exception { byte[] data = new byte[CLIENT_PREFACE_START.length]; try { input.fill(true, data); for (int i = 0; i < CLIENT_PREFACE_START.length; i++) { if (CLIENT_PREFACE_START[i] != data[i]) { throw new ProtocolException(sm.getString("http2Parser.preface.invalid")); } } // Must always be followed by a settings frame readFrame(true, FrameType.SETTINGS); } catch (IOException ioe) { throw new ProtocolException(sm.getString("http2Parser.preface.io"), ioe); } } /** * Interface that must be implemented by the source of data for the parser. */ interface Input { /** * Fill the given array with data unless non-blocking is requested and no data is available. If any data is * available then the buffer will be filled using blocking I/O. * * @param block Should the first read into the provided buffer be a blocking read or not. * @param data Buffer to fill * @param offset Position in buffer to start writing * @param length Number of bytes to read * * @return <code>true</code> if the buffer was filled otherwise <code>false</code> * * @throws IOException If an I/O occurred while obtaining data with which to fill the buffer */ boolean fill(boolean block, byte[] data, int offset, int length) throws IOException; default boolean fill(boolean block, byte[] data) throws IOException { return fill(block, data, 0, data.length); } default boolean fill(boolean block, ByteBuffer data, int len) throws IOException { boolean result = fill(block, data.array(), data.arrayOffset() + data.position(), len); if (result) { data.position(data.position() + len); } return result; } int getMaxFrameSize(); } /** * Interface that must be implemented to receive notifications from the parser as it processes incoming frames. */ interface Output { HpackDecoder getHpackDecoder(); // Data frames ByteBuffer startRequestBodyFrame(int streamId, int dataLength, boolean endOfStream) throws Http2Exception; void endRequestBodyFrame(int streamId, int dataLength) throws Http2Exception, IOException; void receivedEndOfStream(int streamId) throws ConnectionException; /** * Notification triggered when the parser swallows some or all of a DATA frame payload without writing it to the * ByteBuffer returned by {@link #startRequestBodyFrame(int, int, boolean)}. * * @param streamId The stream on which the payload that has been swallowed was received * @param swallowedDataBytesCount The number of bytes that the parser swallowed. * * @throws ConnectionException If an error fatal to the HTTP/2 connection occurs while swallowing the payload * @throws IOException If an I/O occurred while swallowing the payload */ void onSwallowedDataFramePayload(int streamId, int swallowedDataBytesCount) throws ConnectionException, IOException; // Header frames HeaderEmitter headersStart(int streamId, boolean headersEndStream) throws Http2Exception, IOException; void headersContinue(int payloadSize, boolean endOfHeaders); void headersEnd(int streamId, boolean endOfStream) throws Http2Exception; // Reset frames void reset(int streamId, long errorCode) throws Http2Exception; // Settings frames void setting(Setting setting, long value) throws ConnectionException; void settingsEnd(boolean ack) throws IOException; // Ping frames void pingReceive(byte[] payload, boolean ack) throws IOException; // Goaway void goaway(int lastStreamId, long errorCode, String debugData); // Window size void incrementWindowSize(int streamId, int increment) throws Http2Exception; // Priority update void priorityUpdate(int prioritizedStreamID, Priority p) throws Http2Exception; /** * Notification triggered when the parser swallows the payload of an unknown frame. * * @param streamId The stream on which the swallowed frame was received * @param frameTypeId The (unrecognised) type of swallowed frame * @param flags The flags set in the header of the swallowed frame * @param size The payload size of the swallowed frame * * @throws IOException If an I/O occurred while swallowing the unknown frame */ void onSwallowedUnknownFrame(int streamId, int frameTypeId, int flags, int size) throws IOException; void increaseOverheadCount(FrameType frameType); } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
3.97
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9