diff --git a/include/types/session.h b/include/types/session.h
index 4d837162b8..a1530193a6 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 @@ 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 */
diff --git a/src/proto_http.c b/src/proto_http.c
index 4dae1a8e41..e6e4ca7a0d 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -86,6 +86,41 @@ const char *HTTP_401_fmt =
"
401 Unauthorized
\nYou need a valid user and password to access this content.\n\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;
}