diff --git a/mongoose.c b/mongoose.c index 22d59c83..1cc814e4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1683,28 +1683,30 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, const struct mg_http_serve_opts *opts) { char etag[64], tmp[MG_PATH_MAX]; struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct mg_fd *fd = path == NULL ? NULL : mg_fs_open(fs, path, MG_FS_READ); + struct mg_fd *fd = NULL; size_t size = 0; time_t mtime = 0; struct mg_str *inm = NULL; struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); bool gzip = false; - // If file does not exist, we try to open file PATH.gz - and if such - // pre-compressed .gz file exists, serve it with the Content-Encoding: gzip - // Note - we ignore Accept-Encoding, cause we don't have a choice - if (fd == NULL) { - MG_DEBUG(("NULL [%s]", path)); - mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); - if ((fd = mg_fs_open(fs, tmp, MG_FS_READ)) != NULL) { - gzip = true; - path = tmp; - } else if (opts->page404 != NULL) { - // No precompressed file, serve 404 - fd = mg_fs_open(fs, opts->page404, MG_FS_READ); - mime = guess_content_type(mg_str(path), opts->mime_types); - path = opts->page404; + if (path != NULL) { + // If a browser sends us "Accept-Encoding: gzip", try to open .gz first + struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding"); + if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) { + mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); + fd = mg_fs_open(fs, tmp, MG_FS_READ); + if (fd != NULL) gzip = true, path = tmp; } + // No luck opening .gz? Open what we've told to open + if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ); + } + + // Failed to open, and page404 is configured? Open it, then + if (fd == NULL && opts->page404 != NULL) { + fd = mg_fs_open(fs, opts->page404, MG_FS_READ); + mime = guess_content_type(mg_str(path), opts->mime_types); + path = opts->page404; } if (fd == NULL || fs->st(path, &size, &mtime) == 0) { diff --git a/src/http.c b/src/http.c index c63a051c..3136dfcd 100644 --- a/src/http.c +++ b/src/http.c @@ -453,28 +453,30 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, const struct mg_http_serve_opts *opts) { char etag[64], tmp[MG_PATH_MAX]; struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct mg_fd *fd = path == NULL ? NULL : mg_fs_open(fs, path, MG_FS_READ); + struct mg_fd *fd = NULL; size_t size = 0; time_t mtime = 0; struct mg_str *inm = NULL; struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); bool gzip = false; - // If file does not exist, we try to open file PATH.gz - and if such - // pre-compressed .gz file exists, serve it with the Content-Encoding: gzip - // Note - we ignore Accept-Encoding, cause we don't have a choice - if (fd == NULL) { - MG_DEBUG(("NULL [%s]", path)); - mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); - if ((fd = mg_fs_open(fs, tmp, MG_FS_READ)) != NULL) { - gzip = true; - path = tmp; - } else if (opts->page404 != NULL) { - // No precompressed file, serve 404 - fd = mg_fs_open(fs, opts->page404, MG_FS_READ); - mime = guess_content_type(mg_str(path), opts->mime_types); - path = opts->page404; + if (path != NULL) { + // If a browser sends us "Accept-Encoding: gzip", try to open .gz first + struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding"); + if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) { + mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); + fd = mg_fs_open(fs, tmp, MG_FS_READ); + if (fd != NULL) gzip = true, path = tmp; } + // No luck opening .gz? Open what we've told to open + if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ); + } + + // Failed to open, and page404 is configured? Open it, then + if (fd == NULL && opts->page404 != NULL) { + fd = mg_fs_open(fs, opts->page404, MG_FS_READ); + mime = guess_content_type(mg_str(path), opts->mime_types); + path = opts->page404; } if (fd == NULL || fs->st(path, &size, &mtime) == 0) { diff --git a/test/data/gzip.txt b/test/data/gzip.txt new file mode 100644 index 00000000..45b983be --- /dev/null +++ b/test/data/gzip.txt @@ -0,0 +1 @@ +hi diff --git a/test/data/gzip.txt.gz b/test/data/gzip.txt.gz new file mode 100644 index 00000000..1e11fd8d Binary files /dev/null and b/test/data/gzip.txt.gz differ diff --git a/test/unit_test.c b/test/unit_test.c index 325c9a4a..698ba309 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -635,21 +635,25 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url, return fd.code; } -static int cmpbody(const char *buf, const char *str) { +static struct mg_http_message gethm(const char *buf) { struct mg_http_message hm; + memset(&hm, 0, sizeof(hm)); + mg_http_parse(buf, strlen(buf), &hm); + return hm; +} + +static int cmpbody(const char *buf, const char *str) { struct mg_str s = mg_str(str); + struct mg_http_message hm = gethm(buf); size_t len = strlen(buf); mg_http_parse(buf, len, &hm); - if (hm.body.len > len) hm.body.len = len - (size_t)(hm.body.ptr - buf); + if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.ptr - buf); return mg_strcmp(hm.body, s); } static bool cmpheader(const char *buf, const char *name, const char *value) { - struct mg_http_message hm; - struct mg_str *h; - size_t len = strlen(buf); - mg_http_parse(buf, len, &hm); - h = mg_http_get_header(&hm, name); + struct mg_http_message hm = gethm(buf); + struct mg_str *h = mg_http_get_header(&hm, name); return h != NULL && mg_strcmp(*h, mg_str(value)) == 0; } @@ -765,10 +769,24 @@ static void test_http_server(void) { ASSERT(fetch(&mgr, buf, url, "GET /dredir/ HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, "hi\n") == 0); - ASSERT(fetch(&mgr, buf, url, "GET /dredirgz/ HTTP/1.0\n\n") == 200); + ASSERT(fetch(&mgr, buf, url, + "GET /dredirgz/ HTTP/1.0\n" + "Accept-Encoding: gzip\n\n") == 200); ASSERT(cmpheader(buf, "Content-Type", "text/html; charset=utf-8")); ASSERT(cmpheader(buf, "Content-Encoding", "gzip")); + ASSERT(fetch(&mgr, buf, url, "GET /gzip.txt HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, "hi\n") == 0); + ASSERT(gethm(buf).body.len == 3); + ASSERT(cmpheader(buf, "Content-Encoding", "gzip") == false); + + ASSERT(fetch(&mgr, buf, url, + "GET /gzip.txt HTTP/1.0\n" + "Accept-Encoding: foo,gzip\n\n") == 200); + mg_hexdump(buf, strlen(buf)); + ASSERT(cmpheader(buf, "Content-Encoding", "gzip") == true); + ASSERT(gethm(buf).body.len == 23); + ASSERT(fetch(&mgr, buf, url, "GET /..ddot HTTP/1.0\n\n") == 301); ASSERT(fetch(&mgr, buf, url, "GET /..ddot/ HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, "hi\n") == 0); @@ -937,7 +955,9 @@ static void test_http_server(void) { // Pre-compressed files { struct mg_http_message hm; - ASSERT(fetch(&mgr, buf, url, "HEAD /hello.txt HTTP/1.0\n\n") == 200); + ASSERT(fetch(&mgr, buf, url, + "HEAD /hello.txt HTTP/1.0\n" + "Accept-Encoding: gzip\n\n") == 200); mg_http_parse(buf, strlen(buf), &hm); ASSERT(mg_http_get_header(&hm, "Content-Encoding") != NULL); ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Encoding"), @@ -1381,9 +1401,7 @@ static void test_http_range(void) { ASSERT(mgr.conns == NULL); } -static void f1(void *arg) { - (*(int *) arg)++; -} +static void f1(void *arg) { (*(int *) arg)++; } static void test_timer(void) { int v1 = 0, v2 = 0, v3 = 0; @@ -2841,9 +2859,7 @@ static void start_thread(void (*f)(void *), void *p) { pthread_attr_destroy(&attr); } #else -static void start_thread(void (*f)(void *), void *p) { - (void) f, (void) p; -} +static void start_thread(void (*f)(void *), void *p) { (void) f, (void) p; } #endif static void test_queue(void) {