通过读取 stdin(C 中的 CGI)进行 http POST

发布于 2024-09-08 15:45:50 字数 638 浏览 2 评论 0原文

在 C 中,哪种方法可以无错误地在 CGI 中获取 http POST?

我目前正在使用这个。可以吗?如果“CONTENT_LENGTH”不正确并且大于标准输入怎么办?那么 read 将如何表现?


char *STDIN = NULL;
char *pointer = getenv("CONTENT_LENGTH");
if(pointer != NULL)
{
    char charlength[5] = "";
    strncat(charlength, pointer, 4); // limit length to a reasonable number
    unsigned long int length = strtoul(charlength, NULL, 0);
    STDIN = malloc(length + 2);
    ssize_t readbytes = read(0, STDIN, length);
    STDIN[readbytes] = '&'; // for use later on in my program
    memset(STDIN + readbytes + 1, (int)'\0', (length + 2) - (size_t)(readbytes + 1));
}

Which is an error-free way to get a http POST in CGI in C?

I'm currently using this. Is it ok? What if "CONTENT_LENGTH" is incorrect and is larger than stdin is; how will read behave then?


char *STDIN = NULL;
char *pointer = getenv("CONTENT_LENGTH");
if(pointer != NULL)
{
    char charlength[5] = "";
    strncat(charlength, pointer, 4); // limit length to a reasonable number
    unsigned long int length = strtoul(charlength, NULL, 0);
    STDIN = malloc(length + 2);
    ssize_t readbytes = read(0, STDIN, length);
    STDIN[readbytes] = '&'; // for use later on in my program
    memset(STDIN + readbytes + 1, (int)'\0', (length + 2) - (size_t)(readbytes + 1));
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

桃酥萝莉 2024-09-15 15:45:50

read(2) 将返回的字节数不会超过您要求的字节数。这可能会在标准输入文件描述符中留下更多数据以供读取(如果客户端发送 CONTENT_LENGTH 为 0,但将其 /dev/urandom 交给您),但这没关系。您的流程无需阅读全部内容即可自由消失。

read(2) 返回的字节数可能比您要求的少。这可能是因为并非所有数据都已到达并且内核厌倦了阻塞,或者可能是内容小于 CONTENT_LENGTH。我很高兴您将长度限制为“合理”,因为传入最大 size_t 值的 CONTENT_LENGTH 或该值减一或该值减二并玩游戏非常容易使用 malloc() 分配 0、1 或 2 个字节,让您愉快地在内存中乱写乱画。

read(2) will return no more bytes than you asked for. This might leave more data in the stdin file descriptor for reading (in case the client sends a CONTENT_LENGTH of 0 but hands you their /dev/urandom) but that's okay. Your process is free to go away without reading it all.

read(2) may return fewer bytes than you ask for. This could be because not all the data has arrived yet and the kernel is tired of blocking, or it could be that the content is smaller than the CONTENT_LENGTH. I'm glad you're limiting the length to something 'reasonable', as it'd be pretty easy to pass in a CONTENT_LENGTH that is the maximum size_t value, or that value minus one, or that value minus two, and play games with your malloc() allocating 0, 1, or 2 bytes, and let you happily scribble all over your memory.

羁客 2024-09-15 15:45:50

您应该在循环中调用read

一般来说,这是正确的,从套接字读取时尤其如此。中到大量数据很可能需要一段时间才能到达,但 read 通常会尽快返回(我不记得是否需要)。如果第一个 TCP 数据包包含大约 9k 数据,那么第一次调用 read 可能会在下一个数据包到达之前返回该 1k,并且您当前的代码将永远不会读取其余数据。

因此,继续调用 read (并且每次将传入的指针前进所读取的字节数,并同样减少要读取的字节数),直到出现以下情况之一:

  • 总共读取了 CONTENT_LENGTH 字节。
  • read 返回 0(在这种情况下,POST 数据比 CONTENT_LENGTH 所承诺的短)。
  • read 返回 -1(表示发生了错误),并且 errno 不是 EINTR(或 EAGAIN,如果设置了 O_NONBLOCK,在这种情况下您需要在下次读取之前睡眠或类似的操作,但在这种情况下设置 O_NONBLOCK 是没有意义的)。

You should call read in a loop.

This is true in general, and it's especially true when reading from a socket. It's quite likely that medium-to-large amounts of data will take a while to arrive, but read typically returns as soon as possible (I can't remember whether that's required or not). If the first TCP packet contains about 1k of data, out of 9k, then the first call to read will likely return that 1k before the next packet arrives, and your current code will never read the rest.

So, keep calling read (and each time advance the pointer you pass in by the number of bytes read, and reduce the number of bytes to read likewise), until one of the following:

  • you have read CONTENT_LENGTH bytes in total.
  • read returns 0 (in which case the POST data is shorter than promised by CONTENT_LENGTH).
  • read returns -1 (indicating an error has occurred), and errno is something other than EINTR (or EAGAIN, if O_NONBLOCK is set, in which case you'll want to sleep or similar before the next read. But there's no point setting O_NONBLOCK in this case).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文