added support for range header

This commit is contained in:
Unbit
2013-04-06 12:45:03 +02:00
parent 61022c398c
commit a56003d847
5 changed files with 87 additions and 4 deletions
+33
View File
@@ -303,8 +303,41 @@ static int uwsgi_proto_check_9(struct wsgi_request *wsgi_req, char *key, char *b
return 0;
}
static void uwsgi_parse_http_range(char *buf, uint16_t len, size_t *from, size_t *to) {
*from = 0;
*to = 0;
uint16_t rlen = 0;
uint16_t i;
for(i=0;i<len;i++) {
if (buf[i] == ',') break;
rlen++;
}
// bytes=X-
if (rlen < 8) return;
char *equal = memchr(buf, '=', rlen);
if (!equal) return;
if (equal-buf != 5) return;
if (memcmp(buf, "bytes", 5)) return;
char *range = equal+1;
rlen -= 6;
char *dash = memchr(range, '-', rlen);
if (!dash) return;
*from = uwsgi_str_num(range, dash-range);
*to = uwsgi_str_num(dash+1, rlen - ((dash+1)-range));
if (*to > 0 && *from > *to) {
*from = 0;
*to = 0;
}
}
static int uwsgi_proto_check_10(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_RANGE", 10)) {
uwsgi_parse_http_range(buf, len, &wsgi_req->range_from, &wsgi_req->range_to);
return 0;
}
if (!uwsgi_proto_key("UWSGI_FILE", 10)) {
wsgi_req->file = buf;
wsgi_req->file_len = len;
+31 -4
View File
@@ -451,8 +451,31 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
fsize = wsgi_req->range_to - wsgi_req->range_from;
if (fsize > (size_t)st->st_size) {
fsize = st->st_size;
}
}
else {
// reset in case of inconsistent size
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
fsize = 0 ;
}
else {
fsize -= wsgi_req->range_from;
}
}
// HTTP status
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
}
else {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
}
#ifdef UWSGI_PCRE
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
@@ -490,8 +513,12 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
}
// set Content-Length
if (uwsgi_response_add_content_length(wsgi_req, st->st_size)) return -1;
// set Content-Length (to fsize NOT st->st_size)
if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
// here use teh original size !!!
if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
}
int size = set_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
@@ -506,7 +533,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
int fd = open(real_filename, O_RDONLY);
if (fd < 0) return -1;
// fd will be closed in the following function
uwsgi_response_sendfile_do(wsgi_req, fd, 0, st->st_size);
uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
}
wsgi_req->status = 200;
+2
View File
@@ -572,6 +572,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"static-gzip-ext", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
{"static-gzip-suffix", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
{"honour-range", no_argument, 0, "enable support for the HTTP Range header", uwsgi_opt_true, &uwsgi.honour_range, 0},
{"offload-threads", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
{"offload-thread", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
+14
View File
@@ -12,6 +12,19 @@ int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
}
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
char buf[6+(sizeof(UMAX64_STR)*3)+4];
if (end == 0) {
end = cl-1;
}
int ret = snprintf(buf, 6+(sizeof(UMAX64_STR)*3)+4, "bytes %llu-%llu/%llu", (unsigned long long) start, (unsigned long long) end, (unsigned long long) cl);
if (ret <= 0 || ret > (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
}
// status could be NNN or NNN message
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
@@ -225,6 +238,7 @@ sendfile:
if (can_close) close(fd);
return -1;
}
if (pos >= (size_t)st.st_size) return UWSGI_OK;
len = st.st_size;
}
+7
View File
@@ -1351,6 +1351,9 @@ struct uwsgi_router {
// when set, do not send warnings about bad behaviours
int post_warning;
size_t range_from;
size_t range_to;
// current socket mapped to request
struct uwsgi_socket *socket;
@@ -1801,6 +1804,9 @@ struct uwsgi_server {
struct termios termios;
int restore_tc;
// honour the HTTP Range header
int honour_range;
// route all of the logs to the master process
int req_log_master;
int log_master;
@@ -3824,6 +3830,7 @@ int uwsgi_proto_base_sendfile(struct wsgi_request *, int, size_t, size_t);
ssize_t uwsgi_sendfile_do(int, int, size_t, size_t);
int uwsgi_proto_base_fix_headers(struct wsgi_request *);
int uwsgi_response_add_content_length(struct wsgi_request *, uint64_t);
int uwsgi_response_add_content_range(struct wsgi_request *, uint64_t, uint64_t, uint64_t);
const char *uwsgi_http_status_msg(char *, uint16_t *);
int uwsgi_stats_dump_vars(struct uwsgi_stats *, struct uwsgi_core *);