HttpTransact::RequestError_t HttpTransact::check_request_validity(State* s, HTTPHdr* incoming_hdr)
{
  if (incoming_hdr == 0) {
    return NON_EXISTANT_REQUEST_HEADER;
  }

  if (!(HttpTransactHeaders::is_request_proxy_authorized(incoming_hdr))) {
    return FAILED_PROXY_AUTHORIZATION;
  }

  URL *incoming_url = incoming_hdr->url_get();
  int hostname_len;
  const char *hostname = incoming_hdr->host_get(&hostname_len);

  if (hostname == NULL) {
    return MISSING_HOST_FIELD;
  }

  if (hostname_len >= MAXDNAME || hostname_len <= 0 || memchr(hostname, '\0', hostname_len)) {
    return BAD_HTTP_HEADER_SYNTAX;
  }

  int scheme = incoming_url->scheme_get_wksidx();
  int method = incoming_hdr->method_get_wksidx();

  // Check for chunked encoding
  if (incoming_hdr->presence(MIME_PRESENCE_TRANSFER_ENCODING)) {
    MIMEField *field = incoming_hdr->field_find(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
    HdrCsvIter enc_val_iter;
    int enc_val_len;
    const char *enc_value = enc_val_iter.get_first(field, &enc_val_len);

    while (enc_value) {
      const char *wks_value = hdrtoken_string_to_wks(enc_value, enc_val_len);
      if (wks_value == HTTP_VALUE_CHUNKED) {
          s->client_info.transfer_encoding = CHUNKED_ENCODING;
        break;
      }
        enc_value = enc_val_iter.get_next(&enc_val_len);
    }
  }

  /////////////////////////////////////////////////////
  // get request content length                      //
  // To avoid parsing content-length twice, we set   //
  // s->hdr_info.request_content_length here rather  //
  // than in initialize_state_variables_from_request //
  /////////////////////////////////////////////////////
  if (method != HTTP_WKSIDX_TRACE) {
    int64_t length = incoming_hdr->get_content_length();
    s->hdr_info.request_content_length = (length >= 0) ? length : HTTP_UNDEFINED_CL;    // content length less than zero is invalid

    DebugTxn("http_trans", "[init_stat_vars_from_req] set req cont length to %" PRId64,
          s->hdr_info.request_content_length);

  } else {
    s->hdr_info.request_content_length = 0;
  }

  if (!((scheme == URL_WKSIDX_HTTP) && (method == HTTP_WKSIDX_GET))) {
    if (scheme != URL_WKSIDX_HTTP && scheme != URL_WKSIDX_HTTPS &&
        method != HTTP_WKSIDX_CONNECT &&
        ((scheme == URL_WKSIDX_WS || scheme == URL_WKSIDX_WSS) && !s->is_websocket)) {
      if (scheme < 0) {
        return NO_REQUEST_SCHEME;
      } else {
        return SCHEME_NOT_SUPPORTED;
      }
    }

    if (!HttpTransactHeaders::is_this_method_supported(scheme, method)) {
      return METHOD_NOT_SUPPORTED;
    }
    if ((method == HTTP_WKSIDX_CONNECT) && !s->transparent_passthrough && (!is_port_in_range(incoming_hdr->url_get()->port_get(), s->http_config_param->connect_ports))) {
      return BAD_CONNECT_PORT;
    }

    // Require Content-Length/Transfer-Encoding for POST/PUSH/PUT
    if ((scheme == URL_WKSIDX_HTTP || scheme == URL_WKSIDX_HTTPS) &&
        (method == HTTP_WKSIDX_POST || method == HTTP_WKSIDX_PUSH || method == HTTP_WKSIDX_PUT) &&
        s->client_info.transfer_encoding != CHUNKED_ENCODING) {
      if ((s->txn_conf->post_check_content_length_enabled) &&
          !incoming_hdr->presence(MIME_PRESENCE_CONTENT_LENGTH)) {
        return NO_POST_CONTENT_LENGTH;
      }
      if (HTTP_UNDEFINED_CL == s->hdr_info.request_content_length) {
        return INVALID_POST_CONTENT_LENGTH;
      }
    }
  }
  // Check whether a Host header field is missing in the request.
  if (!incoming_hdr->presence(MIME_PRESENCE_HOST) && incoming_hdr->version_get() != HTTPVersion(0, 9)) {
    // Update the number of incoming 1.0 or 1.1 requests that do
    // not contain Host header fields.
    HTTP_INCREMENT_TRANS_STAT(http_missing_host_hdr_stat);
  }
  // Did the client send a "TE: identity;q=0"? We have to respond
  // with an error message because we only support identity
  // Transfer Encoding.

  if (incoming_hdr->presence(MIME_PRESENCE_TE)) {
    MIMEField *te_field = incoming_hdr->field_find(MIME_FIELD_TE, MIME_LEN_TE);
    HTTPValTE *te_val;

    if (te_field) {
      HdrCsvIter csv_iter;
      int te_raw_len;
      const char *te_raw = csv_iter.get_first(te_field, &te_raw_len);

      while (te_raw) {
        te_val = http_parse_te(te_raw, te_raw_len, &s->arena);
        if (te_val->encoding == HTTP_VALUE_IDENTITY) {
          if (te_val->qvalue <= 0.0) {
            s->arena.free(te_val, sizeof(HTTPValTE));
            return UNACCEPTABLE_TE_REQUIRED;
          }
        }
        s->arena.free(te_val, sizeof(HTTPValTE));
        te_raw = csv_iter.get_next(&te_raw_len);
      }
    }
  }

  return NO_REQUEST_HEADER_ERROR;
}