mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-28 17:55:39 +00:00
188 lines
5.5 KiB
C
188 lines
5.5 KiB
C
#include "common.h"
|
|
|
|
extern struct uwsgi_http uhttp;
|
|
|
|
#ifdef UWSGI_ZLIB
|
|
static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
|
|
#endif
|
|
|
|
int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t len) {
|
|
|
|
size_t i;
|
|
size_t next = 0;
|
|
|
|
char *buf = ub->buf;
|
|
|
|
int found = 0;
|
|
// protocol
|
|
for(i=0;i<len;i++) {
|
|
if (buf[i] == ' ') {
|
|
if (hr->session.can_keepalive && uwsgi_strncmp("HTTP/1.1", 8, buf, i)) {
|
|
goto end;
|
|
}
|
|
if (i+1 >= len) return -1;;
|
|
next = i+1;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) goto end;
|
|
|
|
// status
|
|
found = 0;
|
|
for(i=next;i<len;i++) {
|
|
if (buf[i] == '\r' || buf[i] == '\n') {
|
|
// status ready
|
|
if (i+1 >= len) return -1;
|
|
next = i + 1;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) goto end;
|
|
|
|
char *key = NULL;
|
|
|
|
// find first header position
|
|
for(i=next;i<len;i++) {
|
|
if (buf[i] != '\r' && buf[i] != '\n') {
|
|
key = buf + i;
|
|
next = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!key) goto end;
|
|
|
|
uint32_t h_len = 0;
|
|
|
|
int has_size = 0;
|
|
int has_connection = 0;
|
|
|
|
for(i=next;i<len;i++) {
|
|
if (key) {
|
|
if (buf[i] == '\r' || buf[i] == '\n') {
|
|
char *colon = memchr(key, ':', h_len);
|
|
if (!colon) return -1;
|
|
// security check
|
|
if (colon+2 >= buf+len) return -1;
|
|
#ifdef UWSGI_ZLIB
|
|
if (hr->session.can_keepalive || (uhttp.auto_gzip && hr->can_gzip)) {
|
|
#else
|
|
if (hr->session.can_keepalive) {
|
|
#endif
|
|
if (!uwsgi_strnicmp(key, colon-key, "Connection", 10)) {
|
|
has_connection = 1;
|
|
if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "close", 5)) {
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!uwsgi_strnicmp(key, colon-key, "Trailers", 8)) {
|
|
goto end;
|
|
}
|
|
else if (!uwsgi_strnicmp(key, colon-key, "Content-Length", 14)) {
|
|
has_size = 1;
|
|
}
|
|
else if (!uwsgi_strnicmp(key, colon-key, "Transfer-Encoding", 17)) {
|
|
has_size = 1;
|
|
}
|
|
}
|
|
#ifdef UWSGI_ZLIB
|
|
if (uhttp.auto_gzip && hr->can_gzip) {
|
|
if (!uwsgi_strnicmp(key, colon-key, "Content-Encoding", 16)) {
|
|
hr->can_gzip = 0;
|
|
}
|
|
else if (!uwsgi_strnicmp(key, colon-key, "uWSGI-Encoding", 14)) {
|
|
if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "gzip", 4)) {
|
|
hr->has_gzip = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
key = NULL;
|
|
h_len = 0;
|
|
}
|
|
else {
|
|
h_len++;
|
|
}
|
|
}
|
|
else {
|
|
if (buf[i] != '\r' && buf[i] != '\n') {
|
|
key = buf+i;
|
|
h_len = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!has_size) {
|
|
#ifdef UWSGI_ZLIB
|
|
if (hr->has_gzip) {
|
|
hr->force_gzip = 1;
|
|
if (uwsgi_deflate_init(&hr->z, NULL, 0)) {
|
|
hr->force_gzip = 0;
|
|
goto end;
|
|
}
|
|
hr->gzip_crc32 = 0;
|
|
uwsgi_crc32(&hr->gzip_crc32, NULL, 0);
|
|
hr->gzip_size = 0;
|
|
char cr = buf[len-2];
|
|
char nl = buf[len-1];
|
|
if (cr == '\r' && nl == '\n') {
|
|
if (uwsgi_buffer_insert(ub, len-2, "Transfer-Encoding: chunked\r\n", 28)) return -1;
|
|
if (uwsgi_buffer_insert(ub, len-2+28, "Content-Encoding: gzip\r\n", 24)) return -1;
|
|
size_t remains = ub->pos - (len+28+24);
|
|
if (remains > 0) {
|
|
size_t zlen = 0;
|
|
char *ptr = ub->buf + (ub->pos - remains);
|
|
char *gzipped = uwsgi_deflate(&hr->z, ptr, remains, &zlen);
|
|
if (!gzipped) return -1;
|
|
uwsgi_crc32(&hr->gzip_crc32, ptr, remains);
|
|
hr->gzip_size += remains;
|
|
ub->pos = len + 28 + 24;
|
|
if (uwsgi_buffer_append_chunked(ub, zlen + 10)) {free(gzipped); return -1;}
|
|
if (uwsgi_buffer_append(ub, gzheader, 10)) {free(gzipped); return -1;}
|
|
if (uwsgi_buffer_append(ub, gzipped, zlen)) {free(gzipped); return -1;}
|
|
free(gzipped);
|
|
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
|
|
}
|
|
else {
|
|
if (uwsgi_buffer_append_chunked(ub, 10)) return -1;
|
|
if (uwsgi_buffer_append(ub, gzheader, 10)) return -1;
|
|
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
|
|
|
|
}
|
|
}
|
|
} else
|
|
#endif
|
|
if (hr->session.can_keepalive) {
|
|
if (uhttp.auto_chunked) {
|
|
char cr = buf[len-2];
|
|
char nl = buf[len-1];
|
|
if (cr == '\r' && nl == '\n') {
|
|
if (uwsgi_buffer_insert(ub, len-2, "Transfer-Encoding: chunked\r\n", 28)) return -1;
|
|
size_t remains = ub->pos - (len+28);
|
|
if (remains > 0) {
|
|
if (uwsgi_buffer_insert_chunked(ub, len + 28, remains)) return -1;
|
|
if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1;
|
|
}
|
|
hr->force_chunked = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
// avoid iOS making mess...
|
|
if (!has_connection) {
|
|
if (uwsgi_buffer_insert(ub, len-2, "Connection: close\r\n", 19)) return -1;
|
|
}
|
|
hr->session.can_keepalive = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
end:
|
|
hr->session.can_keepalive = 0;
|
|
return 0;
|
|
}
|
|
|