[C++] 简单解析http请求
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <regex>
class HttpRequest {
public:
enum Method {
GET,
POST,
UNKNOWN
};
enum Error {
SUCCESS,
FORMAT_ERROR,
INCOMPLETE_REQUEST
};
HttpRequest() : method(Method::UNKNOWN) {}
Error parse(const std::string& request) {
std::vector<std::string> header_body = split(request, "\r\n\r\n");
if (!header_body.size()) {
return FORMAT_ERROR;
}
std::vector<std::string> lines = split(header_body[0], "\r\n");
for (size_t i = 0; i < lines.size(); ++i) {
if (i == 0) {
std::vector<std::string> tokens = split(lines[i], " ");
if (tokens.size() != 3) {
return FORMAT_ERROR;
}
if (tokens[0] == "GET") {
method = Method::GET;
} else if (tokens[0] == "POST") {
method = Method::POST;
if (header_body.size() == 2) {
body = header_body[1];
}
} else {
method = Method::UNKNOWN;
}
path = tokens[1];
continue;
}
std::string & line = lines[i];
if (line.find(":") != std::string::npos) {
std::vector<std::string> kv = split(line, ": ");
if (kv.size() != 2) {
return FORMAT_ERROR;
}
headers[kv[0]] = kv[1];
}
}
if (method == Method::POST) {
size_t content_length = std::strtold(headers["Content-Length"].c_str(), NULL);
if (body.size() != content_length) {
std::cout << body.size() << ":" << content_length << std::endl;
return INCOMPLETE_REQUEST;
}
}
return SUCCESS;
}
void dump() {
std::cout << "method: " << method << std::endl;
std::cout << "path: " << path << std::endl;
std::cout << "headers: " << std::endl;
for (auto & kv : headers) {
std::cout << kv.first << ": " << kv.second << std::endl;
}
std::cout << "body: " << body << std::endl;
}
private:
Method method;
std::string path;
std::map<std::string, std::string> headers;
std::string body;
std::vector<std::string> split(const std::string &str, const std::string &delim) {
std::vector<std::string> tokens;
std::regex re(delim); // 创建正则表达式对象
std::sregex_token_iterator it(str.begin(), str.end(), re, -1);
std::sregex_token_iterator end;
while (it != end) {
tokens.push_back(*it++);
}
return tokens;
}
};
int main() {
std::string get_request = "GET /index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36\r\n";
HttpRequest req;
req.parse(get_request);
req.dump();
std::string post_request = "POST /submit HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 15\r\n"
"\r\n"
"name=John&age=30";
std::string post_request2 = "POST / HTTP/1.1\r\n"
"Host: 127.0.0.1:8899\r\n"
"User-Agent: curl/7.81.0\r\n"
"Accept: */*\r\n"
"Content-Length: 18\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n"
"SELECT * FROM fff;";
int ret = req.parse(post_request2);
req.dump();
if (ret != HttpRequest::SUCCESS) {
std::cout << "parse error: " << ret << std::endl;
}
return 0;
}
仅实现简单的解析功能,并未考虑性能和http的完整支持。需要说明INCOMPLETE_REQUEST
结果是为了解决tcp
一次接收不到完整包的情况,可能需要多次解析