1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http.internal.frame; 27 28 import jdk.incubator.http.internal.common.ByteBufferReference; 29 import jdk.incubator.http.internal.common.Log; 30 import jdk.incubator.http.internal.common.Utils; 31 32 import java.io.IOException; 33 import java.nio.ByteBuffer; 34 import java.util.ArrayDeque; 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * Frames Decoder 40 * <p> 41 * collect buffers until frame decoding is possible, 42 * all decoded frames are passed to the FrameProcessor callback in order of decoding. 43 * 44 * It's a stateful class due to the fact that FramesDecoder stores buffers inside. 45 * Should be allocated only the single instance per connection. 46 */ 47 public class FramesDecoder { 48 49 50 51 @FunctionalInterface 52 public interface FrameProcessor { 53 void processFrame(Http2Frame frame) throws IOException; 54 } 55 56 private final FrameProcessor frameProcessor; 57 private final int maxFrameSize; 58 59 private ByteBufferReference currentBuffer; // current buffer either null or hasRemaining 60 61 private final java.util.Queue<ByteBufferReference> tailBuffers = new ArrayDeque<>(); 62 private int tailSize = 0; 63 64 private boolean slicedToDataFrame = false; 65 66 private final List<ByteBufferReference> prepareToRelease = new ArrayList<>(); 67 68 // if true - Frame Header was parsed (9 bytes consumed) and subsequent fields have meaning 69 // otherwise - stopped at frames boundary 70 private boolean frameHeaderParsed = false; 71 private int frameLength; 72 private int frameType; 73 private int frameFlags; 74 private int frameStreamid; 75 76 /** 77 * Creates Frame Decoder 78 * 79 * @param frameProcessor - callback for decoded frames 80 */ 81 public FramesDecoder(FrameProcessor frameProcessor) { 82 this(frameProcessor, 16 * 1024); 83 } 84 85 /** 86 * Creates Frame Decoder 87 * @param frameProcessor - callback for decoded frames 88 * @param maxFrameSize - maxFrameSize accepted by this decoder 89 */ 90 public FramesDecoder(FrameProcessor frameProcessor, int maxFrameSize) { 91 this.frameProcessor = frameProcessor; 92 this.maxFrameSize = Math.min(Math.max(16 * 1024, maxFrameSize), 16 * 1024 * 1024 - 1); 93 } 94 95 /** 96 * put next buffer into queue, 97 * if frame decoding is possible - decode all buffers and invoke FrameProcessor 98 * 99 * @param buffer 100 * @throws IOException 101 */ 102 public void decode(ByteBufferReference buffer) throws IOException { 103 int remaining = buffer.get().remaining(); 104 if (remaining > 0) { 105 if (currentBuffer == null) { 106 currentBuffer = buffer; 107 } else { 108 tailBuffers.add(buffer); 109 tailSize += remaining; 110 } 111 } 112 Http2Frame frame; 113 while ((frame = nextFrame()) != null) { 114 frameProcessor.processFrame(frame); 115 frameProcessed(); 116 } 117 } 118 119 private Http2Frame nextFrame() throws IOException { 120 while (true) { 121 if (currentBuffer == null) { 122 return null; // no data at all 123 } 124 if (!frameHeaderParsed) { 125 if (currentBuffer.get().remaining() + tailSize >= Http2Frame.FRAME_HEADER_SIZE) { 126 parseFrameHeader(); 127 if (frameLength > maxFrameSize) { 128 // connection error 129 return new MalformedFrame(ErrorFrame.FRAME_SIZE_ERROR, 130 "Frame type("+frameType+") " +"length("+frameLength+") exceeds MAX_FRAME_SIZE("+ maxFrameSize+")"); 131 } 132 frameHeaderParsed = true; 133 } else { 134 return null; // no data for frame header 135 } 136 } 137 if ((frameLength == 0) || 138 (currentBuffer != null && currentBuffer.get().remaining() + tailSize >= frameLength)) { 139 Http2Frame frame = parseFrameBody(); 140 frameHeaderParsed = false; 141 // frame == null means we have to skip this frame and try parse next 142 if (frame != null) { 143 return frame; 144 } 145 } else { 146 return null; // no data for the whole frame header 147 } 148 } 149 } 150 151 private void frameProcessed() { 152 prepareToRelease.forEach(ByteBufferReference::clear); 153 prepareToRelease.clear(); 154 } 155 156 private void parseFrameHeader() throws IOException { 157 int x = getInt(); 158 this.frameLength = x >> 8; 159 this.frameType = x & 0xff; 160 this.frameFlags = getByte(); 161 this.frameStreamid = getInt() & 0x7fffffff; 162 // R: A reserved 1-bit field. The semantics of this bit are undefined, 163 // MUST be ignored when receiving. 164 } 165 166 // move next buffer from tailBuffers to currentBuffer if required 167 private void nextBuffer() { 168 if (!currentBuffer.get().hasRemaining()) { 169 if (!slicedToDataFrame) { 170 prepareToRelease.add(currentBuffer); 171 } 172 slicedToDataFrame = false; 173 currentBuffer = tailBuffers.poll(); 174 if (currentBuffer != null) { 175 tailSize -= currentBuffer.get().remaining(); 176 } 177 } 178 } 179 180 public int getByte() { 181 ByteBuffer buf = currentBuffer.get(); 182 int res = buf.get() & 0xff; 183 nextBuffer(); 184 return res; 185 } 186 187 public int getShort() { 188 ByteBuffer buf = currentBuffer.get(); 189 if (buf.remaining() >= 2) { 190 int res = buf.getShort() & 0xffff; 191 nextBuffer(); 192 return res; 193 } 194 int val = getByte(); 195 val = (val << 8) + getByte(); 196 return val; 197 } 198 199 public int getInt() { 200 ByteBuffer buf = currentBuffer.get(); 201 if (buf.remaining() >= 4) { 202 int res = buf.getInt(); 203 nextBuffer(); 204 return res; 205 } 206 int val = getByte(); 207 val = (val << 8) + getByte(); 208 val = (val << 8) + getByte(); 209 val = (val << 8) + getByte(); 210 return val; 211 212 } 213 214 public byte[] getBytes(int n) { 215 byte[] bytes = new byte[n]; 216 int offset = 0; 217 while (n > 0) { 218 ByteBuffer buf = currentBuffer.get(); 219 int length = Math.min(n, buf.remaining()); 220 buf.get(bytes, offset, length); 221 offset += length; 222 n -= length; 223 nextBuffer(); 224 } 225 return bytes; 226 227 } 228 229 private ByteBufferReference[] getBuffers(boolean isDataFrame, int bytecount) { 230 List<ByteBufferReference> res = new ArrayList<>(); 231 while (bytecount > 0) { 232 ByteBuffer buf = currentBuffer.get(); 233 int remaining = buf.remaining(); 234 int extract = Math.min(remaining, bytecount); 235 ByteBuffer extractedBuf; 236 if (isDataFrame) { 237 extractedBuf = Utils.slice(buf, extract); 238 slicedToDataFrame = true; 239 } else { 240 // Header frames here 241 // HPACK decoding should performed under lock and immediately after frame decoding. 242 // in that case it is safe to release original buffer, 243 // because of sliced buffer has a very short life 244 extractedBuf = Utils.slice(buf, extract); 245 } 246 res.add(ByteBufferReference.of(extractedBuf)); 247 bytecount -= extract; 248 nextBuffer(); 249 } 250 return res.toArray(new ByteBufferReference[0]); 251 } 252 253 public void skipBytes(int bytecount) { 254 while (bytecount > 0) { 255 ByteBuffer buf = currentBuffer.get(); 256 int remaining = buf.remaining(); 257 int extract = Math.min(remaining, bytecount); 258 buf.position(buf.position() + extract); 259 bytecount -= remaining; 260 nextBuffer(); 261 } 262 } 263 264 private Http2Frame parseFrameBody() throws IOException { 265 assert frameHeaderParsed; 266 switch (frameType) { 267 case DataFrame.TYPE: 268 return parseDataFrame(frameLength, frameStreamid, frameFlags); 269 case HeadersFrame.TYPE: 270 return parseHeadersFrame(frameLength, frameStreamid, frameFlags); 271 case PriorityFrame.TYPE: 272 return parsePriorityFrame(frameLength, frameStreamid, frameFlags); 273 case ResetFrame.TYPE: 274 return parseResetFrame(frameLength, frameStreamid, frameFlags); 275 case SettingsFrame.TYPE: 276 return parseSettingsFrame(frameLength, frameStreamid, frameFlags); 277 case PushPromiseFrame.TYPE: 278 return parsePushPromiseFrame(frameLength, frameStreamid, frameFlags); 279 case PingFrame.TYPE: 280 return parsePingFrame(frameLength, frameStreamid, frameFlags); 281 case GoAwayFrame.TYPE: 282 return parseGoAwayFrame(frameLength, frameStreamid, frameFlags); 283 case WindowUpdateFrame.TYPE: 284 return parseWindowUpdateFrame(frameLength, frameStreamid, frameFlags); 285 case ContinuationFrame.TYPE: 286 return parseContinuationFrame(frameLength, frameStreamid, frameFlags); 287 default: 288 // RFC 7540 4.1 289 // Implementations MUST ignore and discard any frame that has a type that is unknown. 290 Log.logTrace("Unknown incoming frame type: {0}", frameType); 291 skipBytes(frameLength); 292 return null; 293 } 294 } 295 296 private Http2Frame parseDataFrame(int frameLength, int streamid, int flags) { 297 // non-zero stream 298 if (streamid == 0) { 299 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, "zero streamId for DataFrame"); 300 } 301 int padLength = 0; 302 if ((flags & DataFrame.PADDED) != 0) { 303 padLength = getByte(); 304 if(padLength >= frameLength) { 305 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 306 "the length of the padding is the length of the frame payload or greater"); 307 } 308 frameLength--; 309 } 310 DataFrame df = new DataFrame(streamid, flags, 311 getBuffers(true, frameLength - padLength), padLength); 312 skipBytes(padLength); 313 return df; 314 315 } 316 317 private Http2Frame parseHeadersFrame(int frameLength, int streamid, int flags) { 318 // non-zero stream 319 if (streamid == 0) { 320 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, "zero streamId for HeadersFrame"); 321 } 322 int padLength = 0; 323 if ((flags & HeadersFrame.PADDED) != 0) { 324 padLength = getByte(); 325 frameLength--; 326 } 327 boolean hasPriority = (flags & HeadersFrame.PRIORITY) != 0; 328 boolean exclusive = false; 329 int streamDependency = 0; 330 int weight = 0; 331 if (hasPriority) { 332 int x = getInt(); 333 exclusive = (x & 0x80000000) != 0; 334 streamDependency = x & 0x7fffffff; 335 weight = getByte(); 336 frameLength -= 5; 337 } 338 if(frameLength < padLength) { 339 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 340 "Padding exceeds the size remaining for the header block"); | 1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http.internal.frame; 27 28 import jdk.incubator.http.internal.common.Log; 29 import jdk.incubator.http.internal.common.Utils; 30 31 import java.io.IOException; 32 import java.lang.System.Logger.Level; 33 import java.nio.ByteBuffer; 34 import java.util.ArrayDeque; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Queue; 38 39 /** 40 * Frames Decoder 41 * <p> 42 * collect buffers until frame decoding is possible, 43 * all decoded frames are passed to the FrameProcessor callback in order of decoding. 44 * 45 * It's a stateful class due to the fact that FramesDecoder stores buffers inside. 46 * Should be allocated only the single instance per connection. 47 */ 48 public class FramesDecoder { 49 50 static final boolean DEBUG = Utils.DEBUG; // Revisit: temporary dev flag. 51 static final System.Logger DEBUG_LOGGER = 52 Utils.getDebugLogger("FramesDecoder"::toString, DEBUG); 53 54 @FunctionalInterface 55 public interface FrameProcessor { 56 void processFrame(Http2Frame frame) throws IOException; 57 } 58 59 private final FrameProcessor frameProcessor; 60 private final int maxFrameSize; 61 62 private ByteBuffer currentBuffer; // current buffer either null or hasRemaining 63 64 private final Queue<ByteBuffer> tailBuffers = new ArrayDeque<>(); 65 private int tailSize = 0; 66 67 private boolean slicedToDataFrame = false; 68 69 private final List<ByteBuffer> prepareToRelease = new ArrayList<>(); 70 71 // if true - Frame Header was parsed (9 bytes consumed) and subsequent fields have meaning 72 // otherwise - stopped at frames boundary 73 private boolean frameHeaderParsed = false; 74 private int frameLength; 75 private int frameType; 76 private int frameFlags; 77 private int frameStreamid; 78 79 /** 80 * Creates Frame Decoder 81 * 82 * @param frameProcessor - callback for decoded frames 83 */ 84 public FramesDecoder(FrameProcessor frameProcessor) { 85 this(frameProcessor, 16 * 1024); 86 } 87 88 /** 89 * Creates Frame Decoder 90 * @param frameProcessor - callback for decoded frames 91 * @param maxFrameSize - maxFrameSize accepted by this decoder 92 */ 93 public FramesDecoder(FrameProcessor frameProcessor, int maxFrameSize) { 94 this.frameProcessor = frameProcessor; 95 this.maxFrameSize = Math.min(Math.max(16 * 1024, maxFrameSize), 16 * 1024 * 1024 - 1); 96 } 97 98 /** Threshold beyond which data is no longer copied into the current buffer, 99 * if that buffer has enough unused space. */ 100 private static final int COPY_THRESHOLD = 8192; 101 102 /** 103 * Adds the data from the given buffer, and performs frame decoding if 104 * possible. Either 1) appends the data from the given buffer to the 105 * current buffer ( if there is enough unused space ), or 2) adds it to the 106 * next buffer in the queue. 107 * 108 * If there is enough data to perform frame decoding then, all buffers are 109 * decoded and the FrameProcessor is invoked. 110 */ 111 public void decode(ByteBuffer buffer) throws IOException { 112 int remaining = buffer.remaining(); 113 DEBUG_LOGGER.log(Level.DEBUG, "decodes: %d", remaining); 114 if (remaining > 0) { 115 if (currentBuffer == null) { 116 currentBuffer = buffer; 117 } else { 118 int limit = currentBuffer.limit(); 119 int freeSpace = currentBuffer.capacity() - limit; 120 if (remaining <= COPY_THRESHOLD && freeSpace >= remaining) { 121 // append the new data to the unused space in the current buffer 122 ByteBuffer b = buffer; 123 int position = currentBuffer.position(); 124 currentBuffer.position(limit); 125 currentBuffer.limit(limit + b.limit()); 126 currentBuffer.put(b); 127 currentBuffer.position(position); 128 DEBUG_LOGGER.log(Level.DEBUG, "copied: %d", remaining); 129 } else { 130 DEBUG_LOGGER.log(Level.DEBUG, "added: %d", remaining); 131 tailBuffers.add(buffer); 132 tailSize += remaining; 133 } 134 } 135 } 136 DEBUG_LOGGER.log(Level.DEBUG, "Tail size is now: %d, current=", 137 tailSize, 138 (currentBuffer == null ? 0 : 139 currentBuffer.remaining())); 140 Http2Frame frame; 141 while ((frame = nextFrame()) != null) { 142 DEBUG_LOGGER.log(Level.DEBUG, "Got frame: %s", frame); 143 frameProcessor.processFrame(frame); 144 frameProcessed(); 145 } 146 } 147 148 private Http2Frame nextFrame() throws IOException { 149 while (true) { 150 if (currentBuffer == null) { 151 return null; // no data at all 152 } 153 long available = currentBuffer.remaining() + tailSize; 154 if (!frameHeaderParsed) { 155 if (available >= Http2Frame.FRAME_HEADER_SIZE) { 156 parseFrameHeader(); 157 if (frameLength > maxFrameSize) { 158 // connection error 159 return new MalformedFrame(ErrorFrame.FRAME_SIZE_ERROR, 160 "Frame type("+frameType+") " 161 +"length("+frameLength 162 +") exceeds MAX_FRAME_SIZE(" 163 + maxFrameSize+")"); 164 } 165 frameHeaderParsed = true; 166 } else { 167 DEBUG_LOGGER.log(Level.DEBUG, 168 "Not enough data to parse header, needs: %d, has: %d", 169 Http2Frame.FRAME_HEADER_SIZE, available); 170 } 171 } 172 available = currentBuffer == null ? 0 : currentBuffer.remaining() + tailSize; 173 if ((frameLength == 0) || 174 (currentBuffer != null && available >= frameLength)) { 175 Http2Frame frame = parseFrameBody(); 176 frameHeaderParsed = false; 177 // frame == null means we have to skip this frame and try parse next 178 if (frame != null) { 179 return frame; 180 } 181 } else { 182 DEBUG_LOGGER.log(Level.DEBUG, 183 "Not enough data to parse frame body, needs: %d, has: %d", 184 frameLength, available); 185 return null; // no data for the whole frame header 186 } 187 } 188 } 189 190 private void frameProcessed() { 191 prepareToRelease.clear(); 192 } 193 194 private void parseFrameHeader() throws IOException { 195 int x = getInt(); 196 this.frameLength = x >> 8; 197 this.frameType = x & 0xff; 198 this.frameFlags = getByte(); 199 this.frameStreamid = getInt() & 0x7fffffff; 200 // R: A reserved 1-bit field. The semantics of this bit are undefined, 201 // MUST be ignored when receiving. 202 } 203 204 // move next buffer from tailBuffers to currentBuffer if required 205 private void nextBuffer() { 206 if (!currentBuffer.hasRemaining()) { 207 if (!slicedToDataFrame) { 208 prepareToRelease.add(currentBuffer); 209 } 210 slicedToDataFrame = false; 211 currentBuffer = tailBuffers.poll(); 212 if (currentBuffer != null) { 213 tailSize -= currentBuffer.remaining(); 214 } 215 } 216 } 217 218 public int getByte() { 219 int res = currentBuffer.get() & 0xff; 220 nextBuffer(); 221 return res; 222 } 223 224 public int getShort() { 225 if (currentBuffer.remaining() >= 2) { 226 int res = currentBuffer.getShort() & 0xffff; 227 nextBuffer(); 228 return res; 229 } 230 int val = getByte(); 231 val = (val << 8) + getByte(); 232 return val; 233 } 234 235 public int getInt() { 236 if (currentBuffer.remaining() >= 4) { 237 int res = currentBuffer.getInt(); 238 nextBuffer(); 239 return res; 240 } 241 int val = getByte(); 242 val = (val << 8) + getByte(); 243 val = (val << 8) + getByte(); 244 val = (val << 8) + getByte(); 245 return val; 246 247 } 248 249 public byte[] getBytes(int n) { 250 byte[] bytes = new byte[n]; 251 int offset = 0; 252 while (n > 0) { 253 int length = Math.min(n, currentBuffer.remaining()); 254 currentBuffer.get(bytes, offset, length); 255 offset += length; 256 n -= length; 257 nextBuffer(); 258 } 259 return bytes; 260 261 } 262 263 private List<ByteBuffer> getBuffers(boolean isDataFrame, int bytecount) { 264 List<ByteBuffer> res = new ArrayList<>(); 265 while (bytecount > 0) { 266 int remaining = currentBuffer.remaining(); 267 int extract = Math.min(remaining, bytecount); 268 ByteBuffer extractedBuf; 269 if (isDataFrame) { 270 extractedBuf = Utils.slice(currentBuffer, extract); 271 slicedToDataFrame = true; 272 } else { 273 // Header frames here 274 // HPACK decoding should performed under lock and immediately after frame decoding. 275 // in that case it is safe to release original buffer, 276 // because of sliced buffer has a very short life 277 extractedBuf = Utils.slice(currentBuffer, extract); 278 } 279 res.add(extractedBuf); 280 bytecount -= extract; 281 nextBuffer(); 282 } 283 return res; 284 } 285 286 public void skipBytes(int bytecount) { 287 while (bytecount > 0) { 288 int remaining = currentBuffer.remaining(); 289 int extract = Math.min(remaining, bytecount); 290 currentBuffer.position(currentBuffer.position() + extract); 291 bytecount -= remaining; 292 nextBuffer(); 293 } 294 } 295 296 private Http2Frame parseFrameBody() throws IOException { 297 assert frameHeaderParsed; 298 switch (frameType) { 299 case DataFrame.TYPE: 300 return parseDataFrame(frameLength, frameStreamid, frameFlags); 301 case HeadersFrame.TYPE: 302 return parseHeadersFrame(frameLength, frameStreamid, frameFlags); 303 case PriorityFrame.TYPE: 304 return parsePriorityFrame(frameLength, frameStreamid, frameFlags); 305 case ResetFrame.TYPE: 306 return parseResetFrame(frameLength, frameStreamid, frameFlags); 307 case SettingsFrame.TYPE: 308 return parseSettingsFrame(frameLength, frameStreamid, frameFlags); 309 case PushPromiseFrame.TYPE: 310 return parsePushPromiseFrame(frameLength, frameStreamid, frameFlags); 311 case PingFrame.TYPE: 312 return parsePingFrame(frameLength, frameStreamid, frameFlags); 313 case GoAwayFrame.TYPE: 314 return parseGoAwayFrame(frameLength, frameStreamid, frameFlags); 315 case WindowUpdateFrame.TYPE: 316 return parseWindowUpdateFrame(frameLength, frameStreamid, frameFlags); 317 case ContinuationFrame.TYPE: 318 return parseContinuationFrame(frameLength, frameStreamid, frameFlags); 319 default: 320 // RFC 7540 4.1 321 // Implementations MUST ignore and discard any frame that has a type that is unknown. 322 Log.logTrace("Unknown incoming frame type: {0}", frameType); 323 skipBytes(frameLength); 324 return null; 325 } 326 } 327 328 private Http2Frame parseDataFrame(int frameLength, int streamid, int flags) { 329 // non-zero stream 330 if (streamid == 0) { 331 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 332 "zero streamId for DataFrame"); 333 } 334 int padLength = 0; 335 if ((flags & DataFrame.PADDED) != 0) { 336 padLength = getByte(); 337 if (padLength >= frameLength) { 338 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 339 "the length of the padding is the length of the frame payload or greater"); 340 } 341 frameLength--; 342 } 343 DataFrame df = new DataFrame(streamid, flags, 344 getBuffers(true, frameLength - padLength), padLength); 345 skipBytes(padLength); 346 return df; 347 348 } 349 350 private Http2Frame parseHeadersFrame(int frameLength, int streamid, int flags) { 351 // non-zero stream 352 if (streamid == 0) { 353 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 354 "zero streamId for HeadersFrame"); 355 } 356 int padLength = 0; 357 if ((flags & HeadersFrame.PADDED) != 0) { 358 padLength = getByte(); 359 frameLength--; 360 } 361 boolean hasPriority = (flags & HeadersFrame.PRIORITY) != 0; 362 boolean exclusive = false; 363 int streamDependency = 0; 364 int weight = 0; 365 if (hasPriority) { 366 int x = getInt(); 367 exclusive = (x & 0x80000000) != 0; 368 streamDependency = x & 0x7fffffff; 369 weight = getByte(); 370 frameLength -= 5; 371 } 372 if(frameLength < padLength) { 373 return new MalformedFrame(ErrorFrame.PROTOCOL_ERROR, 374 "Padding exceeds the size remaining for the header block"); |