MINOR: proxy: add a new generic proxy_capture_error()

This function now captures an error regardless of its side and protocol.
The caller must pass a number of elements and may pass a protocol-specific
structure and a callback to display it. Later this function may deal with
more advanced allocation techniques to avoid allocating as many buffers
as proxies.
This commit is contained in:
Willy Tarreau 2018-09-07 17:43:26 +02:00
parent 7ccdd8dad9
commit 75fb65a51f
2 changed files with 89 additions and 0 deletions

View File

@ -58,6 +58,13 @@ int proxy_cfg_ensure_no_http(struct proxy *curproxy);
void init_new_proxy(struct proxy *p);
int get_backend_server(const char *bk_name, const char *sv_name,
struct proxy **bk, struct server **sv);
void proxy_capture_error(struct proxy *proxy, int is_back,
struct proxy *other_end, enum obj_type *target,
const struct session *sess,
const struct buffer *buf, long buf_ofs,
unsigned int buf_out, unsigned int err_pos,
const union error_snapshot_ctx *ctx,
void (*show)(struct buffer *, const struct error_snapshot *));
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);

View File

@ -1326,6 +1326,88 @@ int stream_set_backend(struct stream *s, struct proxy *be)
return 1;
}
/* Capture a bad request or response and archive it in the proxy's structure.
* It is relatively protocol-agnostic so it requires that a number of elements
* are passed :
* - <proxy> is the proxy where the error was detected and where the snapshot
* needs to be stored
* - <is_back> indicates that the error happend when receiving the response
* - <other_end> is a pointer to the proxy on the other side when known
* - <target> is the target of the connection, usually a server or a proxy
* - <sess> is the session which experienced the error
* - <ctx> may be NULL or should contain any info relevant to the protocol
* - <buf> is the buffer containing the offending data
* - <buf_ofs> is the position of this buffer's input data in the input
* stream, starting at zero. It may be passed as zero if unknown.
* - <buf_out> is the portion of <buf->data> which was already forwarded and
* which precedes the buffer's input. The buffer's input starts at
* buf->head + buf_out.
* - <err_pos> is the pointer to the faulty byte in the buffer's input.
* - <show> is the callback to use to display <ctx>. It may be NULL.
*/
void proxy_capture_error(struct proxy *proxy, int is_back,
struct proxy *other_end, enum obj_type *target,
const struct session *sess,
const struct buffer *buf, long buf_ofs,
unsigned int buf_out, unsigned int err_pos,
const union error_snapshot_ctx *ctx,
void (*show)(struct buffer *, const struct error_snapshot *))
{
struct error_snapshot *es;
unsigned int buf_len;
int len1, len2;
buf_len = b_data(buf) - buf_out;
len1 = b_size(buf) - buf_len;
if (len1 > buf_len)
len1 = buf_len;
len2 = buf_len - len1;
HA_SPIN_LOCK(PROXY_LOCK, &proxy->lock);
es = is_back ? &proxy->invalid_rep : &proxy->invalid_req;
es->buf_len = buf_len;
if (!es->buf)
es->buf = malloc(global.tune.bufsize);
if (es->buf) {
memcpy(es->buf, b_peek(buf, buf_out), len1);
if (len2)
memcpy(es->buf + len1, b_orig(buf), len2);
}
es->buf_err = err_pos;
es->when = date; // user-visible date
es->srv = objt_server(target);
es->oe = other_end;
if (objt_conn(sess->origin))
es->src = __objt_conn(sess->origin)->addr.from;
else
memset(&es->src, 0, sizeof(es->src));
es->ev_id = HA_ATOMIC_XADD(&error_snapshot_id, 1);
es->buf_wrap = b_wrap(buf) - b_peek(buf, buf_out);
es->buf_out = buf_out;
es->buf_ofs = buf_ofs;
/* be sure to indicate the offset of the first IN byte */
if (es->buf_ofs >= es->buf_len)
es->buf_ofs -= es->buf_len;
else
es->buf_ofs = 0;
/* protocol-specific part now */
if (ctx)
es->ctx = *ctx;
else
memset(&es->ctx, 0, sizeof(es->ctx));
es->show = show;
HA_SPIN_UNLOCK(PROXY_LOCK, &proxy->lock);
}
/* Config keywords below */
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "hard-stop-after", proxy_parse_hard_stop_after },
{ CFG_LISTEN, "timeout", proxy_parse_timeout },