1
0
mirror of https://github.com/graygnuorg/pound.git synced 2026-10-23 22:28:53 +03:00

Experimental feature: request resubmitting

* src/capbio.c (cap_write_ex): Check if cp->mem is not NULL.
(cap_ctrl): Handle BIO_CTLR_CAPTURE_GET_MEM.
* src/capbio.h (BIO_CTLR_CAPTURE_GET_MEM): New ctrl.
(BIO_capture_is_truncated)
(BIO_capture_get_mem_data): New macros.
(BIO_capture_expand,BIO_capture_unwrap): New inline functions.
* src/pound.h (MAX_REQUEST_RESEND): New define.
(http_request): Change the type of body to BIO *.
(_pound_http) [ENABLE_LUA]: New field: resend.
(phttp_lua_stash_reset): Clear resend.
(phttp_resending,phttp_clear_resend): New inline functions (or
dummy macros, if !ENABLE_LUA).
* src/http.c (bio_memcpy): Remove.
(lua_response,http_request_free: Update for change in the body data type.
(backend_response): Handle request resending.
(capture_start,capture_end): Disable capturing for resubmitted requests.
(http_process_request): Handle request resending.
(do_http): Bugfix: clear response_code at initialization stage.
* src/pndlua.c (req_body,resp_get_body,resp_set_body): Update for change
in the body data type.
(pndlua_http_index): New field http.resend available at rewrite response
stage.
(pndlua_http_newindex): New function.
(pndlua_set_http): Use pndlua_http_newindex instead of ro_newindex.
This commit is contained in:
Sergey Poznyakoff
2026-01-27 12:31:37 +02:00
parent 9001526ed0
commit 3758b19774
5 changed files with 210 additions and 116 deletions

View File

@@ -47,7 +47,7 @@ static int
cap_free (BIO *b)
{
struct capture_bio_st *cp;
if (b == NULL)
return 0;
@@ -57,7 +57,7 @@ cap_free (BIO *b)
BIO_free (cp->mem);
free (cp);
}
BIO_set_data (b, NULL);
BIO_set_init (b, 0);
return 1;
@@ -73,25 +73,28 @@ cap_write_ex (BIO *b, const char *buf, size_t size, size_t *in_size)
if (!BIO_write_ex (next, buf, size, &n))
return 0;
*in_size = n;
for (i = 0; i < n; )
if (cp->mem)
{
size_t s = n - i, m;
if (cp->cap != (size_t)-1 && s > (m = cp->cap - cp->len))
s = m;
if (s == 0)
*in_size = n;
for (i = 0; i < n; )
{
cp->trnc = 1;
break;
size_t s = n - i, m;
if (cp->cap != (size_t)-1 && s > (m = cp->cap - cp->len))
s = m;
if (s == 0)
{
cp->trnc = 1;
break;
}
if (!BIO_write_ex (cp->mem, buf + i, s, &m))
{
cp->cap = cp->len;
break;
}
i += m;
cp->len += m;
}
if (!BIO_write_ex (cp->mem, buf + i, s, &m))
{
cp->cap = cp->len;
break;
}
i += m;
cp->len += m;
}
return 1;
@@ -127,11 +130,18 @@ cap_ctrl (BIO *b, int cmd, long lval, void *pval)
break;
case BIO_CTLR_CAPTURE_GET_PTR:
if (!cp->mem)
return 0;
return BIO_get_mem_data (cp->mem, pval);
case BIO_CTLR_CAPTURE_GET_TRNC:
return cp->trnc;
case BIO_CTLR_CAPTURE_GET_MEM:
*(BIO**)pval = cp->mem;
cp->mem = NULL;
break;
default:
return BIO_ctrl (BIO_next(b), cmd, lval, pval);
}
@@ -147,7 +157,7 @@ BIO_f_capture (void)
{
int n = BIO_get_new_index ();
assert(n != -1);
cap = BIO_meth_new (n | BIO_TYPE_FILTER, "capture");
assert(cap != NULL);

View File

@@ -24,8 +24,24 @@ enum
BIO_CTLR_CAPTURE_GET_CAP,
BIO_CTLR_CAPTURE_GET_LEN,
BIO_CTLR_CAPTURE_GET_PTR,
BIO_CTLR_CAPTURE_GET_TRNC
BIO_CTLR_CAPTURE_GET_TRNC,
BIO_CTLR_CAPTURE_GET_MEM
};
const BIO_METHOD *BIO_f_capture (void);
BIO *bio_new_capture (size_t cap);
#define BIO_capture_is_truncated(b) \
BIO_ctrl (b, BIO_CTLR_CAPTURE_GET_TRNC, 0, NULL)
#define BIO_capture_get_mem_data(b,pp) \
BIO_ctrl (b, BIO_CTLR_CAPTURE_GET_PTR, 0, pp)
static inline void BIO_capture_expand(BIO *b, size_t s) {
BIO_ctrl (b, BIO_CTLR_CAPTURE_SET_CAP, s, NULL);
}
static inline BIO *BIO_capture_unwrap(BIO *b) {
BIO *mem;
BIO_ctrl (b, BIO_CTLR_CAPTURE_GET_MEM, 0, &mem);
BIO_free (b);
return mem;
}

