bool HttpRequest::ParseStartLine(const StringPiece& data, HttpMessage::ErrorCode* error) { ErrorCode error_placeholder; if (error == NULL) error = &error_placeholder; static const size_t kMinHttpMethodLength = 3; size_t pos = data.find(' ', kMinHttpMethodLength); if (pos == StringPiece::npos) { *error = ERROR_START_LINE_NOT_COMPLETE; return false; } StringPiece method = data.substr(0, pos); StringTrim(&method); m_method = GetMethodByName(method); if (m_method == METHOD_UNKNOWN) { *error = ERROR_METHOD_NOT_FOUND; return false; } size_t prev_pos = pos + 1; pos = data.find(' ', prev_pos); StringPiece uri; if (pos == StringPiece::npos) { uri = data.substr(prev_pos); } else { uri = data.substr(prev_pos, pos - prev_pos); } StringTrim(&uri); uri.copy_to_string(&m_uri); if (pos != StringPiece::npos) { StringPiece version = data.substr(pos); StringTrim(&version); if (!ParseVersion(version)) { *error = ERROR_VERSION_UNSUPPORTED; return false; } } return true; }
size_t HttpHeaders::Parse(const StringPiece& data, int* error) { int error_placeholder; if (error == NULL) error = &error_placeholder; // Starts with empty line means empty headers. if (StringStartsWith(data, "\n") || StringStartsWith(data, "\r\n")) { m_headers.clear(); return (data[0] == '\r') + 1; // sizeof \n or \r\n } size_t end_pos; size_t tail_size; if ((end_pos = data.find("\r\n\r\n")) != std::string::npos) { tail_size = 4; } else if ((end_pos = data.find("\n\n")) != std::string::npos) { tail_size = 2; } else { *error = HttpMessage::ERROR_MESSAGE_NOT_COMPLETE; return 0; } std::vector<StringPiece> lines; SplitLines(data.substr(0, end_pos + tail_size), &lines); if (lines.empty()) { *error = HttpMessage::ERROR_MESSAGE_NOT_COMPLETE; return 0; } m_headers.clear(); // Skip the head line and the last line(empty but '\n') for (int i = 0; i < static_cast<int>(lines.size() - 1); ++i) { StringPiece line = lines[i]; size_t pos = line.find(':'); if (pos != StringPiece::npos) { StringPiece name = line.substr(0, pos); StringPiece value = line.substr(pos + 1); StringTrim(&name); StringTrim(&value); // Push an empty element and modify it to avoid copy. m_headers.push_back(std::pair<std::string, std::string>()); std::pair<std::string, std::string> &header = m_headers.back(); name.copy_to_string(&header.first); value.copy_to_string(&header.second); } else { if (!lines[i].empty()) { VLOG(3) << "Invalid http header" << lines[i] << ", ignore"; } else { *error = HttpMessage::ERROR_FIELD_NOT_COMPLETE; m_headers.clear(); return 0; } } } *error = HttpMessage::SUCCESS; return end_pos + tail_size; }