Не видит загруженный файл в C при использовании данных формы - PullRequest
0 голосов
/ 07 января 2020

У меня есть простой веб-сервер в C, который распечатывает все, что получает от клиента. Это прекрасно работает, за исключением случаев, когда я пытаюсь загрузить файл, используя multipart/form-data Я пытался сделать это, используя Postman и curl с теми же результатами В чем может быть причина этого?

Но когда я выбираю binary, я вижу свой загруженный файл в выводе.

При использовании form-data я получаю это (я не вижу загруженный файл):

POST /hello-world/ HTTP/1.1
Content-Type: multipart/form-data; boundary=--------------------------257071285279776422109124
User-Agent: PostmanRuntime/7.21.0
Host: localhost:8088
Accept-Encoding: gzip, deflate
Content-Length: 753
Connection: keep-alive

----------------------------257071285279776422109124
Content-Disposition: form-data; name="filecoming2"; filename="imgage.jpg"
Content-Type: image/jpeg

80 79 83 84 32 47 104 101 108 108 111 45 119 111 114 108 100 47 32 72 84 84 80 47 49 46 49 13 10 67 111 110 116 101 110 116 45 84 121 112 101 58 32 109 117 108 116 105 112 97 114 116 47 102 111 114 109 45 100 97 116 97 59 32 98 111 117 110 100 97 114 121 61 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 50 53 55 48 55 49 50 56 53 50 55 57 55 55 54 52 50 50 49 48 57 49 50 52 13 10 85 115 101 114 45 65 103 101 110 116 58 32 80 111 115 116 109 97 110 82 117 110 116 105 109 101 47 55 46 50 49 46 48 13 10 65 99 99 101 112 116 58 32 42 47 42 13 10 67 97 99 104 101 45 67 111 110 116 114 111 108 58 32 110 111 45 99 97 99 104 101 13 10 80 111 115 116 109 97 110 45 84 111 107 101 110 58 32 99 48 50 100 55 99 49 57 45 102 100 50 52 45 52 49 97 48 45 56 52 53 99 45 100 56 54 49 101 99 55 54 48 102 56 99 13 10 72 111 115 116 58 32 108 111 99 97 108 104 111 115 116 58 56 48 56 56 13 10 65 99 99 101 112 116 45 69 110 99 111 100 105 110 103 58 32 103 122 105 112 44 32 100 101 102 108 97 116 101 13 10 67 111 110 116 101 110 116 45 76 101 110 103 116 104 58 32 55 53 51 13 10 67 111 110 110 101 99 116 105 111 110 58 32 107 101 101 112 45 97 108 105 118 101 13 10 13 10 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 50 53 55 48 55 49 50 56 53 50 55 57 55 55 54 52 50 50 49 48 57 49 50 52 13 10 67 111 110 116 101 110 116 45 68 105 115 112 111 115 105 116 105 111 110 58 32 102 111 114 109 45 100 97 116 97 59 32 110 97 109 101 61 34 102 105 108 101 99 111 109 105 110 103 50 34 59 32 102 105 108 101 110 97 109 101 61 34 105 109 103 97 103 101 46 106 112 103 34 13 10 67 111 110 116 101 110 116 45 84 121 112 101 58 32 105 109 97 103 101 47 106 112 101 103 13 10 13 10

При использовании бинарное (в Почтальоне) я вижу свой загруженный файл!

POST /hello-world/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: PostmanRuntime/7.21.0
Host: localhost:8088
Accept-Encoding: gzip, deflate
Content-Length: 538
Connection: keep-alive

����

