mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-28 23:49:44 +08:00
Replace m-part&endpoints mbufs with plain structs
PUBLISHED_FROM=b30cf26077b7c6374f0d588e5ef5ba504f979bb3
This commit is contained in:
parent
69215cf9eb
commit
31c20ab32c
220
mongoose.c
220
mongoose.c
@ -4204,6 +4204,19 @@ struct mg_http_proto_data_chuncked {
|
||||
int64_t body_len; /* How many bytes of chunked body was reassembled. */
|
||||
};
|
||||
|
||||
struct mg_http_endpoint {
|
||||
struct mg_http_endpoint *next;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
mg_event_handler_t handler;
|
||||
};
|
||||
|
||||
struct mg_http_multipart_stream {
|
||||
const char *boundary;
|
||||
const char *var_name;
|
||||
const char *file_name;
|
||||
};
|
||||
|
||||
struct mg_http_proto_data {
|
||||
#ifndef MG_DISABLE_FILESYSTEM
|
||||
struct mg_http_proto_data_file file;
|
||||
@ -4212,10 +4225,10 @@ struct mg_http_proto_data {
|
||||
struct mg_http_proto_data_cgi cgi;
|
||||
#endif
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
struct mbuf strm_state; /* Used by multi-part streaming */
|
||||
struct mg_http_multipart_stream mp_stream;
|
||||
#endif
|
||||
struct mg_http_proto_data_chuncked chunk;
|
||||
struct mbuf endpoints; /* Used by mg_register_http_endpoint */
|
||||
struct mg_http_endpoint *endpoints;
|
||||
mg_event_handler_t endpoint_handler;
|
||||
};
|
||||
|
||||
@ -4231,6 +4244,18 @@ static struct mg_http_proto_data *mg_http_get_proto_data(
|
||||
return (struct mg_http_proto_data *) c->proto_data;
|
||||
}
|
||||
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
static void mg_http_free_proto_data_mp_stream(
|
||||
struct mg_http_multipart_stream *mp) {
|
||||
free((void *) mp->boundary);
|
||||
mp->boundary = NULL;
|
||||
free((void *) mp->var_name);
|
||||
mp->var_name = NULL;
|
||||
free((void *) mp->file_name);
|
||||
mp->file_name = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MG_DISABLE_FILESYSTEM
|
||||
static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) {
|
||||
if (d != NULL) {
|
||||
@ -4251,6 +4276,19 @@ static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
|
||||
struct mg_http_endpoint *current = *ep;
|
||||
|
||||
while (current != NULL) {
|
||||
struct mg_http_endpoint *tmp = current->next;
|
||||
free((void *) current->name);
|
||||
free(current);
|
||||
current = tmp;
|
||||
}
|
||||
|
||||
ep = NULL;
|
||||
}
|
||||
|
||||
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
|
||||
@ -4260,9 +4298,9 @@ static void mg_http_conn_destructor(void *proto_data) {
|
||||
mg_http_free_proto_data_cgi(&pd->cgi);
|
||||
#endif
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
mbuf_free(&pd->strm_state);
|
||||
mg_http_free_proto_data_mp_stream(&pd->mp_stream);
|
||||
#endif
|
||||
mbuf_free(&pd->endpoints);
|
||||
mg_http_free_proto_data_endpoints(&pd->endpoints);
|
||||
free(proto_data);
|
||||
}
|
||||
|
||||
@ -4948,9 +4986,9 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
|
||||
static mg_event_handler_t mg_http_get_endpoint_handler(
|
||||
struct mg_connection *nc, struct mg_str *uri_path) {
|
||||
struct mg_http_proto_data *pd;
|
||||
size_t pos = 0;
|
||||
mg_event_handler_t ret = NULL;
|
||||
int matched, matched_max = 0;
|
||||
struct mg_http_endpoint *ep;
|
||||
|
||||
if (nc == NULL) {
|
||||
return NULL;
|
||||
@ -4958,81 +4996,23 @@ static mg_event_handler_t mg_http_get_endpoint_handler(
|
||||
|
||||
pd = mg_http_get_proto_data(nc);
|
||||
|
||||
while (pos < pd->endpoints.len) {
|
||||
size_t name_len;
|
||||
memcpy(&name_len, pd->endpoints.buf + pos, sizeof(name_len));
|
||||
if ((matched = mg_match_prefix_n(pd->endpoints.buf + pos + sizeof(size_t),
|
||||
name_len, uri_path->p, uri_path->len)) !=
|
||||
-1) {
|
||||
ep = pd->endpoints;
|
||||
while (ep != NULL) {
|
||||
if ((matched = mg_match_prefix_n(ep->name, ep->name_len, uri_path->p,
|
||||
uri_path->len)) != -1) {
|
||||
if (matched > matched_max) {
|
||||
/* Looking for the longest suitable handler */
|
||||
memcpy(&ret,
|
||||
pd->endpoints.buf + pos + sizeof(name_len) + (name_len + 1),
|
||||
sizeof(ret));
|
||||
ret = ep->handler;
|
||||
matched_max = matched;
|
||||
}
|
||||
}
|
||||
|
||||
pos += sizeof(name_len) + (name_len + 1) + sizeof(ret);
|
||||
ep = ep->next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
struct mg_http_stream_info {
|
||||
struct mg_str endpoint;
|
||||
struct mg_str boundary;
|
||||
struct mg_str var_name;
|
||||
struct mg_str file_name;
|
||||
};
|
||||
|
||||
/*
|
||||
* Save/restore state into buf is convinient due to lack of
|
||||
* protocol/connection parameters in mongoose
|
||||
* once mongoose will have way to store connection/protocol
|
||||
* related data these function can be replaced with usual structs
|
||||
* TODO(alashkin): replace once those way will be implemented
|
||||
*/
|
||||
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);
|
||||
si->endpoint.p = ptr;
|
||||
ptr += si->endpoint.len;
|
||||
memcpy(&si->boundary.len, ptr, sizeof(si->boundary.len));
|
||||
ptr += sizeof(si->boundary.len);
|
||||
si->boundary.p = ptr;
|
||||
ptr += si->boundary.len + 1; /* Explicitly zero-terminated */
|
||||
memcpy(&si->var_name.len, ptr, sizeof(si->var_name.len));
|
||||
ptr += sizeof(si->var_name.len);
|
||||
si->var_name.p = ptr;
|
||||
ptr += si->var_name.len + 1;
|
||||
memcpy(&si->file_name.len, ptr, sizeof(si->file_name.len));
|
||||
ptr += sizeof(si->file_name.len);
|
||||
si->file_name.p = ptr;
|
||||
ptr += si->file_name.len + 1;
|
||||
}
|
||||
|
||||
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));
|
||||
mbuf_append(buf, si->endpoint.p, si->endpoint.len);
|
||||
mbuf_append(buf, &si->boundary.len, sizeof(si->boundary.len));
|
||||
mbuf_append(buf, si->boundary.p, si->boundary.len);
|
||||
mbuf_append(buf, &zero, 1); /* Make boundary zero terminated */
|
||||
mbuf_append(buf, &si->var_name.len, sizeof(si->var_name.len));
|
||||
mbuf_append(buf, si->var_name.p, si->var_name.len);
|
||||
mbuf_append(buf, &zero, 1);
|
||||
mbuf_append(buf, &si->file_name.len, sizeof(si->file_name.len));
|
||||
mbuf_append(buf, si->file_name.p, si->file_name.len);
|
||||
mbuf_append(buf, &zero, 1);
|
||||
}
|
||||
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
|
||||
|
||||
static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
|
||||
struct http_message *hm) {
|
||||
struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
|
||||
@ -5087,23 +5067,17 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
#endif
|
||||
if (ev == MG_EV_CLOSE) {
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
if (pd->strm_state.len != 0) {
|
||||
if (pd->mp_stream.boundary != NULL) {
|
||||
/*
|
||||
* Multipart message is in progress, but we get close
|
||||
* MG_EV_HTTP_PART_END with error flag
|
||||
*/
|
||||
struct mg_http_stream_info si;
|
||||
struct mg_http_multipart_part mp;
|
||||
mg_event_handler_t handler;
|
||||
memset(&mp, 0, sizeof(mp));
|
||||
|
||||
mg_http_parse_stream_info(&pd->strm_state, &si);
|
||||
handler = mg_http_get_endpoint_handler(nc->listener, &si.endpoint);
|
||||
|
||||
mp.status = -1;
|
||||
mp.var_name = si.var_name.p;
|
||||
mp.file_name = si.file_name.p;
|
||||
mg_call(nc, (handler ? handler : nc->handler), MG_EV_HTTP_PART_END, &mp);
|
||||
mp.var_name = pd->mp_stream.var_name;
|
||||
mp.file_name = pd->mp_stream.file_name;
|
||||
mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
|
||||
MG_EV_HTTP_PART_END, &mp);
|
||||
} else
|
||||
#endif
|
||||
if (io->len > 0 && mg_parse_http(io->buf, io->len, hm, is_req) > 0) {
|
||||
@ -5130,7 +5104,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
struct mg_str *s;
|
||||
|
||||
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
if (pd->strm_state.len != 0) {
|
||||
if (pd->mp_stream.boundary != NULL) {
|
||||
mg_http_multipart_continue(nc, io, ev, ev_data);
|
||||
return;
|
||||
}
|
||||
@ -5250,8 +5224,6 @@ static void mg_http_multipart_begin(struct mg_connection *nc,
|
||||
const char multipart[] = "multipart";
|
||||
char boundary[100];
|
||||
int boundary_len;
|
||||
struct mg_http_stream_info si;
|
||||
mg_event_handler_t handler;
|
||||
|
||||
if (nc->listener == NULL) {
|
||||
/* No streaming for replies now */
|
||||
@ -5285,24 +5257,22 @@ static void mg_http_multipart_begin(struct mg_connection *nc,
|
||||
|
||||
/* If we reach this place - that is multipart request */
|
||||
|
||||
if (pd->strm_state.len != 0) {
|
||||
if (pd->mp_stream.boundary != NULL) {
|
||||
/*
|
||||
* Another streaming request was in progress,
|
||||
* looks like protocol error
|
||||
*/
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
mbuf_free(&pd->strm_state);
|
||||
} else {
|
||||
si.endpoint = hm->uri;
|
||||
si.boundary.p = boundary;
|
||||
si.boundary.len = boundary_len;
|
||||
si.var_name.p = si.file_name.p = NULL;
|
||||
si.var_name.len = si.file_name.len = 0;
|
||||
pd->mp_stream.boundary = strdup(boundary);
|
||||
pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
|
||||
|
||||
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);
|
||||
pd->endpoint_handler = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
|
||||
if (pd->endpoint_handler == NULL) {
|
||||
pd->endpoint_handler = nc->handler;
|
||||
}
|
||||
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_MULTIPART_REQUEST, hm);
|
||||
|
||||
mbuf_remove(io, req_len);
|
||||
}
|
||||
@ -5313,32 +5283,27 @@ exit_mp:
|
||||
static void mg_http_multipart_continue(struct mg_connection *nc,
|
||||
struct mbuf *io, int ev, void *ev_data) {
|
||||
/* Continue to stream multipart */
|
||||
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_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;
|
||||
mp.file_name = si.file_name.p;
|
||||
boundary = c_strnstr(io->buf, si.boundary.p, io->len);
|
||||
mp.var_name = pd->mp_stream.var_name;
|
||||
mp.file_name = pd->mp_stream.file_name;
|
||||
boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
|
||||
if (boundary == NULL) {
|
||||
mp.data.p = io->buf;
|
||||
mp.data.len = io->len;
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
mbuf_remove(io, io->len);
|
||||
} else {
|
||||
int has_prefix = 0, has_suffix = 0;
|
||||
int has_prefix = 0, has_suffix = 0,
|
||||
boundary_len = strlen(pd->mp_stream.boundary);
|
||||
if (boundary - 2 >= io->buf) {
|
||||
has_prefix = (strncmp(boundary - 2, "--", 2) == 0);
|
||||
}
|
||||
if (boundary + si.boundary.len <= io->buf + io->len) {
|
||||
has_suffix = (strncmp(boundary + si.boundary.len, "--", 2) == 0);
|
||||
if (boundary + boundary_len <= io->buf + io->len) {
|
||||
has_suffix = (strncmp(boundary + boundary_len, "--", 2) == 0);
|
||||
}
|
||||
if (has_prefix && !has_suffix) {
|
||||
/* No suffix - not last boundary */
|
||||
@ -5350,9 +5315,9 @@ static void mg_http_multipart_continue(struct mg_connection *nc,
|
||||
if (num_left > 2) { /* \r\n */
|
||||
mp.data.p = io->buf;
|
||||
mp.data.len = num_left - 2;
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
mp.data.len = 0;
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_END, &mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_END, &mp);
|
||||
mbuf_remove(io, num_left);
|
||||
}
|
||||
|
||||
@ -5362,18 +5327,16 @@ static void mg_http_multipart_continue(struct mg_connection *nc,
|
||||
mp.file_name = filename;
|
||||
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);
|
||||
si.var_name.p = mp.var_name;
|
||||
si.var_name.len = strlen(mp.var_name);
|
||||
si.file_name.p = mp.file_name;
|
||||
si.file_name.len = strlen(mp.file_name);
|
||||
mg_http_store_stream_info(&pd->strm_state, &si);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_BEGIN, &mp);
|
||||
free((void *) pd->mp_stream.var_name);
|
||||
pd->mp_stream.var_name = strdup(mp.var_name);
|
||||
free((void *) pd->mp_stream.file_name);
|
||||
pd->mp_stream.file_name = strdup(mp.file_name);
|
||||
|
||||
mbuf_remove(io, req_len);
|
||||
mp.data.p = io->buf;
|
||||
|
||||
tmp = c_strnstr(io->buf, si.boundary.p, io->len);
|
||||
tmp = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
|
||||
if (tmp == NULL) {
|
||||
mp.data.len = io->len;
|
||||
} else {
|
||||
@ -5382,12 +5345,10 @@ static void mg_http_multipart_continue(struct mg_connection *nc,
|
||||
|
||||
if (mp.data.len != 0) {
|
||||
size_t data_len = mp.data.len;
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_DATA,
|
||||
&mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
if (data_len != io->len) {
|
||||
mp.data.len = 0;
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_END,
|
||||
&mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_END, &mp);
|
||||
}
|
||||
mbuf_remove(io, data_len);
|
||||
}
|
||||
@ -5401,14 +5362,14 @@ static void mg_http_multipart_continue(struct mg_connection *nc,
|
||||
mp.data.p = io->buf;
|
||||
mp.data.len = boundary - io->buf - 4;
|
||||
if (mp.data.len != 0) {
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_DATA, &mp);
|
||||
}
|
||||
|
||||
mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_END, &mp);
|
||||
mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_PART_END, &mp);
|
||||
|
||||
/* Skip epilogue (if any) */
|
||||
mbuf_remove(io, io->len);
|
||||
mbuf_free(&pd->strm_state);
|
||||
mg_http_free_proto_data_mp_stream(&pd->mp_stream);
|
||||
} else {
|
||||
/* Malformed request */
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
@ -7610,10 +7571,13 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
|
||||
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
|
||||
mg_event_handler_t handler) {
|
||||
struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
|
||||
size_t len = strlen(uri_path);
|
||||
mbuf_append(&pd->endpoints, &len, sizeof(len));
|
||||
mbuf_append(&pd->endpoints, uri_path, len + 1);
|
||||
mbuf_append(&pd->endpoints, &handler, sizeof(handler));
|
||||
struct mg_http_endpoint *new_ep =
|
||||
(struct mg_http_endpoint *) calloc(1, sizeof(*new_ep));
|
||||
new_ep->name = strdup(uri_path);
|
||||
new_ep->name_len = strlen(new_ep->name);
|
||||
new_ep->handler = handler;
|
||||
new_ep->next = pd->endpoints;
|
||||
pd->endpoints = new_ep;
|
||||
}
|
||||
|
||||
#endif /* MG_DISABLE_HTTP */
|
||||
|
Loading…
x
Reference in New Issue
Block a user