通过读取 stdin(C 中的 CGI)进行 http POST
在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
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.您应该在循环中调用
read
。一般来说,这是正确的,从套接字读取时尤其如此。中到大量数据很可能需要一段时间才能到达,但
read
通常会尽快返回(我不记得是否需要)。如果第一个 TCP 数据包包含大约 9k 数据,那么第一次调用 read 可能会在下一个数据包到达之前返回该 1k,并且您当前的代码将永远不会读取其余数据。因此,继续调用 read (并且每次将传入的指针前进所读取的字节数,并同样减少要读取的字节数),直到出现以下情况之一:
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 toread
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:
read
returns 0 (in which case the POST data is shorter than promised by CONTENT_LENGTH).read
returns -1 (indicating an error has occurred), anderrno
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).