80 79 83 84 32 47 104 101 108 108 111 45 119 111 114 108 100 47 32 72 84 84 80 47 49 46 49 13 10 67 111 110 116 101 110 116 45 84 121 112 101 58 32 97 112 112 108 105 99 97 116 105 111 110 47 120 45 119 119 119 45 102 111 114 109 45 117 114 108 101 110 99 111 100 101 100 13 10 85 115 101 114 45 65 103 101 110 116 58 32 80 111 115 116 109 97 110 82 117 110 116 105 109 101 47 55 46 50 49 46 48 13 10 65 99 99 101 112 116 58 32 42 47 42 13 10 67 97 99 104 101 45 67 111 110 116 114 111 108 58 32 110 111 45 99 97 99 104 101 13 10 80 111 115 116 109 97 110 45 84 111 107 101 110 58 32 55 51 56 99 55 55 55 51 45 50 102 57 52 45 52 101 100 102 45 56 99 52 102 45 48 48 55 99 54 50 98 51 48 50 55 53 13 10 72 111 115 116 58 32 108 111 99 97 108 104 111 115 116 58 56 48 56 56 13 10 65 99 99 101 112 116 45 69 110 99 111 100 105 110 103 58 32 103 122 105 112 44 32 100 101 102 108 97 116 101 13 10 67 111 110 116 101 110 116 45 76 101 110 103 116 104 58 32 53 51 56 13 10 67 111 110 110 101 99 116 105 111 110 58 32 107 101 101 112 45 97 108 105 118 101 13 10 13 10 -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 1 0 72 0 72 0 0 -1 -2 0 19 67 114 101 97 116 101 100 32 119 105 116 104 32 71 73 77 80 -1 -37 0 67 0 80 55 60 70 60 50 80 70 65 70 90 85 80 95 120 -56 -126 120 110 110 120 -11 -81 -71 -111 -56 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -37 0 67 1 85 90 90 120 105 120 -21 -126 -126 -21 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -62 0 17 8 0 1 0 1 3 1 17 0 2 17 1 3 17 1 -1 -60 0 20 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 -1 -60 0 20 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 12 3 1 0 2 16 3 16 0 0 1 3 -1 -60 0 20 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 1 0 1 5 2 127 -1 -60 0 20 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 3 1 1 63 1 127 -1 -60 0 20 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 2 1 1 63 1 127 -1 -60 0 20 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 1 0 6 63 2 127 -1 -60 0 20 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 1 0 1 63 33 127 -1 -38 0 12 3 1 0 2 0 3 0 0 0 16 -97 -1 -60 0 20 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 3 1 1 63 16 127 -1 -60 0 20 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 2 1 1 63 16 127 -1 -60 0 20 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -38 0 8 1 1 0 1 63 16 127 -1 -39 

Здесь мой веб-сервер в C:

#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <stdbool.h>

#define PORT 8088

int main(void)
{
    int server_fd, new_socket;
    long valread;
    struct sockaddr_in address;

    int addrlen = sizeof(address);

    char *hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 12\n\nHello world!";

    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    //memset(address.sin_zero, '\0', sizeof address.sin_zero);

    bind(server_fd, (struct sockaddr *)&address, sizeof(address));

    listen(server_fd, 10);

    while(true)
    {
        printf("\n+++++++ Waiting for new connection ++++++++\n\n");

        new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);

        char buffer[30000] = {0};

        valread = read(new_socket, buffer, 30000);
        printf("%s\n", buffer);

        printf("\n");
        for (int i = 0; i < valread; i++) { printf("%i ", buffer[i]); }
        printf("\n\n");

        write(new_socket, hello, strlen(hello));
        printf("------------------Hello message sent-------------------\n");

        close(new_socket);
    }
}

Ответы [ 2 ]

1 голос
/ 08 января 2020

TCP ориентирован на поток. Вам нужно повторно звонить read и write. Учитывая ваш пример, один вызов read не гарантирует заполнение буфера всем файлом. Прочитайте HTTP-заголовок, проанализируйте Content-Length и продолжайте чтение, пока ваша общая сумма valread не будет соответствовать размеру заголовка плюс Content-Length.

0 голосов
/ 09 января 2020

Вы не читаете достаточно данных.

read() не гарантирует возвращение столько байтов, сколько вы просите. И нет никакой гарантии, что read() получит полное HTTP-сообщение за одно чтение. TCP является байтовым потоком, вам нужно вызывать read() в al oop, пока полный HTTP-запрос не будет получен полностью. См. RF C 2616, раздел 4.4 и RF C 7230, раздел 3.3.3 , чтобы узнать, как определить конец HTTP-сообщения.

