Commit 731512a9 authored by Dmitry Frank's avatar Dmitry Frank Committed by Cesanta Bot

Define mg_file_upload_handler() only if needed

Namely, define it if only `MG_ENABLE_HTTP_STREAMING_MULTIPART` and
`MG_ENABLE_FILESYSTEM` are on

PUBLISHED_FROM=3094738a4b76ceb09a3c2374e8d9d914b71c3441
parent 304dbca6
...@@ -6034,122 +6034,6 @@ struct file_upload_state { ...@@ -6034,122 +6034,6 @@ struct file_upload_state {
FILE *fp; FILE *fp;
}; };
void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
mg_fu_fname_fn local_name_fn) {
switch (ev) {
case MG_EV_HTTP_PART_BEGIN: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) calloc(1, sizeof(*fus));
mp->user_data = NULL;
struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
if (lfn.p == NULL || lfn.len == 0) {
LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
mg_printf(nc,
"HTTP/1.1 403 Not Allowed\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Not allowed to upload %s\r\n",
mp->file_name);
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
fus->lfn = (char *) malloc(lfn.len + 1);
memcpy(fus->lfn, lfn.p, lfn.len);
fus->lfn[lfn.len] = '\0';
if (lfn.p != mp->file_name) free((char *) lfn.p);
LOG(LL_DEBUG,
("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
fus->fp = mg_fopen(fus->lfn, "w");
if (fus->fp == NULL) {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
/* Do not close the connection just yet, discard remainder of the data.
* This is because at the time of writing some browsers (Chrome) fail to
* render response before all the data is sent. */
}
mp->user_data = (void *) fus;
break;
}
case MG_EV_HTTP_PART_DATA: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) mp->user_data;
if (fus == NULL || fus->fp == NULL) break;
if (fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
mg_get_errno(), (int) fus->num_recd));
if (mg_get_errno() == ENOSPC
#ifdef SPIFFS_ERR_FULL
|| mg_get_errno() == SPIFFS_ERR_FULL
#endif
) {
mg_printf(nc,
"HTTP/1.1 413 Payload Too Large\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
fus->lfn, (int) fus->num_recd);
} else {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
mg_get_errno(), (int) fus->num_recd);
}
fclose(fus->fp);
remove(fus->lfn);
fus->fp = NULL;
/* Do not close the connection just yet, discard remainder of the data.
* This is because at the time of writing some browsers (Chrome) fail to
* render response before all the data is sent. */
return;
}
fus->num_recd += mp->data.len;
LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
(int) fus->num_recd));
break;
}
case MG_EV_HTTP_PART_END: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) mp->user_data;
if (fus == NULL) break;
if (mp->status >= 0 && fus->fp != NULL) {
LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
fus->lfn, (int) fus->num_recd));
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Ok, %s - %d bytes.\r\n",
mp->file_name, (int) fus->num_recd);
} else {
LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
/*
* mp->status < 0 means connection was terminated, so no reason to send
* HTTP reply
*/
}
if (fus->fp != NULL) fclose(fus->fp);
free(fus->lfn);
free(fus);
mp->user_data = NULL;
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
}
}
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
void mg_set_protocol_http_websocket(struct mg_connection *nc) { void mg_set_protocol_http_websocket(struct mg_connection *nc) {
...@@ -7576,6 +7460,124 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm, ...@@ -7576,6 +7460,124 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
} }
} }
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
mg_fu_fname_fn local_name_fn) {
switch (ev) {
case MG_EV_HTTP_PART_BEGIN: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) calloc(1, sizeof(*fus));
mp->user_data = NULL;
struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
if (lfn.p == NULL || lfn.len == 0) {
LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
mg_printf(nc,
"HTTP/1.1 403 Not Allowed\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Not allowed to upload %s\r\n",
mp->file_name);
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
fus->lfn = (char *) malloc(lfn.len + 1);
memcpy(fus->lfn, lfn.p, lfn.len);
fus->lfn[lfn.len] = '\0';
if (lfn.p != mp->file_name) free((char *) lfn.p);
LOG(LL_DEBUG,
("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
fus->fp = mg_fopen(fus->lfn, "w");
if (fus->fp == NULL) {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
/* Do not close the connection just yet, discard remainder of the data.
* This is because at the time of writing some browsers (Chrome) fail to
* render response before all the data is sent. */
}
mp->user_data = (void *) fus;
break;
}
case MG_EV_HTTP_PART_DATA: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) mp->user_data;
if (fus == NULL || fus->fp == NULL) break;
if (fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
mg_get_errno(), (int) fus->num_recd));
if (mg_get_errno() == ENOSPC
#ifdef SPIFFS_ERR_FULL
|| mg_get_errno() == SPIFFS_ERR_FULL
#endif
) {
mg_printf(nc,
"HTTP/1.1 413 Payload Too Large\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
fus->lfn, (int) fus->num_recd);
} else {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
mg_get_errno(), (int) fus->num_recd);
}
fclose(fus->fp);
remove(fus->lfn);
fus->fp = NULL;
/* Do not close the connection just yet, discard remainder of the data.
* This is because at the time of writing some browsers (Chrome) fail to
* render response before all the data is sent. */
return;
}
fus->num_recd += mp->data.len;
LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
(int) fus->num_recd));
break;
}
case MG_EV_HTTP_PART_END: {
struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus =
(struct file_upload_state *) mp->user_data;
if (fus == NULL) break;
if (mp->status >= 0 && fus->fp != NULL) {
LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
fus->lfn, (int) fus->num_recd));
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Ok, %s - %d bytes.\r\n",
mp->file_name, (int) fus->num_recd);
} else {
LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
/*
* mp->status < 0 means connection was terminated, so no reason to send
* HTTP reply
*/
}
if (fus->fp != NULL) fclose(fus->fp);
free(fus->lfn);
free(fus);
mp->user_data = NULL;
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
}
}
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
#endif /* MG_ENABLE_FILESYSTEM */ #endif /* MG_ENABLE_FILESYSTEM */
/* returns 0 on success, -1 on error */ /* returns 0 on success, -1 on error */
......
...@@ -4558,37 +4558,6 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm, ...@@ -4558,37 +4558,6 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
const char *path, const struct mg_str mime_type, const char *path, const struct mg_str mime_type,
const struct mg_str extra_headers); const struct mg_str extra_headers);
#endif /* MG_ENABLE_FILESYSTEM */
/*
* Registers a callback for a specified http endpoint
* Note: if callback is registered it is called instead of the
* callback provided in mg_bind
*
* Example code snippet:
*
* ```c
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* void init() {
* nc = mg_bind(&mgr, local_addr, cb1);
* mg_register_http_endpoint(nc, "/hello1", handle_hello1);
* mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2);
* }
* ```
*/
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
mg_event_handler_t handler);
#if MG_ENABLE_HTTP_STREAMING_MULTIPART #if MG_ENABLE_HTTP_STREAMING_MULTIPART
...@@ -4631,6 +4600,37 @@ typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, ...@@ -4631,6 +4600,37 @@ typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc,
void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
mg_fu_fname_fn local_name_fn); mg_fu_fname_fn local_name_fn);
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
#endif /* MG_ENABLE_FILESYSTEM */
/*
* Registers a callback for a specified http endpoint
* Note: if callback is registered it is called instead of the
* callback provided in mg_bind
*
* Example code snippet:
*
* ```c
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* void init() {
* nc = mg_bind(&mgr, local_addr, cb1);
* mg_register_http_endpoint(nc, "/hello1", handle_hello1);
* mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2);
* }
* ```
*/
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
mg_event_handler_t handler);
/* /*
* Authenticates a HTTP request against an opened password file. * Authenticates a HTTP request against an opened password file.
......
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