[MEDIUM] check the HTTP method after all filters have been applied

The HTTP method is now checked and saved into hreq.meth. It will be
usable at several places instead of those dirty string comparisons.
diff --git a/include/types/session.h b/include/types/session.h
index 4d83716..a153019 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -99,6 +99,18 @@
 #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 @@
 	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 */
diff --git a/src/proto_http.c b/src/proto_http.c
index 4dae1a8..e6e4ca7 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -86,6 +86,41 @@
 	"<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 @@
 }
 
 
+/*
+ * 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 @@
 		 * 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 @@
 		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;
 		}