4.4 Message Length

   The transfer-length of a message is the length of the message-body as
   it appears in the message; that is, after any transfer-codings have
   been applied. When a message-body is included with a message, the
   transfer-length of that body is determined by one of the following
   (in order of precedence):

   1.Any response message which "MUST NOT" include a message-body (such
     as the 1xx, 204, and 304 responses and any response to a HEAD
     request) is always terminated by the first empty line after the
     header fields, regardless of the entity-header fields present in
     the message.

   2.If a Transfer-Encoding header field (section 14.41) is present and
     has any value other than "identity", then the transfer-length is
     defined by use of the "chunked" transfer-coding (section 3.6),
     unless the message is terminated by closing the connection.

   3.If a Content-Length header field (section 14.13) is present, its
     decimal value in OCTETs represents both the entity-length and the
     transfer-length. The Content-Length header field MUST NOT be sent
     if these two lengths are different (i.e., if a Transfer-Encoding
     header field is present). If a message is received with both a
     Transfer-Encoding header field and a Content-Length header field,
     the latter MUST be ignored.

   4.If the message uses the media type "multipart/byteranges", and the
     ransfer-length is not otherwise specified, then this self-
     elimiting media type defines the transfer-length. This media type
     UST NOT be used unless the sender knows that the recipient can arse
     it; the presence in a request of a Range header with ultiple byte-
     range specifiers from a 1.1 client implies that the lient can parse
     multipart/byteranges responses.

       A range header might be forwarded by a 1.0 proxy that does not
       understand multipart/byteranges; in this case the server MUST
       delimit the message using methods defined in items 1,3 or 5 of
       this section.

   5.By the server closing the connection. (Closing the connection
     cannot be used to indicate the end of a request body, since that
     would leave no possibility for the server to send back a response.)

   For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
   containing a message-body MUST include a valid Content-Length header
   field unless the server is known to be HTTP/1.1 compliant. If a
   request contains a message-body and a Content-Length is not given,
   the server SHOULD respond with 400 (bad request) if it cannot
   determine the length of the message, or with 411 (length required) if
   it wishes to insist on receiving a valid Content-Length.

   All HTTP/1.1 applications that receive entities MUST accept the
   "chunked" transfer-coding (section 3.6), thus allowing this mechanism
   to be used for messages when the message length cannot be determined
   in advance.

   Messages MUST NOT include both a Content-Length header field and a
   non-identity transfer-coding. If the message does include a non-
   identity transfer-coding, the Content-Length MUST be ignored.

   When a Content-Length is given in a message where a message-body is
   allowed, its field value MUST exactly match the number of OCTETs in
   the message-body. HTTP/1.1 user agents MUST notify the user when an
   invalid length is received and detected.
