|
|
@@ -1833,6 +1833,31 @@ struct packed_file {
|
|
|
};
|
|
|
|
|
|
#if MG_ENABLE_PACKED_FS
|
|
|
+static const struct packed_file2 {
|
|
|
+ const char *name;
|
|
|
+ const unsigned char *data;
|
|
|
+ size_t size;
|
|
|
+ time_t mtime;
|
|
|
+} packed_files[] = {
|
|
|
+ {NULL, NULL, 0, 0}
|
|
|
+};
|
|
|
+static int scmp(const char *a, const char *b) {
|
|
|
+ while (*a && (*a == *b)) a++, b++;
|
|
|
+ return *(const unsigned char *) a - *(const unsigned char *) b;
|
|
|
+}
|
|
|
+const char *mg_unlist(size_t no) {
|
|
|
+ return packed_files[no].name;
|
|
|
+}
|
|
|
+const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
|
|
|
+ const struct packed_file2 *p;
|
|
|
+ for (p = packed_files; p->name != NULL; p++) {
|
|
|
+ if (scmp(p->name, name) != 0) continue;
|
|
|
+ if (size != NULL) *size = p->size - 1;
|
|
|
+ if (mtime != NULL) *mtime = p->mtime;
|
|
|
+ return (const char *) p->data;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
#else
|
|
|
const char *mg_unpack(const char *path, size_t *size, time_t *mtime) {
|
|
|
*size = 0, *mtime = 0;
|
|
|
@@ -2667,7 +2692,7 @@ int mg_http_reply2(struct mg_connection *c, int code, const char *headers,
|
|
|
int r;
|
|
|
if (c==NULL) return -1;
|
|
|
|
|
|
- mg_printf(c, "HTTP/1.1 %d %s\r\n"
|
|
|
+ /*mg_printf(c, "HTTP/1.1 %d %s\r\n"
|
|
|
"Content-Type: text/html\n"
|
|
|
"Content-Length: %d\n"
|
|
|
"Connection: Keep-Alive\n"
|
|
|
@@ -2677,7 +2702,18 @@ int mg_http_reply2(struct mg_connection *c, int code, const char *headers,
|
|
|
"X-Xss-Protection: 1: mode=block\n"
|
|
|
"Accept-Ranges: bytes\n"
|
|
|
"Vary: Accept-Encoding\n\n"
|
|
|
- "%s\n", code, mg_http_status_code_str(code),strlen(fmt == NULL ? "" : fmt), fmt == NULL ? "" : fmt);
|
|
|
+ "%s\n", code, mg_http_status_code_str(code),strlen(fmt == NULL ? "" : fmt), fmt == NULL ? "" : fmt);*/
|
|
|
+
|
|
|
+ mg_printf(c, "HTTP/1.1 %d %s\r\n"
|
|
|
+ "Content-Type: text/html\n"
|
|
|
+ "Content-Length: %d\n"
|
|
|
+ "Connection: Keep-Alive\n"
|
|
|
+ "Keep-Alive: timeout=30, max=396\n"
|
|
|
+ "X-Content-Type-0ptions: nosniff\n"
|
|
|
+ "X-Frame-0ptions:: SAMEORIGIN\n"
|
|
|
+ "X-Xss-Protection: 1: mode=block\n"
|
|
|
+ "Accept-Ranges: bytes\n"
|
|
|
+ "Vary: Accept-Encoding\n\n", code, mg_http_status_code_str(code),strlen(fmt == NULL ? "" : fmt));
|
|
|
|
|
|
len = c->send.len;
|
|
|
va_start(ap, fmt);
|
|
|
@@ -2892,6 +2928,110 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static char *get_fname(const char *path)
|
|
|
+{
|
|
|
+ char *p=strrchr(path, '/');
|
|
|
+ if(p) {
|
|
|
+ return p+1;
|
|
|
+ }
|
|
|
+ return (char*)path;
|
|
|
+}
|
|
|
+void mg_http_serve_file2(struct mg_connection *c, struct mg_http_message *hm,
|
|
|
+ const char *path,
|
|
|
+ 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 = 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 (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) {
|
|
|
+ char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf);
|
|
|
+ if (ae_ != NULL && strstr(ae_, "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;
|
|
|
+ }
|
|
|
+ free(ae_);
|
|
|
+ }
|
|
|
+ // 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);
|
|
|
+ path = opts->page404;
|
|
|
+ mime = guess_content_type(mg_str(path), opts->mime_types);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fd == NULL || fs->st(path, &size, &mtime) == 0) {
|
|
|
+ mg_http_reply(c, 404, opts->extra_headers, "Not found\n");
|
|
|
+ mg_fs_close(fd);
|
|
|
+ // NOTE: mg_http_etag() call should go first!
|
|
|
+ } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
|
|
|
+ (inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
|
|
|
+ mg_strcasecmp(*inm, mg_str(etag)) == 0) {
|
|
|
+ mg_fs_close(fd);
|
|
|
+ mg_http_reply(c, 304, opts->extra_headers, "");
|
|
|
+ } else {
|
|
|
+ int n, status = 200;
|
|
|
+ char range[100];
|
|
|
+ size_t r1 = 0, r2 = 0, cl = size;
|
|
|
+
|
|
|
+ // Handle Range header
|
|
|
+ struct mg_str *rh = mg_http_get_header(hm, "Range");
|
|
|
+ range[0] = '\0';
|
|
|
+ if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) {
|
|
|
+ // If range is specified like "400-", set second limit to content len
|
|
|
+ if (n == 1) r2 = cl - 1;
|
|
|
+ if (r1 > r2 || r2 >= cl) {
|
|
|
+ status = 416;
|
|
|
+ cl = 0;
|
|
|
+ mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n",
|
|
|
+ (int64_t) size);
|
|
|
+ } else {
|
|
|
+ status = 206;
|
|
|
+ cl = r2 - r1 + 1;
|
|
|
+ mg_snprintf(range, sizeof(range),
|
|
|
+ "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1,
|
|
|
+ (uint64_t) (r1 + cl - 1), (uint64_t) size);
|
|
|
+ fs->sk(fd->fd, r1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mg_printf(c,
|
|
|
+ "HTTP/1.1 %d %s\r\n"
|
|
|
+ "Content-Type: %.*s\r\n"
|
|
|
+ "Content-Disposition: attachment;filename=%s\r\n"
|
|
|
+ "Etag: %s\r\n"
|
|
|
+ "Content-Length: %llu\r\n"
|
|
|
+ "%s%s%s\r\n",
|
|
|
+ status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
|
|
|
+ get_fname(path),
|
|
|
+ etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
|
|
|
+ range, opts->extra_headers ? opts->extra_headers : "");
|
|
|
+ if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) {
|
|
|
+ c->is_draining = 1;
|
|
|
+ c->is_resp = 0;
|
|
|
+ mg_fs_close(fd);
|
|
|
+ } else {
|
|
|
+ // Track to-be-sent content length at the end of c->data, aligned
|
|
|
+ size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
|
|
|
+ sizeof(size_t) * sizeof(size_t)];
|
|
|
+ c->pfn = static_cb;
|
|
|
+ c->pfn_data = fd;
|
|
|
+ *clp = cl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
struct printdirentrydata {
|
|
|
struct mg_connection *c;
|
|
|
struct mg_http_message *hm;
|
|
|
@@ -15219,22 +15359,17 @@ size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len,
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void my_mask(uint8_t *data, size_t len) {
|
|
|
- size_t i;
|
|
|
- uint8_t *p=data, *mask=p-4;
|
|
|
- for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
|
|
|
-}
|
|
|
-size_t mg_ws_send2(struct mg_connection *c, const void *buf, size_t len,
|
|
|
- int op) {
|
|
|
- uint8_t *p=malloc(len+100);
|
|
|
- if(!p) return -1;
|
|
|
+size_t mg_ws_send2(struct mg_connection *c, const void *buf, size_t len, int op, int max_tlen) {
|
|
|
uint8_t header[14];
|
|
|
- size_t header_len = mkhdr(len, op, c->is_client, p);
|
|
|
- memcpy(p+header_len, buf, len);
|
|
|
- //my_mask(p+header_len, len);
|
|
|
- mg_io_send(c, p, header_len+len);
|
|
|
- free(p);
|
|
|
-
|
|
|
+ if(!c) return -1;
|
|
|
+ if(max_tlen>0 && c->send.len>max_tlen) {
|
|
|
+ mg_iobuf_resize(&c->send, 0);
|
|
|
+ }
|
|
|
+ size_t header_len = mkhdr(len, op, c->is_client, header);
|
|
|
+ mg_send(c, header, header_len);
|
|
|
+ MG_VERBOSE(("WS out: %d [%.*s]", (int) len, (int) len, buf));
|
|
|
+ mg_send(c, buf, len);
|
|
|
+ mg_ws_mask(c, len);
|
|
|
return header_len + len;
|
|
|
}
|
|
|
|