Commit 884b9a48 authored by Deomid "rojer" Ryabkov's avatar Deomid "rojer" Ryabkov Committed by Cesanta Bot

Add Content-Encoding: gzip when serving .gz files

If file ends with .gz and has known "secondary extnesion", i.e. test.html.gz,
its content type is determined by the secondary extension and content-encoding is set to gzip.

PUBLISHED_FROM=a238763b4424bafabec2e58ccae4522cacdd7c78
parent 71536900
...@@ -5958,37 +5958,51 @@ static const struct { ...@@ -5958,37 +5958,51 @@ static const struct {
MIME_ENTRY("asf", "video/x-ms-asf"), MIME_ENTRY("asf", "video/x-ms-asf"),
MIME_ENTRY("avi", "video/x-msvideo"), MIME_ENTRY("avi", "video/x-msvideo"),
MIME_ENTRY("bmp", "image/bmp"), MIME_ENTRY("bmp", "image/bmp"),
{NULL, 0, NULL}}; {NULL, 0, NULL},
};
static struct mg_str mg_get_mime_type(const char *path, const char *dflt, static struct mg_str mg_get_mime_types_entry(struct mg_str path) {
size_t i;
for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
if (path.len < mg_static_builtin_mime_types[i].ext_len + 1) continue;
struct mg_str ext = MG_MK_STR_N(mg_static_builtin_mime_types[i].extension, mg_static_builtin_mime_types[i].ext_len);
struct mg_str pext = MG_MK_STR_N(path.p + (path.len - ext.len), ext.len);
if (pext.p[-1] == '.' && mg_strcasecmp(ext, pext) == 0) {
return mg_mk_str(mg_static_builtin_mime_types[i].mime_type);
}
}
return mg_mk_str(NULL);
}
static int mg_get_mime_type_encoding(struct mg_str path, struct mg_str *type,
struct mg_str *encoding,
const struct mg_serve_http_opts *opts) { const struct mg_serve_http_opts *opts) {
const char *ext, *overrides; const char *ext, *overrides;
size_t i, path_len; struct mg_str k, v;
struct mg_str r, k, v;
path_len = strlen(path);
overrides = opts->custom_mime_types; overrides = opts->custom_mime_types;
while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) { while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
ext = path + (path_len - k.len); ext = path.p + (path.len - k.len);
if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) { if (path.len > k.len && mg_vcasecmp(&k, ext) == 0) {
return v; *type = v;
return 1;
} }
} }
for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) { *type = mg_get_mime_types_entry(path);
ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' && /* Check for .html.gz, .js.gz, etc. */
mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) { if (mg_vcmp(type, "application/x-gunzip") == 0) {
r.p = mg_static_builtin_mime_types[i].mime_type; struct mg_str path2 = mg_mk_str_n(path.p, path.len - 3);
r.len = strlen(r.p); struct mg_str type2 = mg_get_mime_types_entry(path2);
return r; LOG(LL_ERROR, ("'%.*s' '%.*s' '%.*s'", (int) path.len, path.p, (int) path2.len, path2.p, (int) type2.len, type2.p));
if (type2.len > 0) {
*type = type2;
*encoding = mg_mk_str("gzip");
} }
} }
r.p = dflt; return (type->len > 0);
r.len = strlen(r.p);
return r;
} }
#endif #endif
...@@ -7088,12 +7102,15 @@ static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a, ...@@ -7088,12 +7102,15 @@ static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
return result; return result;
} }
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, void mg_http_serve_file_internal(struct mg_connection *nc,
const char *path, const struct mg_str mime_type, struct http_message *hm, const char *path,
const struct mg_str extra_headers) { struct mg_str mime_type,
struct mg_str encoding,
struct mg_str extra_headers) {
struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
cs_stat_t st; cs_stat_t st;
LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p)); LOG(LL_DEBUG, ("%p [%s] %.*s %.*s", nc, path, (int) mime_type.len,
mime_type.p, (int) encoding.len, encoding.p));
if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) { if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
int code, err = mg_get_errno(); int code, err = mg_get_errno();
switch (err) { switch (err) {
...@@ -7132,8 +7149,9 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -7132,8 +7149,9 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
} else { } else {
status_code = 206; status_code = 206;
cl = r2 - r1 + 1; cl = r2 - r1 + 1;
snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT snprintf(range, sizeof(range),
"-%" INT64_FMT "/%" INT64_FMT "\r\n", "Content-Range: bytes %" INT64_FMT "-%" INT64_FMT
"/%" INT64_FMT "\r\n",
r1, r1 + cl - 1, (int64_t) st.st_size); r1, r1 + cl - 1, (int64_t) st.st_size);
#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \ #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
_XOPEN_SOURCE >= 600 _XOPEN_SOURCE >= 600
...@@ -7158,13 +7176,6 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -7158,13 +7176,6 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
mg_http_construct_etag(etag, sizeof(etag), &st); mg_http_construct_etag(etag, sizeof(etag), &st);
mg_gmt_time_string(current_time, sizeof(current_time), &t); mg_gmt_time_string(current_time, sizeof(current_time), &t);
mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime); mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
/*
* Content length casted to size_t because:
* 1) that's the maximum buffer size anyway
* 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
* position
* TODO(mkm): fix ESP8266 RTOS SDK
*/
mg_send_response_line_s(nc, status_code, extra_headers); mg_send_response_line_s(nc, status_code, extra_headers);
mg_printf(nc, mg_printf(nc,
"Date: %s\r\n" "Date: %s\r\n"
...@@ -7174,17 +7185,29 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -7174,17 +7185,29 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
"Connection: %s\r\n" "Connection: %s\r\n"
"Content-Length: %" SIZE_T_FMT "Content-Length: %" SIZE_T_FMT
"\r\n" "\r\n"
"%sEtag: %s\r\n\r\n", "%s"
"Etag: %s\r\n",
current_time, last_modified, (int) mime_type.len, mime_type.p, current_time, last_modified, (int) mime_type.len, mime_type.p,
(pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range, (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
etag); etag);
if (encoding.len > 0) {
mg_printf(nc, "Content-Encoding: %.*s\r\n", (int) encoding.len,
encoding.p);
}
mg_send(nc, "\r\n", 2);
pd->file.cl = cl; pd->file.cl = cl;
pd->file.type = DATA_FILE; pd->file.type = DATA_FILE;
mg_http_transfer_file_data(nc); mg_http_transfer_file_data(nc);
} }
} }
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
const char *path, const struct mg_str mime_type,
const struct mg_str extra_headers) {
mg_http_serve_file_internal(nc, hm, path, mime_type, mg_mk_str(NULL),
extra_headers);
}
static void mg_http_serve_file2(struct mg_connection *nc, const char *path, static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
struct http_message *hm, struct http_message *hm,
struct mg_serve_http_opts *opts) { struct mg_serve_http_opts *opts) {
...@@ -7194,7 +7217,11 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path, ...@@ -7194,7 +7217,11 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
return; return;
} }
#endif #endif
mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts), struct mg_str type = MG_NULL_STR, encoding = MG_NULL_STR;
if (!mg_get_mime_type_encoding(mg_mk_str(path), &type, &encoding, opts)) {
type = mg_mk_str("text/plain");
}
mg_http_serve_file_internal(nc, hm, path, type, encoding,
mg_mk_str(opts->extra_headers)); mg_mk_str(opts->extra_headers));
} }
...@@ -7471,7 +7498,7 @@ void cs_md5(char buf[33], ...) { ...@@ -7471,7 +7498,7 @@ void cs_md5(char buf[33], ...) {
va_list ap; va_list ap;
va_start(ap, buf); va_start(ap, buf);
while ((p = va_arg(ap, const unsigned char *) ) != NULL) { while ((p = va_arg(ap, const unsigned char *)) != NULL) {
msgs[num_msgs] = p; msgs[num_msgs] = p;
msg_lens[num_msgs] = va_arg(ap, size_t); msg_lens[num_msgs] = va_arg(ap, size_t);
num_msgs++; num_msgs++;
...@@ -8102,11 +8129,11 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, ...@@ -8102,11 +8129,11 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
*p++ = DIRSEP; *p++ = DIRSEP;
/* No NULs and DIRSEPs in the component (percent-encoded). */ /* No NULs and DIRSEPs in the component (percent-encoded). */
for (i = 0; i < component.len; i++, p++) { for (i = 0; i < component.len; i++, p++) {
if (*p == '\0' || *p == DIRSEP if (*p == '\0' ||
*p == DIRSEP
#ifdef _WIN32 #ifdef _WIN32
/* On Windows, "/" is also accepted, so check for that too. */ /* On Windows, "/" is also accepted, so check for that too. */
|| || *p == '/'
*p == '/'
#endif #endif
) { ) {
ok = 0; ok = 0;
...@@ -8615,7 +8642,8 @@ struct mg_connection *mg_connect_http_opt( ...@@ -8615,7 +8642,8 @@ struct mg_connection *mg_connect_http_opt(
if (path.len == 0) path = mg_mk_str("/"); if (path.len == 0) path = mg_mk_str("/");
if (host.len == 0) host = mg_mk_str(""); if (host.len == 0) host = mg_mk_str("");
mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT mg_printf(nc,
"%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
"\r\n%.*s%s\r\n%s", "\r\n%.*s%s\r\n%s",
(post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p, (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
(int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len, (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
...@@ -9441,7 +9469,7 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc, ...@@ -9441,7 +9469,7 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
const char *path, const char *path,
const struct mg_serve_http_opts *opts) { const struct mg_serve_http_opts *opts) {
FILE *fp; FILE *fp;
struct mg_str mime_type; struct mg_str mime_type = MG_NULL_STR, encoding = MG_NULL_STR;
DBG(("%p %s", nc, path)); DBG(("%p %s", nc, path));
if ((fp = mg_fopen(path, "rb")) == NULL) { if ((fp = mg_fopen(path, "rb")) == NULL) {
...@@ -9449,12 +9477,18 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc, ...@@ -9449,12 +9477,18 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
} else { } else {
mg_set_close_on_exec((sock_t) fileno(fp)); mg_set_close_on_exec((sock_t) fileno(fp));
mime_type = mg_get_mime_type(path, "text/plain", opts); if (!mg_get_mime_type_encoding(mg_mk_str(path), &mime_type, &encoding, opts)) {
mime_type = mg_mk_str("text/plain");
}
mg_send_response_line(nc, 200, opts->extra_headers); mg_send_response_line(nc, 200, opts->extra_headers);
mg_printf(nc, mg_printf(nc,
"Content-Type: %.*s\r\n" "Content-Type: %.*s\r\n"
"Connection: close\r\n\r\n", "Connection: close\r\n",
(int) mime_type.len, mime_type.p); (int) mime_type.len, mime_type.p);
if (encoding.len > 0) {
mg_printf(nc, "Content-Encoding: %.*s\r\n", (int) encoding.len, encoding.p);
}
mg_send(nc, "\r\n", 2);
mg_send_ssi_file(nc, hm, path, fp, 0, opts); mg_send_ssi_file(nc, hm, path, fp, 0, opts);
fclose(fp); fclose(fp);
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
......
...@@ -328,37 +328,53 @@ static const struct { ...@@ -328,37 +328,53 @@ static const struct {
MIME_ENTRY("asf", "video/x-ms-asf"), MIME_ENTRY("asf", "video/x-ms-asf"),
MIME_ENTRY("avi", "video/x-msvideo"), MIME_ENTRY("avi", "video/x-msvideo"),
MIME_ENTRY("bmp", "image/bmp"), MIME_ENTRY("bmp", "image/bmp"),
{NULL, 0, NULL}}; {NULL, 0, NULL},
};
static struct mg_str mg_get_mime_types_entry(struct mg_str path) {
size_t i;
for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
if (path.len < mg_static_builtin_mime_types[i].ext_len + 1) continue;
struct mg_str ext = MG_MK_STR_N(mg_static_builtin_mime_types[i].extension,
mg_static_builtin_mime_types[i].ext_len);
struct mg_str pext = MG_MK_STR_N(path.p + (path.len - ext.len), ext.len);
if (pext.p[-1] == '.' && mg_strcasecmp(ext, pext) == 0) {
return mg_mk_str(mg_static_builtin_mime_types[i].mime_type);
}
}
return mg_mk_str(NULL);
}
static struct mg_str mg_get_mime_type(const char *path, const char *dflt, MG_INTERNAL int mg_get_mime_type_encoding(
struct mg_str path, struct mg_str *type, struct mg_str *encoding,
const struct mg_serve_http_opts *opts) { const struct mg_serve_http_opts *opts) {
const char *ext, *overrides; const char *ext, *overrides;
size_t i, path_len; struct mg_str k, v;
struct mg_str r, k, v;
path_len = strlen(path);
overrides = opts->custom_mime_types; overrides = opts->custom_mime_types;
while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) { while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
ext = path + (path_len - k.len); ext = path.p + (path.len - k.len);
if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) { if (path.len > k.len && mg_vcasecmp(&k, ext) == 0) {
return v; *type = v;
return 1;
} }
} }
for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) { *type = mg_get_mime_types_entry(path);
ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' && /* Check for .html.gz, .js.gz, etc. */
mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) { if (mg_vcmp(type, "application/x-gunzip") == 0) {
r.p = mg_static_builtin_mime_types[i].mime_type; struct mg_str path2 = mg_mk_str_n(path.p, path.len - 3);
r.len = strlen(r.p); struct mg_str type2 = mg_get_mime_types_entry(path2);
return r; LOG(LL_ERROR, ("'%.*s' '%.*s' '%.*s'", (int) path.len, path.p,
(int) path2.len, path2.p, (int) type2.len, type2.p));
if (type2.len > 0) {
*type = type2;
*encoding = mg_mk_str("gzip");
} }
} }
r.p = dflt; return (type->len > 0);
r.len = strlen(r.p);
return r;
} }
#endif #endif
...@@ -1458,12 +1474,15 @@ static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a, ...@@ -1458,12 +1474,15 @@ static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
return result; return result;
} }
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, void mg_http_serve_file_internal(struct mg_connection *nc,
const char *path, const struct mg_str mime_type, struct http_message *hm, const char *path,
const struct mg_str extra_headers) { struct mg_str mime_type,
struct mg_str encoding,
struct mg_str extra_headers) {
struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
cs_stat_t st; cs_stat_t st;
LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p)); LOG(LL_DEBUG, ("%p [%s] %.*s %.*s", nc, path, (int) mime_type.len,
mime_type.p, (int) encoding.len, encoding.p));
if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) { if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
int code, err = mg_get_errno(); int code, err = mg_get_errno();
switch (err) { switch (err) {
...@@ -1502,8 +1521,9 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -1502,8 +1521,9 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
} else { } else {
status_code = 206; status_code = 206;
cl = r2 - r1 + 1; cl = r2 - r1 + 1;
snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT snprintf(range, sizeof(range),
"-%" INT64_FMT "/%" INT64_FMT "\r\n", "Content-Range: bytes %" INT64_FMT "-%" INT64_FMT
"/%" INT64_FMT "\r\n",
r1, r1 + cl - 1, (int64_t) st.st_size); r1, r1 + cl - 1, (int64_t) st.st_size);
#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \ #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
_XOPEN_SOURCE >= 600 _XOPEN_SOURCE >= 600
...@@ -1528,13 +1548,6 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -1528,13 +1548,6 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
mg_http_construct_etag(etag, sizeof(etag), &st); mg_http_construct_etag(etag, sizeof(etag), &st);
mg_gmt_time_string(current_time, sizeof(current_time), &t); mg_gmt_time_string(current_time, sizeof(current_time), &t);
mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime); mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
/*
* Content length casted to size_t because:
* 1) that's the maximum buffer size anyway
* 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
* position
* TODO(mkm): fix ESP8266 RTOS SDK
*/
mg_send_response_line_s(nc, status_code, extra_headers); mg_send_response_line_s(nc, status_code, extra_headers);
mg_printf(nc, mg_printf(nc,
"Date: %s\r\n" "Date: %s\r\n"
...@@ -1544,17 +1557,29 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, ...@@ -1544,17 +1557,29 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
"Connection: %s\r\n" "Connection: %s\r\n"
"Content-Length: %" SIZE_T_FMT "Content-Length: %" SIZE_T_FMT
"\r\n" "\r\n"
"%sEtag: %s\r\n\r\n", "%s"
"Etag: %s\r\n",
current_time, last_modified, (int) mime_type.len, mime_type.p, current_time, last_modified, (int) mime_type.len, mime_type.p,
(pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range, (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
etag); etag);
if (encoding.len > 0) {
mg_printf(nc, "Content-Encoding: %.*s\r\n", (int) encoding.len,
encoding.p);
}
mg_send(nc, "\r\n", 2);
pd->file.cl = cl; pd->file.cl = cl;
pd->file.type = DATA_FILE; pd->file.type = DATA_FILE;
mg_http_transfer_file_data(nc); mg_http_transfer_file_data(nc);
} }
} }
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
const char *path, const struct mg_str mime_type,
const struct mg_str extra_headers) {
mg_http_serve_file_internal(nc, hm, path, mime_type, mg_mk_str(NULL),
extra_headers);
}
static void mg_http_serve_file2(struct mg_connection *nc, const char *path, static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
struct http_message *hm, struct http_message *hm,
struct mg_serve_http_opts *opts) { struct mg_serve_http_opts *opts) {
...@@ -1564,7 +1589,11 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path, ...@@ -1564,7 +1589,11 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
return; return;
} }
#endif #endif
mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts), struct mg_str type = MG_NULL_STR, encoding = MG_NULL_STR;
if (!mg_get_mime_type_encoding(mg_mk_str(path), &type, &encoding, opts)) {
type = mg_mk_str("text/plain");
}
mg_http_serve_file_internal(nc, hm, path, type, encoding,
mg_mk_str(opts->extra_headers)); mg_mk_str(opts->extra_headers));
} }
...@@ -1841,7 +1870,7 @@ void cs_md5(char buf[33], ...) { ...@@ -1841,7 +1870,7 @@ void cs_md5(char buf[33], ...) {
va_list ap; va_list ap;
va_start(ap, buf); va_start(ap, buf);
while ((p = va_arg(ap, const unsigned char *) ) != NULL) { while ((p = va_arg(ap, const unsigned char *)) != NULL) {
msgs[num_msgs] = p; msgs[num_msgs] = p;
msg_lens[num_msgs] = va_arg(ap, size_t); msg_lens[num_msgs] = va_arg(ap, size_t);
num_msgs++; num_msgs++;
...@@ -2472,11 +2501,11 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, ...@@ -2472,11 +2501,11 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
*p++ = DIRSEP; *p++ = DIRSEP;
/* No NULs and DIRSEPs in the component (percent-encoded). */ /* No NULs and DIRSEPs in the component (percent-encoded). */
for (i = 0; i < component.len; i++, p++) { for (i = 0; i < component.len; i++, p++) {
if (*p == '\0' || *p == DIRSEP if (*p == '\0' ||
*p == DIRSEP
#ifdef _WIN32 #ifdef _WIN32
/* On Windows, "/" is also accepted, so check for that too. */ /* On Windows, "/" is also accepted, so check for that too. */
|| || *p == '/'
*p == '/'
#endif #endif
) { ) {
ok = 0; ok = 0;
...@@ -2985,7 +3014,8 @@ struct mg_connection *mg_connect_http_opt( ...@@ -2985,7 +3014,8 @@ struct mg_connection *mg_connect_http_opt(
if (path.len == 0) path = mg_mk_str("/"); if (path.len == 0) path = mg_mk_str("/");
if (host.len == 0) host = mg_mk_str(""); if (host.len == 0) host = mg_mk_str("");
mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT mg_printf(nc,
"%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
"\r\n%.*s%s\r\n%s", "\r\n%.*s%s\r\n%s",
(post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p, (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
(int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len, (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
......
...@@ -170,7 +170,7 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc, ...@@ -170,7 +170,7 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
const char *path, const char *path,
const struct mg_serve_http_opts *opts) { const struct mg_serve_http_opts *opts) {
FILE *fp; FILE *fp;
struct mg_str mime_type; struct mg_str mime_type = MG_NULL_STR, encoding = MG_NULL_STR;
DBG(("%p %s", nc, path)); DBG(("%p %s", nc, path));
if ((fp = mg_fopen(path, "rb")) == NULL) { if ((fp = mg_fopen(path, "rb")) == NULL) {
...@@ -178,12 +178,20 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc, ...@@ -178,12 +178,20 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
} else { } else {
mg_set_close_on_exec((sock_t) fileno(fp)); mg_set_close_on_exec((sock_t) fileno(fp));
mime_type = mg_get_mime_type(path, "text/plain", opts); if (!mg_get_mime_type_encoding(mg_mk_str(path), &mime_type, &encoding,
opts)) {
mime_type = mg_mk_str("text/plain");
}
mg_send_response_line(nc, 200, opts->extra_headers); mg_send_response_line(nc, 200, opts->extra_headers);
mg_printf(nc, mg_printf(nc,
"Content-Type: %.*s\r\n" "Content-Type: %.*s\r\n"
"Connection: close\r\n\r\n", "Connection: close\r\n",
(int) mime_type.len, mime_type.p); (int) mime_type.len, mime_type.p);
if (encoding.len > 0) {
mg_printf(nc, "Content-Encoding: %.*s\r\n", (int) encoding.len,
encoding.p);
}
mg_send(nc, "\r\n", 2);
mg_send_ssi_file(nc, hm, path, fp, 0, opts); mg_send_ssi_file(nc, hm, path, fp, 0, opts);
fclose(fp); fclose(fp);
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
......
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