3.3.3.  Message Body Length

   The length of a message body is determined by one of the following
   (in order of precedence):

   1.  Any response to a HEAD request and any response with a 1xx
       (Informational), 204 (No Content), or 304 (Not Modified) status
       code is always terminated by the first empty line after the
       header fields, regardless of the header fields present in the
       message, and thus cannot contain a message body.

   2.  Any 2xx (Successful) response to a CONNECT request implies that
       the connection will become a tunnel immediately after the empty
       line that concludes the header fields.  A client MUST ignore any
       Content-Length or Transfer-Encoding header fields received in
       such a message.

   3.  If a Transfer-Encoding header field is present and the chunked
       transfer coding (Section 4.1) is the final encoding, the message
       body length is determined by reading and decoding the chunked
       data until the transfer coding indicates the data is complete.

       If a Transfer-Encoding header field is present in a response and
       the chunked transfer coding is not the final encoding, the
       message body length is determined by reading the connection until
       it is closed by the server.  If a Transfer-Encoding header field
       is present in a request and the chunked transfer coding is not
       the final encoding, the message body length cannot be determined
       reliably; the server MUST respond with the 400 (Bad Request)
       status code and then close the connection.

       If a message is received with both a Transfer-Encoding and a
       Content-Length header field, the Transfer-Encoding overrides the
       Content-Length.  Such a message might indicate an attempt to
       perform request smuggling (Section 9.5) or response splitting
       (Section 9.4) and ought to be handled as an error.  A sender MUST
       remove the received Content-Length field prior to forwarding such
       a message downstream.

   4.  If a message is received without Transfer-Encoding and with
       either multiple Content-Length header fields having differing
       field-values or a single Content-Length header field having an
       invalid value, then the message framing is invalid and the
       recipient MUST treat it as an unrecoverable error.  If this is a
       request message, the server MUST respond with a 400 (Bad Request)
       status code and then close the connection.  If this is a response
       message received by a proxy, the proxy MUST close the connection
       to the server, discard the received response, and send a 502 (Bad
       Gateway) response to the client.  If this is a response message
       received by a user agent, the user agent MUST close the
       connection to the server and discard the received response.

   5.  If a valid Content-Length header field is present without
       Transfer-Encoding, its decimal value defines the expected message
       body length in octets.  If the sender closes the connection or
       the recipient times out before the indicated number of octets are
       received, the recipient MUST consider the message to be
       incomplete and close the connection.

   6.  If this is a request message and none of the above are true, then
       the message body length is zero (no message body is present).

   7.  Otherwise, this is a response message without a declared message
       body length, so the message body length is determined by the
       number of octets received prior to the server closing the
       connection.

   Since there is no way to distinguish a successfully completed,
   close-delimited message from a partially received message interrupted
   by network failure, a server SHOULD generate encoding or
   length-delimited messages whenever possible.  The close-delimiting
   feature exists primarily for backwards compatibility with HTTP/1.0.

   A server MAY reject a request that contains a message body but not a
   Content-Length by responding with 411 (Length Required).

   Unless a transfer coding other than chunked has been applied, a
   client that sends a request containing a message body SHOULD use a
   valid Content-Length header field if the message body length is known
   in advance, rather than the chunked transfer coding, since some
   existing services respond to chunked with a 411 (Length Required)
   status code even though they understand the chunked transfer coding.
   This is typically because such services are implemented via a gateway
   that requires a content-length in advance of being called and the
   server is unable or unwilling to buffer the entire request before
   processing.

   A user agent that sends a request containing a message body MUST send
   a valid Content-Length header field if it does not know the server
   will handle HTTP/1.1 (or later) requests; such knowledge can be in
   the form of specific user configuration or by remembering the version
   of a prior received response.

   If the final response to the last request on a connection has been
   completely received and there remains additional data to read, a user
   agent MAY discard the remaining data or attempt to determine if that
   data belongs as part of the prior response body, which might be the
   case if the prior message's Content-Length value is incorrect.  A
   client MUST NOT process, cache, or forward such extra data as a
   separate response, since such behavior would be vulnerable to cache
   poisoning.

Аналогично, write() может не посылать столько байтов, сколько вы просите, поэтому вам также необходимо вызвать write() в al oop.

Например, попытаться что-то сделать Более того:

#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <stdbool.h>

#define PORT 8088

struct data_buffer
{
    void *data;
    size_t size;
    size_t cap;
};

void initDataBuffer(struct data_buffer *buffer)
{
    buffer->data = NULL;
    buffer->size = 0;
    buffer->cap = 0;
}

void freeDataBuffer(struct data_buffer *buffer)
{
    if (buffer->data) free(buffer->data);
    initDataBuffer(buffer);
}

int appendBytes(struct data_buffer *buffer, void *data, size_t data_size)
{
    if ((buffer->cap - buffer->size) < data_size)
    {
        size_t new_cap = (((buffer->size + data_size) + 255) / 256) * 256;
        char *new_buffer = realloc(buffer->data, new_cap);
        if (!new_buffer)
            return -1;
        buffer->data = new_buffer;
        buffer->cap = new_cap;
    }
    memcpy(buffer->data, data, data_size);
    buffer->size += data_size;
    return 0;
}

int readRaw(int fd, void *data, size_t size)
{
    char *ptr = data;
    ssize_t recvd;

    while (size > 0)
    {
        recvd = read(fd, ptr, size);
        if (recvd <= 0)
            return -1;

        printf("%.*s", recvd, ptr);

        ptr += sent;
        size -= sent;
    }

    return 0;
}

