HTTPD_ERR_RET(req, 400, FALSE);
HTTPD_ERR_MSG_RET(req, 400, "Spaces before ':' after header", FALSE);
static int http__parse_hdrs(struct Con *con, Httpd_req_data *req){  Vstr_base *data = con->evnt->io_r;  struct Http_hdrs *http_hdrs = req->http_hdrs;  unsigned int num = 3; /* skip "method URI version" */  int got_content_length = FALSE;  int got_content_lang = FALSE;  int got_content_type = FALSE;  int got_transfer_encoding = FALSE;    while (++num <= req->sects->num)  {    size_t pos = VSTR_SECTS_NUM(req->sects, num)->pos;    size_t len = VSTR_SECTS_NUM(req->sects, num)->len;    size_t hdr_val_pos = 0;    if (0) { /* nothing */ }    /* nothing headers ... use for logging only */    else if (HDR__EQ("User-Agent"))          HDR__SET(ua);    else if (HDR__EQ("Referer"))             HDR__SET(referer);    else if (HDR__EQ("Expect"))              HDR__SET(expect);    else if (HDR__EQ("Host"))                HDR__SET(host);    else if (HDR__EQ("If-Modified-Since"))   HDR__SET(if_modified_since);    else if (HDR__EQ("If-Range"))            HDR__SET(if_range);    else if (HDR__EQ("If-Unmodified-Since")) HDR__SET(if_unmodified_since);    else if (HDR__EQ("Authorization"))       HDR__SET(authorization);    /* allow continuations over multiple headers... *sigh* */    else if (HDR__EQ("Accept"))              HDR__MULTI_SET(accept);    else if (HDR__EQ("Accept-Charset"))      HDR__MULTI_SET(accept_charset);    else if (HDR__EQ("Accept-Encoding"))     HDR__MULTI_SET(accept_encoding);    else if (HDR__EQ("Accept-Language"))     HDR__MULTI_SET(accept_language);    else if (HDR__EQ("Connection"))          HDR__MULTI_SET(connection);    else if (HDR__EQ("If-Match"))            HDR__MULTI_SET(if_match);    else if (HDR__EQ("If-None-Match"))       HDR__MULTI_SET(if_none_match);    else if (HDR__EQ("Range"))               HDR__MULTI_SET(range);    /* allow a 0 (zero) length content-length, some clients do send these */    else if (HDR__EQ("Content-Length"))    {      unsigned int num_flags = 10 | (VSTR_FLAG_PARSE_NUM_NO_BEG_PM |                                     VSTR_FLAG_PARSE_NUM_OVERFLOW);      size_t num_len = 0;            if (req->policy->use_x2_hdr_chk && got_content_length)        HTTPD_ERR_RET(req, 400, FALSE);      got_content_length = TRUE;      http__hdr_fixup(data, &pos, &len, hdr_val_pos);      if (vstr_parse_uint(data, pos, len, num_flags, &num_len, NULL))        HTTPD_ERR_RET(req, 413, FALSE);      if (num_len != len)        HTTPD_ERR_RET(req, 400, FALSE);    }    else if (HDR__EQ("Content-Type"))      got_content_type = TRUE;    else if (HDR__EQ("Content-Language"))      got_content_lang = TRUE;        /* in theory ,,identity;foo=bar;baz="zoom",, is ok ... who cares */    else if (HDR__EQ("Transfer-Encoding"))    {      if (req->policy->use_x2_hdr_chk && got_transfer_encoding)        HTTPD_ERR_RET(req, 400, FALSE);      got_transfer_encoding = TRUE;      http__hdr_fixup(data, &pos, &len, hdr_val_pos);      if (!VEQ(data, pos, len, "identity")) /* 3.6 says 501 */        HTTPD_ERR_RET(req, 501, FALSE);    }    else    {      size_t tmp = 0;      /* all headers _must_ contain a ':' */      tmp = vstr_srch_chr_fwd(data, pos, len, ':');      if (!tmp)        HTTPD_ERR_RET(req, 400, FALSE);      /* make sure unknown header is whitespace "valid" */      tmp = vstr_sc_posdiff(pos, tmp);      if (req->policy->use_non_spc_hdrs &&          (vstr_cspn_cstr_chrs_fwd(data, pos, tmp, HTTP_LWS) != tmp))        HTTPD_ERR_RET(req, 400, FALSE);    }  }  if (got_content_type && !got_content_length) /* FIXME: config. ? */    HTTPD_ERR_RET(req, 400, FALSE);  if (got_content_lang && !got_content_length)    HTTPD_ERR_RET(req, 400, FALSE);  return (TRUE);}