【问题标题】:Chunked transfer encoding - Page is not displayed properly分块传输编码 - 页面显示不正确
【发布时间】:2018-05-03 14:06:16
【问题描述】:

我的任务是实现简单的 HTTP 服务器。当我发送响应时,我应该支持分块传输编码。这是我向客户端发送响应的函数。

static int serve_request(int sock, struct conf_arg *arg, char version[])
{
    FILE *html = NULL;
    char buf[MAX_MSG];

    strcat(arg->root, arg->defdoc);
    html = fopen(arg->root, "r");
    if (!html) {
        not_found(sock, version);
        return 0;
    }
    good_responce(sock, version);
    do {
        fgets(buf, sizeof(buf), html);
        const unsigned chunk = CHUNK_SIZE;
        char *pbuf = buf;
        char tempbuf[chunk + 10];

        while (strlen(pbuf) >= chunk) {
            sprintf(tempbuf, "%x\r\n", chunk);
            write(sock, tempbuf, strlen(tempbuf));
            write(sock, pbuf, chunk);
            pbuf += chunk;
            strcpy(tempbuf, "\r\n");
            write(sock, tempbuf, strlen(tempbuf));
        }
        if (strlen(pbuf) == 0) {
            sprintf(tempbuf, "%x\r\n", 0);
            write(sock, tempbuf, strlen(tempbuf));
        }
        if (strlen(pbuf) > 0) {
            sprintf(tempbuf, "%x\r\n", (unsigned)strlen(pbuf));
            write(sock, tempbuf, strlen(tempbuf));
            write(sock, pbuf, strlen(pbuf));
            sprintf(tempbuf, "%x\r\n", 0);
            write(sock, tempbuf, strlen(tempbuf));
        }
        strcpy(tempbuf, "\r\n");
        write(sock, tempbuf, strlen(tempbuf));
    } while (!feof(html));
    fclose(html);
    return 0;
}

CHUNK_SIZE 定义为 1024,因为我想发送 1KB 大小的块。当我打开页面enter image description here时出现问题 页面显示不正确。 我还设置了 Transfer-Encoding: chunked

strcpy(buf, ENCODING);
send(sock, buf, strlen(buf), 0);

ENCODING 被定义为“Transfer-Encoding: chunked\r\n”

【问题讨论】:

  • 您是否设置了响应标头以指示您的响应是分块的,例如 Transfer-Encoding: chunked
  • 我编辑问题并在我设置响应头的地方添加代码。
  • strcpy() 那里是多余的,你应该直接发送ENCODING,然后发送send(sock, "\r\n", 2, 0)
  • 我按照你的说法更改了代码,但在这种情况下我收到错误 ERR_INVALID_CHUNKED_ENCODING

标签: c http server chunked-encoding http-chunked


【解决方案1】:

我想我知道问题出在哪里,但并不完全确定。

在您的do 循环中,您会得到一个充满数据的buf,然后您将其发送。然后你得到另一个充满数据的缓冲区并发送它。但是在发送了每个缓冲区的数据之后,您终止发送0\r\n。例如:

1024    // send first chunk
1024    // send second chunk
256     // last part of first bufer
0       // terminate transfer
1024    // send first chunk of second buffer
1024    //...
256
0

虽然在发送最后一个块之前再次填充缓冲区可能会更好(使用memmove 将最后一部分向下移动,然后调用fgets 填充剩余部分),您可能会通过发送0\r\n 仅在do ... while 循环之后,例如:

        if (strlen(pbuf) > 0) {
            sprintf(tempbuf, "%x\r\n", (unsigned)strlen(pbuf));
            write(sock, tempbuf, strlen(tempbuf));
            write(sock, pbuf, strlen(pbuf));
            //sprintf(tempbuf, "%x\r\n", 0);
            //write(sock, tempbuf, strlen(tempbuf));
        }
        //strcpy(tempbuf, "\r\n");
        //write(sock, tempbuf, strlen(tempbuf));
    } while (!feof(html));
    sprintf(tempbuf, "%x\r\n", 0);
    write(sock, tempbuf, strlen(tempbuf));
    strcpy(tempbuf, "\r\n");
    write(sock, tempbuf, strlen(tempbuf));

还请注意,您必须检查fgets 的结果,因为它可以在eof 时返回零;缓冲区不会被刷新,您将再次发送最后一部分:

    if (fgets(buf, sizeof(buf), html)==NULL) break;

另请参阅有关您不必要地使用 tempbuf 的 cmets。

【讨论】:

  • 但是当您检查 fgets() 的返回值时,您应该将其与 NULL 进行比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-26
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多