diff options
Diffstat (limited to 'modules/lua/lua_request.c')
-rw-r--r-- | modules/lua/lua_request.c | 225 |
1 files changed, 120 insertions, 105 deletions
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c index 77a88b4..bec8580 100644 --- a/modules/lua/lua_request.c +++ b/modules/lua/lua_request.c @@ -235,33 +235,36 @@ static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size, { int rc = OK; + *rbuf = NULL; + *size = 0; + 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 len_read = -1; + apr_off_t rpos = 0; apr_off_t length = r->remaining; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ if (maxsize != 0 && length > maxsize) { return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */ } - *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; + *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length) + 1); + while ((rpos < length) + && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos, + length - rpos)) > 0) { + rpos += len_read; + } + if (len_read < 0) { + return APR_EINCOMPLETE; } + *size = rpos; + } + else { + rc = DONE; } return (rc); @@ -278,6 +281,8 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * { apr_status_t rc = OK; + *size = 0; + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) return rc; if (ap_should_client_block(r)) { @@ -303,10 +308,47 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * rpos += rsize; } } + else { + rc = DONE; + } return rc; } +/* expose apr_table as (r/o) lua table */ +static int req_aprtable2luatable(lua_State *L, apr_table_t *t) +{ + lua_newtable(L); + lua_newtable(L); /* [table, table] */ + apr_table_do(req_aprtable2luatable_cb, L, t, NULL); + return 2; /* [table<string, string>, table<string, array<string>>] */ +} + +static int req_headers_in_table(lua_State *L) +{ + request_rec *r = ap_lua_check_request_rec(L, 1); + return req_aprtable2luatable(L, r->headers_in); +} +static int req_headers_out_table(lua_State *L) +{ + request_rec *r = ap_lua_check_request_rec(L, 1); + return req_aprtable2luatable(L, r->headers_out); +} +static int req_err_headers_out_table(lua_State *L) +{ + request_rec *r = ap_lua_check_request_rec(L, 1); + return req_aprtable2luatable(L, r->err_headers_out); +} +static int req_notes_table(lua_State *L) +{ + request_rec *r = ap_lua_check_request_rec(L, 1); + return req_aprtable2luatable(L, r->notes); +} +static int req_subprocess_env_table(lua_State *L) +{ + request_rec *r = ap_lua_check_request_rec(L, 1); + return req_aprtable2luatable(L, r->subprocess_env); +} /* r:parseargs() returning a lua table */ static int req_parseargs(lua_State *L) { @@ -376,6 +418,7 @@ static int req_parsebody(lua_State *L) if (end == NULL) break; key = (char *) apr_pcalloc(r->pool, 256); filename = (char *) apr_pcalloc(r->pool, 256); + if (end - crlf <= 8) break; vlen = end - crlf - 8; buffer = (char *) apr_pcalloc(r->pool, vlen+1); memcpy(buffer, crlf + 4, vlen); @@ -2185,23 +2228,20 @@ static int lua_websocket_greet(lua_State *L) return 0; } -static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer, - apr_off_t len) +static apr_status_t lua_websocket_readbytes(conn_rec* c, + apr_bucket_brigade *brigade, + char* buffer, apr_off_t len) { - apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc); + apr_size_t delivered; apr_status_t rv; + rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, len); if (rv == APR_SUCCESS) { - if (!APR_BRIGADE_EMPTY(brigade)) { - apr_bucket* bucket = APR_BRIGADE_FIRST(brigade); - const char* data = NULL; - apr_size_t data_length = 0; - rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ); - if (rv == APR_SUCCESS) { - memcpy(buffer, data, len); - } - apr_bucket_delete(bucket); + delivered = len; + rv = apr_brigade_flatten(brigade, buffer, &delivered); + if ((rv == APR_SUCCESS) && (delivered < len)) { + rv = APR_INCOMPLETE; } } apr_brigade_cleanup(brigade); @@ -2231,35 +2271,28 @@ static int lua_websocket_peek(lua_State *L) static int lua_websocket_read(lua_State *L) { - apr_socket_t *sock; apr_status_t rv; int do_read = 1; int n = 0; - apr_size_t len = 1; apr_size_t plen = 0; unsigned short payload_short = 0; apr_uint64_t payload_long = 0; unsigned char *mask_bytes; char byte; - int plaintext; - - + apr_bucket_brigade *brigade; + conn_rec* c; + request_rec *r = ap_lua_check_request_rec(L, 1); - plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1; + c = r->connection; - mask_bytes = apr_pcalloc(r->pool, 4); - sock = ap_get_conn_socket(r->connection); + + brigade = apr_brigade_create(r->pool, c->bucket_alloc); while (do_read) { do_read = 0; /* Get opcode and FIN bit */ - if (plaintext) { - rv = apr_socket_recv(sock, &byte, &len); - } - else { - rv = lua_websocket_readbytes(r->connection, &byte, 1); - } + rv = lua_websocket_readbytes(c, brigade, &byte, 1); if (rv == APR_SUCCESS) { unsigned char ubyte, fin, opcode, mask, payload; ubyte = (unsigned char)byte; @@ -2269,12 +2302,7 @@ static int lua_websocket_read(lua_State *L) opcode = ubyte & 0xf; /* Get the payload length and mask bit */ - if (plaintext) { - rv = apr_socket_recv(sock, &byte, &len); - } - else { - rv = lua_websocket_readbytes(r->connection, &byte, 1); - } + rv = lua_websocket_readbytes(c, brigade, &byte, 1); if (rv == APR_SUCCESS) { ubyte = (unsigned char)byte; /* Mask is the first bit */ @@ -2285,40 +2313,25 @@ static int lua_websocket_read(lua_State *L) /* Extended payload? */ if (payload == 126) { - len = 2; - if (plaintext) { - /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */ - rv = apr_socket_recv(sock, (char*) &payload_short, &len); - } - else { - rv = lua_websocket_readbytes(r->connection, - (char*) &payload_short, 2); - } - payload_short = ntohs(payload_short); + rv = lua_websocket_readbytes(c, brigade, + (char*) &payload_short, 2); - if (rv == APR_SUCCESS) { - plen = payload_short; - } - else { + if (rv != APR_SUCCESS) { return 0; } + + plen = ntohs(payload_short); } /* Super duper extended payload? */ if (payload == 127) { - len = 8; - if (plaintext) { - rv = apr_socket_recv(sock, (char*) &payload_long, &len); - } - else { - rv = lua_websocket_readbytes(r->connection, - (char*) &payload_long, 8); - } - if (rv == APR_SUCCESS) { - plen = ap_ntoh64(&payload_long); - } - else { + rv = lua_websocket_readbytes(c, brigade, + (char*) &payload_long, 8); + + if (rv != APR_SUCCESS) { return 0; } + + plen = ap_ntoh64(&payload_long); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210) "Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s", @@ -2327,46 +2340,27 @@ static int lua_websocket_read(lua_State *L) mask ? "on" : "off", fin ? "This is a final frame" : "more to follow"); if (mask) { - len = 4; - if (plaintext) { - rv = apr_socket_recv(sock, (char*) mask_bytes, &len); - } - else { - rv = lua_websocket_readbytes(r->connection, - (char*) mask_bytes, 4); - } + rv = lua_websocket_readbytes(c, brigade, + (char*) mask_bytes, 4); + if (rv != APR_SUCCESS) { return 0; } } if (plen < (HUGE_STRING_LEN*1024) && plen > 0) { apr_size_t remaining = plen; - apr_size_t received; - apr_off_t at = 0; char *buffer = apr_palloc(r->pool, plen+1); buffer[plen] = 0; - if (plaintext) { - while (remaining > 0) { - received = remaining; - rv = apr_socket_recv(sock, buffer+at, &received); - if (received > 0 ) { - remaining -= received; - at += received; - } - } - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack", - at); - } - else { - rv = lua_websocket_readbytes(r->connection, buffer, - remaining); - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\ - "pushed to Lua stack", - remaining); + rv = lua_websocket_readbytes(c, brigade, buffer, remaining); + + if (rv != APR_SUCCESS) { + return 0; } + + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Websocket: Frame contained %" APR_SIZE_T_FMT \ + " bytes, pushed to Lua stack", remaining); if (mask) { for (n = 0; n < plen; n++) { buffer[n] ^= mask_bytes[n%4]; @@ -2378,14 +2372,25 @@ static int lua_websocket_read(lua_State *L) return 2; } - /* Decide if we need to react to the opcode or not */ if (opcode == 0x09) { /* ping */ char frame[2]; - plen = 2; + apr_bucket *b; + frame[0] = 0x8A; frame[1] = 0; - apr_socket_send(sock, frame, &plen); /* Pong! */ + + /* Pong! */ + b = apr_bucket_transient_create(frame, 2, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(brigade, b); + + rv = ap_pass_brigade(c->output_filters, brigade); + apr_brigade_cleanup(brigade); + + if (rv != APR_SUCCESS) { + return 0; + } + do_read = 1; } } @@ -2814,14 +2819,24 @@ void ap_lua_load_request_lmodule(lua_State *L, apr_pool_t *p) makefun(&req_proxyreq_field, APL_REQ_FUNTYPE_STRING, p)); apr_hash_set(dispatch, "headers_in", APR_HASH_KEY_STRING, makefun(&req_headers_in, APL_REQ_FUNTYPE_TABLE, p)); + apr_hash_set(dispatch, "headers_in_table", APR_HASH_KEY_STRING, + makefun(&req_headers_in_table, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "headers_out", APR_HASH_KEY_STRING, makefun(&req_headers_out, APL_REQ_FUNTYPE_TABLE, p)); + apr_hash_set(dispatch, "headers_out_table", APR_HASH_KEY_STRING, + makefun(&req_headers_out_table, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "err_headers_out", APR_HASH_KEY_STRING, makefun(&req_err_headers_out, APL_REQ_FUNTYPE_TABLE, p)); + apr_hash_set(dispatch, "err_headers_out_table", APR_HASH_KEY_STRING, + makefun(&req_err_headers_out_table, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "notes", APR_HASH_KEY_STRING, makefun(&req_notes, APL_REQ_FUNTYPE_TABLE, p)); + apr_hash_set(dispatch, "notes_table", APR_HASH_KEY_STRING, + makefun(&req_notes_table, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "subprocess_env", APR_HASH_KEY_STRING, makefun(&req_subprocess_env, APL_REQ_FUNTYPE_TABLE, p)); + apr_hash_set(dispatch, "subprocess_env_table", APR_HASH_KEY_STRING, + makefun(&req_subprocess_env_table, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "flush", APR_HASH_KEY_STRING, makefun(&lua_ap_rflush, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "port", APR_HASH_KEY_STRING, |