Implement Transfer-Encoding chunked for requests
This commit is contained in:
31
src/client.c
31
src/client.c
@ -201,12 +201,6 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if (http_get_header_field(&req.hdr, "Transfer-Encoding") != NULL) {
|
||||
sprintf(err_msg, "This server is unable to process requests with the Transfer-Encoding header field.");
|
||||
res.status = http_get_status(501);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if (conf->type == CONFIG_TYPE_LOCAL) {
|
||||
if (strcmp(req.method, "TRACE") == 0) {
|
||||
res.status = http_get_status(200);
|
||||
@ -254,7 +248,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if (http_get_header_field(&req.hdr, "Content-Length") != NULL) {
|
||||
if (http_get_header_field(&req.hdr, "Content-Length") != NULL || http_get_header_field(&req.hdr, "Transfer-Encoding") != NULL) {
|
||||
res.status = http_get_status(400);
|
||||
sprintf(err_msg, "A GET request must not contain a payload");
|
||||
goto respond;
|
||||
@ -397,18 +391,23 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
||||
}
|
||||
|
||||
const char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
|
||||
const char *client_transfer_encoding = http_get_header_field(&req.hdr, "Transfer-Encoding");
|
||||
if (client_content_length != NULL) {
|
||||
unsigned long client_content_len = strtoul(client_content_length, NULL, 10);
|
||||
ret = fastcgi_receive(&fcgi_conn, client, client_content_len);
|
||||
if (ret != 0) {
|
||||
if (ret < 0) {
|
||||
goto abort;
|
||||
} else {
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
}
|
||||
res.status = http_get_status(502);
|
||||
goto respond;
|
||||
} else if (client_transfer_encoding != NULL && strstr(client_transfer_encoding, "chunked") != NULL) {
|
||||
ret = fastcgi_receive_chunked(&fcgi_conn, client);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
if (ret < 0) {
|
||||
goto abort;
|
||||
} else {
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
}
|
||||
res.status = http_get_status(502);
|
||||
goto respond;
|
||||
}
|
||||
fastcgi_close_stdin(&fcgi_conn);
|
||||
|
||||
@ -679,7 +678,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
||||
}
|
||||
} else if (use_fastcgi) {
|
||||
const char *transfer_encoding = http_get_header_field(&res.hdr, "Transfer-Encoding");
|
||||
int chunked = (transfer_encoding != NULL && strcmp(transfer_encoding, "chunked") == 0);
|
||||
int chunked = (transfer_encoding != NULL && strstr(transfer_encoding, "chunked") != NULL);
|
||||
|
||||
int flags = (chunked ? FASTCGI_CHUNKED : 0) | (use_fastcgi & (FASTCGI_COMPRESS | FASTCGI_COMPRESS_HOLD));
|
||||
ret = fastcgi_send(&fcgi_conn, client, flags);
|
||||
|
@ -619,3 +619,23 @@ int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client) {
|
||||
long ret;
|
||||
unsigned long next_len;
|
||||
char tmp[16];
|
||||
|
||||
do {
|
||||
ret = sock_recv(client, tmp, sizeof(tmp), MSG_PEEK);
|
||||
if (ret < 0) return -2;
|
||||
next_len = strtol(tmp, NULL, 16);
|
||||
char *ptr = strstr(tmp, "\r\n");
|
||||
ret = sock_recv(client, tmp, ptr - tmp + 2, 0);
|
||||
if (ret < 0) return -2;
|
||||
|
||||
ret = fastcgi_receive(conn, client, next_len);
|
||||
if (ret < 0) return ret;
|
||||
} while (next_len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -55,4 +55,6 @@ int fastcgi_dump(fastcgi_conn *conn, char *buf, long len);
|
||||
|
||||
int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len);
|
||||
|
||||
int fastcgi_receive_chunked(fastcgi_conn *conn, sock *client);
|
||||
|
||||
#endif //SESIMOS_FASTCGI_H
|
||||
|
@ -321,31 +321,35 @@ int rev_proxy_init(http_req *req, http_res *res, http_status_ctx *ctx, host_conf
|
||||
}
|
||||
|
||||
const char *content_length = http_get_header_field(&req->hdr, "Content-Length");
|
||||
if (content_length != NULL) {
|
||||
unsigned long content_len = strtoul(content_length, NULL, 10);
|
||||
if (content_len > 0) {
|
||||
ret = sock_splice(&rev_proxy, client, buffer, sizeof(buffer), content_len);
|
||||
if (ret <= 0) {
|
||||
if (ret == -1) {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
print(ERR_STR "Unable to send request to server (2): %s" CLR_STR, sock_strerror(&rev_proxy));
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&rev_proxy));
|
||||
retry = tries < 4;
|
||||
goto proxy_err;
|
||||
} else if (ret == -2) {
|
||||
res->status = http_get_status(400);
|
||||
ctx->origin = CLIENT_REQ;
|
||||
print(ERR_STR "Unable to receive request from client: %s" CLR_STR, sock_strerror(client));
|
||||
sprintf(err_msg, "Unable to receive request from client: %s.", sock_strerror(client));
|
||||
return -1;
|
||||
}
|
||||
res->status = http_get_status(500);
|
||||
ctx->origin = INTERNAL;
|
||||
print(ERR_STR "Unknown Error" CLR_STR);
|
||||
return -1;
|
||||
}
|
||||
unsigned long content_len = content_length != NULL ? strtoul(content_length, NULL, 10) : 0;
|
||||
const char *transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding");
|
||||
|
||||
ret = 0;
|
||||
if (content_len > 0) {
|
||||
ret = sock_splice(&rev_proxy, client, buffer, sizeof(buffer), content_len);
|
||||
} else if (transfer_encoding != NULL && strstr(transfer_encoding, "chunked") != NULL) {
|
||||
ret = sock_splice_chunked(&rev_proxy, client, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
if (ret < 0 || (content_len != 0 && ret != content_len)) {
|
||||
if (ret == -1) {
|
||||
res->status = http_get_status(502);
|
||||
ctx->origin = SERVER_REQ;
|
||||
print(ERR_STR "Unable to send request to server (2): %s" CLR_STR, sock_strerror(&rev_proxy));
|
||||
sprintf(err_msg, "Unable to send request to server: %s.", sock_strerror(&rev_proxy));
|
||||
retry = tries < 4;
|
||||
goto proxy_err;
|
||||
} else if (ret == -2) {
|
||||
res->status = http_get_status(400);
|
||||
ctx->origin = CLIENT_REQ;
|
||||
print(ERR_STR "Unable to receive request from client: %s" CLR_STR, sock_strerror(client));
|
||||
sprintf(err_msg, "Unable to receive request from client: %s.", sock_strerror(client));
|
||||
return -1;
|
||||
}
|
||||
res->status = http_get_status(500);
|
||||
ctx->origin = INTERNAL;
|
||||
print(ERR_STR "Unknown Error" CLR_STR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sock_recv(&rev_proxy, buffer, sizeof(buffer), MSG_PEEK);
|
||||
|
@ -103,6 +103,27 @@ long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigne
|
||||
return (long) send_len;
|
||||
}
|
||||
|
||||
long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len) {
|
||||
long ret;
|
||||
unsigned long send_len = 0;
|
||||
unsigned long next_len;
|
||||
char tmp[16];
|
||||
|
||||
do {
|
||||
ret = sock_recv(src, tmp, sizeof(tmp), MSG_PEEK);
|
||||
if (ret < 0) return -2;
|
||||
next_len = strtol(tmp, NULL, 16);
|
||||
char *ptr = strstr(tmp, "\r\n");
|
||||
ret = sock_recv(src, tmp, ptr - tmp + 2, 0);
|
||||
if (ret < 0) return -2;
|
||||
|
||||
ret = sock_splice(dst, src, buf, buf_len, next_len);
|
||||
if (ret < 0) return ret;
|
||||
} while (next_len > 0);
|
||||
|
||||
return (long) send_len;
|
||||
}
|
||||
|
||||
int sock_close(sock *s) {
|
||||
if ((int) s->enc && s->ssl != NULL) {
|
||||
if (s->_last_ret >= 0) SSL_shutdown(s->ssl);
|
||||
|
@ -32,6 +32,8 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags);
|
||||
|
||||
long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len);
|
||||
|
||||
long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len);
|
||||
|
||||
int sock_close(sock *s);
|
||||
|
||||
int sock_check(sock *s);
|
||||
|
Reference in New Issue
Block a user