mirror of
https://github.com/lammertb/libhttp.git
synced 2025-08-07 16:02:55 +03:00
Alternative to mg_upload (Step 47/?)
This commit is contained in:
@@ -156,7 +156,8 @@ FileHandler(struct mg_connection *conn, void *cbdata)
|
|||||||
|
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/* proposed interface */
|
/* proposed interface - will be moved to the header once it is ready for release
|
||||||
|
*/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FORM_FIELD_STORAGE_SKIP = 0x0,
|
FORM_FIELD_STORAGE_SKIP = 0x0,
|
||||||
@@ -181,8 +182,8 @@ struct mg_form_data_handler {
|
|||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_handle_form_data(struct mg_connection *conn,
|
extern int mg_handle_form_data(struct mg_connection *conn,
|
||||||
struct mg_form_data_handler *fdh);
|
struct mg_form_data_handler *fdh);
|
||||||
|
|
||||||
/* end of interface */
|
/* end of interface */
|
||||||
/********************/
|
/********************/
|
||||||
|
@@ -99,8 +99,13 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int mg_handle_form_data(struct mg_connection *conn,
|
/* Process form data.
|
||||||
struct mg_form_data_handler *fdh);
|
* Returns the number of fields handled, or < 0 in case of an error.
|
||||||
|
* Note: It is possible that several fields are handled succesfully (e.g.,
|
||||||
|
* stored in a file), before the request handling is stopped with an
|
||||||
|
* error. In this case a number < 0 is returned as well. */
|
||||||
|
CIVETWEB_API int mg_handle_form_data(struct mg_connection *conn,
|
||||||
|
struct mg_form_data_handler *fdh);
|
||||||
|
|
||||||
/* end of interface */
|
/* end of interface */
|
||||||
/********************/
|
/********************/
|
||||||
@@ -239,6 +244,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
int buf_fill = 0;
|
int buf_fill = 0;
|
||||||
int r;
|
int r;
|
||||||
FILE *fstore = NULL;
|
FILE *fstore = NULL;
|
||||||
|
int field_count = 0;
|
||||||
|
|
||||||
int has_body_data =
|
int has_body_data =
|
||||||
(conn->request_info.content_length > 0) || (conn->is_chunked);
|
(conn->request_info.content_length > 0) || (conn->is_chunked);
|
||||||
@@ -260,7 +266,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
if (strcmp(conn->request_info.request_method, "GET")) {
|
if (strcmp(conn->request_info.request_method, "GET")) {
|
||||||
/* No body data, but not a GET request.
|
/* No body data, but not a GET request.
|
||||||
* This is not a valid form request. */
|
* This is not a valid form request. */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GET request: form data is in the query string. */
|
/* GET request: form data is in the query string. */
|
||||||
@@ -270,7 +276,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
data = conn->request_info.query_string;
|
data = conn->request_info.query_string;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
/* No query string. */
|
/* No query string. */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Split data in a=1&b=xy&c=3&c=4 ... */
|
/* Split data in a=1&b=xy&c=3&c=4 ... */
|
||||||
@@ -296,6 +302,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
* FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
|
* FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
|
||||||
*/
|
*/
|
||||||
memset(path, 0, sizeof(path));
|
memset(path, 0, sizeof(path));
|
||||||
|
field_count++;
|
||||||
field_storage = url_encoded_field_found(conn,
|
field_storage = url_encoded_field_found(conn,
|
||||||
data,
|
data,
|
||||||
(size_t)keylen,
|
(size_t)keylen,
|
||||||
@@ -378,7 +385,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
data = next;
|
data = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return field_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
content_type = mg_get_header(conn, "Content-Type");
|
content_type = mg_get_header(conn, "Content-Type");
|
||||||
@@ -393,7 +400,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
/* The encoding is like in the "GET" case above, but here we read data
|
/* The encoding is like in the "GET" case above, but here we read data
|
||||||
* on the fly */
|
* on the fly */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* TODO(high): Handle (text) fields with data > sizeof(buf). */
|
/* TODO(high): Handle (text) fields with data size > sizeof(buf). */
|
||||||
const char *val;
|
const char *val;
|
||||||
const char *next;
|
const char *next;
|
||||||
ptrdiff_t keylen, vallen;
|
ptrdiff_t keylen, vallen;
|
||||||
@@ -406,7 +413,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
|
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* read error */
|
/* read error */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
if (r != (int)to_read) {
|
if (r != (int)to_read) {
|
||||||
/* TODO: Create a function to get "all_data_read" from
|
/* TODO: Create a function to get "all_data_read" from
|
||||||
@@ -433,6 +440,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
|
|
||||||
/* Call callback */
|
/* Call callback */
|
||||||
memset(path, 0, sizeof(path));
|
memset(path, 0, sizeof(path));
|
||||||
|
field_count++;
|
||||||
field_storage = url_encoded_field_found(conn,
|
field_storage = url_encoded_field_found(conn,
|
||||||
buf,
|
buf,
|
||||||
(size_t)keylen,
|
(size_t)keylen,
|
||||||
@@ -485,7 +493,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
mg_cry(conn,
|
mg_cry(conn,
|
||||||
"%s: Data too long for callback",
|
"%s: Data too long for callback",
|
||||||
__func__);
|
__func__);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Call callback */
|
/* Call callback */
|
||||||
url_encoded_field_get(
|
url_encoded_field_get(
|
||||||
@@ -517,7 +525,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
buf_fill -= used;
|
buf_fill -= used;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return field_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
|
if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
|
||||||
@@ -537,7 +545,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
/* There has to be a BOUNDARY definition in the Content-Type header */
|
/* There has to be a BOUNDARY definition in the Content-Type header */
|
||||||
if (mg_strncasecmp(content_type + 21, "BOUNDARY=", 9)) {
|
if (mg_strncasecmp(content_type + 21, "BOUNDARY=", 9)) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
boundary = content_type + 30;
|
boundary = content_type + 30;
|
||||||
@@ -552,7 +560,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
* any reasonable request from every browser. If it is not
|
* any reasonable request from every browser. If it is not
|
||||||
* fulfilled, it might be a hand-made request, intended to
|
* fulfilled, it might be a hand-made request, intended to
|
||||||
* interfere with the algorithm. */
|
* interfere with the algorithm. */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -562,22 +570,22 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* read error */
|
/* read error */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
buf_fill += r;
|
buf_fill += r;
|
||||||
buf[buf_fill] = 0;
|
buf[buf_fill] = 0;
|
||||||
if (buf_fill < 1) {
|
if (buf_fill < 1) {
|
||||||
/* No data */
|
/* No data */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] != '-' || buf[1] != '-') {
|
if (buf[0] != '-' || buf[1] != '-') {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strncmp(buf + 2, boundary, bl)) {
|
if (strncmp(buf + 2, boundary, bl)) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
|
if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
|
||||||
/* Every part must end with \r\n, if there is another part.
|
/* Every part must end with \r\n, if there is another part.
|
||||||
@@ -585,7 +593,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
if (((size_t)buf_fill != (size_t)(bl + 6))
|
if (((size_t)buf_fill != (size_t)(bl + 6))
|
||||||
|| (strncmp(buf + bl + 2, "--\r\n", 4))) {
|
|| (strncmp(buf + bl + 2, "--\r\n", 4))) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
/* End of the request */
|
/* End of the request */
|
||||||
break;
|
break;
|
||||||
@@ -596,13 +604,13 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
hend = strstr(hbuf, "\r\n\r\n");
|
hend = strstr(hbuf, "\r\n\r\n");
|
||||||
if (!hend) {
|
if (!hend) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_http_headers(&hbuf, &part_header);
|
parse_http_headers(&hbuf, &part_header);
|
||||||
if ((hend + 2) != hbuf) {
|
if ((hend + 2) != hbuf) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip \r\n\r\n */
|
/* Skip \r\n\r\n */
|
||||||
@@ -613,7 +621,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
content_disp = get_header(&part_header, "Content-Disposition");
|
content_disp = get_header(&part_header, "Content-Disposition");
|
||||||
if (!content_disp) {
|
if (!content_disp) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the mandatory name="..." part of the Content-Disposition
|
/* Get the mandatory name="..." part of the Content-Disposition
|
||||||
@@ -621,13 +629,13 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
nbeg = strstr(content_disp, "name=\"");
|
nbeg = strstr(content_disp, "name=\"");
|
||||||
if (!nbeg) {
|
if (!nbeg) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
nbeg += 6;
|
nbeg += 6;
|
||||||
nend = strchr(nbeg, '\"');
|
nend = strchr(nbeg, '\"');
|
||||||
if (!nend) {
|
if (!nend) {
|
||||||
/* Malformed request */
|
/* Malformed request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the optional filename="..." part of the Content-Disposition
|
/* Get the optional filename="..." part of the Content-Disposition
|
||||||
@@ -639,7 +647,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
if (!fend) {
|
if (!fend) {
|
||||||
/* Malformed request (the filename field is optional, but if
|
/* Malformed request (the filename field is optional, but if
|
||||||
* it exists, it needs to be terminated correctly). */
|
* it exists, it needs to be terminated correctly). */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: check Content-Type */
|
/* TODO: check Content-Type */
|
||||||
@@ -650,6 +658,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(path, 0, sizeof(path));
|
memset(path, 0, sizeof(path));
|
||||||
|
field_count++;
|
||||||
field_storage = url_encoded_field_found(conn,
|
field_storage = url_encoded_field_found(conn,
|
||||||
nbeg,
|
nbeg,
|
||||||
(size_t)(nend - nbeg),
|
(size_t)(nend - nbeg),
|
||||||
@@ -670,7 +679,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
if (!next) {
|
if (!next) {
|
||||||
/* TODO: check for an easy way to get longer data */
|
/* TODO: check for an easy way to get longer data */
|
||||||
mg_cry(conn, "%s: Data too long for callback", __func__);
|
mg_cry(conn, "%s: Data too long for callback", __func__);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call callback */
|
/* Call callback */
|
||||||
@@ -727,13 +736,13 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* read error */
|
/* read error */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
buf_fill += r;
|
buf_fill += r;
|
||||||
buf[buf_fill] = 0;
|
buf[buf_fill] = 0;
|
||||||
if (buf_fill < 1) {
|
if (buf_fill < 1) {
|
||||||
/* No data */
|
/* No data */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find boundary */
|
/* Find boundary */
|
||||||
@@ -774,7 +783,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||||
== FORM_FIELD_STORAGE_ABORT) {
|
== FORM_FIELD_STORAGE_ABORT) {
|
||||||
/* Stop parsing the request */
|
/* Stop parsing the request */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove from the buffer */
|
/* Remove from the buffer */
|
||||||
@@ -784,9 +793,9 @@ mg_handle_form_data(struct mg_connection *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* All parts handled */
|
/* All parts handled */
|
||||||
return 0;
|
return field_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unknown Content-Type */
|
/* Unknown Content-Type */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user