mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-08 18:23:15 +00:00
REORG: http: create http_msg.c to place there some legacy HTTP parts
Lots of HTTP code still uses struct http_msg. Not only this code is still huge, but it's part of the legacy interface. Let's move most of these functions to a separate file http_msg.c to make it more visible which file relies on what. It's mostly symmetrical with what is present in http_htx.c. The function http_transform_header_str() which used to rely on two function pointers to look up a header was simplified to rely on two variants http_legacy_replace_{,full_}header(), making both sides of the function much simpler. No code was changed beyond these moves.
This commit is contained in:
parent
b96b77ed6e
commit
c5a4fd5c30
2
Makefile
2
Makefile
@ -947,7 +947,7 @@ OBJS = src/proto_http.o src/cfgparse-listen.o src/proto_htx.o src/stream.o \
|
|||||||
src/http.o src/hpack-dec.o src/action.o src/proto_udp.o src/http_acl.o \
|
src/http.o src/hpack-dec.o src/action.o src/proto_udp.o src/http_acl.o \
|
||||||
src/xxhash.o src/hpack-enc.o src/h2.o src/freq_ctr.o src/lru.o \
|
src/xxhash.o src/hpack-enc.o src/h2.o src/freq_ctr.o src/lru.o \
|
||||||
src/protocol.o src/arg.o src/hpack-huff.o src/hdr_idx.o src/base64.o \
|
src/protocol.o src/arg.o src/hpack-huff.o src/hdr_idx.o src/base64.o \
|
||||||
src/hash.o src/mailers.o src/activity.o
|
src/hash.o src/mailers.o src/activity.o src/http_msg.o
|
||||||
|
|
||||||
EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o $(EBTREE_DIR)/eb32sctree.o \
|
EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o $(EBTREE_DIR)/eb32sctree.o \
|
||||||
$(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
|
$(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
|
||||||
|
@ -51,6 +51,14 @@ int http_upgrade_v09_to_v10(struct http_txn *txn);
|
|||||||
void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx);
|
void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx);
|
||||||
void http_txn_reset_req(struct http_txn *txn);
|
void http_txn_reset_req(struct http_txn *txn);
|
||||||
void http_txn_reset_res(struct http_txn *txn);
|
void http_txn_reset_res(struct http_txn *txn);
|
||||||
|
int http_legacy_replace_header(struct hdr_idx *idx, struct http_msg *msg,
|
||||||
|
const char *name, unsigned int name_len,
|
||||||
|
const char *str, struct my_regex *re,
|
||||||
|
struct buffer *output);
|
||||||
|
int http_legacy_replace_full_header(struct hdr_idx *idx, struct http_msg *msg,
|
||||||
|
const char *name, unsigned int name_len,
|
||||||
|
const char *str, struct my_regex *re,
|
||||||
|
struct buffer *output);
|
||||||
|
|
||||||
/* Export HTX analyzers and helpers */
|
/* Export HTX analyzers and helpers */
|
||||||
// FIXME: Rename all these functions http_* once legacy code will be removed
|
// FIXME: Rename all these functions http_* once legacy code will be removed
|
||||||
|
506
src/http_msg.c
Normal file
506
src/http_msg.c
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
/*
|
||||||
|
* Legacy HTTP protocol manipulation
|
||||||
|
* If you think you need something from this file, you're mistaken as it will
|
||||||
|
* soon be removed. Please check http_htx.c instead!
|
||||||
|
*
|
||||||
|
* Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <proto/channel.h>
|
||||||
|
#include <proto/hdr_idx.h>
|
||||||
|
#include <proto/proto_http.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds a header and its CRLF at the tail of the message's buffer, just before
|
||||||
|
* the last CRLF. <len> bytes are copied, not counting the CRLF.
|
||||||
|
* The header is also automatically added to the index <hdr_idx>, and the end
|
||||||
|
* of headers is automatically adjusted. The number of bytes added is returned
|
||||||
|
* on success, otherwise <0 is returned indicating an error.
|
||||||
|
*/
|
||||||
|
int http_header_add_tail2(struct http_msg *msg,
|
||||||
|
struct hdr_idx *hdr_idx, const char *text, int len)
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
bytes = ci_insert_line2(msg->chn, msg->eoh, text, len);
|
||||||
|
if (!bytes)
|
||||||
|
return -1;
|
||||||
|
http_msg_move_end(msg, bytes);
|
||||||
|
return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first or next occurrence of header <name> in message buffer <sol>
|
||||||
|
* using headers index <idx>, and return it in the <ctx> structure. This
|
||||||
|
* structure holds everything necessary to use the header and find next
|
||||||
|
* occurrence. If its <idx> member is 0, the header is searched from the
|
||||||
|
* beginning. Otherwise, the next occurrence is returned. The function returns
|
||||||
|
* 1 when it finds a value, and 0 when there is no more. It is very similar to
|
||||||
|
* http_find_header2() except that it is designed to work with full-line headers
|
||||||
|
* whose comma is not a delimiter but is part of the syntax. As a special case,
|
||||||
|
* if ctx->val is NULL when searching for a new values of a header, the current
|
||||||
|
* header is rescanned. This allows rescanning after a header deletion.
|
||||||
|
*/
|
||||||
|
int http_find_full_header2(const char *name, int len,
|
||||||
|
char *sol, struct hdr_idx *idx,
|
||||||
|
struct hdr_ctx *ctx)
|
||||||
|
{
|
||||||
|
char *eol, *sov;
|
||||||
|
int cur_idx, old_idx;
|
||||||
|
|
||||||
|
cur_idx = ctx->idx;
|
||||||
|
if (cur_idx) {
|
||||||
|
/* We have previously returned a header, let's search another one */
|
||||||
|
sol = ctx->line;
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
goto next_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first request for this header */
|
||||||
|
sol += hdr_idx_first_pos(idx);
|
||||||
|
old_idx = 0;
|
||||||
|
cur_idx = hdr_idx_first_idx(idx);
|
||||||
|
while (cur_idx) {
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
/* No argument was passed, we want any header.
|
||||||
|
* To achieve this, we simply build a fake request. */
|
||||||
|
while (sol + len < eol && sol[len] != ':')
|
||||||
|
len++;
|
||||||
|
name = sol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((len < eol - sol) &&
|
||||||
|
(sol[len] == ':') &&
|
||||||
|
(strncasecmp(sol, name, len) == 0)) {
|
||||||
|
ctx->del = len;
|
||||||
|
sov = sol + len + 1;
|
||||||
|
while (sov < eol && HTTP_IS_LWS(*sov))
|
||||||
|
sov++;
|
||||||
|
|
||||||
|
ctx->line = sol;
|
||||||
|
ctx->prev = old_idx;
|
||||||
|
ctx->idx = cur_idx;
|
||||||
|
ctx->val = sov - sol;
|
||||||
|
ctx->tws = 0;
|
||||||
|
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
||||||
|
eol--;
|
||||||
|
ctx->tws++;
|
||||||
|
}
|
||||||
|
ctx->vlen = eol - sov;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
next_hdr:
|
||||||
|
sol = eol + idx->v[cur_idx].cr + 1;
|
||||||
|
old_idx = cur_idx;
|
||||||
|
cur_idx = idx->v[cur_idx].next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first or next header field in message buffer <sol> using headers
|
||||||
|
* index <idx>, and return it in the <ctx> structure. This structure holds
|
||||||
|
* everything necessary to use the header and find next occurrence. If its
|
||||||
|
* <idx> member is 0, the first header is retrieved. Otherwise, the next
|
||||||
|
* occurrence is returned. The function returns 1 when it finds a value, and
|
||||||
|
* 0 when there is no more. It is equivalent to http_find_full_header2() with
|
||||||
|
* no header name.
|
||||||
|
*/
|
||||||
|
int http_find_next_header(char *sol, struct hdr_idx *idx, struct hdr_ctx *ctx)
|
||||||
|
{
|
||||||
|
char *eol, *sov;
|
||||||
|
int cur_idx, old_idx;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
cur_idx = ctx->idx;
|
||||||
|
if (cur_idx) {
|
||||||
|
/* We have previously returned a header, let's search another one */
|
||||||
|
sol = ctx->line;
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
goto next_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first request for this header */
|
||||||
|
sol += hdr_idx_first_pos(idx);
|
||||||
|
old_idx = 0;
|
||||||
|
cur_idx = hdr_idx_first_idx(idx);
|
||||||
|
while (cur_idx) {
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
while (1) {
|
||||||
|
if (len >= eol - sol)
|
||||||
|
goto next_hdr;
|
||||||
|
if (sol[len] == ':')
|
||||||
|
break;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->del = len;
|
||||||
|
sov = sol + len + 1;
|
||||||
|
while (sov < eol && HTTP_IS_LWS(*sov))
|
||||||
|
sov++;
|
||||||
|
|
||||||
|
ctx->line = sol;
|
||||||
|
ctx->prev = old_idx;
|
||||||
|
ctx->idx = cur_idx;
|
||||||
|
ctx->val = sov - sol;
|
||||||
|
ctx->tws = 0;
|
||||||
|
|
||||||
|
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
||||||
|
eol--;
|
||||||
|
ctx->tws++;
|
||||||
|
}
|
||||||
|
ctx->vlen = eol - sov;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
next_hdr:
|
||||||
|
sol = eol + idx->v[cur_idx].cr + 1;
|
||||||
|
old_idx = cur_idx;
|
||||||
|
cur_idx = idx->v[cur_idx].next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first or next occurrence of header <name> in message buffer <sol>
|
||||||
|
* using headers index <idx>, and return it in the <ctx> structure. This
|
||||||
|
* structure holds everything necessary to use the header and find next
|
||||||
|
* occurrence. If its <idx> member is 0, the header is searched from the
|
||||||
|
* beginning. Otherwise, the next occurrence is returned. The function returns
|
||||||
|
* 1 when it finds a value, and 0 when there is no more. It is designed to work
|
||||||
|
* with headers defined as comma-separated lists. As a special case, if ctx->val
|
||||||
|
* is NULL when searching for a new values of a header, the current header is
|
||||||
|
* rescanned. This allows rescanning after a header deletion.
|
||||||
|
*/
|
||||||
|
int http_find_header2(const char *name, int len,
|
||||||
|
char *sol, struct hdr_idx *idx,
|
||||||
|
struct hdr_ctx *ctx)
|
||||||
|
{
|
||||||
|
char *eol, *sov;
|
||||||
|
int cur_idx, old_idx;
|
||||||
|
|
||||||
|
cur_idx = ctx->idx;
|
||||||
|
if (cur_idx) {
|
||||||
|
/* We have previously returned a value, let's search
|
||||||
|
* another one on the same line.
|
||||||
|
*/
|
||||||
|
sol = ctx->line;
|
||||||
|
ctx->del = ctx->val + ctx->vlen + ctx->tws;
|
||||||
|
sov = sol + ctx->del;
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
|
||||||
|
if (sov >= eol)
|
||||||
|
/* no more values in this header */
|
||||||
|
goto next_hdr;
|
||||||
|
|
||||||
|
/* values remaining for this header, skip the comma but save it
|
||||||
|
* for later use (eg: for header deletion).
|
||||||
|
*/
|
||||||
|
sov++;
|
||||||
|
while (sov < eol && HTTP_IS_LWS((*sov)))
|
||||||
|
sov++;
|
||||||
|
|
||||||
|
goto return_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first request for this header */
|
||||||
|
sol += hdr_idx_first_pos(idx);
|
||||||
|
old_idx = 0;
|
||||||
|
cur_idx = hdr_idx_first_idx(idx);
|
||||||
|
while (cur_idx) {
|
||||||
|
eol = sol + idx->v[cur_idx].len;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
/* No argument was passed, we want any header.
|
||||||
|
* To achieve this, we simply build a fake request. */
|
||||||
|
while (sol + len < eol && sol[len] != ':')
|
||||||
|
len++;
|
||||||
|
name = sol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((len < eol - sol) &&
|
||||||
|
(sol[len] == ':') &&
|
||||||
|
(strncasecmp(sol, name, len) == 0)) {
|
||||||
|
ctx->del = len;
|
||||||
|
sov = sol + len + 1;
|
||||||
|
while (sov < eol && HTTP_IS_LWS(*sov))
|
||||||
|
sov++;
|
||||||
|
|
||||||
|
ctx->line = sol;
|
||||||
|
ctx->prev = old_idx;
|
||||||
|
return_hdr:
|
||||||
|
ctx->idx = cur_idx;
|
||||||
|
ctx->val = sov - sol;
|
||||||
|
|
||||||
|
eol = http_find_hdr_value_end(sov, eol);
|
||||||
|
ctx->tws = 0;
|
||||||
|
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
||||||
|
eol--;
|
||||||
|
ctx->tws++;
|
||||||
|
}
|
||||||
|
ctx->vlen = eol - sov;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
next_hdr:
|
||||||
|
sol = eol + idx->v[cur_idx].cr + 1;
|
||||||
|
old_idx = cur_idx;
|
||||||
|
cur_idx = idx->v[cur_idx].next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove one value of a header. This only works on a <ctx> returned by one of
|
||||||
|
* the http_find_header functions. The value is removed, as well as surrounding
|
||||||
|
* commas if any. If the removed value was alone, the whole header is removed.
|
||||||
|
* The ctx is always updated accordingly, as well as the buffer and HTTP
|
||||||
|
* message <msg>. The new index is returned. If it is zero, it means there is
|
||||||
|
* no more header, so any processing may stop. The ctx is always left in a form
|
||||||
|
* that can be handled by http_find_header2() to find next occurrence.
|
||||||
|
*/
|
||||||
|
int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ctx *ctx)
|
||||||
|
{
|
||||||
|
int cur_idx = ctx->idx;
|
||||||
|
char *sol = ctx->line;
|
||||||
|
struct hdr_idx_elem *hdr;
|
||||||
|
int delta, skip_comma;
|
||||||
|
|
||||||
|
if (!cur_idx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hdr = &idx->v[cur_idx];
|
||||||
|
if (sol[ctx->del] == ':' && ctx->val + ctx->vlen + ctx->tws == hdr->len) {
|
||||||
|
/* This was the only value of the header, we must now remove it entirely. */
|
||||||
|
delta = b_rep_blk(&msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
|
||||||
|
http_msg_move_end(msg, delta);
|
||||||
|
idx->used--;
|
||||||
|
hdr->len = 0; /* unused entry */
|
||||||
|
idx->v[ctx->prev].next = idx->v[ctx->idx].next;
|
||||||
|
if (idx->tail == ctx->idx)
|
||||||
|
idx->tail = ctx->prev;
|
||||||
|
ctx->idx = ctx->prev; /* walk back to the end of previous header */
|
||||||
|
ctx->line -= idx->v[ctx->idx].len + idx->v[ctx->idx].cr + 1;
|
||||||
|
ctx->val = idx->v[ctx->idx].len; /* point to end of previous header */
|
||||||
|
ctx->tws = ctx->vlen = 0;
|
||||||
|
return ctx->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This was not the only value of this header. We have to remove between
|
||||||
|
* ctx->del+1 and ctx->val+ctx->vlen+ctx->tws+1 included. If it is the
|
||||||
|
* last entry of the list, we remove the last separator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
skip_comma = (ctx->val + ctx->vlen + ctx->tws == hdr->len) ? 0 : 1;
|
||||||
|
delta = b_rep_blk(&msg->chn->buf, sol + ctx->del + skip_comma,
|
||||||
|
sol + ctx->val + ctx->vlen + ctx->tws + skip_comma,
|
||||||
|
NULL, 0);
|
||||||
|
hdr->len += delta;
|
||||||
|
http_msg_move_end(msg, delta);
|
||||||
|
ctx->val = ctx->del;
|
||||||
|
ctx->tws = ctx->vlen = 0;
|
||||||
|
return ctx->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_legacy_replace_header(struct hdr_idx *idx, struct http_msg *msg,
|
||||||
|
const char *name, unsigned int name_len,
|
||||||
|
const char *str, struct my_regex *re,
|
||||||
|
struct buffer *output)
|
||||||
|
{
|
||||||
|
struct hdr_ctx ctx;
|
||||||
|
char *buf = ci_head(msg->chn);
|
||||||
|
|
||||||
|
ctx.idx = 0;
|
||||||
|
while (http_find_header2(name, name_len, buf, idx, &ctx)) {
|
||||||
|
struct hdr_idx_elem *hdr = idx->v + ctx.idx;
|
||||||
|
int delta, len;
|
||||||
|
char *val = ctx.line + ctx.val;
|
||||||
|
char* val_end = val + ctx.vlen;
|
||||||
|
|
||||||
|
if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = exp_replace(output->area, output->size, val, str, pmatch);
|
||||||
|
if (len == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
delta = b_rep_blk(&msg->chn->buf, val, val_end, output->area, len);
|
||||||
|
|
||||||
|
hdr->len += delta;
|
||||||
|
http_msg_move_end(msg, delta);
|
||||||
|
|
||||||
|
/* Adjust the length of the current value of the index. */
|
||||||
|
ctx.vlen += delta;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_legacy_replace_full_header(struct hdr_idx *idx, struct http_msg *msg,
|
||||||
|
const char *name, unsigned int name_len,
|
||||||
|
const char *str, struct my_regex *re,
|
||||||
|
struct buffer *output)
|
||||||
|
{
|
||||||
|
struct hdr_ctx ctx;
|
||||||
|
char *buf = ci_head(msg->chn);
|
||||||
|
|
||||||
|
ctx.idx = 0;
|
||||||
|
while (http_find_full_header2(name, name_len, buf, idx, &ctx)) {
|
||||||
|
struct hdr_idx_elem *hdr = idx->v + ctx.idx;
|
||||||
|
int delta, len;
|
||||||
|
char *val = ctx.line + ctx.val;
|
||||||
|
char* val_end = val + ctx.vlen;
|
||||||
|
|
||||||
|
if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = exp_replace(output->area, output->size, val, str, pmatch);
|
||||||
|
if (len == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
delta = b_rep_blk(&msg->chn->buf, val, val_end, output->area, len);
|
||||||
|
|
||||||
|
hdr->len += delta;
|
||||||
|
http_msg_move_end(msg, delta);
|
||||||
|
|
||||||
|
/* Adjust the length of the current value of the index. */
|
||||||
|
ctx.vlen += delta;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
|
||||||
|
* header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
|
||||||
|
* performed over the whole headers. Otherwise it must contain a valid header
|
||||||
|
* context, initialised with ctx->idx=0 for the first lookup in a series. If
|
||||||
|
* <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
|
||||||
|
* is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
|
||||||
|
* than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
|
||||||
|
* -1. The value fetch stops at commas, so this function is suited for use with
|
||||||
|
* list headers.
|
||||||
|
* The return value is 0 if nothing was found, or non-zero otherwise.
|
||||||
|
*/
|
||||||
|
unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hlen,
|
||||||
|
struct hdr_idx *idx, int occ,
|
||||||
|
struct hdr_ctx *ctx, char **vptr, size_t *vlen)
|
||||||
|
{
|
||||||
|
struct hdr_ctx local_ctx;
|
||||||
|
char *ptr_hist[MAX_HDR_HISTORY];
|
||||||
|
unsigned int len_hist[MAX_HDR_HISTORY];
|
||||||
|
unsigned int hist_ptr;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
local_ctx.idx = 0;
|
||||||
|
ctx = &local_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (occ >= 0) {
|
||||||
|
/* search from the beginning */
|
||||||
|
while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
||||||
|
occ--;
|
||||||
|
if (occ <= 0) {
|
||||||
|
*vptr = ctx->line + ctx->val;
|
||||||
|
*vlen = ctx->vlen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* negative occurrence, we scan all the list then walk back */
|
||||||
|
if (-occ > MAX_HDR_HISTORY)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
found = hist_ptr = 0;
|
||||||
|
while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
||||||
|
ptr_hist[hist_ptr] = ctx->line + ctx->val;
|
||||||
|
len_hist[hist_ptr] = ctx->vlen;
|
||||||
|
if (++hist_ptr >= MAX_HDR_HISTORY)
|
||||||
|
hist_ptr = 0;
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
if (-occ > found)
|
||||||
|
return 0;
|
||||||
|
/* OK now we have the last occurrence in [hist_ptr-1], and we need to
|
||||||
|
* find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
|
||||||
|
* -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
|
||||||
|
* to remain in the 0..9 range.
|
||||||
|
*/
|
||||||
|
hist_ptr += occ + MAX_HDR_HISTORY;
|
||||||
|
if (hist_ptr >= MAX_HDR_HISTORY)
|
||||||
|
hist_ptr -= MAX_HDR_HISTORY;
|
||||||
|
*vptr = ptr_hist[hist_ptr];
|
||||||
|
*vlen = len_hist[hist_ptr];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
|
||||||
|
* header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
|
||||||
|
* performed over the whole headers. Otherwise it must contain a valid header
|
||||||
|
* context, initialised with ctx->idx=0 for the first lookup in a series. If
|
||||||
|
* <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
|
||||||
|
* is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
|
||||||
|
* than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
|
||||||
|
* -1. This function differs from http_get_hdr() in that it only returns full
|
||||||
|
* line header values and does not stop at commas.
|
||||||
|
* The return value is 0 if nothing was found, or non-zero otherwise.
|
||||||
|
*/
|
||||||
|
unsigned int http_get_fhdr(const struct http_msg *msg, const char *hname, int hlen,
|
||||||
|
struct hdr_idx *idx, int occ,
|
||||||
|
struct hdr_ctx *ctx, char **vptr, size_t *vlen)
|
||||||
|
{
|
||||||
|
struct hdr_ctx local_ctx;
|
||||||
|
char *ptr_hist[MAX_HDR_HISTORY];
|
||||||
|
unsigned int len_hist[MAX_HDR_HISTORY];
|
||||||
|
unsigned int hist_ptr;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
local_ctx.idx = 0;
|
||||||
|
ctx = &local_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (occ >= 0) {
|
||||||
|
/* search from the beginning */
|
||||||
|
while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
||||||
|
occ--;
|
||||||
|
if (occ <= 0) {
|
||||||
|
*vptr = ctx->line + ctx->val;
|
||||||
|
*vlen = ctx->vlen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* negative occurrence, we scan all the list then walk back */
|
||||||
|
if (-occ > MAX_HDR_HISTORY)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
found = hist_ptr = 0;
|
||||||
|
while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
||||||
|
ptr_hist[hist_ptr] = ctx->line + ctx->val;
|
||||||
|
len_hist[hist_ptr] = ctx->vlen;
|
||||||
|
if (++hist_ptr >= MAX_HDR_HISTORY)
|
||||||
|
hist_ptr = 0;
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
if (-occ > found)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* OK now we have the last occurrence in [hist_ptr-1], and we need to
|
||||||
|
* find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
|
||||||
|
* -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
|
||||||
|
* to remain in the 0..9 range.
|
||||||
|
*/
|
||||||
|
hist_ptr += occ + MAX_HDR_HISTORY;
|
||||||
|
if (hist_ptr >= MAX_HDR_HISTORY)
|
||||||
|
hist_ptr -= MAX_HDR_HISTORY;
|
||||||
|
*vptr = ptr_hist[hist_ptr];
|
||||||
|
*vlen = len_hist[hist_ptr];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
461
src/proto_http.c
461
src/proto_http.c
@ -86,296 +86,6 @@ const char *stat_status_codes[STAT_STATUS_SIZE] = {
|
|||||||
[STAT_STATUS_UNKN] = "UNKN",
|
[STAT_STATUS_UNKN] = "UNKN",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds a header and its CRLF at the tail of the message's buffer, just before
|
|
||||||
* the last CRLF. <len> bytes are copied, not counting the CRLF.
|
|
||||||
* The header is also automatically added to the index <hdr_idx>, and the end
|
|
||||||
* of headers is automatically adjusted. The number of bytes added is returned
|
|
||||||
* on success, otherwise <0 is returned indicating an error.
|
|
||||||
*/
|
|
||||||
int http_header_add_tail2(struct http_msg *msg,
|
|
||||||
struct hdr_idx *hdr_idx, const char *text, int len)
|
|
||||||
{
|
|
||||||
int bytes;
|
|
||||||
|
|
||||||
bytes = ci_insert_line2(msg->chn, msg->eoh, text, len);
|
|
||||||
if (!bytes)
|
|
||||||
return -1;
|
|
||||||
http_msg_move_end(msg, bytes);
|
|
||||||
return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the first or next occurrence of header <name> in message buffer <sol>
|
|
||||||
* using headers index <idx>, and return it in the <ctx> structure. This
|
|
||||||
* structure holds everything necessary to use the header and find next
|
|
||||||
* occurrence. If its <idx> member is 0, the header is searched from the
|
|
||||||
* beginning. Otherwise, the next occurrence is returned. The function returns
|
|
||||||
* 1 when it finds a value, and 0 when there is no more. It is very similar to
|
|
||||||
* http_find_header2() except that it is designed to work with full-line headers
|
|
||||||
* whose comma is not a delimiter but is part of the syntax. As a special case,
|
|
||||||
* if ctx->val is NULL when searching for a new values of a header, the current
|
|
||||||
* header is rescanned. This allows rescanning after a header deletion.
|
|
||||||
*/
|
|
||||||
int http_find_full_header2(const char *name, int len,
|
|
||||||
char *sol, struct hdr_idx *idx,
|
|
||||||
struct hdr_ctx *ctx)
|
|
||||||
{
|
|
||||||
char *eol, *sov;
|
|
||||||
int cur_idx, old_idx;
|
|
||||||
|
|
||||||
cur_idx = ctx->idx;
|
|
||||||
if (cur_idx) {
|
|
||||||
/* We have previously returned a header, let's search another one */
|
|
||||||
sol = ctx->line;
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
goto next_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first request for this header */
|
|
||||||
sol += hdr_idx_first_pos(idx);
|
|
||||||
old_idx = 0;
|
|
||||||
cur_idx = hdr_idx_first_idx(idx);
|
|
||||||
while (cur_idx) {
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
/* No argument was passed, we want any header.
|
|
||||||
* To achieve this, we simply build a fake request. */
|
|
||||||
while (sol + len < eol && sol[len] != ':')
|
|
||||||
len++;
|
|
||||||
name = sol;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((len < eol - sol) &&
|
|
||||||
(sol[len] == ':') &&
|
|
||||||
(strncasecmp(sol, name, len) == 0)) {
|
|
||||||
ctx->del = len;
|
|
||||||
sov = sol + len + 1;
|
|
||||||
while (sov < eol && HTTP_IS_LWS(*sov))
|
|
||||||
sov++;
|
|
||||||
|
|
||||||
ctx->line = sol;
|
|
||||||
ctx->prev = old_idx;
|
|
||||||
ctx->idx = cur_idx;
|
|
||||||
ctx->val = sov - sol;
|
|
||||||
ctx->tws = 0;
|
|
||||||
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
|
||||||
eol--;
|
|
||||||
ctx->tws++;
|
|
||||||
}
|
|
||||||
ctx->vlen = eol - sov;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
next_hdr:
|
|
||||||
sol = eol + idx->v[cur_idx].cr + 1;
|
|
||||||
old_idx = cur_idx;
|
|
||||||
cur_idx = idx->v[cur_idx].next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the first or next header field in message buffer <sol> using headers
|
|
||||||
* index <idx>, and return it in the <ctx> structure. This structure holds
|
|
||||||
* everything necessary to use the header and find next occurrence. If its
|
|
||||||
* <idx> member is 0, the first header is retrieved. Otherwise, the next
|
|
||||||
* occurrence is returned. The function returns 1 when it finds a value, and
|
|
||||||
* 0 when there is no more. It is equivalent to http_find_full_header2() with
|
|
||||||
* no header name.
|
|
||||||
*/
|
|
||||||
int http_find_next_header(char *sol, struct hdr_idx *idx, struct hdr_ctx *ctx)
|
|
||||||
{
|
|
||||||
char *eol, *sov;
|
|
||||||
int cur_idx, old_idx;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
cur_idx = ctx->idx;
|
|
||||||
if (cur_idx) {
|
|
||||||
/* We have previously returned a header, let's search another one */
|
|
||||||
sol = ctx->line;
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
goto next_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first request for this header */
|
|
||||||
sol += hdr_idx_first_pos(idx);
|
|
||||||
old_idx = 0;
|
|
||||||
cur_idx = hdr_idx_first_idx(idx);
|
|
||||||
while (cur_idx) {
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
while (1) {
|
|
||||||
if (len >= eol - sol)
|
|
||||||
goto next_hdr;
|
|
||||||
if (sol[len] == ':')
|
|
||||||
break;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->del = len;
|
|
||||||
sov = sol + len + 1;
|
|
||||||
while (sov < eol && HTTP_IS_LWS(*sov))
|
|
||||||
sov++;
|
|
||||||
|
|
||||||
ctx->line = sol;
|
|
||||||
ctx->prev = old_idx;
|
|
||||||
ctx->idx = cur_idx;
|
|
||||||
ctx->val = sov - sol;
|
|
||||||
ctx->tws = 0;
|
|
||||||
|
|
||||||
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
|
||||||
eol--;
|
|
||||||
ctx->tws++;
|
|
||||||
}
|
|
||||||
ctx->vlen = eol - sov;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
next_hdr:
|
|
||||||
sol = eol + idx->v[cur_idx].cr + 1;
|
|
||||||
old_idx = cur_idx;
|
|
||||||
cur_idx = idx->v[cur_idx].next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the first or next occurrence of header <name> in message buffer <sol>
|
|
||||||
* using headers index <idx>, and return it in the <ctx> structure. This
|
|
||||||
* structure holds everything necessary to use the header and find next
|
|
||||||
* occurrence. If its <idx> member is 0, the header is searched from the
|
|
||||||
* beginning. Otherwise, the next occurrence is returned. The function returns
|
|
||||||
* 1 when it finds a value, and 0 when there is no more. It is designed to work
|
|
||||||
* with headers defined as comma-separated lists. As a special case, if ctx->val
|
|
||||||
* is NULL when searching for a new values of a header, the current header is
|
|
||||||
* rescanned. This allows rescanning after a header deletion.
|
|
||||||
*/
|
|
||||||
int http_find_header2(const char *name, int len,
|
|
||||||
char *sol, struct hdr_idx *idx,
|
|
||||||
struct hdr_ctx *ctx)
|
|
||||||
{
|
|
||||||
char *eol, *sov;
|
|
||||||
int cur_idx, old_idx;
|
|
||||||
|
|
||||||
cur_idx = ctx->idx;
|
|
||||||
if (cur_idx) {
|
|
||||||
/* We have previously returned a value, let's search
|
|
||||||
* another one on the same line.
|
|
||||||
*/
|
|
||||||
sol = ctx->line;
|
|
||||||
ctx->del = ctx->val + ctx->vlen + ctx->tws;
|
|
||||||
sov = sol + ctx->del;
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
|
|
||||||
if (sov >= eol)
|
|
||||||
/* no more values in this header */
|
|
||||||
goto next_hdr;
|
|
||||||
|
|
||||||
/* values remaining for this header, skip the comma but save it
|
|
||||||
* for later use (eg: for header deletion).
|
|
||||||
*/
|
|
||||||
sov++;
|
|
||||||
while (sov < eol && HTTP_IS_LWS((*sov)))
|
|
||||||
sov++;
|
|
||||||
|
|
||||||
goto return_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first request for this header */
|
|
||||||
sol += hdr_idx_first_pos(idx);
|
|
||||||
old_idx = 0;
|
|
||||||
cur_idx = hdr_idx_first_idx(idx);
|
|
||||||
while (cur_idx) {
|
|
||||||
eol = sol + idx->v[cur_idx].len;
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
/* No argument was passed, we want any header.
|
|
||||||
* To achieve this, we simply build a fake request. */
|
|
||||||
while (sol + len < eol && sol[len] != ':')
|
|
||||||
len++;
|
|
||||||
name = sol;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((len < eol - sol) &&
|
|
||||||
(sol[len] == ':') &&
|
|
||||||
(strncasecmp(sol, name, len) == 0)) {
|
|
||||||
ctx->del = len;
|
|
||||||
sov = sol + len + 1;
|
|
||||||
while (sov < eol && HTTP_IS_LWS(*sov))
|
|
||||||
sov++;
|
|
||||||
|
|
||||||
ctx->line = sol;
|
|
||||||
ctx->prev = old_idx;
|
|
||||||
return_hdr:
|
|
||||||
ctx->idx = cur_idx;
|
|
||||||
ctx->val = sov - sol;
|
|
||||||
|
|
||||||
eol = http_find_hdr_value_end(sov, eol);
|
|
||||||
ctx->tws = 0;
|
|
||||||
while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
|
|
||||||
eol--;
|
|
||||||
ctx->tws++;
|
|
||||||
}
|
|
||||||
ctx->vlen = eol - sov;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
next_hdr:
|
|
||||||
sol = eol + idx->v[cur_idx].cr + 1;
|
|
||||||
old_idx = cur_idx;
|
|
||||||
cur_idx = idx->v[cur_idx].next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove one value of a header. This only works on a <ctx> returned by one of
|
|
||||||
* the http_find_header functions. The value is removed, as well as surrounding
|
|
||||||
* commas if any. If the removed value was alone, the whole header is removed.
|
|
||||||
* The ctx is always updated accordingly, as well as the buffer and HTTP
|
|
||||||
* message <msg>. The new index is returned. If it is zero, it means there is
|
|
||||||
* no more header, so any processing may stop. The ctx is always left in a form
|
|
||||||
* that can be handled by http_find_header2() to find next occurrence.
|
|
||||||
*/
|
|
||||||
int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ctx *ctx)
|
|
||||||
{
|
|
||||||
int cur_idx = ctx->idx;
|
|
||||||
char *sol = ctx->line;
|
|
||||||
struct hdr_idx_elem *hdr;
|
|
||||||
int delta, skip_comma;
|
|
||||||
|
|
||||||
if (!cur_idx)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hdr = &idx->v[cur_idx];
|
|
||||||
if (sol[ctx->del] == ':' && ctx->val + ctx->vlen + ctx->tws == hdr->len) {
|
|
||||||
/* This was the only value of the header, we must now remove it entirely. */
|
|
||||||
delta = b_rep_blk(&msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
|
|
||||||
http_msg_move_end(msg, delta);
|
|
||||||
idx->used--;
|
|
||||||
hdr->len = 0; /* unused entry */
|
|
||||||
idx->v[ctx->prev].next = idx->v[ctx->idx].next;
|
|
||||||
if (idx->tail == ctx->idx)
|
|
||||||
idx->tail = ctx->prev;
|
|
||||||
ctx->idx = ctx->prev; /* walk back to the end of previous header */
|
|
||||||
ctx->line -= idx->v[ctx->idx].len + idx->v[ctx->idx].cr + 1;
|
|
||||||
ctx->val = idx->v[ctx->idx].len; /* point to end of previous header */
|
|
||||||
ctx->tws = ctx->vlen = 0;
|
|
||||||
return ctx->idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This was not the only value of this header. We have to remove between
|
|
||||||
* ctx->del+1 and ctx->val+ctx->vlen+ctx->tws+1 included. If it is the
|
|
||||||
* last entry of the list, we remove the last separator.
|
|
||||||
*/
|
|
||||||
|
|
||||||
skip_comma = (ctx->val + ctx->vlen + ctx->tws == hdr->len) ? 0 : 1;
|
|
||||||
delta = b_rep_blk(&msg->chn->buf, sol + ctx->del + skip_comma,
|
|
||||||
sol + ctx->val + ctx->vlen + ctx->tws + skip_comma,
|
|
||||||
NULL, 0);
|
|
||||||
hdr->len += delta;
|
|
||||||
http_msg_move_end(msg, delta);
|
|
||||||
ctx->val = ctx->del;
|
|
||||||
ctx->tws = ctx->vlen = 0;
|
|
||||||
return ctx->idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function handles a server error at the stream interface level. The
|
/* This function handles a server error at the stream interface level. The
|
||||||
* stream interface is assumed to be already in a closed state. An optional
|
* stream interface is assumed to be already in a closed state. An optional
|
||||||
* message is copied into the input buffer.
|
* message is copied into the input buffer.
|
||||||
@ -1639,50 +1349,18 @@ int http_transform_header_str(struct stream* s, struct http_msg *msg,
|
|||||||
const char *str, struct my_regex *re,
|
const char *str, struct my_regex *re,
|
||||||
int action)
|
int action)
|
||||||
{
|
{
|
||||||
struct hdr_ctx ctx;
|
|
||||||
char *buf = ci_head(msg->chn);
|
|
||||||
struct hdr_idx *idx = &s->txn->hdr_idx;
|
struct hdr_idx *idx = &s->txn->hdr_idx;
|
||||||
int (*http_find_hdr_func)(const char *name, int len, char *sol,
|
|
||||||
struct hdr_idx *idx, struct hdr_ctx *ctx);
|
|
||||||
struct buffer *output = get_trash_chunk();
|
struct buffer *output = get_trash_chunk();
|
||||||
|
|
||||||
ctx.idx = 0;
|
|
||||||
|
|
||||||
/* Choose the header browsing function. */
|
/* Choose the header browsing function. */
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ACT_HTTP_REPLACE_VAL:
|
case ACT_HTTP_REPLACE_VAL:
|
||||||
http_find_hdr_func = http_find_header2;
|
return http_legacy_replace_header(idx, msg, name, name_len, str, re, output);
|
||||||
break;
|
|
||||||
case ACT_HTTP_REPLACE_HDR:
|
case ACT_HTTP_REPLACE_HDR:
|
||||||
http_find_hdr_func = http_find_full_header2;
|
return http_legacy_replace_full_header(idx, msg, name, name_len, str, re, output);
|
||||||
break;
|
|
||||||
default: /* impossible */
|
default: /* impossible */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (http_find_hdr_func(name, name_len, buf, idx, &ctx)) {
|
|
||||||
struct hdr_idx_elem *hdr = idx->v + ctx.idx;
|
|
||||||
int delta, len;
|
|
||||||
char *val = ctx.line + ctx.val;
|
|
||||||
char* val_end = val + ctx.vlen;
|
|
||||||
|
|
||||||
if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
len = exp_replace(output->area, output->size, val, str, pmatch);
|
|
||||||
if (len == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
delta = b_rep_blk(&msg->chn->buf, val, val_end, output->area, len);
|
|
||||||
|
|
||||||
hdr->len += delta;
|
|
||||||
http_msg_move_end(msg, delta);
|
|
||||||
|
|
||||||
/* Adjust the length of the current value of the index. */
|
|
||||||
ctx.vlen += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int http_transform_header(struct stream* s, struct http_msg *msg,
|
static int http_transform_header(struct stream* s, struct http_msg *msg,
|
||||||
@ -6164,7 +5842,7 @@ int apply_filters_to_request(struct stream *s, struct channel *req, struct proxy
|
|||||||
* - there are non-space chars before <from> ;
|
* - there are non-space chars before <from> ;
|
||||||
* - there is a CR/LF at or after <next>.
|
* - there is a CR/LF at or after <next>.
|
||||||
*/
|
*/
|
||||||
int del_hdr_value(struct buffer *buf, char **from, char *next)
|
static int del_hdr_value(struct buffer *buf, char **from, char *next)
|
||||||
{
|
{
|
||||||
char *prev = *from;
|
char *prev = *from;
|
||||||
|
|
||||||
@ -7435,139 +7113,6 @@ void http_capture_bad_message(struct proxy *proxy, struct stream *s,
|
|||||||
&ctx, http_show_error_snapshot);
|
&ctx, http_show_error_snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
|
|
||||||
* header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
|
|
||||||
* performed over the whole headers. Otherwise it must contain a valid header
|
|
||||||
* context, initialised with ctx->idx=0 for the first lookup in a series. If
|
|
||||||
* <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
|
|
||||||
* is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
|
|
||||||
* than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
|
|
||||||
* -1. The value fetch stops at commas, so this function is suited for use with
|
|
||||||
* list headers.
|
|
||||||
* The return value is 0 if nothing was found, or non-zero otherwise.
|
|
||||||
*/
|
|
||||||
unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hlen,
|
|
||||||
struct hdr_idx *idx, int occ,
|
|
||||||
struct hdr_ctx *ctx, char **vptr, size_t *vlen)
|
|
||||||
{
|
|
||||||
struct hdr_ctx local_ctx;
|
|
||||||
char *ptr_hist[MAX_HDR_HISTORY];
|
|
||||||
unsigned int len_hist[MAX_HDR_HISTORY];
|
|
||||||
unsigned int hist_ptr;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
if (!ctx) {
|
|
||||||
local_ctx.idx = 0;
|
|
||||||
ctx = &local_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (occ >= 0) {
|
|
||||||
/* search from the beginning */
|
|
||||||
while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
|
||||||
occ--;
|
|
||||||
if (occ <= 0) {
|
|
||||||
*vptr = ctx->line + ctx->val;
|
|
||||||
*vlen = ctx->vlen;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* negative occurrence, we scan all the list then walk back */
|
|
||||||
if (-occ > MAX_HDR_HISTORY)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
found = hist_ptr = 0;
|
|
||||||
while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
|
||||||
ptr_hist[hist_ptr] = ctx->line + ctx->val;
|
|
||||||
len_hist[hist_ptr] = ctx->vlen;
|
|
||||||
if (++hist_ptr >= MAX_HDR_HISTORY)
|
|
||||||
hist_ptr = 0;
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
if (-occ > found)
|
|
||||||
return 0;
|
|
||||||
/* OK now we have the last occurrence in [hist_ptr-1], and we need to
|
|
||||||
* find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
|
|
||||||
* -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
|
|
||||||
* to remain in the 0..9 range.
|
|
||||||
*/
|
|
||||||
hist_ptr += occ + MAX_HDR_HISTORY;
|
|
||||||
if (hist_ptr >= MAX_HDR_HISTORY)
|
|
||||||
hist_ptr -= MAX_HDR_HISTORY;
|
|
||||||
*vptr = ptr_hist[hist_ptr];
|
|
||||||
*vlen = len_hist[hist_ptr];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
|
|
||||||
* header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
|
|
||||||
* performed over the whole headers. Otherwise it must contain a valid header
|
|
||||||
* context, initialised with ctx->idx=0 for the first lookup in a series. If
|
|
||||||
* <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
|
|
||||||
* is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
|
|
||||||
* than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
|
|
||||||
* -1. This function differs from http_get_hdr() in that it only returns full
|
|
||||||
* line header values and does not stop at commas.
|
|
||||||
* The return value is 0 if nothing was found, or non-zero otherwise.
|
|
||||||
*/
|
|
||||||
unsigned int http_get_fhdr(const struct http_msg *msg, const char *hname, int hlen,
|
|
||||||
struct hdr_idx *idx, int occ,
|
|
||||||
struct hdr_ctx *ctx, char **vptr, size_t *vlen)
|
|
||||||
{
|
|
||||||
struct hdr_ctx local_ctx;
|
|
||||||
char *ptr_hist[MAX_HDR_HISTORY];
|
|
||||||
unsigned int len_hist[MAX_HDR_HISTORY];
|
|
||||||
unsigned int hist_ptr;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
if (!ctx) {
|
|
||||||
local_ctx.idx = 0;
|
|
||||||
ctx = &local_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (occ >= 0) {
|
|
||||||
/* search from the beginning */
|
|
||||||
while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
|
||||||
occ--;
|
|
||||||
if (occ <= 0) {
|
|
||||||
*vptr = ctx->line + ctx->val;
|
|
||||||
*vlen = ctx->vlen;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* negative occurrence, we scan all the list then walk back */
|
|
||||||
if (-occ > MAX_HDR_HISTORY)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
found = hist_ptr = 0;
|
|
||||||
while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
|
|
||||||
ptr_hist[hist_ptr] = ctx->line + ctx->val;
|
|
||||||
len_hist[hist_ptr] = ctx->vlen;
|
|
||||||
if (++hist_ptr >= MAX_HDR_HISTORY)
|
|
||||||
hist_ptr = 0;
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
if (-occ > found)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* OK now we have the last occurrence in [hist_ptr-1], and we need to
|
|
||||||
* find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
|
|
||||||
* -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
|
|
||||||
* to remain in the 0..9 range.
|
|
||||||
*/
|
|
||||||
hist_ptr += occ + MAX_HDR_HISTORY;
|
|
||||||
if (hist_ptr >= MAX_HDR_HISTORY)
|
|
||||||
hist_ptr -= MAX_HDR_HISTORY;
|
|
||||||
*vptr = ptr_hist[hist_ptr];
|
|
||||||
*vlen = len_hist[hist_ptr];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a debug line with a header. Always stop at the first CR or LF char,
|
* Print a debug line with a header. Always stop at the first CR or LF char,
|
||||||
* so it is safe to pass it a full buffer if needed. If <err> is not NULL, an
|
* so it is safe to pass it a full buffer if needed. If <err> is not NULL, an
|
||||||
|
Loading…
Reference in New Issue
Block a user