private State readHeaders(ChannelBuffer buffer) throws TooLongFrameException {
    headerSize = 0;
    String line = readHeader(buffer);
    int match = 0;
    String name = null;
    String value = null;
    boolean nameToInsert = false;
    boolean hasContentLength = false;
    if (line.length() != 0) {
      do {
        char firstChar = line.charAt(0);
        if (name != null && (firstChar == ' ' || firstChar == '\t')) {
          value = value + ' ' + line.trim();
        } else {
          if (name != null && nameToInsert) {
            match++;
            message.addHeader(name, value);
          }
          if (match < 3 && firstChar == 'C') {
            if (line.startsWith("Connection: ")) {
              name = "Connection";
              value = line.substring(12);
              nameToInsert = true;
            } else if (line.startsWith("Cookie: ")) {
              name = "Cookie";
              value = line.substring(8);
              nameToInsert = true;
            } else if (line.startsWith("Content-Length: ")) {
              name = "Content-Length";
              value = line.substring(16);
              nameToInsert = true;
              hasContentLength = true;
            } else {
              nameToInsert = false;
            }
          }
        }

        line = readHeader(buffer);
      } while (line.length() != 0);

      // Add the last header.
      if (name != null && nameToInsert) {
        match++;
        message.addHeader(name, value);
      }
    }

    if (hasContentLength) {
      return State.READ_FIXED_LENGTH_CONTENT;
    } else {
      return State.READ_VARIABLE_LENGTH_CONTENT;
    }
  }
  private Object reset() {
    HttpMessage message = this.message;
    ChannelBuffer content = this.content;

    if (content != null) {
      message.setContent(content);
      this.content = null;
    }
    this.message = null;

    checkpoint(State.SKIP_CONTROL_CHARS);
    return message;
  }
 private long getContentLength(HttpMessage message, int defaultValue) {
   String value = message.getHeader("Content-Length");
   if (FastIntegerParser.isNumber(value)) {
     return FastIntegerParser.parseLong(value);
   }
   return defaultValue;
 }
