]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] check the HTTP method after all filters have been applied
authorWilly Tarreau <w@1wt.eu>
Sun, 17 Dec 2006 12:37:46 +0000 (13:37 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 17 Dec 2006 12:37:46 +0000 (13:37 +0100)
The HTTP method is now checked and saved into hreq.meth. It will be
usable at several places instead of those dirty string comparisons.

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

index 4d837162b82f540c8c6c3dbb87bb8167f9741a36..a1530193a602ef131fc77f91e0103ba3d8850559 100644 (file)
 #define SN_SELF_GEN    0x02000000      /* the proxy generates data for the client (eg: stats) */
 #define SN_CLTARPIT    0x04000000      /* the session is tarpitted (anti-dos) */
 
+typedef enum {
+       HTTP_METH_NONE = 0,
+       HTTP_METH_OPTIONS,
+       HTTP_METH_GET,
+       HTTP_METH_HEAD,
+       HTTP_METH_POST,
+       HTTP_METH_PUT,
+       HTTP_METH_DELETE,
+       HTTP_METH_TRACE,
+       HTTP_METH_CONNECT,
+       HTTP_METH_OTHER,
+} http_meth_t;
 
 /* WARNING: if new fields are added, they must be initialized in event_accept() */
 struct session {
@@ -122,6 +134,7 @@ struct session {
        char **rsp_cap;                         /* array of captured response headers (may be NULL) */
        struct {
                int hdr_state;                  /* where we are in the current header parsing */
+               http_meth_t meth;               /* HTTP method */
                int sor, eoh;                   /* Start Of Request and End Of Headers, relative to buffer */
                struct hdr_idx hdr_idx;         /* array of header indexes (max: MAX_HTTP_HDR) */
                struct chunk start;             /* points to first line, called "start line" in RFC2616 */
index 4dae1a8e41d24c3e3db12cc24bbccd0b70551ee2..e6e4ca7a0d217a44cadbab41ad217588d7f49ff3 100644 (file)
@@ -86,6 +86,41 @@ const char *HTTP_401_fmt =
        "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
 
 
+/*
+ * We have 26 list of methods (1 per first letter), each of which can have
+ * up to 3 entries (2 valid, 1 null).
+ */
+struct http_method_desc {
+       http_meth_t meth;
+       int len;
+       const char text[8];
+};
+
+static struct http_method_desc http_methods[26][3] = {
+       ['C' - 'A'] = {
+               [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
+       },
+       ['D' - 'A'] = {
+               [0] = { .meth = HTTP_METH_DELETE  , .len=6, .text="DELETE"  },
+       },
+       ['G' - 'A'] = {
+               [0] = { .meth = HTTP_METH_GET     , .len=3, .text="GET"     },
+       },
+       ['H' - 'A'] = {
+               [0] = { .meth = HTTP_METH_HEAD    , .len=4, .text="HEAD"    },
+       },
+       ['P' - 'A'] = {
+               [0] = { .meth = HTTP_METH_POST    , .len=4, .text="POST"    },
+               [1] = { .meth = HTTP_METH_PUT     , .len=3, .text="PUT"     },
+       },
+       ['T' - 'A'] = {
+               [0] = { .meth = HTTP_METH_TRACE   , .len=5, .text="TRACE"   },
+       },
+       /* rest is empty like this :
+        *      [1] = { .meth = HTTP_METH_NONE    , .len=0, .text=""        },
+        */
+};
+
 #ifdef DEBUG_FULL
 static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
 static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
@@ -148,6 +183,37 @@ void srv_close_with_err(struct session *t, int err, int finst,
 }
 
 
+/*
+ * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
+ * string), HTTP_METH_OTHER for unknown methods, or the identified method.
+ */
+static http_meth_t find_http_meth(const char *str, const int len)
+{
+       unsigned char m;
+       struct http_method_desc *h;
+
+       m = ((unsigned)*str - 'A');
+
+       if (m < 26) {
+               int l;
+               for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
+                       if (len <= l)
+                               continue;
+
+                       if (str[l] != ' ' && str[l] != '\t')
+                               continue;
+
+                       if (memcmp(str, h->text, l) == 0) {
+                               return h->meth;
+                       }
+               };
+               return HTTP_METH_OTHER;
+       }
+       return HTTP_METH_NONE;
+
+}
+
+
 /* Processes the client and server jobs of a session task, then
  * puts it back to the wait queue in a clean state, or
  * cleans up its resources if it must be deleted. Returns
@@ -839,13 +905,25 @@ int process_cli(struct session *t)
                 * to match the reverse of the forward sequence.
                 */
 
+               t->hreq.start.str = req->data + t->hreq.sor;      /* start of the REQURI */
+               t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len; /* end of the REQURI */
+
+               t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
+
                do {
                        rule_set = t->be;
 
                        /* try headers filters */
-                       if (rule_set->req_exp != NULL)
+                       if (rule_set->req_exp != NULL) {
                                apply_filters_to_session(t, req, rule_set->req_exp);
 
+                               /* the start line might have been modified */
+                               t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len;
+                               t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
+
+                               t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
+                       }
+
                        /* has the request been denied ? */
                        if (t->flags & SN_CLDENY) {
                                /* no need to go further */
@@ -887,9 +965,7 @@ int process_cli(struct session *t)
                t->hreq.start.str = req->data + t->hreq.sor;      /* start of the REQURI */
                t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len; /* end of the REQURI */
 
-               if ((t->hreq.start.len >= 5) &&
-                   (t->hreq.start.str[4] == ' ' || t->hreq.start.str[4] == '\t') &&
-                   (!memcmp(t->hreq.start.str, "POST", 4))) {
+               if (t->hreq.meth == HTTP_METH_POST) {
                        /* this is a POST request, which is not cacheable by default */
                        t->flags |= SN_POST;
                }