【发布时间】:2022-01-18 21:23:49
【问题描述】:
我正在开发一个 C++ 项目,我在其中侦听套接字并根据我在 fds 上从客户端收到的请求生成 HTTP 响应,简而言之,我使用浏览器发送请求,最终得到原始请求,我解析它并生成相应的http响应。
但是在大型 POST 请求的情况下,通常会发生我收到部分请求,所以在第一部分我通常只会找到第一行(版本/方法/uri),一些标头但没有正文,并且我想应该以某种方式得到身体的其余部分,但是我无法弄清楚两件事,
首先,我如何知道我收到的请求是部分请求还是仅从第一部分完成?我没有得到任何与范围有关的信息,这是我的客户向我发送 POST 请求时得到的第一部分。
POST / HTTP/1.1
Host: localhost:8081
Connection: keep-alive
Content-Length: 8535833
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Origin: http://127.0.0.1:8081
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryOs6fsdbaegBIumqh
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8081/
Accept-Encoding: gzip, deflate, br
Accept-Language: fr,en-US;q=0.9,en;q=0.8
我如何才能从中确定是收到部分请求还是仅收到错误请求(如果请求说它具有 X 内容长度但正文大小,我需要生成 400 错误不同)
第二个问题是,假设我已经知道它是否是部分请求,我该如何继续将整个请求存储在缓冲区中,然后再将其发送到我的解析器并生成响应?这是我的接收功能(我已经知道客户的 fd,所以我只是接收它
void Client::receive_request(void)
{
char buffer[2024];
int ret;
ret = recv(_fd, buffer, 2024, 0);
buffer[ret] = 0;
_received_request += buffer;
_bytes_request += ret;
std::cout << "Raw Request:\n" << _received_request << std::endl;
if (buffer[ret-1] == '\n')
{
_ready_request = true;
_request.parse(_received_request, _server->get_config());
}
}
这是检查客户端是否尝试发送请求、解析并生成响应的代码
int Connections::check_clients() {
int fd;
for (std::vector<Client*>::iterator client = clients.begin();
client != clients.end() && ready_fd != 0 ; client++)
{
fd = (*client)->get_fd();
if (FD_ISSET(fd, &ready_rset))
{
ready_fd--;
(*client)->receive_request();
if ((*client)->request_is_ready())
{
(*client)->wait_response();
close(fd);
FD_CLR(fd, &active_set);
fd_list.remove(fd);
max_fd = *std::max_element(fd_list.begin(), fd_list.end());
free(*client);
client = clients.erase(client);
}
}
}
return 0;
}
正如您所看到的,我用 C++ (98) 编写所有内容,并且不想得到只是驳回我的问题并让我参考不同的技术或库的答案,除非它可以帮助我理解做错了什么以及如何处理部分问题请求。
对于信息,我只处理 HTTP 1.1(仅限 GET/POST/DELETE),并且我通常只在获取大块文件或具有非常大主体的文件上传时才会遇到此问题。谢谢
PS : 如果需要,如果您想进一步查看代码,我可以链接当前项目的 github 存储库
【问题讨论】:
-
阅读 RFC 2616 Section 4.4 和 RFC 7230 Section 3.3.3 了解如何确定 HTTP 消息的长度。在您的情况下,客户端以
multipart/form-data格式发送数据,这是一种自终止格式,因此在 theory 中,您可以继续从套接字读取,直到检测到最终终止符边界。但是,另一方面,客户端也在发送Content-Length,因此如果您没有收到完全指定的字节数,则请求失败。
标签: c++ http sockets server upload