mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-06-16 02:15:48 +00:00
163 lines
5.4 KiB
C
163 lines
5.4 KiB
C
#include <uwsgi.h>
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
/*
|
|
|
|
Chunked input implementation
|
|
|
|
--chunked-input-limit <bytes> (default 1MB)
|
|
|
|
--chunked-input-timeout <s> (default --socket-timeout)
|
|
|
|
chunk = uwsgi.chunked_read([timeout])
|
|
|
|
timeout = -1 (wait forever)
|
|
timeout = 0 (default)
|
|
|
|
*/
|
|
|
|
static ssize_t uwsgi_chunked_input_recv(struct wsgi_request *wsgi_req, int timeout, int nb) {
|
|
|
|
if (timeout == 0) timeout = uwsgi.chunked_input_timeout;
|
|
if (timeout == 0) timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
|
|
|
int ret = -1;
|
|
|
|
for(;;) {
|
|
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos);
|
|
if (rlen > 0) return rlen;
|
|
if (rlen == 0) return -1;
|
|
if (rlen < 0) {
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
|
if (nb) return -1;
|
|
goto wait;
|
|
}
|
|
uwsgi_error("uwsgi_chunked_input_recv()");
|
|
return -1;
|
|
}
|
|
|
|
wait:
|
|
ret = uwsgi.wait_read_hook(wsgi_req->fd, timeout);
|
|
if (ret > 0) {
|
|
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos);
|
|
if (rlen > 0) return rlen;
|
|
if (rlen <= 0) return -1;
|
|
}
|
|
if (ret < 0) {
|
|
uwsgi_error("uwsgi_chunked_input_recv()");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t uwsgi_chunked_readline(struct wsgi_request *wsgi_req) {
|
|
size_t i;
|
|
int found = 0;
|
|
for(i=0;i<wsgi_req->chunked_input_buf->pos;i++) {
|
|
if (found) {
|
|
if (wsgi_req->chunked_input_buf->buf[i] == '\n') {
|
|
// strtoul will stop at \r
|
|
size_t num = strtoul(wsgi_req->chunked_input_buf->buf, NULL, 16);
|
|
if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, i+1)) return -1;
|
|
return num;
|
|
}
|
|
return -1;
|
|
}
|
|
if ((wsgi_req->chunked_input_buf->buf[i] >= '0' && wsgi_req->chunked_input_buf->buf[i] <= '9') ||
|
|
(wsgi_req->chunked_input_buf->buf[i] >= 'a' && wsgi_req->chunked_input_buf->buf[i] <= 'z') ||
|
|
(wsgi_req->chunked_input_buf->buf[i] >= 'A' && wsgi_req->chunked_input_buf->buf[i] <= 'Z')) continue;
|
|
if (wsgi_req->chunked_input_buf->buf[i] == '\r') { found = 1; continue; }
|
|
return -1;
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
/*
|
|
|
|
0 -> waiting for \r\n
|
|
1 -> waiting for whole body
|
|
|
|
*/
|
|
|
|
char *uwsgi_chunked_read(struct wsgi_request *wsgi_req, size_t *len, int timeout, int nb) {
|
|
|
|
if (!wsgi_req->chunked_input_buf) {
|
|
wsgi_req->chunked_input_buf = uwsgi_buffer_new(uwsgi.page_size);
|
|
wsgi_req->chunked_input_buf->limit = uwsgi.chunked_input_limit;
|
|
}
|
|
|
|
// the whole chunk stream has been consumed
|
|
if (wsgi_req->chunked_input_complete) {
|
|
*len = 0;
|
|
return wsgi_req->chunked_input_buf->buf;
|
|
}
|
|
|
|
if (wsgi_req->chunked_input_decapitate > 0) {
|
|
if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, wsgi_req->chunked_input_decapitate)) return NULL;
|
|
wsgi_req->chunked_input_decapitate = 0;
|
|
}
|
|
|
|
for(;;) {
|
|
if (wsgi_req->chunked_input_need > 0 || wsgi_req->chunked_input_buf->pos == 0) {
|
|
if (uwsgi_buffer_ensure(wsgi_req->chunked_input_buf, UMAX((uint64_t)uwsgi.page_size, wsgi_req->chunked_input_need))) return NULL;
|
|
ssize_t rlen = uwsgi_chunked_input_recv(wsgi_req, timeout, nb);
|
|
if (rlen <= 0) return NULL;
|
|
// update buffer position
|
|
wsgi_req->chunked_input_buf->pos += rlen;
|
|
if (wsgi_req->chunked_input_need > 0) {
|
|
if ((size_t)rlen > wsgi_req->chunked_input_need) {
|
|
wsgi_req->chunked_input_need = 0;
|
|
}
|
|
else {
|
|
wsgi_req->chunked_input_need -= rlen;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wsgi_req->chunked_input_need > 0) continue;
|
|
|
|
// ok we have a frame, let's parse it
|
|
if (wsgi_req->chunked_input_buf->pos > 0) {
|
|
switch(wsgi_req->chunked_input_parser_status) {
|
|
case 0:
|
|
wsgi_req->chunked_input_chunk_len = uwsgi_chunked_readline(wsgi_req);
|
|
if (wsgi_req->chunked_input_chunk_len == -2) {
|
|
wsgi_req->chunked_input_need++;
|
|
break;
|
|
}
|
|
else if (wsgi_req->chunked_input_chunk_len < 0) {
|
|
return NULL;
|
|
}
|
|
else if (wsgi_req->chunked_input_chunk_len == 0) {
|
|
*len = 0;
|
|
wsgi_req->chunked_input_complete = 1;
|
|
return wsgi_req->chunked_input_buf->buf;
|
|
}
|
|
// if here the buffer has been already decapitated
|
|
if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) {
|
|
wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos;
|
|
wsgi_req->chunked_input_parser_status = 1;
|
|
break;
|
|
}
|
|
*len = wsgi_req->chunked_input_chunk_len;
|
|
wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2;
|
|
return wsgi_req->chunked_input_buf->buf;
|
|
case 1:
|
|
if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) {
|
|
wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos;
|
|
break;
|
|
}
|
|
*len = wsgi_req->chunked_input_chunk_len;
|
|
wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2;
|
|
wsgi_req->chunked_input_parser_status = 0;
|
|
return wsgi_req->chunked_input_buf->buf;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|