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->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; 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; if (hr->can_keepalive) { if (!uwsgi_strnicmp(key, colon-key, "Connection", 10)) { 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; } } key = NULL; h_len = 0; } else { h_len++; } } else { if (buf[i] != '\r' && buf[i] != '\n') { key = buf+i; h_len = 1; } } } if (hr->can_keepalive && !has_size) { 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; } } hr->can_keepalive = 0; } return 0; end: hr->can_keepalive = 0; return 0; }
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->is_rtsp && 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 we are in RTSP mode we need to ensure a 200 is returned if (hr->is_rtsp) { if (next + 3 >= len) return -1; char *code = buf + next; if (code[0] != '2' || code[1] != '0' || code[2] != '0') { hr->is_rtsp = 0; hr->session.can_keepalive = 0; } } 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 && !hr->is_rtsp) { #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; }