1
0
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:
bel
2016-02-12 01:40:44 +01:00
parent af913ce5fc
commit 30b7abbd20
2 changed files with 123 additions and 106 deletions

View File

@ -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;

View File

@ -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,18 +285,18 @@ 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,
field_storage = url_encoded_field_found(conn,
data,
(size_t)keylen,
NULL,
@ -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,7 +433,7 @@ mg_handle_form_data(struct mg_connection *conn,
/* Call callback */
memset(path, 0, sizeof(path));
disposition = url_encoded_field_found(conn,
field_storage = url_encoded_field_found(conn,
buf,
(size_t)keylen,
NULL,
@ -415,13 +442,13 @@ mg_handle_form_data(struct mg_connection *conn,
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,7 +650,7 @@ mg_handle_form_data(struct mg_connection *conn,
}
memset(path, 0, sizeof(path));
disposition = url_encoded_field_found(conn,
field_storage = url_encoded_field_found(conn,
nbeg,
(size_t)(nend - nbeg),
fbeg,
@ -640,9 +661,12 @@ mg_handle_form_data(struct mg_connection *conn,
/* 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;
}