]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MAJOR] kill CL_STINSPECT and CL_STHEADERS (step 1)
authorWilly Tarreau <w@1wt.eu>
Sun, 10 Aug 2008 20:55:22 +0000 (22:55 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 13 Aug 2008 22:18:38 +0000 (00:18 +0200)
This is a first attempt at separating data processing from the
TCP state machine. Those two states have been replaced with flags
in the session indicating what needs to be analyzed. The corresponding
code is still called before and in lieu of TCP states.

Next change should get rid of the specific SV_STANALYZE which is in
fact a client state.

Then next change should consist in making it possible to analyze
TCP contents while being in CL_STDATA (or CL_STSHUT*).

include/types/proto_http.h
include/types/session.h
src/client.c
src/proto_http.c
src/proto_uxst.c

index 713da49c1e45300936544718c12e1ba7e4cecb07..546564b989a9485134b46dc6c8034033c4f153ea 100644 (file)
  */
 
 /* different possible states for the client side */
-#define CL_STINSPECT   0
-#define CL_STHEADERS   1
-#define CL_STDATA      2
-#define CL_STSHUTR     3
-#define CL_STSHUTW     4
-#define CL_STCLOSE     5
+#define CL_STDATA      0
+#define CL_STSHUTR     1
+#define CL_STSHUTW     2
+#define CL_STCLOSE     3
 
 /* different possible states for the server side */
 #define SV_STIDLE      0
index 5bcd0d795d8810ec7423c31a769336601f77618c..c94401ae17e4e50a07f05da961e560643ef80a33 100644 (file)
  * and freed in session_free() !
  */
 
+/* analysis flags */
+#define AN_REQ_INSPECT          0x00000001  /* inspect request contents */
+#define AN_REQ_HTTP_HDR         0x00000002  /* inspect HTTP request headers */
+#define AN_REQ_HTTP_BODY        0x00000004  /* inspect HTTP request body */
+#define AN_REQ_ANY              (AN_REQ_INSPECT|AN_REQ_HTTP_HDR|AN_REQ_HTTP_BODY)
+
+#define AN_RTR_INSPECT          0x00000008  /* inspect response contents */
+#define AN_RTR_HTTP_HDR         0x00000010  /* inspect HTTP response headers */
+#define AN_RTR_HTTP_BODY        0x00000020  /* inspect HTTP response body */
+#define AN_RTR_ANY              (AN_RTR_INSPECT|AN_RTR_HTTP_HDR|AN_RTR_HTTP_BODY)
+
+
 /*
  * Note: some session flags have dependencies :
  *  - SN_DIRECT cannot exist without SN_ASSIGNED, because a server is
@@ -105,6 +117,7 @@ struct session {
        int srv_state;                          /* state of the server side */
        int conn_retries;                       /* number of connect retries left */
        int flags;                              /* some flags describing the session */
+       unsigned int analysis;                  /* bit field indicating remaining analysis to perform on data */
        struct buffer *req;                     /* request buffer */
        struct buffer *rep;                     /* response buffer */
        struct sockaddr_storage cli_addr;       /* the client address */
index e04a066ff2f2600f91a473fcf09ef91f584f3a09..cbe5f119834b734922a0ee0ad7e7f27513fd0e21 100644 (file)
@@ -106,10 +106,12 @@ int event_accept(int fd) {
                        goto out_close;
                }
 
+               s->flags = 0;
+               s->analysis = 0;
+
                /* if this session comes from a known monitoring system, we want to ignore
                 * it as soon as possible, which means closing it immediately for TCP.
                 */
-               s->flags = 0;
                if (addr.ss_family == AF_INET &&
                    p->mon_mask.s_addr &&
                    (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
@@ -159,26 +161,19 @@ int event_accept(int fd) {
                 * TCP mode there will be no header processing so any default
                 * backend must be assigned if set.
                 */
-               if (p->mode == PR_MODE_HTTP) {
-                       if (s->fe->tcp_req.inspect_delay)
-                               s->cli_state = CL_STINSPECT;
-                       else
-                               s->cli_state = CL_STHEADERS;
-               } else {
-                       /* We must assign any default backend now since
-                        * there will be no header processing.
-                        */
-                       if (p->mode == PR_MODE_TCP) {
-                               if (p->defbe.be)
-                                       s->be = p->defbe.be;
-                               s->flags |= SN_BE_ASSIGNED;
-                       }
-                       if (s->fe->tcp_req.inspect_delay)
-                               s->cli_state = CL_STINSPECT;
-                       else
-                               s->cli_state = CL_STDATA; /* no HTTP headers for non-HTTP proxies */
+               if (p->mode == PR_MODE_TCP) {
+                       if (p->defbe.be)
+                               s->be = p->defbe.be;
+                       s->flags |= SN_BE_ASSIGNED;
                }
 
+               if (p->mode == PR_MODE_HTTP)
+                       s->analysis |= AN_REQ_HTTP_HDR;
+
+               if (s->fe->tcp_req.inspect_delay)
+                       s->analysis |= AN_REQ_INSPECT;
+
+               s->cli_state = CL_STDATA;
                s->srv_state = SV_STIDLE;
                s->req = s->rep = NULL; /* will be allocated later */
 
@@ -341,7 +336,7 @@ int event_accept(int fd) {
                if (p->mode == PR_MODE_HTTP) /* reserve some space for header rewriting */
                        s->req->rlim -= MAXREWRITE;
 
-               if (s->cli_state == CL_STDATA)
+               if (!(s->analysis & AN_REQ_ANY))
                        s->req->flags |= BF_MAY_CONNECT;  /* don't wait to establish connection */
 
                s->req->rto = s->fe->timeout.client;
@@ -405,13 +400,15 @@ int event_accept(int fd) {
                        }
                }
 
-               if (s->cli_state == CL_STHEADERS && s->fe->timeout.httpreq) {
-                       s->txn.exp = tick_add(now_ms, s->fe->timeout.httpreq);
-                       t->expire = tick_first(t->expire, s->txn.exp);
-               }
-               else if (s->cli_state == CL_STINSPECT && s->fe->tcp_req.inspect_delay) {
-                       s->inspect_exp = tick_add(now_ms, s->fe->tcp_req.inspect_delay);
-                       t->expire = tick_first(t->expire, s->inspect_exp);
+               if (s->analysis & AN_REQ_ANY) {
+                       if (s->analysis & AN_REQ_INSPECT) {
+                               s->inspect_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
+                               t->expire = tick_first(t->expire, s->inspect_exp);
+                       }
+                       else if (s->analysis & AN_REQ_HTTP_HDR) {
+                               s->txn.exp = tick_add_ifset(now_ms, s->fe->timeout.httpreq);
+                               t->expire = tick_first(t->expire, s->txn.exp);
+                       }
                }
 
                if (p->mode != PR_MODE_HEALTH)
index 8a8bfffcab0d2fee50e948d4d575c67609c467f5..83406b61044e764ec5a0529a937863d086d17d52 100644 (file)
@@ -365,8 +365,8 @@ const char http_is_ver_token[256] = {
 
 
 #ifdef DEBUG_FULL
-static char *cli_stnames[6] = {"INS", "HDR", "DAT", "SHR", "SHW", "CLS" };
-static char *srv_stnames[8] = {"IDL", "ANA", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
+static char *cli_stnames[4] = { "DAT", "SHR", "SHW", "CLS" };
+static char *srv_stnames[8] = { "IDL", "ANA", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
 #endif
 
 static void http_sess_log(struct session *s);
@@ -676,10 +676,12 @@ void process_session(struct task *t, int *next)
                t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
                                       tick_first(s->rep->rex, s->rep->wex));
                t->expire = tick_first(t->expire, s->req->cex);
-               if (s->cli_state == CL_STHEADERS)
-                       t->expire = tick_first(t->expire, s->txn.exp);
-               else if (s->cli_state == CL_STINSPECT)
-                       t->expire = tick_first(t->expire, s->inspect_exp);
+               if (s->analysis & AN_REQ_ANY) {
+                       if (s->analysis & AN_REQ_INSPECT)
+                               t->expire = tick_first(t->expire, s->inspect_exp);
+                       else if (s->analysis & AN_REQ_HTTP_HDR)
+                               t->expire = tick_first(t->expire, s->txn.exp);
+               }
 
                /* restore t to its place in the task list */
                task_queue(t);
@@ -1549,7 +1551,7 @@ int process_cli(struct session *t)
                EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
                req->rex, rep->wex);
 
-       if (c == CL_STINSPECT) {
+       if (t->analysis & AN_REQ_INSPECT) {
                struct tcp_rule *rule;
                int partial;
 
@@ -1564,6 +1566,7 @@ int process_cli(struct session *t)
                        buffer_shutw_done(rep);
                        fd_delete(t->cli_fd);
                        t->cli_state = CL_STCLOSE;
+                       t->analysis &= ~AN_REQ_ANY;
                        t->fe->failed_req++;
                        if (!(t->flags & SN_ERR_MASK))
                                t->flags |= SN_ERR_CLICL;
@@ -1579,6 +1582,7 @@ int process_cli(struct session *t)
                        buffer_shutw_done(rep);
                        fd_delete(t->cli_fd);
                        t->cli_state = CL_STCLOSE;
+                       t->analysis &= ~AN_REQ_ANY;
                        t->fe->failed_req++;
                        if (!(t->flags & SN_ERR_MASK))
                                t->flags |= SN_ERR_CLITO;
@@ -1623,6 +1627,7 @@ int process_cli(struct session *t)
                                        buffer_shutw_done(rep);
                                        fd_delete(t->cli_fd);
                                        t->cli_state = CL_STCLOSE;
+                                       t->analysis &= ~AN_REQ_ANY;
                                        t->fe->failed_req++;
                                        if (!(t->flags & SN_ERR_MASK))
                                                t->flags |= SN_ERR_PRXCOND;
@@ -1636,21 +1641,21 @@ int process_cli(struct session *t)
                        }
                }
                
-               /* if we get there, it means we have no rule which matches, so
-                * we apply the default accept.
+               /* if we get there, it means we have no rule which matches, or
+                * we have an explicit accept, so we apply the default accept.
                 */
                req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-               if (t->fe->mode == PR_MODE_HTTP) {
-                       t->cli_state = CL_STHEADERS;
+               t->analysis &= ~AN_REQ_INSPECT;
+               if (t->analysis & AN_REQ_HTTP_HDR)
                        t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
-               } else {
-                       t->cli_state = CL_STDATA;
+               else
                        req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
-               }
+
                t->inspect_exp = TICK_ETERNITY;
                return 1;
        }
-       else if (c == CL_STHEADERS) {
+
+       if (t->analysis & AN_REQ_HTTP_HDR) {
                /*
                 * Now parse the partial (or complete) lines.
                 * We will check the request syntax, and also join multi-line
@@ -1732,6 +1737,7 @@ int process_cli(struct session *t)
                                buffer_shutw_done(rep);
                                fd_delete(t->cli_fd);
                                t->cli_state = CL_STCLOSE;
+                               t->analysis &= ~AN_REQ_ANY;
                                t->fe->failed_req++;
                                if (!(t->flags & SN_ERR_MASK))
                                        t->flags |= SN_ERR_CLICL;
@@ -1746,6 +1752,7 @@ int process_cli(struct session *t)
                                /* read timeout : give up with an error message. */
                                txn->status = 408;
                                client_retnclose(t, error_message(t, HTTP_ERR_408));
+                               t->analysis &= ~AN_REQ_ANY;
                                t->fe->failed_req++;
                                if (!(t->flags & SN_ERR_MASK))
                                        t->flags |= SN_ERR_CLITO;
@@ -1762,7 +1769,8 @@ int process_cli(struct session *t)
                                 */
                                req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
                        }
-                       return t->cli_state != CL_STHEADERS;
+                       /* we don't need to resync if the state has not changed */
+                       return !(t->analysis & AN_REQ_HTTP_HDR);
                }
 
 
@@ -1772,6 +1780,8 @@ int process_cli(struct session *t)
                 * of each header's length, so we can parse them quickly.       *
                 ****************************************************************/
 
+               t->analysis &= ~AN_REQ_HTTP_HDR;
+
                /* ensure we keep this pointer to the beginning of the message */
                msg->sol = req->data + msg->som;
 
@@ -2334,6 +2344,7 @@ int process_cli(struct session *t)
                                http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
                                if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
                                        t->srv_state = SV_STANALYZE;
+                                       t->analysis |= AN_REQ_HTTP_BODY;
                                } else {
                                        ctx.idx = 0;
                                        http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
@@ -2353,8 +2364,10 @@ int process_cli(struct session *t)
                                        if ( t->be->url_param_post_limit < hint )
                                                hint = t->be->url_param_post_limit;
                                        /* now do we really need to buffer more data? */
-                                       if ( len < hint )
+                                       if ( len < hint ) {
                                                t->srv_state = SV_STANALYZE;
+                                               t->analysis |= AN_REQ_HTTP_BODY;
+                                       }
                                        /* else... There are no body bytes to wait for */
                                }
                        }
@@ -2366,9 +2379,7 @@ int process_cli(struct session *t)
                 * could. Let's switch to the DATA state.                    *
                 ************************************************************/
 
-               t->cli_state = CL_STDATA;
                req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
-
                req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
 
                t->logs.tv_request = now;
@@ -2416,9 +2427,9 @@ int process_cli(struct session *t)
                if (!(t->flags & SN_FINST_MASK))
                        t->flags |= SN_FINST_R;
                return 1;
-
        }
-       else if (c == CL_STDATA) {
+
+       if (c == CL_STDATA) {
        process_data:
                /* FIXME: this error handling is partly buggy because we always report
                 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
@@ -5239,6 +5250,7 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend)
                msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
                txn->status = 401;
                client_retnclose(t, &msg);
+               t->analysis &= ~AN_REQ_ANY;
                if (!(t->flags & SN_ERR_MASK))
                        t->flags |= SN_ERR_PRXCOND;
                if (!(t->flags & SN_FINST_MASK))
index 8c892416712a818e37819d2cc8e54f81b76fe34a..f3938eaf67d101f6ee576a568835314ed527c850 100644 (file)
@@ -412,6 +412,7 @@ int uxst_event_accept(int fd) {
                }
 
                s->flags = 0;
+               s->analysis = 0;
 
                if ((t = pool_alloc2(pool2_task)) == NULL) {
                        Alert("out of memory in uxst_event_accept().\n");