Skip to content
Browse files

added support for range header

  • Loading branch information...
1 parent 61022c3 commit a56003d8475de7e89f62a81acfdf600efefb650e @unbit committed Apr 6, 2013
Showing with 87 additions and 4 deletions.
  1. +33 −0 core/protocol.c
  2. +31 −4 core/static.c
  3. +2 −0 core/uwsgi.c
  4. +14 −0 core/writer.c
  5. +7 −0 uwsgi.h
View
33 core/protocol.c
@@ -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;
View
35 core/static.c
@@ -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;
View
2 core/uwsgi.c
@@ -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},
View
14 core/writer.c
@@ -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 @@ int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos
if (can_close) close(fd);
return -1;
}
+ if (pos >= (size_t)st.st_size) return UWSGI_OK;
len = st.st_size;
}
View
7 uwsgi.h
@@ -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 *);

0 comments on commit a56003d

Please sign in to comment.
Something went wrong with that request. Please try again.