static char *parse_field_content(http_parser_t *parser) { char *start, *str, ch; start = parser->parse_ptr; do { if (parser->parse_ptr - parser->data >= parser->len) break; ch = *parser->parse_ptr; if (is_ctl(ch)) break; if (!parse_crlf(parser)) break; parser->parse_ptr++; } while (1); if (parser->parse_ptr - start == 0) return NULL; str = malloc(parser->parse_ptr - start + 1); ASSERT(str != NULL); strncpy(str, start, parser->parse_ptr - start); str[parser->parse_ptr - start] = '\0'; return str; }
// token = 1*<any CHAR except CTLs or separators> const char* parse_token(unsigned char **p) { int len = 0; while (1) { if (is_char(**p) && !(is_ctl(**p) || is_separator(**p))) { (*p)++; len++; continue; } else { if (len > 0) { return NULL; } return ERR; } } }
// qdtext = <any TEXT except <">> const char* parse_qdtext(unsigned char **p) { int len = 0; while (0 != (char)**p) { if (!parse_lws(p)) { len++; continue; } else if (is_ctl(**p) || DQUOTE == **p) { break; } len++; (*p)++; } return len ? NULL : ERR; }
bool parse_http_headers(Iterator begin, Iterator end, std::string& content_type, std::size_t& content_length, std::string& location) { enum { first_header_line_start, header_line_start, header_lws, header_name, space_before_header_value, header_value, linefeed, final_linefeed, fail } state = first_header_line_start; Iterator iter = begin; std::string reason; std::string name; std::string value; while (iter != end && state != fail) { char c = *iter++; switch (state) { case first_header_line_start: if (c == '\r') state = final_linefeed; else if (!is_char(c) || is_ctl(c) || is_tspecial(c)) state = fail; else { name.push_back(c); state = header_name; } break; case header_line_start: if (c == '\r') { check_header(name, value, content_type, content_length, location); name.clear(); value.clear(); state = final_linefeed; } else if (c == ' ' || c == '\t') state = header_lws; else if (!is_char(c) || is_ctl(c) || is_tspecial(c)) state = fail; else { check_header(name, value, content_type, content_length, location); name.clear(); value.clear(); name.push_back(c); state = header_name; } break; case header_lws: if (c == '\r') state = linefeed; else if (c == ' ' || c == '\t') ; // Discard character. else if (is_ctl(c)) state = fail; else { state = header_value; value.push_back(c); } break; case header_name: if (c == ':') state = space_before_header_value; else if (!is_char(c) || is_ctl(c) || is_tspecial(c)) state = fail; else name.push_back(c); break; case space_before_header_value: state = (c == ' ') ? header_value : fail; break; case header_value: if (c == '\r') state = linefeed; else if (is_ctl(c)) state = fail; else value.push_back(c); break; case linefeed: state = (c == '\n') ? header_line_start : fail; break; case final_linefeed: return (c == '\n'); default: return false; } } return false; }
/// Handle the next character of input. result_type consume(char input) { switch (state_) { case METHOD_START: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { state_ = METHOD; method_.push_back(input); return indeterminate; } case METHOD: if (input == ' ') { state_ = URI; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { method_.push_back(input); return indeterminate; } case URI: if (input == ' ') { state_ = HTTP_VERSION_H; return indeterminate; } else if (is_ctl(input)) { return bad; } else { url_.push_back(input); return indeterminate; } case HTTP_VERSION_H: if (input == 'H') { state_ = HTTP_VERSUIN_T_1; return indeterminate; } else { return bad; } case HTTP_VERSUIN_T_1: if (input == 'T') { state_ = HTTP_VERSION_T_2; return indeterminate; } else { return bad; } case HTTP_VERSION_T_2: if (input == 'T') { state_ = HTTP_VERSION_P; return indeterminate; } else { return bad; } case HTTP_VERSION_P: if (input == 'P') { state_ = HTTP_VERSION_SLASH; return indeterminate; } else { return bad; } case HTTP_VERSION_SLASH: if (input == '/') { version_major_ = 0; version_minor_ = 0; state_ = HTTP_VERSION_MAJOR_START; return indeterminate; } else { return bad; } case HTTP_VERSION_MAJOR_START: if (is_digit(input)) { version_major_ = version_major_ * 10 + input - '0'; state_ = HTTP_VERSION_MAJOR; return indeterminate; } else { return bad; } case HTTP_VERSION_MAJOR: if (input == '.') { state_ = HTTP_VERSION_MINOR_START; return indeterminate; } else if (is_digit(input)) { version_major_ = version_major_ * 10 + input - '0'; return indeterminate; } else { return bad; } case HTTP_VERSION_MINOR_START: if (is_digit(input)) { version_minor_ = version_minor_ * 10 + input - '0'; state_ = HTTP_VERSION_MINOR; return indeterminate; } else { return bad; } case HTTP_VERSION_MINOR: if (input == '\r') { state_ = EXPECTING_NEWLINE_1; return indeterminate; } else if (is_digit(input)) { version_minor_ = version_minor_ * 10 + input - '0'; return indeterminate; } else { return bad; } case EXPECTING_NEWLINE_1: if (input == '\n') { state_ = HEADER_LINE_START; return indeterminate; } else { return bad; } case HEADER_LINE_START: if (input == '\r') { state_ = EXPECTING_NEWLINE_3; return indeterminate; } else if (header_.size() != 0 && (input == ' ' || input == '\t')) { state_ = HEADER_LWS; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { current_header_key_.clear(); current_header_val_.clear(); current_header_key_.push_back(input); state_ = HEADER_NAME; return indeterminate; } case HEADER_LWS: if (input == '\r') { state_ = EXPECTING_NEWLINE_2; return indeterminate; } else if (input == ' ' || input == '\t') { return indeterminate; } else if (is_ctl(input)) { return bad; } else { state_ = HEADER_VALUE; current_header_val_.push_back(input); return indeterminate; } case HEADER_NAME: if (input == ':') { state_ = SPACE_BEFORE_HEADER_VALUE; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { current_header_key_.push_back(input); return indeterminate; } case SPACE_BEFORE_HEADER_VALUE: if (input == ' ') return indeterminate; else if(is_ctl(input)) return bad; current_header_val_.push_back(input); state_ = HEADER_VALUE; return indeterminate; case HEADER_VALUE: if (input == '\r') { auto tmp = boost::trim_right_copy_if(current_header_val_, [](const char c)->bool{return c == ' ';}); header_.add(current_header_key_, std::move(tmp)); state_ = EXPECTING_NEWLINE_2; return indeterminate; } else if (is_ctl(input)) { return bad; } else { current_header_val_.push_back(input); return indeterminate; } case EXPECTING_NEWLINE_2: if (input == '\n') { state_ = HEADER_LINE_START; return indeterminate; } else { return bad; } case EXPECTING_NEWLINE_3: { if (input != '\n') { return bad; } if (header_.get_count("content-length") !=0 ) { content_length_ = boost::lexical_cast<unsigned int>(header_.get_val("content-length")); if (content_length_ > 0) { state_ = REQUEST_BODY; return indeterminate; } return good; } content_length_ = 0; return good; } case REQUEST_BODY: { body_.push_back(input); if (body_.size() < content_length_) { return indeterminate; } else { return good; } } default: return bad; } }
boost::tribool HTTPRequestParser::consume(HTTPRequest& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri_start: if (is_ctl(input)) { return false; } else { state_ = uri; req.uri.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { _currentHeaderKey.clear(); _currentHeaderValue.clear(); _currentHeaderKey.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; _currentHeaderValue.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { _currentHeaderKey.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { req.headers.insert(make_pair(_currentHeaderKey, _currentHeaderValue)); state_ = expecting_newline_2; return boost::indeterminate; } else if (is_ctl(input)) { req.headers.insert(make_pair(_currentHeaderKey, _currentHeaderValue)); return false; } else { _currentHeaderValue.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case expecting_newline_3: if (input == '\n') { if(req.method != "POST") return true; HTTPRequest::Headers::const_iterator it(req.headers.find("Content-Length")); if(it == req.headers.end()) return false; _postToDownload = lexical_cast<size_t>(it->second); state_ = postData; return boost::indeterminate; } else { return false; } case postData: req.postData.push_back(input); --_postToDownload; if(_postToDownload) return boost::indeterminate; else return true; default: return false; } }
static gboolean accelerator_parse (const gchar *accelerator, MetaKeyCombo *combo) { guint keyval, keycode; MetaVirtualModifier mods; gint len; combo->keysym = 0; combo->keycode = 0; combo->modifiers = 0; if (accelerator == NULL) return FALSE; keyval = 0; keycode = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_primary (accelerator)) { /* Primary is treated the same as Control */ accelerator += 9; len -= 9; mods |= META_VIRTUAL_CONTROL_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= META_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= META_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= META_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= META_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { META_VIRTUAL_ALT_MASK, META_VIRTUAL_MOD2_MASK, META_VIRTUAL_MOD3_MASK, META_VIRTUAL_MOD4_MASK, META_VIRTUAL_MOD5_MASK, }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= META_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= META_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= META_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= META_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= META_VIRTUAL_SUPER_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { if (len >= 4 && is_keycode (accelerator)) { keycode = strtoul (accelerator, NULL, 16); goto out; } else if (strcmp (accelerator, "Above_Tab") == 0) { keyval = META_KEY_ABOVE_TAB; goto out; } else { keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE); if (keyval == XKB_KEY_NoSymbol) { char *with_xf86 = g_strconcat ("XF86", accelerator, NULL); keyval = xkb_keysym_from_name (with_xf86, XKB_KEYSYM_CASE_INSENSITIVE); g_free (with_xf86); if (keyval == XKB_KEY_NoSymbol) return FALSE; } } accelerator += len; len -= len; } } out: combo->keysym = keyval; combo->keycode = keycode; combo->modifiers = mods; return TRUE; }
boost::tribool request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri_start: if (is_ctl(input)) { return false; } else { state_ = uri; req.uri.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; std::vector<header>::const_iterator cit = req.headers.begin(); for (; cit != req.headers.end(); ++cit) { std::string n = (*cit).name; std::transform(n.begin(), n.end(), n.begin(), ::toupper); if (n == UPPER_CONTENT_LENGTH) { try { cl_ = boost::lexical_cast<int>((*cit).value); } catch (const boost::bad_lexical_cast& e) { return false; } } else if (n == UPPER_CONTENT_TYPE) { std::string m = (*cit).value; std::transform(m.begin(), m.end(), m.begin(), ::toupper); if (m != UPPER_MIME_TYPE) { return false; } } } return boost::indeterminate; } else { return false; } case expecting_newline_3: { if (0 == cl_) { return (input == '\n'); } else { state_ = post_data; return boost::indeterminate; } } case post_data: { req.post_data.push_back(input); if (0 == --cl_) return true; else return ((cl_ < 0) ? false : boost::indeterminate); } default: return false; } }
Result ws::http_request_parser::consume(char c) { switch(state_) { case METHOD_GET_1: return require_char(c, 'G', METHOD_GET_2); break; case METHOD_GET_2: return require_char(c, 'E', METHOD_GET_3); break; case METHOD_GET_3: return require_char(c, 'T', METHOD_GET_SP); break; case METHOD_GET_SP: return require_char(c, ' ', URI); break; case URI: if (c == ' ') state_ = HTTP_1; else if (!is_ctl(c)) request.uri.push_back(c); else return BAD_REQUEST; return INDETERMINATE; break; case HTTP_1: return require_char(c, 'H', HTTP_2); break; case HTTP_2: return require_char(c, 'T', HTTP_3); break; case HTTP_3: return require_char(c, 'T', HTTP_4); break; case HTTP_4: return require_char(c, 'P', HTTP_SLASH); break; case HTTP_SLASH: return require_char(c, '/', HTTP_VERSION_MAJOR); break; case HTTP_VERSION_MAJOR: return require_char(c, '1', HTTP_VERSION_POINT); break; case HTTP_VERSION_POINT: return require_char(c, '.', HTTP_VERSION_MINOR); break; case HTTP_VERSION_MINOR: return require_char(c, '1', REQUEST_LINE_CR); break; case REQUEST_LINE_CR: return require_char(c, CR, REQUEST_LINE_LF); break; case REQUEST_LINE_LF: return require_char(c, LF, HEADER_START); break; case HEADER_START: if (c == CR) { state_ = FINAL_LF; return INDETERMINATE; } state_ = HEADER_NAME; return process_header_name_char(c); break; case HEADER_NAME: if (c == ':') { state_ = HEADER_VALUE_START; return INDETERMINATE; } return process_header_name_char(c); break; case HEADER_VALUE_START: if (is_lws(c)) return INDETERMINATE; state_ = HEADER_VALUE; return process_header_value_char(c); break; case HEADER_VALUE: if (c == CR) { header_value_complete(); state_ = HEADER_LF; return INDETERMINATE; } return process_header_value_char(c); break; case HEADER_LF: return require_char(c, LF, HEADER_START); break; case FINAL_LF: if (c == LF) { state_ = AFTER_FINAL_LF; return GOOD; } else return BAD_REQUEST; break; case AFTER_FINAL_LF: return BAD_REQUEST; break; } return BAD_REQUEST; }
request_parser::result_type request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { state_ = method; req.method.push_back(input); return indeterminate; } case method: if (input == ' ') { state_ = uri; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.method.push_back(input); return indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return indeterminate; } else if (is_ctl(input)) { return bad; } else { req.uri.push_back(input); return indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return indeterminate; } else { return bad; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return indeterminate; } else { return bad; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return indeterminate; } else { return bad; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return indeterminate; } else { return bad; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return indeterminate; } else { return bad; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return indeterminate; } else { return bad; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return indeterminate; } else { return bad; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return indeterminate; } else { return bad; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return indeterminate; } else { return bad; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return indeterminate; } else { return bad; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return indeterminate; } else if (input == ' ' || input == '\t') { return indeterminate; } else if (is_ctl(input)) { return bad; } else { state_ = header_value; req.headers.back().value.push_back(input); return indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.headers.back().name.push_back(input); return indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return indeterminate; } else { return bad; } case header_value: if (input == '\r') { if (req.headers.back().name == "Content-Length") { body_content_length_ = std::stoi(req.headers.back().value); } state_ = expecting_newline_2; return indeterminate; } else if (is_ctl(input)) { return bad; } else { req.headers.back().value.push_back(input); return indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return indeterminate; } else { return bad; } case expecting_newline_3: if (body_content_length_ > 0) { state_ = body; return indeterminate; } return (input == '\n') ? good : bad; case body: req.body.push_back(input); if (req.body.length() < body_content_length_) { return indeterminate; } return good; default: return bad; } }
request_parser::result_type request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { state_ = method; req.method.push_back(input); return indeterminate; } case method: if (input == ' ') { state_ = uri; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.method.push_back(input); return indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return indeterminate; } else if (is_ctl(input)) { return bad; } else { req.uri.push_back(input); return indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return indeterminate; } else { return bad; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return indeterminate; } else { return bad; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return indeterminate; } else { return bad; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return indeterminate; } else { return bad; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return indeterminate; } else { return bad; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return indeterminate; } else { return bad; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return indeterminate; } else { return bad; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return indeterminate; } else { return bad; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return indeterminate; } else { return bad; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return indeterminate; } else { return bad; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return indeterminate; } else if (input == ' ' || input == '\t') { return indeterminate; } else if (is_ctl(input)) { return bad; } else { state_ = header_value; req.headers.back().value.push_back(input); return indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { req.headers.back().name.push_back(input); return indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return indeterminate; } else { return bad; } case header_value: if (input == '\r') { state_ = expecting_newline_2; return indeterminate; } else if (is_ctl(input)) { return bad; } else { req.headers.back().value.push_back(input); return indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; // try parse content-length if(!req.headers.empty() && 0 == stricmp("Content-Length", req.headers.rbegin()->name.c_str() )) { req.content_length = atoi(req.headers.rbegin()->value.c_str()); } return indeterminate; } else { return bad; } case expecting_newline_3: // headers parse complete return (input == '\n') ? good : bad; default: return bad; } }
boost::tribool request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri_start: if (is_ctl(input)) { return false; } else { state_ = uri; req.uri.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case expecting_newline_3: if (input == '\n') { if( req.method != "POST" ) { // finished return true; } else { // this is a post request, so we need to read the content req.content_length = 0; for( std::vector<header>::iterator ph = req.headers.begin(); ph != req.headers.end(); ++ph ) { if( (*ph).name == "Content-Length" ) { req.content_length = atoi( (*ph).value.c_str()); break; } } state_ = reading_content; return boost::indeterminate; } } else { return false; } case reading_content: req.content += input; if( req.content.length() == req.content_length ) { return true; } else { return boost::indeterminate; } default: return false; } }
boost::tribool& RequestParser::consume(Request& req, char input) { static boost::tribool False(false); static boost::tribool True(true); static boost::tribool Indeterminate(boost::indeterminate); if (++requestSize_ > MAX_REQUEST_HEADER_SIZE) return False; switch (httpState_) { case method_start: if (input == '\r') { /* * allow a new line before a request -- this seems to be * accepted practice when dealing with multiple requests * in one connection, separated by a CRLF. */ httpState_ = expecting_newline_0; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { httpState_ = method; consumeToString(req.method, MAX_METHOD_SIZE); consumeChar(input); return Indeterminate; } case expecting_newline_0: if (input == '\n') { httpState_ = method_start; return Indeterminate; } else { return False; } case method: if (input == ' ') { consumeComplete(); httpState_ = uri_start; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { if (consumeChar(input)) return Indeterminate; else return False; } case uri_start: if (is_ctl(input)) { return False; } else { httpState_ = uri; consumeToString(req.uri, MAX_URI_SIZE); consumeChar(input); return Indeterminate; } case uri: if (input == ' ') { consumeComplete(); httpState_ = http_version_h; return Indeterminate; } else if (is_ctl(input)) { return False; } else { if (consumeChar(input)) return Indeterminate; else return False; } case http_version_h: if (input == 'H') { httpState_ = http_version_t_1; return Indeterminate; } else { return False; } case http_version_t_1: if (input == 'T') { httpState_ = http_version_t_2; return Indeterminate; } else { return False; } case http_version_t_2: if (input == 'T') { httpState_ = http_version_p; return Indeterminate; } else { return False; } case http_version_p: if (input == 'P') { httpState_ = http_version_slash; return Indeterminate; } else { return False; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; httpState_ = http_version_major_start; return Indeterminate; } else { return False; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; httpState_ = http_version_major; return Indeterminate; } else { return False; } case http_version_major: if (input == '.') { httpState_ = http_version_minor_start; return Indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return Indeterminate; } else { return False; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; httpState_ = http_version_minor; return Indeterminate; } else { return False; } case http_version_minor: if (input == '\r') { httpState_ = expecting_newline_1; return Indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return Indeterminate; } else { return False; } case expecting_newline_1: if (input == '\n') { httpState_ = header_line_start; return Indeterminate; } else { return False; } case header_line_start: if (input == '\r') { httpState_ = expecting_newline_3; return Indeterminate; } else if (!req.headerMap.empty() && (input == ' ' || input == '\t')) { // continuation of previous header httpState_ = header_lws; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { consumeToString(headerName_, MAX_FIELD_NAME_SIZE); consumeChar(input); httpState_ = header_name; return Indeterminate; } case header_lws: if (input == '\r') { httpState_ = expecting_newline_2; return Indeterminate; } else if (input == ' ' || input == '\t') { return Indeterminate; } else if (is_ctl(input)) { return False; } else { httpState_ = header_value; headerValue_.push_back(input); return Indeterminate; } case header_name: if (input == ':') { consumeComplete(); httpState_ = space_before_header_value; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { if (consumeChar(input)) return Indeterminate; else return False; } case space_before_header_value: if (input == ' ') { consumeToString(headerValue_, MAX_FIELD_VALUE_SIZE); httpState_ = header_value; return Indeterminate; } else { consumeToString(headerValue_, MAX_FIELD_VALUE_SIZE); httpState_ = header_value; } case header_value: if (input == '\r') { consumeComplete(); if (req.headerMap.find(headerName_) != req.headerMap.end()) { req.headerMap[headerName_] += ',' + headerValue_; } else { Request::HeaderMap::iterator i = req.headerMap.insert(std::make_pair(headerName_, headerValue_)) .first; req.headerOrder.push_back(i); } httpState_ = expecting_newline_2; return Indeterminate; } else if (is_ctl(input)) { return False; } else { if (consumeChar(input)) return Indeterminate; else return False; } case expecting_newline_2: if (input == '\n') { httpState_ = header_line_start; return Indeterminate; } else { return False; } case expecting_newline_3: if (input == '\n') return True; else return False; default: return False; } }
boost::tribool request_parser::consume(request& req, const char input) { switch(state_) { case command_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = command; req.command.push_back(input); return boost::indeterminate; } case command: if (':' == input) { state_ = argument; return boost::indeterminate; } else if ('\r' == input) { state_ = newline_1; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.command.push_back(input); return boost::indeterminate; } case argument: if ('\r' == input) { state_ = newline_1; return boost::indeterminate; } else if (!is_char(input)) { return false; } else { req.argument.push_back(input); return boost::indeterminate; } case newline_1: if ('\n' == input) { state_ = command_start; return true; } else { return false; } } }
bool parse_http_status_line(Iterator begin, Iterator end, int& version_major, int& version_minor, int& status) { enum { http_version_h, http_version_t_1, http_version_t_2, http_version_p, http_version_slash, http_version_major_start, http_version_major, http_version_minor_start, http_version_minor, status_code_start, status_code, reason_phrase, linefeed, fail } state = http_version_h; Iterator iter = begin; std::string reason; while (iter != end && state != fail) { char c = *iter++; switch (state) { case http_version_h: state = (c == 'H') ? http_version_t_1 : fail; break; case http_version_t_1: state = (c == 'T') ? http_version_t_2 : fail; break; case http_version_t_2: state = (c == 'T') ? http_version_p : fail; break; case http_version_p: state = (c == 'P') ? http_version_slash : fail; break; case http_version_slash: state = (c == '/') ? http_version_major_start : fail; break; case http_version_major_start: if (is_digit(c)) { version_major = version_major * 10 + c - '0'; state = http_version_major; } else state = fail; break; case http_version_major: if (c == '.') state = http_version_minor_start; else if (is_digit(c)) version_major = version_major * 10 + c - '0'; else state = fail; break; case http_version_minor_start: if (is_digit(c)) { version_minor = version_minor * 10 + c - '0'; state = http_version_minor; } else state = fail; break; case http_version_minor: if (c == ' ') state = status_code_start; else if (is_digit(c)) version_minor = version_minor * 10 + c - '0'; else state = fail; break; case status_code_start: if (is_digit(c)) { status = status * 10 + c - '0'; state = status_code; } else state = fail; break; case status_code: if (c == ' ') state = reason_phrase; else if (is_digit(c)) status = status * 10 + c - '0'; else state = fail; break; case reason_phrase: if (c == '\r') state = linefeed; else if (is_ctl(c)) state = fail; else reason.push_back(c); break; case linefeed: return (c == '\n'); default: return false; } } return false; }
boost::tribool& RequestParser::consume(Request& req, Buffer::iterator it) { static boost::tribool False(false); static boost::tribool True(true); static boost::tribool Indeterminate(boost::indeterminate); const char input = *it; if (++requestSize_ > MAX_REQUEST_HEADER_SIZE) return False; switch (httpState_) { case method_start: if (input == '\r') { /* * allow a new line before a request -- this seems to be * accepted practice when dealing with multiple requests * in one connection, separated by a CRLF. */ httpState_ = expecting_newline_0; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { httpState_ = method; consumeToString(req.method, MAX_METHOD_SIZE); consumeChar(it); return Indeterminate; } case expecting_newline_0: if (input == '\n') { httpState_ = method_start; return Indeterminate; } else { return False; } case method: if (input == ' ') { consumeComplete(it); httpState_ = uri_start; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { if (consumeChar(it)) return Indeterminate; else return False; } case uri_start: if (is_ctl(input)) { return False; } else { httpState_ = uri; consumeToString(req.uri, MAX_URI_SIZE); consumeChar(it); return Indeterminate; } case uri: if (input == ' ') { consumeComplete(it); httpState_ = http_version_h; return Indeterminate; } else if (is_ctl(input)) { return False; } else { if (consumeChar(it)) return Indeterminate; else return False; } case http_version_h: if (input == 'H') { httpState_ = http_version_t_1; return Indeterminate; } else { return False; } case http_version_t_1: if (input == 'T') { httpState_ = http_version_t_2; return Indeterminate; } else { return False; } case http_version_t_2: if (input == 'T') { httpState_ = http_version_p; return Indeterminate; } else { return False; } case http_version_p: if (input == 'P') { httpState_ = http_version_slash; return Indeterminate; } else { return False; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; httpState_ = http_version_major_start; return Indeterminate; } else { return False; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; httpState_ = http_version_major; return Indeterminate; } else { return False; } case http_version_major: if (input == '.') { httpState_ = http_version_minor_start; return Indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return Indeterminate; } else { return False; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; httpState_ = http_version_minor; return Indeterminate; } else { return False; } case http_version_minor: if (input == '\r') { httpState_ = expecting_newline_1; return Indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return Indeterminate; } else { return False; } case expecting_newline_1: if (input == '\n') { httpState_ = header_line_start; return Indeterminate; } else { return False; } case header_line_start: if (input == '\r') { httpState_ = expecting_newline_3; return Indeterminate; } else if ((input == ' ' || input == '\t') && haveHeader_) { // continuation of previous header httpState_ = header_lws; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { req.headers.push_back(Request::Header()); haveHeader_ = true; consumeToString(req.headers.back().name, MAX_FIELD_NAME_SIZE); consumeChar(it); httpState_ = header_name; return Indeterminate; } case header_lws: if (input == '\r') { httpState_ = expecting_newline_2; return Indeterminate; } else if (input == ' ' || input == '\t') { return Indeterminate; } else if (is_ctl(input)) { return False; } else { httpState_ = header_value; consumeChar(it); return Indeterminate; } case header_name: if (input == ':') { consumeComplete(it); httpState_ = space_before_header_value; return Indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return False; } else { if (consumeChar(it)) return Indeterminate; else return False; } case space_before_header_value: if (input == ' ') { consumeToString(req.headers.back().value, MAX_FIELD_VALUE_SIZE); httpState_ = header_value; return Indeterminate; } else { consumeToString(req.headers.back().value, MAX_FIELD_VALUE_SIZE); httpState_ = header_value; /* fall through */ } case header_value: if (input == '\r') { consumeComplete(it); httpState_ = expecting_newline_2; return Indeterminate; } else if (is_ctl(input)) { return False; } else { if (consumeChar(it)) return Indeterminate; else return False; } case expecting_newline_2: if (input == '\n') { httpState_ = header_line_start; return Indeterminate; } else { return False; } case expecting_newline_3: if (input == '\n') return True; else return False; default: return False; } }
bool ws::http_request_parser::is_valid_header_value_char(char c) { return (!is_ctl(c)); }
static bool is_token(int ch) { /* Can by antying except a ctl character or a tspecial */ return !is_ctl(ch) && !is_tspecial(ch); }
NPLMsgIn_parser::Consume_Result NPLMsgIn_parser::consume(NPLMsgIn& req, char input) { switch (state_) { case method_start: if (input == ' ' || input == '\r' || input == '\n') { return c_res_indeterminate; } else { // allowing char [0-255] as method name characters, escaping only \r\n and ' '. state_ = method; req.reset(); req.method.push_back(input); return c_res_indeterminate; } case method: if (input == ' ') { // this fix a bug when http url contains the '(', it may be mis-interpreted. state_ = req.IsNPLFileActivation() ? uri : uri_http; return c_res_indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return c_res_false; } else { req.method.push_back(input); return c_res_indeterminate; } case uri_http: if (input == ' ') { state_ = npl_version_n; return c_res_indeterminate; } else if (input == '\n' || input == '\r') { state_ = header_line_start; // version is omitted on first line. return c_res_indeterminate; } else { req.m_n_filename = 0; req.m_filename.push_back(input); return c_res_indeterminate; } case uri: if (is_ctl(input)) { req.npl_version_major = NPL_VERSION_MAJOR; req.npl_version_minor = NPL_VERSION_MINOR; state_ = header_line_start; // version is omitted on first line. return c_res_indeterminate; } else if (input == '(') { state_ = uri_rts_name; return c_res_indeterminate; } else if (is_digit(input)) { req.m_n_filename = req.m_n_filename * 10 + input - '0'; req.m_filename.push_back(input); return c_res_indeterminate; } else if (input == ' ') { state_ = npl_version_n; return c_res_indeterminate; } else { req.m_n_filename = 0; req.m_filename.push_back(input); return c_res_indeterminate; } case uri_rts_name: if (input == ')') { state_ = uri; return c_res_indeterminate; } else if(is_ctl(input)) { return c_res_false; } else { req.m_rts_name.push_back(input); return c_res_indeterminate; } case npl_version_n: if (input == '/') { req.npl_version_major = 0; req.npl_version_minor = 0; state_ = npl_version_major; return c_res_indeterminate; } else if (input == '\n') { state_ = header_line_start; return c_res_indeterminate; } else if (input == '\r') return c_res_indeterminate; else if (is_char(input)) { // any character is accepted, such as "NPL", "HTTP" if(req.m_filename.empty() && req.m_n_filename > 0) { // for http response, this stores the third parameter "OK", "Error" req.m_filename.push_back(input); } return c_res_indeterminate; } else { return c_res_false; } case npl_version_major: if (is_digit(input)) { req.npl_version_major = req.npl_version_major * 10 + input - '0'; return c_res_indeterminate; } else if (input == '.') { state_ = npl_version_minor; return c_res_indeterminate; } else { return c_res_false; } case npl_version_minor: if (is_digit(input)) { req.npl_version_minor = req.npl_version_minor * 10 + input - '0'; return c_res_indeterminate; } else if (input == '\n') { state_ = header_line_start; return c_res_indeterminate; } else if (input == '\r') return c_res_indeterminate; else { return c_res_false; } case header_line_start: if (input == '\n') { // continue to read the code length state_ = code_length; if(req.method.size()>2 && req.method != "npl") { // only do check header if method has at least three characters. int nCount = (int)req.headers.size(); for (int i=0;i <nCount; ++i) { if(req.headers[i].name == "Content-Length") { int nLength = atoi(req.headers[i].value.c_str()); if(nLength>0) { state_ = code_body; req.m_nLength = nLength; req.m_code.reserve(req.m_nLength+1); m_bCompressed = false; return c_res_code_body; } else { break; } } } m_bCompressed = false; reset(); return c_res_true; } return c_res_indeterminate; } else if (input == '\r') return c_res_indeterminate; else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return c_res_indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return c_res_false; } else { req.headers.push_back(NPLMsgHeader()); req.headers.back().name.push_back(input); state_ = header_name; return c_res_indeterminate; } case header_lws: if (input == '\n') { state_ = header_line_start; return c_res_indeterminate; } else if (input == '\r') return c_res_indeterminate; else if (input == ' ' || input == '\t') { return c_res_indeterminate; } else if (is_ctl(input)) { return c_res_false; } else { state_ = header_value; req.headers.back().value.push_back(input); return c_res_indeterminate; } case header_name: if (input == ':') { state_ = header_value; return c_res_indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return c_res_false; } else { req.headers.back().name.push_back(input); return c_res_indeterminate; } case header_value: if (input == '\n') { state_ = header_line_start; return c_res_indeterminate; } else if (input == '\r') return c_res_indeterminate; else if (is_ctl(input)) { return c_res_false; } else { string& value_ = req.headers.back().value; if( !(value_.empty() && (input == ' ' || input == '\t')) ) value_.push_back(input); return c_res_indeterminate; } case code_length: if(is_digit(input)) { req.m_nLength = req.m_nLength * 10 + input - '0'; return c_res_indeterminate; } else if(input == ':' || input == '>') { state_ = code_body; m_bCompressed = (input == '>'); if(req.m_nLength == 0) { reset(); return c_res_true; } else { req.m_code.reserve(req.m_nLength+1); return c_res_code_body; } } case code_body: if(req.m_nLength>(int)req.m_code.size()) { // I used a special return value c_res_code_body to indicate that code body is met, // so that we can read to end or length instead of doing the lexical work by char at a time. req.m_code.push_back(input); if (req.m_nLength >(int)req.m_code.size()) return c_res_code_body; else { reset(); return c_res_true; } } default: return c_res_false; } }
/** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator * @accelerator_key: return location for accelerator keyval * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing a virtual accelerator. The format * looks like "<Control>a" or "<Shift><Alt>F1" or * "<Release>z" (the last one is for key release). The parser * is fairly liberal and allows lower or upper case, and also * abbreviations such as "<Ctl>" and "<Ctrl>". * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero) and %FALSE will be returned. If the string contains * only modifiers, @accelerator_key will be set to 0 but %TRUE will be * returned. * * The virtual vs. concrete accelerator distinction is a relic of * how the X Window System works; there are modifiers Mod2-Mod5 that * can represent various keyboard keys (numlock, meta, hyper, etc.), * the virtual modifier represents the keyboard key, the concrete * modifier the actual Mod2-Mod5 bits in the key press event. * * Returns: %TRUE on success. */ gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, guint *keycode, EggVirtualModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; gint len; gboolean bad_keyval; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; if (keycode) *keycode = 0; g_return_val_if_fail (accelerator != NULL, FALSE); bad_keyval = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_release (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_RELEASE_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SUPER_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { keyval = gdk_keyval_from_name (accelerator); if (keyval == 0) { /* If keyval is 0, than maybe it's a keycode. Check for 0x## */ if (len >= 4 && is_keycode (accelerator)) { char keystring[5]; gchar *endptr; gint tmp_keycode; memcpy (keystring, accelerator, 4); keystring [4] = '\000'; tmp_keycode = strtol (keystring, &endptr, 16); if (endptr == NULL || *endptr != '\000') { bad_keyval = TRUE; } else if (keycode != NULL) { *keycode = tmp_keycode; /* 0x00 is an invalid keycode too. */ if (*keycode == 0) bad_keyval = TRUE; } } } else if (keycode != NULL) *keycode = XKeysymToKeycode (GDK_DISPLAY(), keyval); accelerator += len; len -= len; } } if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = mods; return !bad_keyval; }
boost::tribool request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { if (req.method != "POST") return false; // only POST method is allowed state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input) || input == '?') { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_before_first_header; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_before_first_header: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_body_start; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.emplace_back(); header& h = req.headers.back(); h.name.reserve(64); h.value.reserve(64); h.name.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { state_ = expecting_newline; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case expecting_body_start: if (input == '\n') { state_ = expecting_json_start; return boost::indeterminate; } else { return false; } case expecting_json_start: req.body.push_back(input); if (input == '{') { ++nesting_level_; state_ = expecting_json_end; } return boost::indeterminate; case expecting_json_end: req.body.push_back(input); if (input == '{') { ++nesting_level_; } else if (input == '}') { --nesting_level_; if (!nesting_level_) return true; } return boost::indeterminate; default: return false; } }
/** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator * @accelerator_key: return location for accelerator keyval * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing a virtual accelerator. The format * looks like "<Control>a" or "<Shift><Alt>F1" or * "<Release>z" (the last one is for key release). The parser * is fairly liberal and allows lower or upper case, and also * abbreviations such as "<Ctl>" and "<Ctrl>". * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero) and %FALSE will be returned. If the string contains * only modifiers, @accelerator_key will be set to 0 but %TRUE will be * returned. * * The virtual vs. concrete accelerator distinction is a relic of * how the X Window System works; there are modifiers Mod2-Mod5 that * can represent various keyboard keys (numlock, meta, hyper, etc.), * the virtual modifier represents the keyboard key, the concrete * modifier the actual Mod2-Mod5 bits in the key press event. * * Returns: %TRUE on success. */ gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, EggVirtualModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; gint len; gboolean bad_keyval; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; g_return_val_if_fail (accelerator != NULL, FALSE); bad_keyval = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_release (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_RELEASE_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SUPER_MASK; } else if (len >= 9 && is_primary (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { keyval = gdk_keyval_from_name (accelerator); if (keyval == 0) bad_keyval = TRUE; accelerator += len; len -= len; } } if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = mods; return !bad_keyval; }
boost::tribool request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { state_ = expecting_newline_2; if (req.headers.back().name == content_length_name_) content_length_ = boost::lexical_cast<std::size_t>(req.headers.back().value); return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case expecting_newline_3: state_ = content; if (content_length_ > 0) return boost::indeterminate; return (input == '\n'); case content: // Content. /*std::cout << state_ << std::endl; std::cout << input << std::endl; std::cout << req.content.size() << std::endl; std::cout << content_length_ << std::endl;*/ req.content.push_back(input); if (req.content.size() == content_length_) return true; return boost::indeterminate; default: return false; } }
boost::tribool request_parser::consume(request& req, char input) { switch (state_) { case method_start: if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { state_ = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { state_ = uri; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { state_ = http_version_h; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { state_ = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.http_version_major = 0; req.http_version_minor = 0; state_ = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; state_ = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_major = req.http_version_major * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; state_ = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; return boost::indeterminate; } else if (is_digit(input)) { req.http_version_minor = req.http_version_minor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.push_back(header()); req.headers.back().name.push_back(input); state_ = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { state_ = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return boost::indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { state_ = expecting_newline_2; return boost::indeterminate; } else if (is_ctl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return boost::indeterminate; } else { return false; } case expecting_newline_3: return (input == '\n'); default: return false; } }
Response::Parser::state Response::Parser::consume(Response& resp, char input) { switch (state_) { case http_version_h: if (input == 'H') { state_ = http_version_t_1; return indeterminate; } else { return bad; } case http_version_t_1: if (input == 'T') { state_ = http_version_t_2; return indeterminate; } else { return bad; } case http_version_t_2: if (input == 'T') { state_ = http_version_p; return indeterminate; } else { return bad; } case http_version_p: if (input == 'P') { state_ = http_version_slash; return indeterminate; } else { return bad; } case http_version_slash: if (input == '/') { resp.major_ = resp.minor_ = 0; state_ = http_version_major_start; return indeterminate; } else { return bad; } case http_version_major_start: if (is_digit(input)) { resp.major_ = resp.major_ * 10 + (input - '0'); state_ = http_version_major; return indeterminate; } else { return bad; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return indeterminate; } else if (is_digit(input)) { resp.major_ = resp.major_ * 10 + (input - '0'); return indeterminate; } else { return bad; } case http_version_minor_start: if (is_digit(input)) { resp.minor_ = resp.minor_ * 10 + (input - '0'); state_ = http_version_minor; return indeterminate; } else { return bad; } case http_version_minor: if (input == ' ') { resp.status_code_ = 0; state_ = http_status_code; return indeterminate; } else if (is_digit(input)) { resp.minor_ = resp.minor_ * 10 + (input - '0'); return indeterminate; } else { return bad; } case http_status_code: if (is_digit(input)) { resp.status_code_ = resp.status_code_ * 10 + (input - '0'); return indeterminate; } else if (input == ' ') { state_ = http_status_msg; return indeterminate; } else { return bad; } case http_status_msg: if (input == '\r') { state_ = expecting_newline_1; return indeterminate; } else if (is_char(input)) { resp.desc.push_back(input); return indeterminate; } else { return bad; } case expecting_newline_1: if (input == '\n') { state_ = header_line_start; return indeterminate; } else { return bad; } case header_line_start: if (input == '\r') { state_ = expecting_newline_3; return indeterminate; } else if (!resp.headers.empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { resp.headers.emplace_back(); resp.headers.back().first.push_back(input); state_ = header_name; return indeterminate; } case header_lws: if (input == '\r') { state_ = expecting_newline_2; return indeterminate; } else if (input == ' ' || input == '\t') { return indeterminate; } else if (is_ctl(input)) { return bad; } else { state_ = header_value; resp.headers.back().second.push_back(input); return indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return indeterminate; } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { return bad; } else { resp.headers.back().first.push_back(input); return indeterminate; } case space_before_header_value: if (input == ' ') { state_ = header_value; return indeterminate; } else { return bad; } case header_value: if (input == '\r') { state_ = expecting_newline_2; return indeterminate; } else if (is_ctl(input)) { return bad; } else { resp.headers.back().second.push_back(input); return indeterminate; } case expecting_newline_2: if (input == '\n') { state_ = header_line_start; return indeterminate; } else { return bad; } case expecting_newline_3: return (input == '\n') ? good : bad; default: return bad; } }