Example #1
0
  private boolean handleKnownHeaders(ByteBuffer buffer) {
    boolean add_to_connection_trie = false;
    switch (_header) {
      case CONTENT_LENGTH:
        if (_endOfContent != EndOfContent.CHUNKED_CONTENT) {
          try {
            _contentLength = Long.parseLong(_valueString);
          } catch (NumberFormatException e) {
            LOG.ignore(e);
            throw new BadMessage(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.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0) {
            throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Bad chunking");
          }
        }
        break;

      case HOST:
        add_to_connection_trie = _connectionFields != null && _field == null;
        _host = true;
        String host = _valueString;
        int port = 0;
        if (host == null || host.length() == 0) {
          throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Bad Host header");
        }

        int len = host.length();
        loop:
        for (int i = len; i-- > 0; ) {
          char c2 = (char) (0xff & host.charAt(i));
          switch (c2) {
            case ']':
              break loop;

            case ':':
              try {
                len = i;
                port = StringUtil.toInt(host.substring(i + 1));
              } catch (NumberFormatException e) {
                if (DEBUG) LOG.debug(e);
                throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Bad Host header");
              }
              break loop;
          }
        }
        if (host.charAt(0) == '[') {
          if (host.charAt(len - 1) != ']') {
            throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Bad IPv6 Host header");
          }
          host = host.substring(1, len - 1);
        } else if (len != host.length()) host = host.substring(0, len);

        if (_requestHandler != null) _requestHandler.parsedHostHeader(host, port);

        break;

      case CONNECTION:
        // Don't cache if not persistent
        if (_valueString != null && _valueString.indexOf("close") >= 0) {
          _closed = true;
          _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) {
      _field = new HttpField(_header, _valueString);
      _connectionFields.put(_field);
    }

    return false;
  }
Example #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 BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
      }

      switch (_state) {
        case HEADER:
          switch (ch) {
            case HttpTokens.COLON:
            case HttpTokens.SPACE:
            case HttpTokens.TAB:
              {
                // header value without name - continuation?
                if (_valueString == null) {
                  _string.setLength(0);
                  _length = 0;
                } else {
                  setString(_valueString);
                  _string.append(' ');
                  _length++;
                  _valueString = null;
                }
                setState(State.HEADER_VALUE);
                break;
              }

            default:
              {
                // 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 && handleKnownHeaders(buffer)) {
                    _headerString = _valueString = null;
                    _header = null;
                    _value = null;
                    _field = null;
                    return true;
                  }
                  handle =
                      _handler.parsedHeader(
                              _field != null
                                  ? _field
                                  : new HttpField(_header, _headerString, _valueString))
                          || handle;
                }
                _headerString = _valueString = null;
                _header = null;
                _value = null;
                _field = null;

                // now handle the ch
                if (ch == HttpTokens.LINE_FEED) {
                  _contentPosition = 0;

                  // End of headers!

                  // Was there a required host header?
                  if (!_host && _version != HttpVersion.HTTP_1_0 && _requestHandler != null) {
                    throw new BadMessage(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;
                      break;

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

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

                    default:
                      setState(State.CONTENT);
                      handle = _handler.headerComplete() || handle;
                      break;
                  }
                } else if (ch <= HttpTokens.SPACE) throw new BadMessage();
                else {
                  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 =
                            BufferUtil.toString(
                                buffer,
                                buffer.position() - 1,
                                fn.length(),
                                StandardCharsets.US_ASCII);
                        if (fv == null) v = null;
                        else {
                          v =
                              BufferUtil.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 || ch == HttpTokens.LINE_FEED) {
            if (_headerString == null) {
              _headerString = takeString();
              _header = HttpHeader.CACHE.get(_headerString);
            }
            _length = -1;

            setState(ch == HttpTokens.LINE_FEED ? State.HEADER : State.HEADER_VALUE);
            break;
          }

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

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

          throw new BadMessage("Illegal character");

        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) {
            if (_length > 0) {
              _value = null;
              _valueString =
                  (_valueString == null) ? takeString() : (_valueString + " " + takeString());
            }
            setState(State.HEADER);
            break;
          }

          throw new BadMessage("Illegal character");

        case HEADER_IN_VALUE:
          if (ch >= HttpTokens.SPACE || ch < 0) {
            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;
            }
            setState(State.HEADER);
            break;
          }
          throw new BadMessage("Illegal character");

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

    return handle;
  }
Example #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 HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE, type);
      CACHE.put(field);

      for (String charset : new String[] {"UTF-8", "ISO-8859-1"}) {
        CACHE.put(
            field =
                new HttpGenerator.CachedHttpField(
                    HttpHeader.CONTENT_TYPE, type + ";charset=" + charset));
        CACHE.put(
            new HttpGenerator.CachedHttpField(
                HttpHeader.CONTENT_TYPE, type + "; charset=" + charset));
      }
    }

    // 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));
  }