예제 #1
0
  private void parsedHeader() {
    // handler last header if any. Delayed to here just in case there was a
    // continuation line (above)
    if (_headerString != null || _valueString != null) {
      // Handle known headers
      if (_header != null) {
        boolean add_to_connection_trie = false;
        switch (_header) {
          case CONTENT_LENGTH:
            if (_endOfContent != EndOfContent.CHUNKED_CONTENT) {
              try {
                _contentLength = Long.parseLong(_valueString);
              } catch (NumberFormatException e) {
                throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad Content-Length");
              }
              if (_contentLength <= 0) _endOfContent = EndOfContent.NO_CONTENT;
              else _endOfContent = EndOfContent.CONTENT_LENGTH;
            }
            break;

          case TRANSFER_ENCODING:
            if (_value == HttpHeaderValue.CHUNKED) _endOfContent = EndOfContent.CHUNKED_CONTENT;
            else {
              if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
                _endOfContent = EndOfContent.CHUNKED_CONTENT;
              else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) {
                throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad chunking");
              }
            }
            break;

          case HOST:
            _host = true;
            if (!(_field instanceof HostPortHttpField)) {
              _field =
                  new HostPortHttpField(
                      _header, _strict ? _headerString : _header.asString(), _valueString);
              add_to_connection_trie = _connectionFields != null;
            }
            break;

          case CONNECTION:
            // Don't cache if not persistent
            if (_valueString != null && _valueString.contains("close")) _connectionFields = null;

            break;

          case AUTHORIZATION:
          case ACCEPT:
          case ACCEPT_CHARSET:
          case ACCEPT_ENCODING:
          case ACCEPT_LANGUAGE:
          case COOKIE:
          case CACHE_CONTROL:
          case USER_AGENT:
            add_to_connection_trie = _connectionFields != null && _field == null;
            break;

          default:
            break;
        }

        if (add_to_connection_trie
            && !_connectionFields.isFull()
            && _header != null
            && _valueString != null) {
          if (_field == null)
            _field =
                new HttpField(_header, _strict ? _headerString : _header.asString(), _valueString);
          _connectionFields.put(_field);
        }
      }
      _handler.parsedHeader(
          _field != null ? _field : new HttpField(_header, _headerString, _valueString));
    }

    _headerString = _valueString = null;
    _header = null;
    _value = null;
    _field = null;
  }