char* readLine(int fd)
{
    struct data_buffer line_buffer;
    char ch;

    line_buffer.data = NULL;
    line_buffer.size = 0;
    line_buffer.cap = 0;

    while (true)
    {
        if (read(fd, &ch, 1) <= 0)
        {
            freeDataBuffer(&line_buffer);
            return NULL;
        }

        if (ch == '\r')
        {
            if (read(fd, &ch, 1) <= 0)
            {
                freeDataBuffer(&line_buffer);
                return NULL;
            }

            if (ch != '\n')
            {
                printf("%c", '\r');

                if (appendBytes(&line_buffer, "\r", 1) < 0)
                {
                    freeDataBuffer(&line_buffer);
                    return NULL;
                }
            }
        }

        printf("%c", ch);

        if (ch == '\n')
            break;

        if (appendBytes(&line_buffer, &ch, 1) < 0)
        {
            freeDataBuffer(&line_buffer);
            return NULL;
        }
    }

    if (!appendBytes(&line_buffer, "\0", 1))
    {
        freeDataBuffer(&line_buffer);
        return NULL;
    }

    return line_buffer.data;
}

struct string_list
{
    char **strings;
    size_t count;
    size_t cap;
};

void initStringList(struct string_list *list)
{
    list->strings = NULL;
    list->count = 0;
    list->cap = 0;
}

void freeStringList(struct string_list *list)
{
    if (list->strings)
    {
        for(size_t i = 0 ; i < list->count; ++i)
            free(list->strings[i]);
        free(list->strings);
    }
    initStringList(list);
}

int appendString(struct string_list *list, char *str)
{
    if (list->count >= list->cap)
    {
        size_t new_cap = list->cap + 10;
        char **new_strings = realloc(list->strings, sizeof(char*) * new_cap);
        if (!new_strings)
            return -1;
        list->strings = new_strings;
        list->cap = new_cap;
    }
    list->strings[list->count] = str;
    list->count += 1;
    return 0;
}

int readHeaders(int fd, struct string_list *headers)
{
    char *line;

    initStringList(headers);

    while (true)
    {
        line = readLine(fd);
        if (!line)
        {
            freeStringList(headers);
            return -1;
        }

        if (*line == '\0')
        {
            free(line);
            break;
        }

        if (!appendLine(headers, line))
        {
            free(line);
            freeStringList(headers);
            return -1;
        }
    }

    return 0;
}

int sendRaw(int fd, void *data, size_t size)
{
    char *ptr = data;
    ssize_t sent;

    while (size > 0)
    {
        sent = write(fd, ptr, size);
        if (sent < 1)
            return -1;
        ptr += sent;
        size -= sent;
    }

    return 0;
}

int sendString(int fd, char *str)
{
    return sendRaw(fd, line, strlen(line));
}

int sendLine(int fd, char *line)
{
    if (sendString(fd, line) < 0)
        return -1;

    return sendRaw(fd, "\r\n", 2);
}

int sendResponse(int fd, int code, char *status, char **headers, void *data, size_t data_size)
{
    char tmp[50];

    sprintf(tmp, "HTTP/1.1 %d ", code);
    if (sendString(fd, tmp) < 0)
        return -1;

    if (sendLine(fd, status) < 0)
        return -1;

    if (headers)
    {
        for(size_t i = 0; headers[i] != NULL; ++i)
        {
            if (sendLine(fd, headers[i]) < 0)
                return -1;
        }
    }

    sprintf(tmp, "Content-Length: %u ", data_size);
    if (sendLine(fd, tmp) < 0)
        return -1;

    if (sendRaw(fd, "\r\n", 2) < 0)
        return -1;

    return sendRaw(fd, data, data_size);
}

struct httpRequest
{
    struct string_list headers;
    struct data_buffer body;
};

void initHttpRequest(struct httpRequest *req)
{
    initStringList(&(req->headers));
    initDataBuffer(&(req->body));
}

void freeHttpRequest(struct httpRequest *req)
{
    freeStringList(&(req->headers));
    freeDataBuffer(&(req->body));
}

