diff --git a/docs/c-api/http.h/mg_set_protocol_http_websocket.md b/docs/c-api/http.h/mg_set_protocol_http_websocket.md index 3229b651..a78ff358 100644 --- a/docs/c-api/http.h/mg_set_protocol_http_websocket.md +++ b/docs/c-api/http.h/mg_set_protocol_http_websocket.md @@ -12,11 +12,6 @@ The user-defined event handler will receive following extra events: - MG_EV_HTTP_REQUEST: HTTP request has arrived. Parsed HTTP request is passed as `struct http_message` through the handler's `void *ev_data` pointer. -- MG_EV_HTTP_MULTIPART_REQUEST: A multipart POST request has received. - This event is sent before body is parsed. After this, the user - should expect a sequence of MG_EV_HTTP_PART_BEGIN/DATA/END requests. - This is also the last time when headers and other request fields are - accessible. - MG_EV_HTTP_REPLY: The HTTP reply has arrived. The parsed HTTP reply is passed as `struct http_message` through the handler's `void *ev_data` pointer. @@ -38,14 +33,27 @@ The user-defined event handler will receive following extra events: handshake. `ev_data` is `NULL`. - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is `struct websocket_message *` -- MG_EV_HTTP_PART_BEGIN: new part of multipart message is started, - extra parameters are passed in mg_http_multipart_part -- MG_EV_HTTP_PART_DATA: new portion of data from the multiparted message - no additional headers are available, only data and data size -- MG_EV_HTTP_PART_END: final boundary received, analogue to maybe used to - find the end of packet - Note: Mongoose should be compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART - to enable MG_EV_HTTP_MULTIPART_REQUEST, MG_EV_HTTP_REQUEST_END, - MG_EV_HTTP_REQUEST_CANCEL, MG_EV_HTTP_PART_BEGIN, MG_EV_HTTP_PART_DATA, - MG_EV_HTTP_PART_END constants + +When compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART, Mongoose parses +multipart requests and splits them into separate events: +- MG_EV_HTTP_MULTIPART_REQUEST: Start of the request. + This event is sent before body is parsed. After this, the user + should expect a sequence of PART_BEGIN/DATA/END requests. + This is also the last time when headers and other request fields are + accessible. +- MG_EV_HTTP_PART_BEGIN: Start of a part of a multipart message. + Argument: mg_http_multipart_part with var_name and file_name set + (if present). No data is passed in this message. +- MG_EV_HTTP_PART_DATA: new portion of data from the multipart message. + Argument: mg_http_multipart_part. var_name and file_name are preserved, + data is available in mg_http_multipart_part.data. +- MG_EV_HTTP_PART_END: End of the current part. var_name, file_name are + the same, no data in the message. If status is 0, then the part is + properly terminated with a boundary, status < 0 means that connection + was terminated. +- MG_EV_HTTP_MULTIPART_REQUEST_END: End of the multipart request. + Argument: mg_http_multipart_part, var_name and file_name are NULL, + status = 0 means request was properly closed, < 0 means connection + was terminated (note: in this case both PART_END and REQUEST_END are + delivered). diff --git a/mongoose.c b/mongoose.c index 7911cc24..9a311930 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4506,17 +4506,20 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { #if MG_ENABLE_HTTP_STREAMING_MULTIPART if (pd->mp_stream.boundary != NULL) { /* - * Multipart message is in progress, but we get close - * MG_EV_HTTP_PART_END with error flag + * Multipart message is in progress, but connection is closed. + * Finish part and request with an error flag. */ struct mg_http_multipart_part mp; memset(&mp, 0, sizeof(mp)); - mp.status = -1; 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); + mp.var_name = NULL; + mp.file_name = NULL; + mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler), + MG_EV_HTTP_MULTIPART_REQUEST_END, &mp); } else #endif if (io->len > 0 && mg_parse_http(io->buf, io->len, hm, is_req) > 0) { @@ -4766,6 +4769,11 @@ static int mg_http_multipart_finalize(struct mg_connection *c) { struct mg_http_proto_data *pd = mg_http_get_proto_data(c); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0); + free((void *) pd->mp_stream.file_name); + pd->mp_stream.file_name = NULL; + free((void *) pd->mp_stream.var_name); + pd->mp_stream.var_name = NULL; + mg_http_multipart_call_handler(c, MG_EV_HTTP_MULTIPART_REQUEST_END, NULL, 0); mg_http_free_proto_data_mp_stream(&pd->mp_stream); pd->mp_stream.state = MPS_FINISHED; @@ -4783,11 +4791,13 @@ static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) { boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len); if (boundary != NULL) { - if (io->len - (boundary - io->buf) < 4) { + const char *boundary_end = (boundary + pd->mp_stream.boundary_len); + if (io->len - (boundary_end - io->buf) < 4) { return 0; } - if (memcmp(boundary + pd->mp_stream.boundary_len, "--", 2) == 0) { + if (memcmp(boundary_end, "--\r\n", 4) == 0) { pd->mp_stream.state = MPS_FINALIZE; + mbuf_remove(io, (boundary_end - io->buf) + 4); } else { pd->mp_stream.state = MPS_GOT_BOUNDARY; } diff --git a/mongoose.h b/mongoose.h index c0148dc4..08b6b90b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2823,10 +2823,11 @@ struct mg_ssi_call_ctx { #endif #if MG_ENABLE_HTTP_STREAMING_MULTIPART -#define MG_EV_HTTP_MULTIPART_REQUEST 121 /* struct http_message */ -#define MG_EV_HTTP_PART_BEGIN 122 /* struct mg_http_multipart_part */ -#define MG_EV_HTTP_PART_DATA 123 /* struct mg_http_multipart_part */ -#define MG_EV_HTTP_PART_END 124 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_MULTIPART_REQUEST 121 /* struct http_message */ +#define MG_EV_HTTP_PART_BEGIN 122 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_PART_DATA 123 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_PART_END 124 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_MULTIPART_REQUEST_END 125 /* struct mg_http_multipart_part */ #endif /* @@ -2836,11 +2837,6 @@ struct mg_ssi_call_ctx { * - MG_EV_HTTP_REQUEST: HTTP request has arrived. Parsed HTTP request * is passed as * `struct http_message` through the handler's `void *ev_data` pointer. - * - MG_EV_HTTP_MULTIPART_REQUEST: A multipart POST request has received. - * This event is sent before body is parsed. After this, the user - * should expect a sequence of MG_EV_HTTP_PART_BEGIN/DATA/END requests. - * This is also the last time when headers and other request fields are - * accessible. * - MG_EV_HTTP_REPLY: The HTTP reply has arrived. The parsed HTTP reply is * passed as `struct http_message` through the handler's `void *ev_data` * pointer. @@ -2862,16 +2858,29 @@ struct mg_ssi_call_ctx { * handshake. `ev_data` is `NULL`. * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is * `struct websocket_message *` - * - MG_EV_HTTP_PART_BEGIN: new part of multipart message is started, - * extra parameters are passed in mg_http_multipart_part - * - MG_EV_HTTP_PART_DATA: new portion of data from the multiparted message - * no additional headers are available, only data and data size - * - MG_EV_HTTP_PART_END: final boundary received, analogue to maybe used to - * find the end of packet - * Note: Mongoose should be compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART - * to enable MG_EV_HTTP_MULTIPART_REQUEST, MG_EV_HTTP_REQUEST_END, - * MG_EV_HTTP_REQUEST_CANCEL, MG_EV_HTTP_PART_BEGIN, MG_EV_HTTP_PART_DATA, - * MG_EV_HTTP_PART_END constants + * + * When compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART, Mongoose parses + * multipart requests and splits them into separate events: + * - MG_EV_HTTP_MULTIPART_REQUEST: Start of the request. + * This event is sent before body is parsed. After this, the user + * should expect a sequence of PART_BEGIN/DATA/END requests. + * This is also the last time when headers and other request fields are + * accessible. + * - MG_EV_HTTP_PART_BEGIN: Start of a part of a multipart message. + * Argument: mg_http_multipart_part with var_name and file_name set + * (if present). No data is passed in this message. + * - MG_EV_HTTP_PART_DATA: new portion of data from the multipart message. + * Argument: mg_http_multipart_part. var_name and file_name are preserved, + * data is available in mg_http_multipart_part.data. + * - MG_EV_HTTP_PART_END: End of the current part. var_name, file_name are + * the same, no data in the message. If status is 0, then the part is + * properly terminated with a boundary, status < 0 means that connection + * was terminated. + * - MG_EV_HTTP_MULTIPART_REQUEST_END: End of the multipart request. + * Argument: mg_http_multipart_part, var_name and file_name are NULL, + * status = 0 means request was properly closed, < 0 means connection + * was terminated (note: in this case both PART_END and REQUEST_END are + * delivered). */ void mg_set_protocol_http_websocket(struct mg_connection *nc);