diff --git a/mongoose.c b/mongoose.c index eb02306d..bc070da7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2147,6 +2147,9 @@ void mg_if_poll(struct mg_connection *nc, time_t now) { } static void mg_destroy_conn(struct mg_connection *conn) { + if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) { + conn->proto_data_destructor(conn->proto_data); + } mg_if_destroy_conn(conn); #ifdef MG_ENABLE_SSL if (conn->ssl != NULL) SSL_free(conn->ssl); @@ -2155,9 +2158,6 @@ static void mg_destroy_conn(struct mg_connection *conn) { mbuf_free(&conn->recv_mbuf); mbuf_free(&conn->send_mbuf); mbuf_free(&conn->endpoints); -#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART - mbuf_free(&conn->strm_state); -#endif memset(conn, 0, sizeof(*conn)); MG_FREE(conn); @@ -2598,7 +2598,6 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { nc = mg_create_connection(lc->mgr, lc->handler, opts); if (nc == NULL) return NULL; nc->listener = lc; - nc->proto_data = lc->proto_data; nc->proto_handler = lc->proto_handler; nc->user_data = lc->user_data; nc->recv_mbuf_limit = lc->recv_mbuf_limit; @@ -2686,7 +2685,6 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, nc->sock = lc->sock; nc->listener = lc; nc->sa = *sa; - nc->proto_data = lc->proto_data; nc->proto_handler = lc->proto_handler; nc->user_data = lc->user_data; nc->recv_mbuf_limit = lc->recv_mbuf_limit; @@ -4161,19 +4159,82 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) { /* Amalgamated: #include "common/sha1.h" */ /* Amalgamated: #include "common/md5.h" */ -enum http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT, DATA_CGI }; +enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT }; -struct proto_data_http { -#ifndef MG_DISABLE_FILESYSTEM - FILE *fp; /* Opened file. */ -#endif - int64_t cl; /* Content-Length. How many bytes to send. */ - int64_t sent; /* How many bytes have been already sent. */ - int64_t body_len; /* How many bytes of chunked body was reassembled. */ - struct mg_connection *cgi_nc; - enum http_proto_data_type type; +struct mg_http_proto_data_file { + FILE *fp; /* Opened file. */ + int64_t cl; /* Content-Length. How many bytes to send. */ + int64_t sent; /* How many bytes have been already sent. */ + enum mg_http_proto_data_type type; }; +struct mg_http_proto_data_cgi { + struct mg_connection *cgi_nc; +}; + +struct mg_http_proto_data_chuncked { + int64_t body_len; /* How many bytes of chunked body was reassembled. */ +}; + +struct mg_http_proto_data { +#ifndef MG_DISABLE_FILESYSTEM + struct mg_http_proto_data_file file; +#endif +#ifndef MG_DISABLE_CGI + struct mg_http_proto_data_cgi cgi; +#endif +#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART + struct mbuf strm_state; /* Used by multi-part streaming */ +#endif + struct mg_http_proto_data_chuncked chunk; +}; + +static void mg_http_conn_destructor(void *proto_data); + +static struct mg_http_proto_data *mg_http_get_proto_data( + struct mg_connection *c) { + if (c->proto_data == NULL) { + c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data)); + c->proto_data_destructor = mg_http_conn_destructor; + } + + return (struct mg_http_proto_data *) c->proto_data; +} + +#ifndef MG_DISABLE_FILESYSTEM +static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) { + if (d != NULL) { + if (d->fp != NULL) { + fclose(d->fp); + } + memset(d, 0, sizeof(struct mg_http_proto_data_file)); + } +} +#endif + +#ifndef MG_DISABLE_CGI +static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) { + if (d != NULL) { + if (d->cgi_nc != NULL) d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY; + memset(d, 0, sizeof(struct mg_http_proto_data_cgi)); + } +} +#endif + +static void mg_http_conn_destructor(void *proto_data) { + struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data; +#ifndef MG_DISABLE_FILESYSTEM + mg_http_free_proto_data_file(&pd->file); +#endif +#ifndef MG_DISABLE_CGI + mg_http_free_proto_data_cgi(&pd->cgi); +#endif +#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART + mbuf_free(&pd->strm_state); +#endif + free(proto_data); +} + /* * This structure helps to create an environment for the spawned CGI program. * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, @@ -4184,7 +4245,7 @@ struct proto_data_http { * We satisfy both worlds: we create an envp array (which is vars), all * entries are actually pointers inside buf. */ -struct cgi_env_block { +struct mg_cgi_env_block { struct mg_connection *nc; char buf[MG_CGI_ENVIRONMENT_SIZE]; /* Environment buffer */ const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */ @@ -4198,7 +4259,7 @@ static const struct { const char *extension; size_t ext_len; const char *mime_type; -} static_builtin_mime_types[] = { +} mg_static_builtin_mime_types[] = { MIME_ENTRY("html", "text/html"), MIME_ENTRY("html", "text/html"), MIME_ENTRY("htm", "text/html"), @@ -4262,8 +4323,8 @@ static int mg_mkdir(const char *path, uint32_t mode) { } #endif -static struct mg_str get_mime_type(const char *path, const char *dflt, - const struct mg_serve_http_opts *opts) { +static struct mg_str mg_get_mime_type(const char *path, const char *dflt, + const struct mg_serve_http_opts *opts) { const char *ext, *overrides; size_t i, path_len; struct mg_str r, k, v; @@ -4278,11 +4339,11 @@ static struct mg_str get_mime_type(const char *path, const char *dflt, } } - for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) { - ext = path + (path_len - static_builtin_mime_types[i].ext_len); - if (path_len > static_builtin_mime_types[i].ext_len && ext[-1] == '.' && - mg_casecmp(ext, static_builtin_mime_types[i].extension) == 0) { - r.p = static_builtin_mime_types[i].mime_type; + for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) { + 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] == '.' && + mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) { + r.p = mg_static_builtin_mime_types[i].mime_type; r.len = strlen(r.p); return r; } @@ -4300,7 +4361,7 @@ static struct mg_str get_mime_type(const char *path, const char *dflt, * 0 if request is not yet fully buffered * >0 actual request length, including last \r\n\r\n */ -static int get_request_len(const char *s, int buf_len) { +static int mg_http_get_request_len(const char *s, int buf_len) { const unsigned char *buf = (unsigned char *) s; int i; @@ -4318,8 +4379,8 @@ static int get_request_len(const char *s, int buf_len) { return 0; } -static const char *parse_http_headers(const char *s, const char *end, int len, - struct http_message *req) { +static const char *mg_http_parse_headers(const char *s, const char *end, + int len, struct http_message *req) { int i; for (i = 0; i < (int) ARRAY_SIZE(req->header_names) - 1; i++) { struct mg_str *k = &req->header_names[i], *v = &req->header_values[i]; @@ -4348,7 +4409,7 @@ static const char *parse_http_headers(const char *s, const char *end, int len, int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) { const char *end, *qs; - int len = get_request_len(s, n); + int len = mg_http_get_request_len(s, n); if (len <= 0) return len; @@ -4383,7 +4444,7 @@ int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) { s = mg_skip(s, end, "\r\n", &hm->resp_status_msg); } - s = parse_http_headers(s, end, len, hm); + s = mg_http_parse_headers(s, end, len, hm); /* * mg_parse_http() is used to parse both HTTP requests and HTTP @@ -4424,16 +4485,16 @@ struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) { #ifndef MG_DISABLE_HTTP_WEBSOCKET -static int is_ws_fragment(unsigned char flags) { +static int mg_is_ws_fragment(unsigned char flags) { return (flags & 0x80) == 0 || (flags & 0x0f) == 0; } -static int is_ws_first_fragment(unsigned char flags) { +static int mg_is_ws_first_fragment(unsigned char flags) { return (flags & 0x80) == 0 && (flags & 0x0f) != 0; } -static void handle_incoming_websocket_frame(struct mg_connection *nc, - struct websocket_message *wsm) { +static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, + struct websocket_message *wsm) { if (wsm->flags & 0x8) { mg_call(nc, nc->handler, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm); } else { @@ -4441,19 +4502,19 @@ static void handle_incoming_websocket_frame(struct mg_connection *nc, } } -static int deliver_websocket_data(struct mg_connection *nc) { +static int mg_deliver_websocket_data(struct mg_connection *nc) { /* Using unsigned char *, cause of integer arithmetic below */ uint64_t i, data_len = 0, frame_len = 0, buf_len = nc->recv_mbuf.len, len, mask_len = 0, header_len = 0; unsigned char *p = (unsigned char *) nc->recv_mbuf.buf, *buf = p, *e = p + buf_len; unsigned *sizep = (unsigned *) &p[1]; /* Size ptr for defragmented frames */ - int ok, reass = buf_len > 0 && is_ws_fragment(p[0]) && + int ok, reass = buf_len > 0 && mg_is_ws_fragment(p[0]) && !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG); /* If that's a continuation frame that must be reassembled, handle it */ - if (reass && !is_ws_first_fragment(p[0]) && buf_len >= 1 + sizeof(*sizep) && - buf_len >= 1 + sizeof(*sizep) + *sizep) { + if (reass && !mg_is_ws_first_fragment(p[0]) && + buf_len >= 1 + sizeof(*sizep) && buf_len >= 1 + sizeof(*sizep) + *sizep) { buf += 1 + sizeof(*sizep) + *sizep; buf_len -= 1 + sizeof(*sizep) + *sizep; } @@ -4493,7 +4554,7 @@ static int deliver_websocket_data(struct mg_connection *nc) { if (reass) { /* On first fragmented frame, nullify size */ - if (is_ws_first_fragment(wsm.flags)) { + if (mg_is_ws_first_fragment(wsm.flags)) { mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.size + sizeof(*sizep)); p[0] &= ~0x0f; /* Next frames will be treated as continuation */ buf = p + 1 + sizeof(*sizep); @@ -4509,12 +4570,12 @@ static int deliver_websocket_data(struct mg_connection *nc) { if (wsm.flags & 0x80) { wsm.data = p + 1 + sizeof(*sizep); wsm.size = *sizep; - handle_incoming_websocket_frame(nc, &wsm); + mg_handle_incoming_websocket_frame(nc, &wsm); mbuf_remove(&nc->recv_mbuf, 1 + sizeof(*sizep) + *sizep); } } else { /* TODO(lsm): properly handle OOB control frames during defragmentation */ - handle_incoming_websocket_frame(nc, &wsm); + mg_handle_incoming_websocket_frame(nc, &wsm); mbuf_remove(&nc->recv_mbuf, (size_t) frame_len); /* Cleanup frame */ } @@ -4532,7 +4593,7 @@ struct ws_mask_ctx { uint32_t mask; }; -static uint32_t ws_random_mask(void) { +static uint32_t mg_ws_random_mask(void) { /* * The spec requires WS client to generate hard to * guess mask keys. From RFC6455, Section 5.3: @@ -4586,7 +4647,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len, if (nc->listener == NULL) { header[1] |= 1 << 7; /* set masking flag */ mg_send(nc, header, header_len); - ctx->mask = ws_random_mask(); + ctx->mask = mg_ws_random_mask(); mg_send(nc, &ctx->mask, sizeof(ctx->mask)); ctx->pos = nc->send_mbuf.len; } else { @@ -4595,7 +4656,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len, } } -static void ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) { +static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) { size_t i; if (ctx->pos == 0) return; for (i = 0; i < (mbuf->len - ctx->pos); i++) { @@ -4609,7 +4670,7 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data, mg_send_ws_header(nc, op, len, &ctx); mg_send(nc, data, len); - ws_mask_frame(&nc->send_mbuf, &ctx); + mg_ws_mask_frame(&nc->send_mbuf, &ctx); if (op == WEBSOCKET_OP_CLOSE) { nc->flags |= MG_F_SEND_AND_CLOSE; @@ -4631,7 +4692,7 @@ void mg_send_websocket_framev(struct mg_connection *nc, int op, mg_send(nc, strv[i].p, strv[i].len); } - ws_mask_frame(&nc->send_mbuf, &ctx); + mg_ws_mask_frame(&nc->send_mbuf, &ctx); if (op == WEBSOCKET_OP_CLOSE) { nc->flags |= MG_F_SEND_AND_CLOSE; @@ -4655,13 +4716,14 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op, } } -static void websocket_handler(struct mg_connection *nc, int ev, void *ev_data) { +static void mg_websocket_handler(struct mg_connection *nc, int ev, + void *ev_data) { mg_call(nc, nc->handler, ev, ev_data); switch (ev) { case MG_EV_RECV: do { - } while (deliver_websocket_data(nc)); + } while (mg_deliver_websocket_data(nc)); break; case MG_EV_POLL: /* Ping idle websocket connections */ @@ -4678,7 +4740,8 @@ static void websocket_handler(struct mg_connection *nc, int ev, void *ev_data) { } } -static void ws_handshake(struct mg_connection *nc, const struct mg_str *key) { +static void mg_ws_handshake(struct mg_connection *nc, + const struct mg_str *key) { static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; char buf[MG_VPRINTF_BUFFER_SIZE], sha[20], b64_sha[sizeof(sha) * 2]; cs_sha1_ctx sha_ctx; @@ -4700,28 +4763,14 @@ static void ws_handshake(struct mg_connection *nc, const struct mg_str *key) { #endif /* MG_DISABLE_HTTP_WEBSOCKET */ -static void free_http_proto_data(struct mg_connection *nc) { - struct proto_data_http *dp = (struct proto_data_http *) nc->proto_data; - if (dp != NULL) { #ifndef MG_DISABLE_FILESYSTEM - if (dp->fp != NULL) fclose(dp->fp); -#endif -#ifndef MG_DISABLE_CGI - if (dp->cgi_nc != NULL) dp->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY; -#endif - MG_FREE(dp); - nc->proto_data = NULL; - } -} - -#ifndef MG_DISABLE_FILESYSTEM -static void transfer_file_data(struct mg_connection *nc) { - struct proto_data_http *dp = (struct proto_data_http *) nc->proto_data; +static void mg_http_transfer_file_data(struct mg_connection *nc) { + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); char buf[MG_MAX_HTTP_SEND_MBUF]; - int64_t left = dp->cl - dp->sent; + int64_t left = pd->file.cl - pd->file.sent; size_t n = 0, to_read = 0; - if (dp->type == DATA_FILE) { + if (pd->file.type == DATA_FILE) { struct mbuf *io = &nc->send_mbuf; if (io->len < sizeof(buf)) { to_read = sizeof(buf) - io->len; @@ -4733,38 +4782,42 @@ static void transfer_file_data(struct mg_connection *nc) { if (to_read == 0) { /* Rate limiting. send_mbuf is too full, wait until it's drained. */ - } else if (dp->sent < dp->cl && (n = fread(buf, 1, to_read, dp->fp)) > 0) { + } else if (pd->file.sent < pd->file.cl && + (n = fread(buf, 1, to_read, pd->file.fp)) > 0) { mg_send(nc, buf, n); - dp->sent += n; + pd->file.sent += n; } else { - free_http_proto_data(nc); + mg_http_free_proto_data_file(&pd->file); #ifdef MG_DISABLE_HTTP_KEEP_ALIVE nc->flags |= MG_F_SEND_AND_CLOSE; #endif } - } else if (dp->type == DATA_PUT) { + } else if (pd->file.type == DATA_PUT) { struct mbuf *io = &nc->recv_mbuf; size_t to_write = left <= 0 ? 0 : left < (int64_t) io->len ? (size_t) left : io->len; - size_t n = fwrite(io->buf, 1, to_write, dp->fp); + size_t n = fwrite(io->buf, 1, to_write, pd->file.fp); if (n > 0) { mbuf_remove(io, n); - dp->sent += n; + pd->file.sent += n; } - if (n == 0 || dp->sent >= dp->cl) { - free_http_proto_data(nc); + if (n == 0 || pd->file.sent >= pd->file.cl) { + mg_http_free_proto_data_file(&pd->file); #ifdef MG_DISABLE_HTTP_KEEP_ALIVE nc->flags |= MG_F_SEND_AND_CLOSE; #endif } - } else if (dp->type == DATA_CGI) { + } +#ifndef MG_DISABLE_CGI + else if (pd->cgi.cgi_nc != NULL) { /* This is POST data that needs to be forwarded to the CGI process */ - if (dp->cgi_nc != NULL) { - mg_forward(nc, dp->cgi_nc); + if (pd->cgi.cgi_nc != NULL) { + mg_forward(nc, pd->cgi.cgi_nc); } else { nc->flags |= MG_F_SEND_AND_CLOSE; } } +#endif } #endif /* MG_DISABLE_FILESYSTEM */ @@ -4773,8 +4826,8 @@ static void transfer_file_data(struct mg_connection *nc) { * if it's incomplete. If the chunk is fully buffered, return total number of * bytes in a chunk, and store data in `data`, `data_len`. */ -static size_t parse_chunk(char *buf, size_t len, char **chunk_data, - size_t *chunk_len) { +static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data, + size_t *chunk_len) { unsigned char *s = (unsigned char *) buf; size_t n = 0; /* scanned chunk length */ size_t i = 0; /* index in s */ @@ -4809,24 +4862,17 @@ static size_t parse_chunk(char *buf, size_t len, char **chunk_data, MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, struct http_message *hm, char *buf, size_t blen) { - struct proto_data_http *dp; + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); char *data; size_t i, n, data_len, body_len, zero_chunk_received = 0; - /* If not allocated, allocate proto_data to hold reassembled offset */ - if (nc->proto_data == NULL && - (nc->proto_data = MG_CALLOC(1, sizeof(*dp))) == NULL) { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - return 0; - } - /* Find out piece of received data that is not yet reassembled */ - dp = (struct proto_data_http *) nc->proto_data; - body_len = dp->body_len; + body_len = pd->chunk.body_len; assert(blen >= body_len); /* Traverse all fully buffered chunks */ - for (i = body_len; (n = parse_chunk(buf + i, blen - i, &data, &data_len)) > 0; + for (i = body_len; + (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0; i += n) { /* Collapse chunk data to the rest of HTTP body */ memmove(buf + body_len, data, data_len); @@ -4846,7 +4892,7 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, memmove(buf + body_len, buf + i, blen - i); memset(buf + body_len + blen - i, 0, i - body_len); nc->recv_mbuf.len -= i - body_len; - dp->body_len = body_len; + pd->chunk.body_len = body_len; /* Send MG_EV_HTTP_CHUNK event */ nc->flags &= ~MG_F_DELETE_CHUNK; @@ -4857,19 +4903,19 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, memset(buf, 0, body_len); memmove(buf, buf + body_len, blen - i); nc->recv_mbuf.len -= body_len; - hm->body.len = dp->body_len = 0; + hm->body.len = pd->chunk.body_len = 0; } if (zero_chunk_received) { - hm->message.len = dp->body_len + blen - i; + hm->message.len = pd->chunk.body_len + blen - i; } } return body_len; } -static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc, - struct mg_str *uri_path) { +static mg_event_handler_t mg_http_get_endpoint_handler( + struct mg_connection *nc, struct mg_str *uri_path) { size_t pos = 0; mg_event_handler_t ret = NULL; int matched, matched_max = 0; @@ -4900,7 +4946,7 @@ static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc, } #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART -struct stream_info { +struct mg_http_stream_info { struct mg_str endpoint; struct mg_str boundary; struct mg_str var_name; @@ -4914,7 +4960,8 @@ struct stream_info { * related data these function can be replaced with usual structs * TODO(alashkin): replace once those way will be implemented */ -static void mg_parse_stream_info(struct mbuf *buf, struct stream_info *si) { +static void mg_http_parse_stream_info(struct mbuf *buf, + struct mg_http_stream_info *si) { const char *ptr = buf->buf; memcpy(&si->endpoint.len, ptr, sizeof(si->endpoint.len)); ptr += sizeof(si->endpoint.len); @@ -4934,7 +4981,8 @@ static void mg_parse_stream_info(struct mbuf *buf, struct stream_info *si) { ptr += si->file_name.len + 1; } -static void mg_store_stream_info(struct mbuf *buf, struct stream_info *si) { +static void mg_http_store_stream_info(struct mbuf *buf, + struct mg_http_stream_info *si) { char zero = 0; mbuf_remove(buf, buf->len); mbuf_append(buf, &si->endpoint.len, sizeof(si->endpoint.len)); @@ -4951,21 +4999,22 @@ static void mg_store_stream_info(struct mbuf *buf, struct stream_info *si) { } #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ -static void mg_call_endpoint_handler(struct mg_connection *nc, int ev, - struct http_message *hm) { +static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, + struct http_message *hm) { mg_event_handler_t uri_handler = - ev == MG_EV_HTTP_REQUEST ? get_endpoint_handler(nc->listener, &hm->uri) - : NULL; + ev == MG_EV_HTTP_REQUEST + ? mg_http_get_endpoint_handler(nc->listener, &hm->uri) + : NULL; mg_call(nc, uri_handler ? uri_handler : nc->handler, ev, hm); } #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART -static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, - int ev, void *ev_data); +static void mg_http_multipart_continue(struct mg_connection *nc, + struct mbuf *io, int ev, void *ev_data); -static void mg_multipart_begin(struct mg_connection *nc, - struct http_message *hm, struct mbuf *io, - int req_len); +static void mg_http_multipart_begin(struct mg_connection *nc, + struct http_message *hm, struct mbuf *io, + int req_len); #endif @@ -4975,21 +5024,22 @@ static void mg_multipart_begin(struct mg_connection *nc, * even bigger (round up to 4k, from 700 bytes of actual size). */ #ifdef __xtensa__ -static void http_handler2(struct mg_connection *nc, int ev, void *ev_data, - struct http_message *hm) __attribute__((noinline)); +static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data, + struct http_message *hm) __attribute__((noinline)); -void http_handler(struct mg_connection *nc, int ev, void *ev_data) { +void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { struct http_message hm; - http_handler2(nc, ev, ev_data, &hm); + mg_http_handler2(nc, ev, ev_data, &hm); } -static void http_handler2(struct mg_connection *nc, int ev, void *ev_data, - struct http_message *hm) { +static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data, + struct http_message *hm) { #else /* !__XTENSA__ */ -void http_handler(struct mg_connection *nc, int ev, void *ev_data) { +void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { struct http_message shm; struct http_message *hm = &shm; #endif /* __XTENSA__ */ + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mbuf *io = &nc->recv_mbuf; int req_len; const int is_req = (nc->listener != NULL); @@ -5005,14 +5055,13 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; hm->message.len = io->len; hm->body.len = io->buf + io->len - hm->body.p; - mg_call_endpoint_handler(nc, ev2, hm); + mg_http_call_endpoint_handler(nc, ev2, hm); } - free_http_proto_data(nc); } #ifndef MG_DISABLE_FILESYSTEM - if (nc->proto_data != NULL) { - transfer_file_data(nc); + if (pd->file.fp != NULL) { + mg_http_transfer_file_data(nc); } #endif @@ -5022,8 +5071,8 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mg_str *s; #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART - if (nc->strm_state.len != 0) { - mg_multipart_continue(nc, io, ev, ev_data); + if (pd->strm_state.len != 0) { + mg_http_multipart_continue(nc, io, ev, ev_data); return; } #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ @@ -5050,25 +5099,25 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { /* We're websocket client, got handshake response from server. */ /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */ mbuf_remove(io, req_len); - nc->proto_handler = websocket_handler; + nc->proto_handler = mg_websocket_handler; nc->flags |= MG_F_IS_WEBSOCKET; mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); - websocket_handler(nc, MG_EV_RECV, ev_data); + mg_websocket_handler(nc, MG_EV_RECV, ev_data); } else if (nc->listener != NULL && (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) { /* This is a websocket request. Switch protocol handlers. */ mbuf_remove(io, req_len); - nc->proto_handler = websocket_handler; + nc->proto_handler = mg_websocket_handler; nc->flags |= MG_F_IS_WEBSOCKET; /* Send handshake */ mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST, hm); if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { if (nc->send_mbuf.len == 0) { - ws_handshake(nc, vec); + mg_ws_handshake(nc, vec); } mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); - websocket_handler(nc, MG_EV_RECV, ev_data); + mg_websocket_handler(nc, MG_EV_RECV, ev_data); } #endif /* MG_DISABLE_HTTP_WEBSOCKET */ } else if (hm->message.len <= io->len) { @@ -5119,29 +5168,30 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { if (js_callback_handled_request) { nc->flags |= MG_F_SEND_AND_CLOSE; } else { - mg_call_endpoint_handler(nc, trigger_ev, hm); + mg_http_call_endpoint_handler(nc, trigger_ev, hm); } #else - mg_call_endpoint_handler(nc, trigger_ev, hm); + mg_http_call_endpoint_handler(nc, trigger_ev, hm); #endif mbuf_remove(io, hm->message.len); #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART } else { - mg_multipart_begin(nc, hm, io, req_len); + mg_http_multipart_begin(nc, hm, io, req_len); #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ } } } #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART -static void mg_multipart_begin(struct mg_connection *nc, - struct http_message *hm, struct mbuf *io, - int req_len) { +static void mg_http_multipart_begin(struct mg_connection *nc, + struct http_message *hm, struct mbuf *io, + int req_len) { + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mg_str *ct; const char multipart[] = "multipart"; char boundary[100]; int boundary_len; - struct stream_info si; + struct mg_http_stream_info si; mg_event_handler_t handler; if (nc->listener == NULL) { @@ -5176,13 +5226,13 @@ static void mg_multipart_begin(struct mg_connection *nc, /* If we reach this place - that is multipart request */ - if (nc->strm_state.len != 0) { + if (pd->strm_state.len != 0) { /* * Another streaming request was in progress, * looks like protocol error */ nc->flags |= MG_F_CLOSE_IMMEDIATELY; - mbuf_free(&nc->strm_state); + mbuf_free(&pd->strm_state); } else { si.endpoint = hm->uri; si.boundary.p = boundary; @@ -5190,8 +5240,8 @@ static void mg_multipart_begin(struct mg_connection *nc, si.var_name.p = si.file_name.p = NULL; si.var_name.len = si.file_name.len = 0; - mg_store_stream_info(&nc->strm_state, &si); - handler = get_endpoint_handler(nc->listener, &si.endpoint); + mg_http_store_stream_info(&pd->strm_state, &si); + handler = mg_http_get_endpoint_handler(nc->listener, &si.endpoint); mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_MULTIPART_REQUEST, hm); @@ -5201,17 +5251,18 @@ exit_mp: ; } -static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, - int ev, void *ev_data) { +static void mg_http_multipart_continue(struct mg_connection *nc, + struct mbuf *io, int ev, void *ev_data) { /* Continue to stream multipart */ - struct stream_info si; + struct mg_http_stream_info si; mg_event_handler_t handler; struct mg_http_multipart_part mp; const char *boundary; int req_len; + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); - mg_parse_stream_info(&nc->strm_state, &si); - handler = get_endpoint_handler(nc->listener, &si.endpoint); + mg_http_parse_stream_info(&pd->strm_state, &si); + handler = mg_http_get_endpoint_handler(nc->listener, &si.endpoint); memset(&mp, 0, sizeof(mp)); mp.var_name = si.var_name.p; @@ -5250,7 +5301,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, sizeof(filename), &data, &data_len); mp.var_name = varname; mp.file_name = filename; - if ((req_len = get_request_len(io->buf, io->len)) > 0) { + if ((req_len = mg_http_get_request_len(io->buf, io->len)) > 0) { const char *tmp; mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_BEGIN, &mp); @@ -5258,7 +5309,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, si.var_name.len = strlen(mp.var_name); si.file_name.p = mp.file_name; si.file_name.len = strlen(mp.file_name); - mg_store_stream_info(&nc->strm_state, &si); + mg_http_store_stream_info(&pd->strm_state, &si); mbuf_remove(io, req_len); mp.data.p = io->buf; @@ -5283,7 +5334,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, } if (io->len != 0) { - http_handler(nc, ev, ev_data); + mg_http_handler(nc, ev, ev_data); } } /* else wait for data */ } else if (has_prefix && has_suffix) { @@ -5298,7 +5349,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, /* Skip epilogue (if any) */ mbuf_remove(io, io->len); - mbuf_free(&nc->strm_state); + mbuf_free(&pd->strm_state); } else { /* Malformed request */ nc->flags |= MG_F_CLOSE_IMMEDIATELY; @@ -5309,7 +5360,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io, #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ void mg_set_protocol_http_websocket(struct mg_connection *nc) { - nc->proto_handler = http_handler; + nc->proto_handler = mg_http_handler; } #ifndef MG_DISABLE_HTTP_WEBSOCKET @@ -5384,16 +5435,16 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm, mg_send_head(nc, 501, 0, NULL); } #else -static void send_http_error(struct mg_connection *nc, int code, - const char *reason) { +static void mg_http_send_http_error(struct mg_connection *nc, int code, + const char *reason) { (void) reason; mg_send_head(nc, code, 0, NULL); } #ifndef MG_DISABLE_SSI -static void send_ssi_file(struct mg_connection *, const char *, FILE *, int, - const struct mg_serve_http_opts *); +static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int, + const struct mg_serve_http_opts *); -static void send_file_data(struct mg_connection *nc, FILE *fp) { +static void mg_send_file_data(struct mg_connection *nc, FILE *fp) { char buf[BUFSIZ]; size_t n; while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { @@ -5401,9 +5452,9 @@ static void send_file_data(struct mg_connection *nc, FILE *fp) { } } -static void do_ssi_include(struct mg_connection *nc, const char *ssi, char *tag, - int include_level, - const struct mg_serve_http_opts *opts) { +static void mg_do_ssi_include(struct mg_connection *nc, const char *ssi, + char *tag, int include_level, + const struct mg_serve_http_opts *opts) { char file_name[BUFSIZ], path[MAX_PATH_SIZE], *p; FILE *fp; @@ -5439,9 +5490,9 @@ static void do_ssi_include(struct mg_connection *nc, const char *ssi, char *tag, mg_set_close_on_exec(fileno(fp)); if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) > 0) { - send_ssi_file(nc, path, fp, include_level + 1, opts); + mg_send_ssi_file(nc, path, fp, include_level + 1, opts); } else { - send_file_data(nc, fp); + mg_send_file_data(nc, fp); } fclose(fp); } @@ -5457,13 +5508,13 @@ static void do_ssi_exec(struct mg_connection *nc, char *tag) { } else if ((fp = popen(cmd, "r")) == NULL) { mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno)); } else { - send_file_data(nc, fp); + mg_send_file_data(nc, fp); pclose(fp); } } #endif /* !MG_DISABLE_POPEN */ -static void do_ssi_call(struct mg_connection *nc, char *tag) { +static void mg_do_ssi_call(struct mg_connection *nc, char *tag) { mg_call(nc, NULL, MG_EV_SSI_CALL, tag); } @@ -5471,9 +5522,9 @@ static void do_ssi_call(struct mg_connection *nc, char *tag) { * SSI directive has the following format: * */ -static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp, - int include_level, - const struct mg_serve_http_opts *opts) { +static void mg_send_ssi_file(struct mg_connection *nc, const char *path, + FILE *fp, int include_level, + const struct mg_serve_http_opts *opts) { static const struct mg_str btag = MG_MK_STR("