int readRequest(int fd, struct httpRequest *req)
{
    char *transferEncoding = NULL;
    char *contentLength = NULL;
    char* error_headers[] = {"Connection: close", NULL};

    initHttpRequest(req);

    if (readHeaders(fd, &(req->headers)) < 0)
    {
        freeHttpRequest(req);
        sendResponse(fd, 500, "Internal Server Error", error_headers, NULL, 0);
        return -1;
    }

    for (size_t i = 0; req->headers[i] != NULL; ++i)
    {
        if (strncmpi(req->headers[i], "Transfer-Encoding:", 18) == 0)
            transferEncoding = req->headers[i] + 18;

        else if (strncmpi(req->headers[i], "Content-Length:", 15) == 0)
            contentLength = req->headers[i] + 15;
    }

    if (transferEncoding)
    {
        size_t len = strlen(transferEncoding);
        if ((len < 7) || (strncmpi(transferEncoding + len - 7, "chunked", 7) != 0))
        {
            freeHttpRequest(req);
            sendResponse(fd, 400, "Bad Request", error_headers, NULL, 0);
            return -1;
        }

        char chunk_data[1024];

        while (true)
        {
            char *chunk_line = readLine(fd);
            if (!chunk_line)
            {
                freeHttpRequest(req);
                sendResponse(fd, 500, "Internal Server Error", error_headers, NULL, 0);
                return -1;
            }

            long chunk_size = strtol(chunk_line, NULL, 16);
            free(chunk_line);

            if ((chunk_size < 0) || (chunk_size >= LONG_MAX))
            {
                freeHttpRequest(req);
                sendResponse(fd, 400, "Bad Request", error_headers, NULL, 0);
                return -1;
            }

            if (chunk_size == 0)
                break;

            while (chunk_size > 0)
            {
                size_t size = min(chunk_size, sizeof(chunk_data));
                if (readRaw(fd, chunk_data, size) < 0)
                {
                    freeHttpRequest(req);
                    return -1;
                }

                if (!appendBytes(&(req->body), chunk_data, size))
                {
                    freeHttpRequest(req);
                    sendResponse(fd, 500, "Internal Server Error", error_headers, NULL, 0);
                    return -1;
                }
            }
        }

        struct string_list trailer_headers;
        if (readHeaders(fd, &trailer_headers) < 0)
        {
            freeHttpRequest(req);
            sendResponse(fd, 500, "Internal Server Error", error_headers, NULL, 0);
            return -1;
        }

        // update entries of req->headers with entries of trailer_headers as needed...

        freeStringList(&trailer_headers);
    }
    else if (contentLength)
    {
        long content_size = strtol(contentLength, NULL, 10);
        if ((content_size < 0) || (content_size >= LONG_MAX))
        {
            freeHttpRequest(req);
            sendResponse(fd, 400, "Bad Request", error_headers, NULL, 0);
            return -1;
        }

        req->body.data = malloc(content_size);
        if (!req->body.data)
        {
            freeHttpRequest(req);
            sendResponse(fd, 500, "Internal Server Error", error_headers, NULL, 0);
            return -1;
        }

        req->data_cap = content_size;

        if (readRaw(fd, req->body.data, content_size) < 0)
        {
            freeHttpRequest(req);
            return -1;
        }

        req->data_size = content_size;
    }

    return 0;
}

int main(void)
{
    int server_fd, new_socket;
    struct sockaddr_in address;
    struct httpRequest req;

    int addrlen = sizeof(address);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("socket");
        return 1;
    }

    memset(&address, 0, sizeof address);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    {
        perror("bind");
        return 1;
    }

    if (listen(server_fd, 10) < 0)
    {
        perror("listen");
        return 1;
    }

    while (true)
    {
        printf("\n+++++++ Waiting for new connection ++++++++\n\n");

        addrlen = sizeof(address);
        new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
        if (new_socket < 0)
        {
            perror("accept");
            return 1;
        }

        if (readRequest(new_socket, &req) < 0)
        {
            close(new_socket);
            continue;
        }

        // use req as needed...
        printf("\n");
        for (size_t i = 0; i < req->body.size; i++)
            printf("%02X ", (int) ((char*)req->body.data)[i]);
        printf("\n\n");

        freeHttpRequest(&req);

        char* resp_headers[] = {"Connection: close", "Content-Type: text/plain", NULL};
        if (sendResponse(new_socket, 200, "OK", resp_headers, "Hello world!", 12) == 0)
            printf("------------------Hello message sent-------------------\n");

        close(new_socket);
    }

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...