예제 #2
0
  /*
   * Parse the message headers and return true if the handler has signaled for
   * a return
   */
  protected boolean parseHeaders(ByteBuffer buffer) {
    boolean handle = false;

    // Process headers
    while (_state.ordinal() < State.CONTENT.ordinal() && buffer.hasRemaining() && !handle) {
      // process each character
      byte ch = next(buffer);
      if (ch == 0) break;

      if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) {
        log.warn("Header is too large > {}", _maxHeaderBytes);
        throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
      }

      switch (_state) {
        case HEADER:
          switch (ch) {
            case HttpTokens.COLON:
            case HttpTokens.SPACE:
            case HttpTokens.TAB:
              throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad Continuation");

            case HttpTokens.LINE_FEED:
              {
                _contentPosition = 0;

                // End of headers!

                // Was there a required host header?
                if (!_host && _version == HttpVersion.HTTP_1_1 && _requestHandler != null) {
                  throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "No Host");
                }

                // is it a response that cannot have a body?
                if (_responseHandler != null
                    && // response
                    (_responseStatus == 304
                        || // not-modified response
                        _responseStatus == 204
                        || // no-content
                        // response
                        _responseStatus < 200)) // 1xx response
                _endOfContent = EndOfContent.NO_CONTENT; // ignore any
                // other
                // headers
                // set

                // else if we don't know framing
                else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) {
                  if (_responseStatus == 0 // request
                      || _responseStatus == 304 // not-modified
                      // response
                      || _responseStatus == 204 // no-content response
                      || _responseStatus < 200) // 1xx response
                  _endOfContent = EndOfContent.NO_CONTENT;
                  else _endOfContent = EndOfContent.EOF_CONTENT;
                }

                // How is the message ended?
                switch (_endOfContent) {
                  case EOF_CONTENT:
                    setState(State.EOF_CONTENT);
                    handle = _handler.headerComplete() || handle;
                    return handle;

                  case CHUNKED_CONTENT:
                    setState(State.CHUNKED_CONTENT);
                    handle = _handler.headerComplete() || handle;
                    return handle;

                  case NO_CONTENT:
                    handle = _handler.headerComplete() || handle;
                    setState(State.END);
                    handle = _handler.messageComplete() || handle;
                    return handle;

                  default:
                    setState(State.CONTENT);
                    handle = _handler.headerComplete() || handle;
                    return handle;
                }
              }

            default:
              {
                // now handle the ch
                if (ch <= HttpTokens.SPACE) throw new BadMessageException();

                if (buffer.hasRemaining()) {
                  // Try a look ahead for the known header name and value.
                  HttpField field =
                      _connectionFields == null
                          ? null
                          : _connectionFields.getBest(buffer, -1, buffer.remaining());
                  if (field == null) field = CACHE.getBest(buffer, -1, buffer.remaining());

                  if (field != null) {
                    final String n;
                    final String v;

                    if (_strict) {
                      // Have to get the fields exactly from the
                      // buffer to match case
                      String fn = field.getName();
                      String fv = field.getValue();
                      n =
                          BufferUtils.toString(
                              buffer,
                              buffer.position() - 1,
                              fn.length(),
                              StandardCharsets.US_ASCII);
                      if (fv == null) v = null;
                      else {
                        v =
                            BufferUtils.toString(
                                buffer,
                                buffer.position() + fn.length() + 1,
                                fv.length(),
                                StandardCharsets.ISO_8859_1);
                        field = new HttpField(field.getHeader(), n, v);
                      }
                    } else {
                      n = field.getName();
                      v = field.getValue();
                    }

                    _header = field.getHeader();
                    _headerString = n;

                    if (v == null) {
                      // Header only
                      setState(State.HEADER_VALUE);
                      _string.setLength(0);
                      _length = 0;
                      buffer.position(buffer.position() + n.length() + 1);
                      break;
                    } else {
                      // Header and value
                      int pos = buffer.position() + n.length() + v.length() + 1;
                      byte b = buffer.get(pos);

                      if (b == HttpTokens.CARRIAGE_RETURN || b == HttpTokens.LINE_FEED) {
                        _field = field;
                        _valueString = v;
                        setState(State.HEADER_IN_VALUE);

                        if (b == HttpTokens.CARRIAGE_RETURN) {
                          _cr = true;
                          buffer.position(pos + 1);
                        } else buffer.position(pos);
                        break;
                      } else {
                        setState(State.HEADER_IN_VALUE);
                        setString(v);
                        buffer.position(pos);
                        break;
                      }
                    }
                  }
                }

                // New header
                setState(State.HEADER_IN_NAME);
                _string.setLength(0);
                _string.append((char) ch);
                _length = 1;
              }
          }
          break;

        case HEADER_IN_NAME:
          if (ch == HttpTokens.COLON) {
            if (_headerString == null) {
              _headerString = takeString();
              _header = HttpHeader.CACHE.get(_headerString);
            }
            _length = -1;

            setState(State.HEADER_VALUE);
            break;
          }

          if (ch > HttpTokens.SPACE) {
            if (_header != null) {
              setString(_header.asString());
              _header = null;
              _headerString = null;
            }

            _string.append((char) ch);
            if (ch > HttpTokens.SPACE) _length = _string.length();
            break;
          }

          throw new IllegalCharacterException(_state, ch, buffer);

        case HEADER_VALUE:
          if (ch > HttpTokens.SPACE || ch < 0) {
            _string.append((char) (0xff & ch));
            _length = _string.length();
            setState(State.HEADER_IN_VALUE);
            break;
          }

          if (ch == HttpTokens.SPACE || ch == HttpTokens.TAB) break;

          if (ch == HttpTokens.LINE_FEED) {
            _value = null;
            _string.setLength(0);
            _valueString = null;
            _length = -1;

            parsedHeader();
            setState(State.HEADER);
            break;
          }
          throw new IllegalCharacterException(_state, ch, buffer);

        case HEADER_IN_VALUE:
          if (ch >= HttpTokens.SPACE || ch < 0 || ch == HttpTokens.TAB) {
            if (_valueString != null) {
              setString(_valueString);
              _valueString = null;
              _field = null;
            }
            _string.append((char) (0xff & ch));
            if (ch > HttpTokens.SPACE || ch < 0) _length = _string.length();
            break;
          }

          if (ch == HttpTokens.LINE_FEED) {
            if (_length > 0) {
              _value = null;
              _valueString = takeString();
              _length = -1;
            }
            parsedHeader();
            setState(State.HEADER);
            break;
          }

          throw new IllegalCharacterException(_state, ch, buffer);

        default:
          throw new IllegalStateException(_state.toString());
      }
    }

    return handle;
  }
예제 #3
0
  static {
    CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE));
    CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE));
    CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.UPGRADE));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip,deflate,sdch"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-US,en;q=0.5"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-GB,en-US;q=0.8,en;q=0.6"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT, "*/*"));
    CACHE.put(new HttpField(HttpHeader.ACCEPT, "image/png,image/*;q=0.8,*/*;q=0.5"));
    CACHE.put(
        new HttpField(
            HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
    CACHE.put(new HttpField(HttpHeader.PRAGMA, "no-cache"));
    CACHE.put(
        new HttpField(
            HttpHeader.CACHE_CONTROL, "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
    CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "no-cache"));
    CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH, "0"));
    CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "gzip"));
    CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "deflate"));
    CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING, "chunked"));
    CACHE.put(new HttpField(HttpHeader.EXPIRES, "Fri, 01 Jan 1990 00:00:00 GMT"));

    // Add common Content types as fields
    for (String type :
        new String[] {
          "text/plain",
          "text/html",
          "text/xml",
          "text/json",
          "application/json",
          "application/x-www-form-urlencoded"
        }) {
      HttpField field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type);
      CACHE.put(field);

      for (String charset : new String[] {"utf-8", "iso-8859-1"}) {
        CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset));
        CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset));
        CACHE.put(
            new PreEncodedHttpField(
                HttpHeader.CONTENT_TYPE, type + ";charset=" + charset.toUpperCase()));
        CACHE.put(
            new PreEncodedHttpField(
                HttpHeader.CONTENT_TYPE, type + "; charset=" + charset.toUpperCase()));
      }
    }

    // Add headers with null values so HttpParser can avoid looking up name
    // again for unknown values
    for (HttpHeader h : HttpHeader.values())
      if (!CACHE.put(new HttpField(h, (String) null)))
        throw new IllegalStateException("CACHE FULL");
    // Add some more common headers
    CACHE.put(new HttpField(HttpHeader.REFERER, (String) null));
    CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE, (String) null));
    CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH, (String) null));
    CACHE.put(new HttpField(HttpHeader.AUTHORIZATION, (String) null));
    CACHE.put(new HttpField(HttpHeader.COOKIE, (String) null));
  }