[MEDIUM] make process_cli() not depend on req->h anymore

Local variables now keep the start and end of line at any moment.
req->h has been removed and will soon be removable from the buffer.
This commit is contained in:
Willy Tarreau 2006-12-16 19:57:26 +01:00
parent 09733ab109
commit a4cd1f50cc

View File

@ -25,6 +25,7 @@
#include <common/appsession.h> #include <common/appsession.h>
#include <common/compat.h> #include <common/compat.h>
#include <common/config.h> #include <common/config.h>
#include <common/debug.h>
#include <common/memory.h> #include <common/memory.h>
#include <common/mini-clist.h> #include <common/mini-clist.h>
#include <common/standard.h> #include <common/standard.h>
@ -225,7 +226,6 @@ int process_cli(struct session *t)
int delete_header = 0; int delete_header = 0;
int cur_hdr, cur_idx; int cur_hdr, cur_idx;
char *ptr;
#ifdef DEBUG_FULL #ifdef DEBUG_FULL
fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n", fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
@ -260,19 +260,20 @@ int process_cli(struct session *t)
* skipped. * skipped.
* *
* Here is the information we currently have : * Here is the information we currently have :
* req->h = beginning of current line or header * req->data = beginning of request
* req->lr = first non-visited byte * req->lr = first non-visited byte
* req->r = end of data * req->r = end of data
*/ */
char *sol, *eol; /* Start Of Line, End Of Line */
eol = sol = req->data;
while (req->lr < req->r) { while (req->lr < req->r) {
char *ptr;
int parse; int parse;
#ifdef DEBUG_FULL DPRINTF(stderr, "WHL: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%p, lr=%p, r=%p\n",
fprintf(stderr, "WHL: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%p, lr=%p, r=%p\n", t->hdr_state, t->hdr_idx.used, t->hdr_idx.tail, t->hdr_idx.last, sol, req->lr, req->r);
t->hdr_state, t->hdr_idx.used, t->hdr_idx.tail, t->hdr_idx.last, req->h, req->lr, req->r);
#endif
if (t->hdr_state & HTTP_PA_LF_EXP) { if (t->hdr_state & HTTP_PA_LF_EXP) {
if (*req->lr != '\n') { if (*req->lr != '\n') {
@ -298,9 +299,10 @@ int process_cli(struct session *t)
continue; continue;
} }
DPRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n", sol-req->data, req->lr-req->data, req->r-req->data);
#if PARSE_PRESERVE_EMPTY_LINES #if PARSE_PRESERVE_EMPTY_LINES
/* only skip empty leading lines, don't remove them */ /* only skip empty leading lines, don't remove them */
t->hdr_idx.v[0].len = req->lr - req->h; t->hdr_idx.v[0].len = req->lr - sol;
#else #else
/* remove empty leading lines, as recommended by /* remove empty leading lines, as recommended by
* RFC2616. This takes a lot of time because we * RFC2616. This takes a lot of time because we
@ -309,9 +311,10 @@ int process_cli(struct session *t)
* cleaner when we'll be able to start sending * cleaner when we'll be able to start sending
* the request from any place in the buffer. * the request from any place in the buffer.
*/ */
buffer_replace2(req, req->h, req->lr, NULL, 0); buffer_replace2(req, sol, req->lr, NULL, 0);
#endif #endif
req->h = req->lr; sol = req->lr;
DPRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n", sol-req->data, req->lr-req->data, req->r-req->data);
t->hdr_state = HTTP_PA_START; t->hdr_state = HTTP_PA_START;
#ifndef DEBUG_PARSE_NO_SPEEDUP #ifndef DEBUG_PARSE_NO_SPEEDUP
@ -350,12 +353,12 @@ int process_cli(struct session *t)
parse_strt_lf: parse_strt_lf:
/* The LF validating the request line */ /* The LF validating the request line */
ptr = req->lr; eol = req->lr;
if (t->hdr_state & HTTP_PA_CR_SKIP) if (t->hdr_state & HTTP_PA_CR_SKIP)
ptr--; /* Get back to the CR */ eol--; /* Get back to the CR */
/* We have the complete start line between /* We have the complete start line between
* req->h and ptr (excluded). lr points to * sol and eol (excluded). lr points to
* the LF. * the LF.
*/ */
@ -365,17 +368,17 @@ int process_cli(struct session *t)
/* 1: we might have to print this header */ /* 1: we might have to print this header */
if ((global.mode & MODE_DEBUG) && if ((global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
debug_hdr("clireq", t, req->h, ptr); debug_hdr("clireq", t, sol, eol);
/* 2: maybe we have to copy the original REQURI for the logs ? */ /* 2: maybe we have to copy the original REQURI for the logs ? */
if (t->logs.logwait & LW_REQ) { if (t->logs.logwait & LW_REQ) {
/* we have a complete HTTP request that we must log */ /* we have a complete HTTP request that we must log */
if ((t->logs.uri = pool_alloc(requri)) != NULL) { if ((t->logs.uri = pool_alloc(requri)) != NULL) {
int urilen = ptr - req->h; int urilen = eol - sol;
if (urilen >= REQURI_LEN) if (urilen >= REQURI_LEN)
urilen = REQURI_LEN - 1; urilen = REQURI_LEN - 1;
memcpy(t->logs.uri, req->h, urilen); memcpy(t->logs.uri, sol, urilen);
t->logs.uri[urilen] = 0; t->logs.uri[urilen] = 0;
if (!(t->logs.logwait &= ~LW_REQ)) if (!(t->logs.logwait &= ~LW_REQ))
@ -386,14 +389,14 @@ int process_cli(struct session *t)
} }
/* 3: reference this line as the start line */ /* 3: reference this line as the start line */
if (hdr_idx_add(ptr - req->h, req->lr - ptr, if (hdr_idx_add(eol - sol, req->lr - eol,
&t->hdr_idx, t->hdr_idx.tail) < 0) { &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
break; break;
} }
req->lr++; req->lr++;
req->h = req->lr; sol = req->lr;
/* in fact, a state is missing here, we should /* in fact, a state is missing here, we should
* be able to distinguish between an empty line * be able to distinguish between an empty line
* and a header. * and a header.
@ -437,13 +440,13 @@ int process_cli(struct session *t)
* now if this LF/CRLF closes an empty line, in * now if this LF/CRLF closes an empty line, in
* which case it means the end of the request. * which case it means the end of the request.
*/ */
ptr = req->lr; eol = req->lr;
if (t->hdr_state & HTTP_PA_CR_SKIP) if (t->hdr_state & HTTP_PA_CR_SKIP)
ptr--; /* Get back to the CR */ eol--; /* Get back to the CR */
if (ptr == req->h) { if (eol == sol) {
/* We have found the end of the headers. /* We have found the end of the headers.
* req->h points to the ending LF/CRLF, * sol points to the ending LF/CRLF,
* and req->lr points to the first byte * and req->lr points to the first byte
* after the LF, so it is easy to append * after the LF, so it is easy to append
* anything there. * anything there.
@ -472,8 +475,8 @@ int process_cli(struct session *t)
* allows it. <lr> now points to the * allows it. <lr> now points to the
* first space char of the LWS part. * first space char of the LWS part.
*/ */
for (;ptr < req->lr; ptr++) for (;eol < req->lr; eol++)
*ptr = ' '; *eol = ' ';
t->hdr_state = HTTP_PA_HDR_LWS; t->hdr_state = HTTP_PA_HDR_LWS;
#ifndef DEBUG_PARSE_NO_SPEEDUP #ifndef DEBUG_PARSE_NO_SPEEDUP
@ -485,7 +488,7 @@ int process_cli(struct session *t)
/********************************************** /**********************************************
* We now have one complete header between * * We now have one complete header between *
* req->h and ptr, with a possible CR at ptr, * * sol and eol, with a possible CR at eol, *
* everything ending before req->lr. Some very* * everything ending before req->lr. Some very*
* early processing can be applied. * * early processing can be applied. *
**********************************************/ **********************************************/
@ -501,7 +504,7 @@ int process_cli(struct session *t)
/* 1: we might have to print this header */ /* 1: we might have to print this header */
if ((global.mode & MODE_DEBUG) && if ((global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
debug_hdr("clihdr", t, req->h, ptr); debug_hdr("clihdr", t, sol, eol);
/* 2: maybe we have to copy this header for the logs ? */ /* 2: maybe we have to copy this header for the logs ? */
@ -511,9 +514,9 @@ int process_cli(struct session *t)
struct cap_hdr *h; struct cap_hdr *h;
int len; int len;
for (h = t->fi->req_cap; h; h = h->next) { for (h = t->fi->req_cap; h; h = h->next) {
if ((h->namelen + 2 <= ptr - req->h) && if ((h->namelen + 2 <= eol - sol) &&
(req->h[h->namelen] == ':') && (sol[h->namelen] == ':') &&
(strncasecmp(req->h, h->name, h->namelen) == 0)) { (strncasecmp(sol, h->name, h->namelen) == 0)) {
if (t->req_cap[h->index] == NULL) if (t->req_cap[h->index] == NULL)
t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1); t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
@ -522,11 +525,11 @@ int process_cli(struct session *t)
continue; continue;
} }
len = ptr - (req->h + h->namelen + 2); len = eol - (sol + h->namelen + 2);
if (len > h->len) if (len > h->len)
len = h->len; len = h->len;
memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len); memcpy(t->req_cap[h->index], sol + h->namelen + 2, len);
t->req_cap[h->index][len]=0; t->req_cap[h->index][len]=0;
} }
} }
@ -535,7 +538,7 @@ int process_cli(struct session *t)
/* 3: We might need to remove "connection:" */ /* 3: We might need to remove "connection:" */
if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE) if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
&& (strncasecmp(req->h, "Connection:", 11) == 0)) { && (strncasecmp(sol, "Connection:", 11) == 0)) {
delete_header = 1; delete_header = 1;
} }
@ -546,7 +549,7 @@ int process_cli(struct session *t)
if (!delete_header) { if (!delete_header) {
/* we insert it into the index */ /* we insert it into the index */
if (hdr_idx_add(ptr - req->h, req->lr - ptr - 1, if (hdr_idx_add(eol - sol, req->lr - eol - 1,
&t->hdr_idx, t->hdr_idx.tail) < 0) { &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
break; break;
@ -554,15 +557,15 @@ int process_cli(struct session *t)
} else { } else {
/* we remove it */ /* we remove it */
delete_header = 0; delete_header = 0;
buffer_replace2(req, req->h, req->lr, NULL, 0); buffer_replace2(req, sol, req->lr, NULL, 0);
/* WARNING: ptr is not valid anymore, since the /* WARNING: eol is not valid anymore, since the
* header may have been deleted or truncated ! */ * header may have been deleted or truncated ! */
} }
/* In any case, we set the next header pointer /* In any case, we set the next header pointer
* to the next line. * to the next line.
*/ */
req->h = req->lr; sol = req->lr;
#ifndef DEBUG_PARSE_NO_SPEEDUP #ifndef DEBUG_PARSE_NO_SPEEDUP
/* /*
@ -570,14 +573,14 @@ int process_cli(struct session *t)
* It is interesting to directly branch to the * It is interesting to directly branch to the
* matching state. * matching state.
*/ */
ptr = req->lr; eol = req->lr;
if (IS_CTL(*req->lr)) { if (IS_CTL(*req->lr)) {
if (*ptr == '\r') { if (*eol == '\r') {
req->lr++; req->lr++;
t->hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP; t->hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
continue; continue;
} }
else if (*ptr == '\n') { else if (*eol == '\n') {
t->hdr_state = HTTP_PA_LFLF; t->hdr_state = HTTP_PA_LFLF;
goto parse_lflf; goto parse_lflf;
} }
@ -618,7 +621,7 @@ int process_cli(struct session *t)
} else if (parse == HTTP_PA_LFLF) { } else if (parse == HTTP_PA_LFLF) {
parse_lflf: parse_lflf:
req->lr ++; req->lr ++;
/* req->h points to either CR or CRLF, and /* sol points to either CR or CRLF, and
* req->lr points to 1 char after LF. * req->lr points to 1 char after LF.
*/ */
@ -632,10 +635,8 @@ int process_cli(struct session *t)
} /* end of the "while(req->lr < req->r)" loop */ } /* end of the "while(req->lr < req->r)" loop */
#ifdef DEBUG_FULL DPRINTF(stderr, "END: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%p, lr=%p, r=%p\n",
fprintf(stderr, "END: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%p, lr=%p, r=%p\n", t->hdr_state, t->hdr_idx.used, t->hdr_idx.tail, t->hdr_idx.last, sol, req->lr, req->r);
t->hdr_state, t->hdr_idx.used, t->hdr_idx.tail, t->hdr_idx.last, req->h, req->lr, req->r);
#endif
/* /*
* Now, let's catch bad requests. * Now, let's catch bad requests.
@ -736,9 +737,9 @@ int process_cli(struct session *t)
/* It needs to look into the URI */ /* It needs to look into the URI */
if (t->be->appsession_name) { if (t->be->appsession_name) {
req->h = req->data + t->hdr_idx.v[0].len; /* start of the URI */ sol = req->data + t->hdr_idx.v[0].len; /* start of the URI */
ptr = req->h + t->hdr_idx.v[t->hdr_idx.v[0].next].len; /* end of the URI */ eol = sol + t->hdr_idx.v[t->hdr_idx.v[0].next].len; /* end of the URI */
get_srv_from_appsession(t, req->h, ptr); get_srv_from_appsession(t, sol, eol);
} }
@ -778,13 +779,14 @@ int process_cli(struct session *t)
* 3: save a pointer to the first line as the request, and * 3: save a pointer to the first line as the request, and
* check the method (needed for cookies). * check the method (needed for cookies).
*/ */
req->h = req->data + t->hdr_idx.v[0].len; /* start of the REQURI */
ptr = req->h + t->hdr_idx.v[t->hdr_idx.v[0].next].len; /* end of the REQURI */
t->req_line.str = req->h; t->req_line.str = req->data + t->hdr_idx.v[0].len; /* start of the REQURI */
t->req_line.len = ptr - req->h; t->req_line.len = t->hdr_idx.v[t->hdr_idx.v[0].next].len; /* end of the REQURI */
if (!memcmp(req->h, "POST ", 5)) { sol = t->req_line.str;
eol = sol + t->req_line.len;
if (!memcmp(sol, "POST ", 5)) {
/* this is a POST request, which is not cacheable by default */ /* this is a POST request, which is not cacheable by default */
t->flags |= SN_POST; t->flags |= SN_POST;
} }
@ -925,19 +927,19 @@ int process_cli(struct session *t)
*/ */
#if READABLE_PARSER_VERSION #if READABLE_PARSER_VERSION
for (req->h = req->data + t->hdr_idx.v[cur_idx=0].len; for (sol = req->data + t->hdr_idx.v[cur_idx=0].len;
(cur_idx = t->hdr_idx.v[cur_idx].next); (cur_idx = t->hdr_idx.v[cur_idx].next);
req->h += t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx]cr + 1); sol += t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx]cr + 1);
#else #else
req->h = req->data; sol = req->data;
cur_idx = 0; cur_idx = 0;
while ((req->h += t->hdr_idx.v[cur_idx].len, while ((sol += t->hdr_idx.v[cur_idx].len,
cur_idx = t->hdr_idx.v[cur_idx].next)) cur_idx = t->hdr_idx.v[cur_idx].next))
req->h += t->hdr_idx.v[cur_idx].cr + 1; sol += t->hdr_idx.v[cur_idx].cr + 1;
#endif #endif
/* now req->h points to the last LF/CRLF */ /* now sol points to the last LF/CRLF */
/* /*
* 7: add request headers * 7: add request headers
@ -945,7 +947,7 @@ int process_cli(struct session *t)
*/ */
for (cur_hdr = 0; cur_hdr < t->fi->nb_reqadd; cur_hdr++) { for (cur_hdr = 0; cur_hdr < t->fi->nb_reqadd; cur_hdr++) {
int len = sprintf(trash, "%s\r\n", t->fi->req_add[cur_hdr]); int len = sprintf(trash, "%s\r\n", t->fi->req_add[cur_hdr]);
buffer_replace2(req, req->h, req->h, trash, len); buffer_replace2(req, sol, sol, trash, len);
if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) { if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
break; break;
@ -963,7 +965,7 @@ int process_cli(struct session *t)
pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr; pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n", len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
pn[0], pn[1], pn[2], pn[3]); pn[0], pn[1], pn[2], pn[3]);
buffer_replace2(req, req->h, req->h, trash, len); buffer_replace2(req, sol, sol, trash, len);
if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) { if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
t->logs.status = 400; t->logs.status = 400;
@ -982,7 +984,7 @@ int process_cli(struct session *t)
(const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr, (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
pn, sizeof(pn)); pn, sizeof(pn));
len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn); len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
buffer_replace2(req, req->h, req->h, trash, len); buffer_replace2(req, sol, sol, trash, len);
if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) { if (hdr_idx_add(len - 2, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
t->logs.status = 400; t->logs.status = 400;
@ -1003,7 +1005,7 @@ int process_cli(struct session *t)
/* add a "connection: close" line if needed */ /* add a "connection: close" line if needed */
if (t->fe->options & PR_O_HTTP_CLOSE) { if (t->fe->options & PR_O_HTTP_CLOSE) {
buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19); buffer_replace2(req, sol, sol, "Connection: close\r\n", 19);
if (hdr_idx_add(17, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) { if (hdr_idx_add(17, 1, &t->hdr_idx, t->hdr_idx.tail) < 0) {
t->hdr_state = HTTP_PA_ERROR; t->hdr_state = HTTP_PA_ERROR;
t->logs.status = 400; t->logs.status = 400;
@ -1075,25 +1077,25 @@ int process_cli(struct session *t)
fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT)); fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
fprintf(stderr, "req->h=%d\n", req->h - req->data); fprintf(stderr, "sol=%d\n", sol - req->data);
req->h = req->data + t->hdr_idx.v[0].len; sol = req->data + t->hdr_idx.v[0].len;
cur_hdr = 0; cur_hdr = 0;
cur_idx = t->hdr_idx.v[0].next; cur_idx = t->hdr_idx.v[0].next;
cur_hdr = 1; cur_hdr = 1;
while (cur_hdr < t->hdr_idx.used) { while (cur_hdr < t->hdr_idx.used) {
ptr = req->h + t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx].cr + 1; eol = sol + t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx].cr + 1;
fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n", fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
req->lr - req->data, req->r - req->data, req->lr - req->data, req->r - req->data,
cur_hdr, cur_idx, cur_hdr, cur_idx,
req->h - req->data, sol - req->data,
req->h - req->data + t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx].cr, sol - req->data + t->hdr_idx.v[cur_idx].len + t->hdr_idx.v[cur_idx].cr,
t->hdr_idx.v[cur_idx].len, t->hdr_idx.v[cur_idx].len,
t->hdr_idx.v[cur_idx].cr); t->hdr_idx.v[cur_idx].cr);
write(2, req->h, ptr - req->h); write(2, sol, eol - sol);
req->h = ptr; sol = eol;
cur_idx = t->hdr_idx.v[cur_idx].next; cur_idx = t->hdr_idx.v[cur_idx].next;
cur_hdr++; cur_hdr++;
} }