Commit a0e54945 authored by Sergey Lyubka's avatar Sergey Lyubka

Merge pull request #177 from arvidn/master

support serving pre-gzipped files
parents f62c7339 d283e316
...@@ -420,8 +420,11 @@ struct file { ...@@ -420,8 +420,11 @@ struct file {
int64_t size; int64_t size;
FILE *fp; FILE *fp;
const char *membuf; // Non-NULL if file data is in memory const char *membuf; // Non-NULL if file data is in memory
// set to 1 if the content is gzipped
// in which case we need a content-encoding: gzip header
int gzipped;
}; };
#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL} #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
// Describes listening socket, or socket which was accept()-ed by the master // Describes listening socket, or socket which was accept()-ed by the master
// thread and queued for future handling by the worker thread. // thread and queued for future handling by the worker thread.
...@@ -1772,6 +1775,8 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1772,6 +1775,8 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
const char *rewrite, *uri = conn->request_info.uri; const char *rewrite, *uri = conn->request_info.uri;
char *p; char *p;
int match_len; int match_len;
char gz_path[PATH_MAX];
char const* accept_encoding;
// Using buf_len - 1 because memmove() for PATH_INFO may shift part // Using buf_len - 1 because memmove() for PATH_INFO may shift part
// of the path one byte on the right. // of the path one byte on the right.
...@@ -1787,7 +1792,24 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1787,7 +1792,24 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
} }
} }
if (!mg_stat(conn, buf, filep)) { if (mg_stat(conn, buf, filep)) return;
// if we can't find the actual file, look for the file
// with the same name but a .gz extension. If we find it,
// use that and set the gzipped flag in the file struct
// to indicate that the response need to have the content-
// encoding: gzip header
// we can only do this if the browser declares support
if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
if (strstr(accept_encoding,"gzip") != NULL) {
snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
if (mg_stat(conn, gz_path, filep)) {
filep->gzipped = 1;
return;
}
}
}
// Support PATH_INFO for CGI scripts. // Support PATH_INFO for CGI scripts.
for (p = buf + strlen(buf); p > buf + 1; p--) { for (p = buf + strlen(buf); p > buf + 1; p--) {
if (*p == '/') { if (*p == '/') {
...@@ -1809,7 +1831,6 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1809,7 +1831,6 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
} }
} }
} }
}
} }
// Check whether full request is buffered. Return: // Check whether full request is buffered. Return:
...@@ -2828,17 +2849,29 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -2828,17 +2849,29 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
int64_t cl, r1, r2; int64_t cl, r1, r2;
struct vec mime_vec; struct vec mime_vec;
int n; int n;
char gz_path[PATH_MAX];
char const* encoding = "";
get_mime_type(conn->ctx, path, &mime_vec); get_mime_type(conn->ctx, path, &mime_vec);
cl = filep->size; cl = filep->size;
conn->status_code = 200; conn->status_code = 200;
range[0] = '\0'; range[0] = '\0';
// if this file is in fact a pre-gzipped file, rewrite its filename
// it's important to rewrite the filename after resolving
// the mime type from it, to preserve the actual file's type
if (filep->gzipped) {
snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
path = gz_path;
encoding = "Content-Encoding: gzip\r\n";
}
if (!mg_fopen(conn, path, "rb", filep)) { if (!mg_fopen(conn, path, "rb", filep)) {
send_http_error(conn, 500, http_500_error, send_http_error(conn, 500, http_500_error,
"fopen(%s): %s", path, strerror(ERRNO)); "fopen(%s): %s", path, strerror(ERRNO));
return; return;
} }
fclose_on_exec(filep); fclose_on_exec(filep);
// If Range: header specified, act accordingly // If Range: header specified, act accordingly
...@@ -2846,6 +2879,12 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -2846,6 +2879,12 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
hdr = mg_get_header(conn, "Range"); hdr = mg_get_header(conn, "Range");
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
r1 >= 0 && r2 >= 0) { r1 >= 0 && r2 >= 0) {
// actually, range requests don't play well with a pre-gzipped
// file (since the range is specified in the uncmpressed space)
if (filep->gzipped) {
send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported");
return;
}
conn->status_code = 206; conn->status_code = 206;
cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1; cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
mg_snprintf(conn, range, sizeof(range), mg_snprintf(conn, range, sizeof(range),
...@@ -2871,9 +2910,9 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -2871,9 +2910,9 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
"Content-Length: %" INT64_FMT "\r\n" "Content-Length: %" INT64_FMT "\r\n"
"Connection: %s\r\n" "Connection: %s\r\n"
"Accept-Ranges: bytes\r\n" "Accept-Ranges: bytes\r\n"
"%s\r\n", "%s%s\r\n",
conn->status_code, msg, date, lm, etag, (int) mime_vec.len, conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
mime_vec.ptr, cl, suggest_connection_header(conn), range); mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding);
if (strcmp(conn->request_info.request_method, "HEAD") != 0) { if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
send_file_data(conn, filep, r1, cl); send_file_data(conn, filep, r1, cl);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment