boost::tribool RequestParser::consume(Request& req, char input) { switch (m_state) { case method_start: if (!isChar(input) || isCtl(input) || isTspecial(input)) { return false; } else { m_state = method; req.method.push_back(input); return boost::indeterminate; } case method: if (input == ' ') { m_state = uri; return boost::indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return false; } else { req.method.push_back(input); return boost::indeterminate; } case uri: if (input == ' ') { m_state = http_version_h; return boost::indeterminate; } else if (isCtl(input)) { return false; } else { req.uri.push_back(input); return boost::indeterminate; } case http_version_h: if (input == 'H') { m_state = http_version_t_1; return boost::indeterminate; } else { return false; } case http_version_t_1: if (input == 'T') { m_state = http_version_t_2; return boost::indeterminate; } else { return false; } case http_version_t_2: if (input == 'T') { m_state = http_version_p; return boost::indeterminate; } else { return false; } case http_version_p: if (input == 'P') { m_state = http_version_slash; return boost::indeterminate; } else { return false; } case http_version_slash: if (input == '/') { req.httpVersionMajor = 0; req.httpVersionMinor = 0; m_state = http_version_major_start; return boost::indeterminate; } else { return false; } case http_version_major_start: if (isDigit(input)) { req.httpVersionMajor = req.httpVersionMajor * 10 + input - '0'; m_state = http_version_major; return boost::indeterminate; } else { return false; } case http_version_major: if (input == '.') { m_state = http_version_minor_start; return boost::indeterminate; } else if (isDigit(input)) { req.httpVersionMajor = req.httpVersionMajor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case http_version_minor_start: if (isDigit(input)) { req.httpVersionMinor = req.httpVersionMinor * 10 + input - '0'; m_state = http_version_minor; return boost::indeterminate; } else { return false; } case http_version_minor: if (input == '\r') { m_state = expecting_newline_1; return boost::indeterminate; } else if (isDigit(input)) { req.httpVersionMinor = req.httpVersionMinor * 10 + input - '0'; return boost::indeterminate; } else { return false; } case expecting_newline_1: if (input == '\n') { m_state = header_line_start; return boost::indeterminate; } else { return false; } case header_line_start: if (input == '\r') { m_state = expecting_newline_3; return boost::indeterminate; } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { m_state = header_lws; return boost::indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return false; } else { req.headers.push_back(Header()); req.headers.back().name.push_back(input); m_state = header_name; return boost::indeterminate; } case header_lws: if (input == '\r') { m_state = expecting_newline_2; return boost::indeterminate; } else if (input == ' ' || input == '\t') { return boost::indeterminate; } else if (isCtl(input)) { return false; } else { m_state = header_value; req.headers.back().value.push_back(input); return boost::indeterminate; } case header_name: if (input == ':') { m_state = space_before_header_value; return boost::indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return false; } else { req.headers.back().name.push_back(input); return boost::indeterminate; } case space_before_header_value: if (input == ' ') { m_state = header_value; return boost::indeterminate; } else { return false; } case header_value: if (input == '\r') { m_state = expecting_newline_2; return boost::indeterminate; } else if (isCtl(input)) { return false; } else { req.headers.back().value.push_back(input); return boost::indeterminate; } case expecting_newline_2: if (input == '\n') { m_state = header_line_start; return boost::indeterminate; } else { return false; } case expecting_newline_3: { if(input == '\n') { req.headerIsReady = true; if(req.method == "POST") { // gonna read by chunk the rest findBoundary(req); if(req.boundary == "") { return false; } else { m_state = postData_boundary; return boost::indeterminate; } } else { // GET, PUT, etc.. return true; } } else { return false; } } case postData_boundary: { if(input == '\r') { m_state = postData_headerLine1; } return boost::indeterminate; } case postData_headerLine1: { if(input == '\r') { m_state = postData_headerLine2; } return boost::indeterminate; } case postData_headerLine2: { if(input == '\r') { m_state = postData_headerEmptyLineR; } return boost::indeterminate; } case postData_headerEmptyLineR: { if(input == '\r') { m_state = postData_headerEmptyLineN; } return boost::indeterminate; } case postData_headerEmptyLineN: { if(input == '\n') { m_state = postData_rawData; } return boost::indeterminate; } case postData_rawData: { if(m_postDataBuffer.size() == req.boundary.length()) { char topChar = m_postDataBuffer.front(); m_postDataBuffer.pop_front(); m_postDataBuffer.push_back(input); req.postChunk[req.postChunkSize] = topChar; req.postChunkSize++; if(isPostDataBufferIsEnd(req)) { return true; } } else { m_postDataBuffer.push_back(input); } return boost::indeterminate; } default: return false; } }
HttpRequestParser::ParseResult HttpRequestParser::consume(HttpRequest &request, char input) { switch (state_) { case method_start: if (!isChar(input) || isCtl(input) || isTspecial(input)) { return bad; } else { state_ = method; request.pushBackMethod(input); return indeterminate; } case method: if (input == ' ') { state_ = uri; return indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return bad; } else { request.pushBackMethod(input); return indeterminate; } case uri: if (input == '?') { state_ = query_param_start; return indeterminate; } else if (input == ' ') { state_ = http_version_h; return indeterminate; } else if (isCtl(input)) { return bad; } else { request.pushBackUri(input); return indeterminate; } case query_param_start: state_ = query_param_name; request.getQueryParameters().push_back(PairNameValue()); request.getQueryParameters().back().name.push_back(input); return indeterminate; case query_param_name: if (input == '=') { state_ = query_param_value; return indeterminate; } else { request.getQueryParameters().back().name.push_back(input); return indeterminate; } case query_param_value: if (input == '&') { state_ = query_param_start; return indeterminate; } else if (input == ' ') { state_ = http_version_h; return indeterminate; } else { request.getQueryParameters().back().value.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 == '/') { state_ = http_version_major_start; request.setHttpVersionMajor(0); request.setHttpVersionMinor(0); return indeterminate; } else { return bad; } case http_version_major_start: if (isDigit(input)) { state_ = http_version_major; request.setHttpVersionMajor(request.getHttpVersionMajor() * 10 + input - '0'); return indeterminate; } else { return bad; } case http_version_major: if (input == '.') { state_ = http_version_minor_start; return indeterminate; } else { return bad; } case http_version_minor_start: if (isDigit(input)) { state_ = http_version_minor; request.setHttpVersionMinor(request.getHttpVersionMinor() * 10 + input - '0'); return indeterminate; } else { return bad; } case http_version_minor: if (input == '\r') { state_ = expecting_newline_1; 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 (!request.getHeaders().empty() && (input == ' ' || input == '\t')) { state_ = header_lws; return indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return bad; } else { request.getHeaders().push_back(PairNameValue()); request.getHeaders().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 (isCtl(input)) { return bad; } else { state_ = header_value; return indeterminate; } case header_name: if (input == ':') { state_ = space_before_header_value; return indeterminate; } else if (!isChar(input) || isCtl(input) || isTspecial(input)) { return bad; } else { request.getHeaders().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 (isCtl(input)) { return bad; } else { request.getHeaders().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: return (input == '\n') ? good: bad; default: return bad; } }