1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-05 16:55:50 +03:00

lua_request.c: Add support for parsing multipart form data via r:parsebody. This is a bit RFC-centric, suggestions are most welcome.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1420286 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Daniel Gruno
2012-12-11 17:09:40 +00:00
parent c945772cba
commit 1a50285096

View File

@@ -21,6 +21,7 @@
#include "scoreboard.h"
APLOG_USE_MODULE(lua);
#define POST_MAX_VARS 500
typedef char *(*req_field_string_f) (request_rec * r);
typedef int (*req_field_int_f) (request_rec * r);
@@ -151,6 +152,46 @@ static int req_aprtable2luatable_cb(void *l, const char *key,
return 1;
}
/*
=======================================================================================================================
lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size): Reads any additional form data sent in POST/PUT
requests. Used for multipart POST data.
=======================================================================================================================
*/
static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size)
{
int rc = OK;
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
return (rc);
}
if (ap_should_client_block(r)) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
char argsbuffer[HUGE_STRING_LEN];
apr_off_t rsize, len_read, rpos = 0;
apr_off_t length = r->remaining;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
*rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
*size = length;
while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
if ((rpos + len_read) > length) {
rsize = length - rpos;
}
else {
rsize = len_read;
}
memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
rpos += rsize;
}
}
return (rc);
}
/* r:parseargs() returning a lua table */
static int req_parseargs(lua_State *L)
{
@@ -163,7 +204,7 @@ static int req_parseargs(lua_State *L)
return 2; /* [table<string, string>, table<string, array<string>>] */
}
/* r:parsebody() returning a lua table */
/* r:parsebody(): Parses regular (url-enocded) or multipart POST data and returns two tables*/
static int req_parsebody(lua_State *L)
{
apr_array_header_t *pairs;
@@ -171,21 +212,64 @@ static int req_parsebody(lua_State *L)
int res;
apr_size_t size;
apr_size_t max_post_size;
char *buffer;
char *multipart;
const char *contentType;
request_rec *r = ap_lua_check_request_rec(L, 1);
max_post_size = (apr_size_t) luaL_optint(L, 2, MAX_STRING_LEN);
multipart = apr_pcalloc(r->pool, 256);
contentType = apr_table_get(r->headers_in, "Content-Type");
lua_newtable(L);
lua_newtable(L); /* [table, table] */
res = ap_parse_form_data(r, NULL, &pairs, -1, max_post_size);
if (res == OK) {
while(pairs && !apr_is_empty_array(pairs)) {
ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs);
apr_brigade_length(pair->value, 1, &len);
size = (apr_size_t) len;
buffer = apr_palloc(r->pool, size + 1);
apr_brigade_flatten(pair->value, buffer, &size);
buffer[len] = 0;
req_aprtable2luatable_cb(L, pair->name, buffer);
lua_newtable(L); /* [table, table] */
if (contentType != NULL && (sscanf(contentType, "multipart/form-data; boundary=%250c", multipart) == 1)) {
char *buffer, *key, *filename;
char *start = 0, *end = 0, *crlf = 0;
const char *data;
int i, z;
size_t vlen = 0;
size_t len = 0;
if (lua_read_body(r, &data, &size) != OK) {
return 2;
}
len = strlen(multipart);
i = 0;
for
(
start = strstr((char *) data, multipart);
start != start + size;
start = end
) {
i++;
if (i == POST_MAX_VARS) break;
end = strstr((char *) (start + 1), multipart);
if (!end) end = start + size;
crlf = strstr((char *) start, "\r\n\r\n");
if (!crlf) break;
key = (char *) apr_pcalloc(r->pool, 256);
filename = (char *) apr_pcalloc(r->pool, 256);
buffer = (char *) apr_palloc(r->pool, end - crlf);
vlen = end - crlf - 8;
memcpy(buffer, crlf + 4, vlen);
sscanf(start + len + 2,
"Content-Disposition: form-data; name=\"%255[^\"]\"; filename=\"%255[^\"]\"",
key, filename);
if (strlen(key)) {
req_aprtable2luatable_cb(L, key, buffer);
}
}
}
else {
char *buffer;
res = ap_parse_form_data(r, NULL, &pairs, -1, max_post_size);
if (res == OK) {
while(pairs && !apr_is_empty_array(pairs)) {
ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs);
apr_brigade_length(pair->value, 1, &len);
size = (apr_size_t) len;
buffer = apr_palloc(r->pool, size + 1);
apr_brigade_flatten(pair->value, buffer, &size);
buffer[len] = 0;
req_aprtable2luatable_cb(L, pair->name, buffer);
}
}
}
return 2; /* [table<string, string>, table<string, array<string>>] */