View File

@@ -1309,26 +1309,6 @@ copy_bin (BIO *cl, BIO *be, CONTENT_LENGTH cont, int no_write,
return COPY_OK;
}
static int
bio_memcpy (BIO *out, char const *buf, size_t len, CONTENT_LENGTH *res_bytes)
{
BIO *in;
int rc;
if ((in = BIO_new_mem_buf (buf, len)) == NULL)
{
logmsg (LOG_WARNING, "(%"PRItid") can't create BIO_new_mem_buf",
POUND_TID ());
return -1;
}
rc = copy_bin (in, out, len, 0, res_bytes);
BIO_free_all (in);
return rc;
}
static int
acme_response (POUND_HTTP *phttp)
{
@@ -1594,24 +1574,38 @@ lua_response (POUND_HTTP *phttp)
}
else
{
struct stringbuf *body;
BIO *body;
if (rewrite_apply (phttp, &phttp->response, REWRITE_RESPONSE))
return HTTP_STATUS_INTERNAL_SERVER_ERROR;
body = phttp->response.body;
phttp->res_bytes = body ? stringbuf_len (body) : 0;
phttp->res_bytes = body ? BIO_get_mem_data (body, NULL) : 0;
bio_http_reply_start_list (phttp->cl,
phttp->request.version,
phttp->response_code,
/* FIXME: Use RESP_REASON_START from
pndlua.c */
phttp->response.request + 13,
phttp->response.request + 13,
&phttp->response.headers,
(CONTENT_LENGTH) phttp->res_bytes);
if (body)
BIO_write (phttp->cl, stringbuf_value (body), phttp->res_bytes);
{
int rc;
BIO_set_flags (body, BIO_FLAGS_NONCLEAR_RST);
BIO_reset (body);
rc = copy_bin (body, phttp->cl, phttp->res_bytes, 0, NULL);
if (rc != COPY_OK)
{
phttp_log (phttp, PHTTP_LOG_BACKEND, -1, 0,
"error sending data: %s",
copy_status_string (rc));
}
}
BIO_flush (phttp->cl);
res = HTTP_STATUS_OK;
@@ -3355,10 +3349,7 @@ http_request_free (struct http_request *req)
free (req->orig_request_line);
free (req->eval_result);
if (req->body)
{
stringbuf_free (req->body);
free (req->body);
}
BIO_free (req->body);
http_request_init (req);
}
@@ -4689,6 +4680,8 @@ backend_response (POUND_HTTP *phttp)
{
if (rewrite_apply (phttp, &phttp->response, REWRITE_RESPONSE))
return HTTP_STATUS_INTERNAL_SERVER_ERROR;
if (phttp_resending (phttp))
resp_mode = RESP_DRAIN;
}
/*
@@ -4708,11 +4701,11 @@ backend_response (POUND_HTTP *phttp)
* Replace the Content-Length header if they supplied
* a new body.
*/
char *p;
struct stringbuf sb;
char *p;
size_t len = BIO_get_mem_data (phttp->response.body, NULL);
stringbuf_init_log (&sb);
stringbuf_printf (&sb, "Content-Length: %zu",
stringbuf_len (phttp->response.body));
stringbuf_printf (&sb, "Content-Length: %zu", len);
if ((p = stringbuf_finish (&sb)) == NULL)
{
stringbuf_free (&sb);
@@ -4743,10 +4736,14 @@ backend_response (POUND_HTTP *phttp)
if (resp_mode == RESP_OK && phttp->response.body)
{
int rc = bio_memcpy (phttp->cl,
stringbuf_value (phttp->response.body),
stringbuf_len (phttp->response.body),
&phttp->res_bytes);
int rc;
BIO_set_flags (phttp->response.body, BIO_FLAGS_NONCLEAR_RST);
BIO_reset (phttp->response.body);
rc = copy_bin (phttp->response.body, phttp->cl,
BIO_get_mem_data (phttp->response.body, NULL), 0,
&phttp->res_bytes);
if (rc != COPY_OK)
{
phttp_log (phttp, PHTTP_LOG_DFL,
@@ -4756,9 +4753,11 @@ backend_response (POUND_HTTP *phttp)
return -1;
}
resp_mode = RESP_DRAIN;
res_bytes = NULL;
}
if (resp_mode == RESP_DRAIN)
res_bytes = NULL;
if (!phttp->no_cont)
{
/*
@@ -5055,7 +5054,7 @@ backend_response (POUND_HTTP *phttp)
static void
capture_start (POUND_HTTP *phttp)
{
if (phttp->svc->capture_size > 0)
if (!phttp_resending (phttp) && phttp->svc->capture_size > 0)
{
BIO *cap = bio_new_capture (phttp->svc->capture_size);
phttp->be = BIO_push (cap, phttp->be);
@@ -5073,35 +5072,16 @@ capture_end (POUND_HTTP *phttp)
BIO *cap = phttp->be;
phttp->be = BIO_pop (phttp->be);
phttp->capturing = 0;
if (!BIO_ctrl (cap, BIO_CTLR_CAPTURE_GET_TRNC, 0, NULL))
if (!BIO_capture_is_truncated (cap))
{
long len;
char *ptr;
len = BIO_ctrl (cap, BIO_CTLR_CAPTURE_GET_PTR, 0, &ptr);
if (!phttp->request.body)
{
phttp->request.body = malloc (sizeof (*phttp->request.body));
if (!phttp->request.body)
{
phttp_log (phttp, PHTTP_LOG_DFL,
-1, errno, "capturing disabled");
BIO_free (cap);
return;
}
stringbuf_init_log (phttp->request.body);
}
else
stringbuf_reset (phttp->request.body);
if (stringbuf_add (phttp->request.body, ptr, len))
{
phttp_log (phttp, PHTTP_LOG_DFL,
-1, 0, "capturing disabled");
stringbuf_reset (phttp->request.body);
}
phttp_log (phttp, PHTTP_LOG_BACKEND, -1, 0,
"discarding truncated capture");
BIO_free (cap);
}
else
{
phttp->request.body = BIO_capture_unwrap (cap);
}
}
}
@@ -5510,6 +5490,7 @@ http_process_request (POUND_HTTP *phttp)
char *val;
/* FIXME: this belongs to struct http_request, perhaps. */
int transfer_encoding;
int resend_count;
/*
* check for correct request
@@ -5771,14 +5752,58 @@ http_process_request (POUND_HTTP *phttp)
break;
case BE_REGULAR:
/* Send the request. */
res = send_to_backend (phttp,
!is_http10 (phttp) &&
(transfer_encoding == TRANSFER_ENCODING_CHUNKED),
content_length);
if (res == 0)
/* Process the response. */
res = backend_response (phttp);
resend_count = 0;
do
{
/* Send the request. */
res = send_to_backend (phttp,
!is_http10 (phttp) &&
(transfer_encoding == TRANSFER_ENCODING_CHUNKED),
content_length);
if (phttp_resending (phttp))
{
phttp->cl = BIO_pop (phttp->cl);
phttp_clear_resend (phttp);
}
if (res == 0)
{
/* Process the response. */
res = backend_response (phttp);
if (phttp_resending (phttp))
{
if (resend_count == MAX_REQUEST_RESEND)
{
res = HTTP_STATUS_INTERNAL_SERVER_ERROR;
phttp_log (phttp, PHTTP_LOG_BACKEND,
HTTP_STATUS_INTERNAL_SERVER_ERROR, 0,
"refusing to do more than %d resends",
MAX_REQUEST_RESEND);
break;
}
resend_count++;
if (!phttp->be)
{
if ((res = select_backend (phttp)) != 0)
break;
}
http_request_free (&phttp->response);
if (phttp->request.body)
{
BIO_set_flags (phttp->request.body,
BIO_FLAGS_NONCLEAR_RST);
BIO_reset (phttp->request.body);
}
else
phttp->request.body = BIO_new (BIO_s_null ());
phttp->cl = BIO_push (phttp->request.body, phttp->cl);
}
}
}
while (res == 0 && phttp_resending (phttp));
break;
case BE_FILE:
@@ -5880,6 +5905,7 @@ do_http (POUND_HTTP *phttp)
{
http_request_free (&phttp->request);
http_request_free (&phttp->response);
phttp->response_code = 0;
submatch_queue_free (&phttp->smq);
phttp_lua_stash_reset (phttp);

View File

@@ -1059,11 +1059,11 @@ static int
req_body (lua_State *L)
{
struct req_ud *ud = pndlua_get_userdata (L, 1);
struct stringbuf *body = ud->req->body;
if (body)
lua_pushlstring (L, stringbuf_value (body), stringbuf_len (body));
else
lua_pushlstring (L, "", 0);
char *ptr;
size_t len;
len = BIO_get_mem_data (ud->req->body, &ptr);
lua_pushlstring (L, ptr, len);
return 1;
}
@@ -1264,11 +1264,11 @@ static int
resp_get_body (lua_State *L)
{
struct http_ud *ud = pndlua_get_userdata (L, 1);
struct stringbuf *body = ud->phttp->response.body;
if (body)
lua_pushlstring (L, stringbuf_value (body), stringbuf_len (body));
else
lua_pushlstring (L, "", 0);
char *ptr;
size_t len;
len = BIO_get_mem_data (ud->phttp->response.body, &ptr);
lua_pushlstring (L, ptr, len);
return 1;
}
@@ -1333,22 +1333,27 @@ static int
resp_set_body (lua_State *L)
{
struct http_ud *ud = pndlua_get_userdata (L, 1);
struct stringbuf *body = ud->phttp->response.body;
BIO *body;
if (!body)
if (!ud->phttp->response.body)
{
if ((body = malloc (sizeof (*body))) == NULL)
if ((ud->phttp->response.body = BIO_new (BIO_s_mem ())) == NULL)
return pndlua_memerr (L);
stringbuf_init_log (body);
ud->phttp->response.body = body;
}
else
{
/* Just in case. */
BIO_clear_flags (ud->phttp->response.body, BIO_FLAGS_NONCLEAR_RST);
BIO_reset (ud->phttp->response.body);
}
stringbuf_reset (body);
body = ud->phttp->response.body;
if (!lua_isnil (L, 3))
{
size_t len;
char const *val = lua_tolstring (L, 3, &len);
if (stringbuf_add (body, val, len))
if (BIO_write (body, val, len) == -1)
luaL_error (L, "out if memory");
}
return 0;
@@ -1486,6 +1491,14 @@ http_resp (lua_State *L)
return 1;
}
static int
http_resend (lua_State *L)
{
struct http_ud *ud = pndlua_get_userdata (L, 1);
lua_pushboolean (L, ud->phttp->resend);
return 1;
}
static int
pndlua_http_index (lua_State *L)
{
@@ -1495,10 +1508,11 @@ pndlua_http_index (lua_State *L)
int rw = http->modresp != 0;
static char *letidx[] = { "r", "rr" };
static char *letidx[] = { "r", "rrr" };
static struct luaL_Reg reg[] = {
{ "req", http_req },
{ "resp", http_resp }
{ "resp", http_resp },
{ "resend", http_resend },
};
field = lua_tostring (L, 2);
@@ -1507,6 +1521,18 @@ pndlua_http_index (lua_State *L)
return fun (L);
}
static int
pndlua_http_newindex (lua_State *L)
{
struct http_ud *ud = pndlua_get_userdata (L, 1);
char const *field = lua_tostring (L, 2);
if (strcmp(field, "resend"))
luaL_error (L, "attempt to modify read-only data");
ud->phttp->resend = lua_toboolean (L, 3);
return 0;
}
/*
* Prepare and set the "http" global in the Lua state. If modresp is not 0,
* the http.resp element will be available and assignments to http.resp.body
@@ -1528,7 +1554,7 @@ pndlua_set_http (lua_State *L, POUND_HTTP *phttp, int modresp)
/* Create __index entry. */
pndlua_dcl_function (L, "__index", pndlua_http_index);
/* Create __newindex entry. */
pndlua_dcl_function (L, "__newindex", ro_newindex);
pndlua_dcl_function (L, "__newindex", pndlua_http_newindex);
/* Set metatable. */
lua_setmetatable (L, -2);

View File

@@ -76,6 +76,8 @@
#define PORT_HTTP_STR TOSTR(PORT_HTTP)
#define PORT_HTTPS_STR TOSTR(PORT_HTTPS)
#define MAX_REQUEST_RESEND 4
#if HAVE_OPENSSL_SSL_H
# define OPENSSL_THREAD_DEFINES
# include <openssl/ssl.h>
@@ -428,9 +430,8 @@ struct http_request
int split;
char *eval_result; /* Array of return statuses from evaluation of
detached conditions. */
struct stringbuf *body; /* Response body overridden by modification
request. Deliberately not using any stream
type here. */
BIO *body; /* For requests: captured response body.
For responses: modified response body. */
};
static inline void http_request_init (struct http_request *http)
@@ -1153,6 +1154,7 @@ typedef struct _pound_http
#if ENABLE_LUA
char stash_init[2];
int resend;
#endif
SLIST_ENTRY(_pound_http) next;
@@ -1432,7 +1434,19 @@ int tbf_eval (TBF *env, char const *keyid);
static inline void phttp_lua_stash_reset (POUND_HTTP *p)
{
p->stash_init[PNDLUA_CTX_GLOBAL] = p->stash_init[PNDLUA_CTX_THREAD] = 0;
p->resend = 0;
}
static inline int phttp_resending (POUND_HTTP *p)
{
return p->resend;
}
static inline void phttp_clear_resend (POUND_HTTP *p)
{
p->resend = 0;
}
int pndlua_init (void);
int pndlua_match (POUND_HTTP *phttp, struct pndlua_closure const *cond,
char **argv, void *data);
@@ -1444,7 +1458,9 @@ int pndlua_parse_config (void *call_data, void *section_data);
int pndlua_parse_closure (struct pndlua_closure *cond);
#else
# define phttp_lua_stash_reset(p)
static inline int pndlua_init (void) { return 0; }
# define phttp_resending(p) 0
# define phttp_clear_resend(p)
# define pndlua_init() 0
static inline int
cfg_no_lua (void)
{