mirror of
https://github.com/lammertb/libhttp.git
synced 2025-07-29 21:01:13 +03:00
Alternative to mg_upload (Step 46/?)
This commit is contained in:
@ -159,11 +159,11 @@ FileHandler(struct mg_connection *conn, void *cbdata)
|
||||
/* proposed interface */
|
||||
|
||||
enum {
|
||||
FORM_DISPOSITION_SKIP = 0x0,
|
||||
FORM_DISPOSITION_GET = 0x1,
|
||||
FORM_DISPOSITION_STORE = 0x2,
|
||||
/* FORM_DISPOSITION_READ = 0x3, not in the first step */
|
||||
FORM_DISPOSITION_ABORT = 0x10
|
||||
FORM_FIELD_STORAGE_SKIP = 0x0,
|
||||
FORM_FIELD_STORAGE_GET = 0x1,
|
||||
FORM_FIELD_STORAGE_STORE = 0x2,
|
||||
/* FORM_FIELD_STORAGE_READ = 0x3, not in the first step */
|
||||
FORM_FIELD_STORAGE_ABORT = 0x10
|
||||
};
|
||||
|
||||
|
||||
@ -174,7 +174,6 @@ struct mg_form_data_handler {
|
||||
size_t pathlen,
|
||||
void *user_data);
|
||||
int (*field_get)(const char *key,
|
||||
const char *filename,
|
||||
const char *value,
|
||||
size_t valuelen,
|
||||
void *user_data);
|
||||
@ -202,18 +201,14 @@ field_found(const char *key,
|
||||
|
||||
if (filename && *filename) {
|
||||
_snprintf(path, pathlen, "C:\\tmp\\%s", filename);
|
||||
return FORM_DISPOSITION_STORE;
|
||||
return FORM_FIELD_STORAGE_STORE;
|
||||
}
|
||||
return FORM_DISPOSITION_GET;
|
||||
return FORM_FIELD_STORAGE_GET;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
field_get(const char *key,
|
||||
const char *filename,
|
||||
const char *value,
|
||||
size_t valuelen,
|
||||
void *user_data)
|
||||
field_get(const char *key, const char *value, size_t valuelen, void *user_data)
|
||||
{
|
||||
struct mg_connection *conn = (struct mg_connection *)user_data;
|
||||
|
||||
|
@ -27,31 +27,78 @@
|
||||
/**********************/
|
||||
/* proposed interface */
|
||||
|
||||
enum {
|
||||
FORM_DISPOSITION_SKIP = 0x0,
|
||||
FORM_DISPOSITION_GET = 0x1,
|
||||
FORM_DISPOSITION_STORE = 0x2,
|
||||
/* FORM_DISPOSITION_READ = 0x3, not in the first step */
|
||||
FORM_DISPOSITION_ABORT = 0x10
|
||||
};
|
||||
|
||||
|
||||
/* This structure contains callback functions for handling form fields.
|
||||
It is used as an argument to mg_handle_form_data.
|
||||
*/
|
||||
struct mg_form_data_handler {
|
||||
/* This callback is called, if a new field is about to be read.
|
||||
* Parameters:
|
||||
* key: Name of the field ("name" property of the HTML input field).
|
||||
* filename: Name of a file to upload, at the client computer.
|
||||
* Only set for input fields of type "file", otherwise NULL.
|
||||
* path: Output parameter: File name (incl. path) to store the file
|
||||
* at the server computer. Only used if FORM_FIELD_STORAGE_STORE
|
||||
* is returned by this callback.
|
||||
* pathlen: Length of the buffer for path.
|
||||
* user_data: Value of the member user_data of mg_form_data_handler
|
||||
* Return value:
|
||||
* The callback must return the intended storage for this field
|
||||
* (See FORM_FIELD_STORAGE_*).
|
||||
*/
|
||||
int (*field_found)(const char *key,
|
||||
const char *filename,
|
||||
char *path,
|
||||
size_t pathlen,
|
||||
void *user_data);
|
||||
|
||||
/* If the "field_found" callback returned FORM_FIELD_STORAGE_GET,
|
||||
* this callback will receive the field data.
|
||||
* Parameters:
|
||||
* key: Name of the field ("name" property of the HTML input field).
|
||||
* value: Value of the input field.
|
||||
* user_data: Value of the member user_data of mg_form_data_handler
|
||||
* Return value:
|
||||
* TODO: Needs to be defined.
|
||||
*/
|
||||
int (*field_get)(const char *key,
|
||||
const char *filename,
|
||||
const char *value,
|
||||
size_t valuelen,
|
||||
void *user_data);
|
||||
|
||||
/* If the "field_found" callback returned FORM_FIELD_STORAGE_STORE,
|
||||
* the data will be stored into a file. If the file has been written
|
||||
* sucessfully, this callback will be called.
|
||||
* Parameters:
|
||||
* path: Path of the file stored at the server.
|
||||
* user_data: Value of the member user_data of mg_form_data_handler
|
||||
* Return value:
|
||||
* TODO: Needs to be defined.
|
||||
*/
|
||||
int (*field_stored)(const char *path, void *user_data);
|
||||
|
||||
/* User supplied argument, passed to all callbacks. */
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
|
||||
/* Return values definition for the "field_found" callback in
|
||||
* mg_form_data_handler. */
|
||||
enum {
|
||||
/* Skip this field (neither get nor store it). Continue with the
|
||||
* next field. */
|
||||
FORM_FIELD_STORAGE_SKIP = 0x0,
|
||||
/* Get the field value. */
|
||||
FORM_FIELD_STORAGE_GET = 0x1,
|
||||
/* Store the field value into a file. */
|
||||
FORM_FIELD_STORAGE_STORE = 0x2,
|
||||
/* Read the filed in chunks using a read function. */
|
||||
/* FORM_FIELD_STORAGE_READ = 0x3, not in the first step */
|
||||
/* Stop parsing this request. Skip the remaining fields. */
|
||||
FORM_FIELD_STORAGE_ABORT = 0x10
|
||||
};
|
||||
|
||||
|
||||
int mg_handle_form_data(struct mg_connection *conn,
|
||||
struct mg_form_data_handler *fdh);
|
||||
|
||||
@ -77,7 +124,7 @@ url_encoded_field_found(const struct mg_connection *conn,
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
|
||||
return FORM_DISPOSITION_SKIP;
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
@ -91,7 +138,7 @@ url_encoded_field_found(const struct mg_connection *conn,
|
||||
|| (filename_dec_len < 0)) {
|
||||
/* Log error message and skip this field. */
|
||||
mg_cry(conn, "%s: Cannot decode filename", __func__);
|
||||
return FORM_DISPOSITION_SKIP;
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
} else {
|
||||
filename_dec[0] = 0;
|
||||
@ -106,14 +153,11 @@ static int
|
||||
url_encoded_field_get(const struct mg_connection *conn,
|
||||
const char *key,
|
||||
size_t key_len,
|
||||
const char *filename,
|
||||
size_t filename_len,
|
||||
const char *value,
|
||||
size_t value_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
char key_dec[1024];
|
||||
char filename_dec[1024];
|
||||
|
||||
char *value_dec = mg_malloc(value_len + 1);
|
||||
int value_dec_len;
|
||||
@ -124,26 +168,15 @@ url_encoded_field_get(const struct mg_connection *conn,
|
||||
"%s: Not enough memory (required: %lu)",
|
||||
__func__,
|
||||
(unsigned long)(value_len + 1));
|
||||
return FORM_DISPOSITION_ABORT;
|
||||
return FORM_FIELD_STORAGE_ABORT;
|
||||
}
|
||||
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
if (filename) {
|
||||
mg_url_decode(filename,
|
||||
(int)filename_len,
|
||||
filename_dec,
|
||||
(int)sizeof(filename_dec),
|
||||
1);
|
||||
} else {
|
||||
filename_dec[0] = 0;
|
||||
}
|
||||
|
||||
value_dec_len =
|
||||
mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
|
||||
|
||||
return fdh->field_get(key_dec,
|
||||
filename_dec,
|
||||
value_dec,
|
||||
(size_t)value_dec_len,
|
||||
fdh->user_data);
|
||||
@ -202,7 +235,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
const char *content_type;
|
||||
char path[512];
|
||||
char buf[1024];
|
||||
int disposition;
|
||||
int field_storage;
|
||||
int buf_fill = 0;
|
||||
int r;
|
||||
FILE *fstore = NULL;
|
||||
@ -252,25 +285,25 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
keylen = val - data;
|
||||
|
||||
/* In every "field_found" callback we ask what to do with the
|
||||
* data ("disposition"). This could be:
|
||||
* FORM_DISPOSITION_SKIP (0) ... ignore the value of this field
|
||||
* FORM_DISPOSITION_GET (1) ... read the data and call the get
|
||||
* data ("field_storage"). This could be:
|
||||
* FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
|
||||
* FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
|
||||
* callback function
|
||||
* FORM_DISPOSITION_STORE (2) ... store the data in a file
|
||||
* FORM_DISPOSITION_READ (3) ... let the user read the data
|
||||
* FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
|
||||
* FORM_FIELD_STORAGE_READ (3) ... let the user read the data
|
||||
* (for parsing long data on the fly)
|
||||
* (currently not implemented)
|
||||
* FORM_DISPOSITION_ABORT (flag) ... stop parsing
|
||||
* FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
|
||||
*/
|
||||
memset(path, 0, sizeof(path));
|
||||
disposition = url_encoded_field_found(conn,
|
||||
data,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
data,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
val++;
|
||||
next = strchr(val, '&');
|
||||
@ -282,18 +315,12 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
next = val + vallen;
|
||||
}
|
||||
|
||||
if (disposition == FORM_DISPOSITION_GET) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
/* Call callback */
|
||||
url_encoded_field_get(conn,
|
||||
data,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
val,
|
||||
(size_t)vallen,
|
||||
fdh);
|
||||
url_encoded_field_get(
|
||||
conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
|
||||
}
|
||||
if (disposition == FORM_DISPOSITION_STORE) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
fstore = fopen(path, "wb");
|
||||
if (fstore != NULL) {
|
||||
@ -328,21 +355,21 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
/* if (disposition == FORM_DISPOSITION_READ) { */
|
||||
/* The idea of "disposition=read" is to let the API user read
|
||||
/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
|
||||
/* The idea of "field_storage=read" is to let the API user read
|
||||
* data chunk by chunk and to some data processing on the fly.
|
||||
* This should avoid the need to store data in the server:
|
||||
* It should neither be stored in memory, like
|
||||
* "disposition=get" does, nor in a file like
|
||||
* "disposition=store".
|
||||
* "field_storage=get" does, nor in a file like
|
||||
* "field_storage=store".
|
||||
* However, for a "GET" request this does not make any much
|
||||
* sense, since the data is already stored in memory, as it is
|
||||
* part of the query string.
|
||||
*/
|
||||
/* } */
|
||||
|
||||
if ((disposition & FORM_DISPOSITION_ABORT)
|
||||
== FORM_DISPOSITION_ABORT) {
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
@ -406,22 +433,22 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
|
||||
/* Call callback */
|
||||
memset(path, 0, sizeof(path));
|
||||
disposition = url_encoded_field_found(conn,
|
||||
buf,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
buf,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
if ((disposition & FORM_DISPOSITION_ABORT)
|
||||
== FORM_DISPOSITION_ABORT) {
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
|
||||
if (disposition == FORM_DISPOSITION_STORE) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
fstore = fopen(path, "wb");
|
||||
if (!fstore) {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
@ -452,7 +479,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
}
|
||||
if (disposition == FORM_DISPOSITION_GET) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
if (!end_of_key_value_pair_found && !all_data_read) {
|
||||
/* TODO: check for an easy way to get longer data */
|
||||
mg_cry(conn,
|
||||
@ -461,14 +488,8 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
return 0;
|
||||
}
|
||||
/* Call callback */
|
||||
url_encoded_field_get(conn,
|
||||
buf,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
val,
|
||||
(size_t)vallen,
|
||||
fdh);
|
||||
url_encoded_field_get(
|
||||
conn, buf, (size_t)keylen, val, (size_t)vallen, fdh);
|
||||
}
|
||||
|
||||
if (!end_of_key_value_pair_found) {
|
||||
@ -629,20 +650,23 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
}
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
disposition = url_encoded_field_found(conn,
|
||||
nbeg,
|
||||
(size_t)(nend - nbeg),
|
||||
fbeg,
|
||||
(size_t)(fend - fbeg),
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
nbeg,
|
||||
(size_t)(nend - nbeg),
|
||||
fbeg,
|
||||
(size_t)(fend - fbeg),
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
/* If the boundary is already in the buffer, get the address,
|
||||
* otherwise next will be NULL. */
|
||||
next = search_boundary(hbuf, buf - hbuf + buf_fill, boundary, bl);
|
||||
next = search_boundary(hbuf,
|
||||
(size_t)((buf - hbuf) + buf_fill),
|
||||
boundary,
|
||||
bl);
|
||||
|
||||
if (disposition == FORM_DISPOSITION_GET) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
if (!next) {
|
||||
/* TODO: check for an easy way to get longer data */
|
||||
mg_cry(conn, "%s: Data too long for callback", __func__);
|
||||
@ -653,14 +677,12 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
url_encoded_field_get(conn,
|
||||
nbeg,
|
||||
(size_t)(nend - nbeg),
|
||||
fbeg,
|
||||
(size_t)(fend - fbeg),
|
||||
hend,
|
||||
(size_t)(next - hend),
|
||||
fdh);
|
||||
}
|
||||
|
||||
if (disposition == FORM_DISPOSITION_STORE) {
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
size_t towrite, n;
|
||||
size_t flen = 0;
|
||||
@ -715,7 +737,7 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
}
|
||||
|
||||
/* Find boundary */
|
||||
next = search_boundary(buf, buf_fill, boundary, bl);
|
||||
next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
|
||||
}
|
||||
|
||||
if (fstore) {
|
||||
@ -749,8 +771,8 @@ mg_handle_form_data(struct mg_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
if ((disposition & FORM_DISPOSITION_ABORT)
|
||||
== FORM_DISPOSITION_ABORT) {
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user