简体   繁体   English

C 原始套接字 HTTP 请求总是返回状态 400

[英]C Raw Sockets HTTP Request Always Returning Status 400

I normally write a bunch of Typescript/Javascript code, and I took the HTTP protocol for granted.我通常会写一堆 Typescript/Javascript 代码,我认为 HTTP 协议是理所当然的。 I decided to write a C++ program that can make GET requests to a given URL with sockets to learn more about how HTTP works.我决定编写一个 C++ 程序,该程序可以使用套接字向给定的 URL 发出 GET 请求,以了解有关 HTTP 工作原理的更多信息。 I've coded up what I think is the basic structure of what I should be doing:我已经编码了我认为我应该做的基本结构:

  1. Create a socket创建套接字
  2. Connect the socket to host将套接字连接到主机
  3. Send request byte by byte逐字节发送请求
  4. Received response byte by byte逐字节接收响应

The issue is that the request always returns status code 400:问题是请求总是返回状态码 400:

>>>> Request sent:
GET /links HTTP/1.1


>>>> Response received:
HTTP/1.1 400 Bad Request
Server: cloudflare
Date: Sun, 11 Oct 2020 05:57:11 GMT
Content-Type: text/html
Content-Length: 155
Connection: close
CF-RAY: -

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

Here's the code I'm using to create the socket and connect it to the host:这是我用来创建套接字并将其连接到主机的代码:

    // ---- Create the socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("!!!! ERROR opening socket");

    // ---- Look up (and parse) the server host, route
    std::string host = parseHost(url);
    std::string route = parseRoute(url);
    struct hostent *server = gethostbyname(host.c_str()); // host.c_str())
    if (server == NULL)
        error("!!!! ERROR, no such host");

    // ---- Fill in the server address structure
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT); // PORT
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);

    // ---- Connect the socket to the given url's host
    const int didConnect = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (didConnect < 0) error("!!!! ERROR connecting to host");

If that logic seems correct, then here's the code that sends the request and receives the response:如果这个逻辑看起来是正确的,那么这里是发送请求和接收响应的代码:

    // ---- Send the GET request byte by byte
    int bytes, sent, received;
    char response[MAX_CONTENT_LENGTH];
    int total = sizeof(response) - 1;
    sent = 0;
    std::string message = "GET " + route + "HTTP/1.1" + "\r\n\r\n";
    do
    {
        bytes = write(sockfd, message.c_str() + sent, total - sent);
        if (bytes < 0) error("!!!! ERROR writing message to socket");
        if (bytes == 0) break;
        sent += bytes;
    } while (sent < total);

    std::cout << ">>>> Request sent: \n" << message << std::endl;

    // ---- Receive the response byte by byte
    memset(response, 0, sizeof(response));
    total = sizeof(response) - 1;
    received = 0;
    do {
        bytes = read(sockfd, response + received, total - received);
        if (bytes < 0)
            error("!!!! ERROR reading response from socket");
        if (bytes == 0)
            break;
        received += bytes;
    } while (received < total);

    if (received == total)
        error("!!!! ERROR storing complete response from socket (not enough space allocated)");
  • TLDR: Am I sending the right char array to the server? TLDR:我是否将正确的字符数组发送到服务器? As of right now it has this format: "GET /route HTTP/1.1\\r\\n\\r\\n" .截至目前,它具有以下格式: "GET /route HTTP/1.1\\r\\n\\r\\n" Am I forgetting any headers/other information that lets the server know that it's a GET request?我是否忘记了让服务器知道这是 GET 请求的任何标头/其他信息?
>>>> Request sent:
GET /links HTTP/1.1

This is not a valid HTTP request.这不是有效的 HTTP 请求。 It is missing the Host header with the target domain name, ie it should be at least something like this它缺少带有目标域名的 Host 标头,即它至少应该是这样的

GET /links HTTP/1.1
Host: www.example.com

Apart from that your code simply tries to read data until the server closes the connection or the size of your internal buffer is reached.除此之外,您的代码只是尝试读取数据,直到服务器关闭连接或达到内部缓冲区的大小。 But HTTP/1.1 by default uses persistent connection.但是 HTTP/1.1 默认使用持久连接。 So the server might simply keep the connection open after the response is sent because it expects your next request, which means that your program will simply block doing nothing.因此,服务器可能会在响应发送后简单地保持连接打开,因为它期待您的下一个请求,这意味着您的程序将简单地阻止什么都不做。

Note that HTTP is far more complex than it looks.请注意,HTTP 远比看起来复杂。 Please study the actual standard if you want to implement it instead of using existing libraries.如果您想实现它而不是使用现有库,请研究实际标准 That's what standards are for.这就是标准的用途。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM