< prev index next >

src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/frame/FramesDecoder.java

Print this page


   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");


< prev index next >