Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
96150bf5
Commit
96150bf5
authored
Mar 31, 2016
by
Deomid Ryabkov
Committed by
rojer
Apr 01, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Commonize file upload and make it part of Mongoose
PUBLISHED_FROM=23819ed308aeb8c1d6bdb08f5edd257df458ab38
parent
f49df515
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
167 additions
and
0 deletions
+167
-0
struct_mg_http_multipart_part.md
docs/c-api/http.h/struct_mg_http_multipart_part.md
+1
-0
mongoose.c
mongoose.c
+125
-0
mongoose.h
mongoose.h
+41
-0
No files found.
docs/c-api/http.h/struct_mg_http_multipart_part.md
View file @
96150bf5
...
...
@@ -8,6 +8,7 @@ signature: |
const char *var_name;
struct mg_str data;
int status; /* <0 on error */
void *user_data;
};
---
...
...
mongoose.c
View file @
96150bf5
...
...
@@ -4254,6 +4254,7 @@ struct mg_http_multipart_stream {
int
boundary_len
;
const
char
*
var_name
;
const
char
*
file_name
;
void
*
user_data
;
int
prev_io_len
;
enum
mg_http_multipart_stream_state
state
;
int
processing_part
;
...
...
@@ -5342,9 +5343,11 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev,
mp
.
var_name
=
pd
->
mp_stream
.
var_name
;
mp
.
file_name
=
pd
->
mp_stream
.
file_name
;
mp
.
user_data
=
pd
->
mp_stream
.
user_data
;
mp
.
data
.
p
=
data
;
mp
.
data
.
len
=
data_len
;
mg_call
(
c
,
pd
->
endpoint_handler
,
ev
,
&
mp
);
pd
->
mp_stream
.
user_data
=
mp
.
user_data
;
}
static
int
mg_http_multipart_got_chunk
(
struct
mg_connection
*
c
)
{
...
...
@@ -5526,6 +5529,128 @@ static void mg_http_multipart_continue(struct mg_connection *c) {
}
}
struct
file_upload_state
{
char
*
lfn
;
size_t
num_recd
;
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
=
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
,
errno
));
mg_printf
(
nc
,
"Failed to open %s: %d
\n
"
,
fus
->
lfn
,
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
,
errno
,
(
int
)
fus
->
num_recd
));
if
(
errno
==
ENOSPC
#ifdef SPIFFS_ERR_FULL
||
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
,
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 */
void
mg_set_protocol_http_websocket
(
struct
mg_connection
*
nc
)
{
...
...
mongoose.h
View file @
96150bf5
...
...
@@ -1994,6 +1994,7 @@ struct mg_http_multipart_part {
const
char
*
var_name
;
struct
mg_str
data
;
int
status
;
/* <0 on error */
void
*
user_data
;
};
/* HTTP and websocket events. void *ev_data is described in a comment. */
...
...
@@ -2526,6 +2527,46 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
void
mg_register_http_endpoint
(
struct
mg_connection
*
nc
,
const
char
*
uri_path
,
mg_event_handler_t
handler
);
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
/*
* File upload handler.
* This handler can be used to implement file uploads with minimum code.
* This handler will process MG_EV_HTTP_PART_* events and store file data into
* a local file.
* `local_name_fn` will be invoked with whatever name was provided by the client
* and will expect the name of the local file to open. Return value of NULL will
* abort file upload (client will get a "403 Forbidden" response). If non-null,
* the returned string must be heap-allocated and will be freed by the caller.
* Exception: it is ok to return the same string verbatim.
*
* Example:
*
* ```c
* struct mg_str upload_fname(struct mg_connection *nc, struct mg_str fname) {
* // Just return the same filename. Do not actually do this except in test!
* // fname is user-controlled and needs to be sanitized.
* return fname;
* }
* void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
* switch (ev) {
* ...
* case MG_EV_HTTP_PART_BEGIN:
* case MG_EV_HTTP_PART_DATA:
* case MG_EV_HTTP_PART_END:
* mg_file_upload_handler(nc, ev, ev_data, upload_fname);
* break;
* }
* }
* ```
*/
typedef
struct
mg_str
(
*
mg_fu_fname_fn
)(
struct
mg_connection
*
nc
,
struct
mg_str
fname
);
void
mg_file_upload_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
,
mg_fu_fname_fn
local_name_fn
);
#endif
/* MG_ENABLE_HTTP_STREAMING_MULTIPART */
#ifdef __cplusplus
}
#endif
/* __cplusplus */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment