public HttpField(String name, String value) {
   this(HttpHeader.CACHE.get(name), name, value);
 }
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;
  }