Example #4
0
  static boolean isTransferEncodingChunked(HttpMessage m) {
    List<String> chunked = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
    if (chunked.isEmpty()) {
      return false;
    }

    for (String v : chunked) {
      if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
        return true;
      }
    }
    return false;
  }
  @Override
  protected Object decode(
      ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state)
      throws Exception {
    switch (state) {
      case SKIP_CONTROL_CHARS:
        {
          try {
            skipControlCharacters(buffer);
            checkpoint(State.READ_INITIAL);
          } finally {
            checkpoint();
          }
        }
      case READ_INITIAL:
        {
          final String[] initialLine = splitInitialLine(readLine(buffer, maxInitialLineLength));
          if (initialLine.length < 3) {
            // Invalid initial line - ignore.
            checkpoint(State.SKIP_CONTROL_CHARS);
            return null;
          }
          message = createMessage(initialLine);
          checkpoint(State.READ_HEADER);
        }
      case READ_HEADER:
        {
          State nextState = readHeaders(buffer);
          checkpoint(nextState);
          if (nextState == State.SKIP_CONTROL_CHARS) {
            return message;
          } else {
            long contentLength = getContentLength(message, -1);
            if (contentLength == 0 || contentLength == -1 && isDecodingRequest()) {
              content = ChannelBuffers.EMPTY_BUFFER;
              return reset();
            }

            switch (nextState) {
              case READ_FIXED_LENGTH_CONTENT:
                if (contentLength > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) {
                  // Generate HttpMessage first. HttpChunks will follow.
                  checkpoint(State.READ_FIXED_LENGTH_CONTENT_AS_CHUNKS);
                  message.setChunked(true);
                  // chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT_AS_CHUNKS
                  // state reads data chunk by chunk.
                  chunkSize = getContentLength(message, -1);
                  return message;
                }
                break;
              case READ_VARIABLE_LENGTH_CONTENT:
                if (buffer.readableBytes() > maxChunkSize
                    || HttpHeaders.is100ContinueExpected(message)) {
                  // Generate HttpMessage first. HttpChunks will follow.
                  checkpoint(State.READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS);
                  message.setChunked(true);
                  return message;
                }
                break;
              default:
                throw new IllegalStateException("Unexpected state: " + nextState);
            }
          }
          // We return null here, this forces decode to be called again where we will decode the
          // content
          return null;
        }
      case READ_VARIABLE_LENGTH_CONTENT:
        {
          if (content == null) {
            content = ChannelBuffers.dynamicBuffer(channel.getConfig().getBufferFactory());
          }
          // this will cause a replay error until the channel is closed where this will read what's
          // left in the buffer
          content.writeBytes(buffer.readBytes(buffer.readableBytes()));
          return reset();
        }
      case READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS:
        {
          // Keep reading data as a chunk until the end of connection is reached.
          int chunkSize = Math.min(maxChunkSize, buffer.readableBytes());
          HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes(chunkSize));

          if (!buffer.readable()) {
            // Reached to the end of the connection.
            reset();
            if (!chunk.isLast()) {
              // Append the last chunk.
              return new Object[] {chunk, HttpChunk.LAST_CHUNK};
            }
          }
          return chunk;
        }
      case READ_FIXED_LENGTH_CONTENT:
        {
          // we have a content-length so we just read the correct number of bytes
          readFixedLengthContent(buffer);
          return reset();
        }
      case READ_FIXED_LENGTH_CONTENT_AS_CHUNKS:
        {
          long chunkSize = this.chunkSize;
          HttpChunk chunk;
          if (chunkSize > maxChunkSize) {
            chunk = new DefaultHttpChunk(buffer.readBytes(maxChunkSize));
            chunkSize -= maxChunkSize;
          } else {
            assert chunkSize <= Integer.MAX_VALUE;
            chunk = new DefaultHttpChunk(buffer.readBytes((int) chunkSize));
            chunkSize = 0;
          }
          this.chunkSize = chunkSize;

          if (chunkSize == 0) {
            // Read all content.
            reset();
            if (!chunk.isLast()) {
              // Append the last chunk.
              return new Object[] {chunk, HttpChunk.LAST_CHUNK};
            }
          }
          return chunk;
        }
        /**
         * everything else after this point takes care of reading chunked content. basically, read
         * chunk size, read chunk, read and ignore the CRLF and repeat until 0
         */
      case READ_CHUNK_SIZE:
        {
          String line = readLine(buffer, maxInitialLineLength);
          int chunkSize = getChunkSize(line);
          this.chunkSize = chunkSize;
          if (chunkSize == 0) {
            checkpoint(State.READ_CHUNK_FOOTER);
            return null;
          } else if (chunkSize > maxChunkSize) {
            // A chunk is too large. Split them into multiple chunks again.
            checkpoint(State.READ_CHUNKED_CONTENT_AS_CHUNKS);
          } else {
            checkpoint(State.READ_CHUNKED_CONTENT);
          }
        }
      case READ_CHUNKED_CONTENT:
        {
          assert chunkSize <= Integer.MAX_VALUE;
          HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes((int) chunkSize));
          checkpoint(State.READ_CHUNK_DELIMITER);
          return chunk;
        }
      case READ_CHUNKED_CONTENT_AS_CHUNKS:
        {
          long chunkSize = this.chunkSize;
          HttpChunk chunk;
          if (chunkSize > maxChunkSize) {
            chunk = new DefaultHttpChunk(buffer.readBytes(maxChunkSize));
            chunkSize -= maxChunkSize;
          } else {
            assert chunkSize <= Integer.MAX_VALUE;
            chunk = new DefaultHttpChunk(buffer.readBytes((int) chunkSize));
            chunkSize = 0;
          }
          this.chunkSize = chunkSize;

          if (chunkSize == 0) {
            // Read all content.
            checkpoint(State.READ_CHUNK_DELIMITER);
          }

          if (!chunk.isLast()) {
            return chunk;
          }
        }
      case READ_CHUNK_DELIMITER:
        {
          for (; ; ) {
            byte next = buffer.readByte();
            if (next == HttpCodecUtil.CR) {
              if (buffer.readByte() == HttpCodecUtil.LF) {
                checkpoint(State.READ_CHUNK_SIZE);
                return null;
              }
            } else if (next == HttpCodecUtil.LF) {
              checkpoint(State.READ_CHUNK_SIZE);
              return null;
            }
          }
        }
      case READ_CHUNK_FOOTER:
        {
          HttpChunkTrailer trailer = readTrailingHeaders(buffer);
          if (maxChunkSize == 0) {
            // Chunked encoding disabled.
            return reset();
          } else {
            reset();
            // The last chunk, which is empty
            return trailer;
          }
        }
      default:
        {
          throw new Error("Shouldn't reach here.");
        }
    }
  }
 private long getContentLength(HttpMessage message) {
   return FastIntegerParser.parseInt(message.getHeader("Content-Length"));
 }
Example #7
0
 public static void setContentLength(HttpMessage message, long contentLength) {
   message.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength));
 }
Example #8
0
 public static boolean isKeepAlive(HttpMessage message) {
   return HttpHeaders.isKeepAlive(message)
       && message.getProtocolVersion().equals(HttpVersion.HTTP_1_1);
 }