]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: sample/http_proto: Add new type called method
authorThierry FOURNIER <tfournier@exceliance.fr>
Tue, 17 Dec 2013 00:10:10 +0000 (01:10 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Mar 2014 17:06:07 +0000 (18:06 +0100)
The method are actuelly stored using two types. Integer if the method is
known and string if the method is not known. The fetch is declared as
UINT, but in some case it can provides STR.

This patch create new type called METH. This type contain interge for
known method and string for the other methods. It can be used with
automatic converters.

The pattern matching can expect method.

During the free or prune function, http_meth pettern is freed. This
patch initialise the freed pointer to NULL.

include/proto/proto_http.h
include/types/proto_http.h
include/types/sample.h
src/proto_http.c
src/sample.c

index 20751769a5543bd082cbc88a598ca1f72dce5c2e..c836eb446edf1a518815a2afb8b22ec0d7d3e34b 100644 (file)
@@ -120,6 +120,8 @@ struct chunk *http_error_message(struct session *s, int msgnum);
 struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
                                                const char **args, char **errmsg, int use_fmt);
 
+enum http_meth_t find_http_meth(const char *str, const int len);
+
 /* to be used when contents change in an HTTP message */
 #define http_msg_move_end(msg, bytes) do { \
                unsigned int _bytes = (bytes);  \
index c24216a4bbc5903a10372f852179c57dc4ee1f0d..f3fc1fc0b779016dd3f7cb668c38703631cdd91a 100644 (file)
@@ -227,7 +227,7 @@ enum http_meth_t {
        HTTP_METH_DELETE,
        HTTP_METH_TRACE,
        HTTP_METH_CONNECT,
-       HTTP_METH_OTHER,
+       HTTP_METH_OTHER, /* Must be the last entry */
 } __attribute__((packed));
 
 enum ht_auth_m {
@@ -442,6 +442,13 @@ struct hdr_ctx {
        int  prev; /* index of previous header */
 };
 
+struct http_method_name {
+       char *name;
+       int len;
+};
+
+extern const struct http_method_name http_known_methods[HTTP_METH_OTHER];
+
 #endif /* _TYPES_PROTO_HTTP_H */
 
 /*
index 0f189fd7f1beee081ac229434ea0e3ea518ad955..ce1bba92a48f4b98391bb2f38de90157b48e2bfc 100644 (file)
@@ -29,6 +29,7 @@
 #include <common/chunk.h>
 #include <common/mini-clist.h>
 #include <types/arg.h>
+#include <types/proto_http.h>
 
 /* input and output sample types */
 enum {
@@ -40,6 +41,7 @@ enum {
        SMP_T_IPV6,      /* ipv6 type */
        SMP_T_STR,       /* char string type */
        SMP_T_BIN,       /* buffer type */
+       SMP_T_METH,      /* contain method */
        SMP_TYPES        /* number of types, must always be last */
 };
 
@@ -220,6 +222,11 @@ union smp_ctx {
        void *a[8];     /* any array of up to 8 pointers */
 };
 
+struct meth {
+       enum http_meth_t meth;
+       struct chunk str;
+};
+
 /* a sample is a typed data extracted from a stream. It has a type, contents,
  * validity constraints, a context for use in iterative calls.
  */
@@ -232,6 +239,7 @@ struct sample {
                struct in_addr  ipv4;  /* used for ipv4 addresses */
                struct in6_addr ipv6;  /* used for ipv6 addresses */
                struct chunk    str;   /* used for char strings or buffers */
+               struct meth     meth;  /* used for http method */
        } data;                        /* sample data */
        union smp_ctx ctx;
 };
@@ -245,6 +253,7 @@ struct sample_storage {
                struct in_addr  ipv4;  /* used for ipv4 addresses */
                struct in6_addr ipv6;  /* used for ipv6 addresses */
                struct chunk    str;   /* used for char strings or buffers */
+               struct meth     meth;  /* used for http method */
        } data;                        /* sample data */
 };
 
index eca5a33f40f52a74011820b6c09c2b6642061645..dcf91ede462d85a8947fbfb0e6bc3ec17c2a681a 100644 (file)
@@ -352,6 +352,18 @@ const struct http_method_desc http_methods[26][3] = {
         */
 };
 
+const struct http_method_name http_known_methods[HTTP_METH_OTHER] = {
+       [HTTP_METH_NONE]    = { "",         0 },
+       [HTTP_METH_OPTIONS] = { "OPTIONS",  7 },
+       [HTTP_METH_GET]     = { "GET",      3 },
+       [HTTP_METH_HEAD]    = { "HEAD",     4 },
+       [HTTP_METH_POST]    = { "POST",     4 },
+       [HTTP_METH_PUT]     = { "PUT",      3 },
+       [HTTP_METH_DELETE]  = { "DELETE",   6 },
+       [HTTP_METH_TRACE]   = { "TRACE",    5 },
+       [HTTP_METH_CONNECT] = { "CONNECT",  7 },
+};
+
 /* It is about twice as fast on recent architectures to lookup a byte in a
  * table than to perform a boolean AND or OR between two tests. Refer to
  * RFC2616 for those chars.
@@ -795,7 +807,7 @@ struct chunk *http_error_message(struct session *s, int msgnum)
  * 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 enum http_meth_t find_http_meth(const char *str, const int len)
+enum http_meth_t find_http_meth(const char *str, const int len)
 {
        unsigned char m;
        const struct http_method_desc *h;
@@ -8993,8 +9005,11 @@ static int pat_parse_meth(const char *text, struct pattern *pattern, char **err)
                pattern->expect_type = SMP_T_STR;
                pattern->len = len;
        }
-       else
+       else {
+               pattern->ptr.str = NULL;
+               pattern->len = 0;
                pattern->expect_type = SMP_T_UINT;
+       }
        return 1;
 }
 
@@ -9016,17 +9031,15 @@ smp_fetch_meth(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
        CHECK_HTTP_MESSAGE_FIRST_PERM();
 
        meth = txn->meth;
-       smp->flags = 0;
-       smp->type = SMP_T_UINT;
-       smp->data.uint = meth;
+       smp->type = SMP_T_METH;
+       smp->data.meth.meth = meth;
        if (meth == HTTP_METH_OTHER) {
                if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
                        /* ensure the indexes are not affected */
                        return 0;
-               smp->type = SMP_T_STR;
                smp->flags |= SMP_F_CONST;
-               smp->data.str.len = txn->req.sl.rq.m_l;
-               smp->data.str.str = txn->req.chn->buf->p;
+               smp->data.meth.str.len = txn->req.sl.rq.m_l;
+               smp->data.meth.str.str = txn->req.chn->buf->p;
        }
        smp->flags |= SMP_F_VOL_1ST;
        return 1;
@@ -9037,27 +9050,23 @@ static enum pat_match_res pat_match_meth(struct sample *smp, struct pattern *pat
 {
        int icase;
 
-
-       if (smp->type == SMP_T_UINT) {
-               /* well-known method */
-               if (smp->data.uint == pattern->val.i)
+       /* well-known method */
+       if (pattern->val.i != HTTP_METH_OTHER) {
+               if (smp->data.meth.meth == pattern->val.i)
                        return PAT_MATCH;
-               return PAT_NOMATCH;
+               else
+                       return PAT_NOMATCH;
        }
 
-       /* Uncommon method, only HTTP_METH_OTHER is accepted now */
-       if (pattern->val.i != HTTP_METH_OTHER)
-               return PAT_NOMATCH;
-
        /* Other method, we must compare the strings */
-       if (pattern->len != smp->data.str.len)
+       if (pattern->len != smp->data.meth.str.len)
                return PAT_NOMATCH;
 
        icase = pattern->flags & PAT_F_IGNORE_CASE;
-       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) != 0) ||
-           (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) != 0))
-               return PAT_NOMATCH;
-       return PAT_MATCH;
+       if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0) ||
+           (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0))
+               return PAT_MATCH;
+       return PAT_NOMATCH;
 }
 
 static int
@@ -10465,7 +10474,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "http_auth",       smp_fetch_http_auth,      ARG1(1,USR),      NULL,    SMP_T_BOOL, SMP_USE_HRQHV },
        { "http_auth_group", smp_fetch_http_auth_grp,  ARG1(1,USR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
        { "http_first_req",  smp_fetch_http_first_req, 0,                NULL,    SMP_T_BOOL, SMP_USE_HRQHP },
-       { "method",          smp_fetch_meth,           0,                NULL,    SMP_T_UINT, SMP_USE_HRQHP },
+       { "method",          smp_fetch_meth,           0,                NULL,    SMP_T_METH, SMP_USE_HRQHP },
        { "path",            smp_fetch_path,           0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
 
        /* HTTP protocol on the request path */
index e6653fa71c93ce407a452bf18c7b591ef8614126..356caf6bb05584b210cb2aa842360750d5fff46d 100644 (file)
@@ -24,6 +24,7 @@
 #include <proto/arg.h>
 #include <proto/auth.h>
 #include <proto/log.h>
+#include <proto/proto_http.h>
 #include <proto/proxy.h>
 #include <proto/sample.h>
 #include <proto/stick_table.h>
@@ -607,6 +608,51 @@ static int c_str2int(struct sample *smp)
        return 1;
 }
 
+static int c_str2meth(struct sample *smp)
+{
+       enum http_meth_t meth;
+       int len;
+
+       meth = find_http_meth(smp->data.str.str, smp->data.str.len);
+       if (meth == HTTP_METH_OTHER) {
+               len = smp->data.str.len;
+               smp->data.meth.str.str = smp->data.str.str;
+               smp->data.meth.str.len = len;
+       }
+       else
+               smp->flags &= ~SMP_F_CONST;
+       smp->data.meth.meth = meth;
+       smp->type = SMP_T_METH;
+       return 1;
+}
+
+static int c_meth2str(struct sample *smp)
+{
+       int len;
+       enum http_meth_t meth;
+
+       if (smp->data.meth.meth == HTTP_METH_OTHER) {
+               /* The method is unknown. Copy the original pointer. */
+               len = smp->data.meth.str.len;
+               smp->data.str.str = smp->data.meth.str.str;
+               smp->data.str.len = len;
+               smp->type = SMP_T_STR;
+       }
+       else if (smp->data.meth.meth < HTTP_METH_OTHER) {
+               /* The method is known, copy the pointer containing the string. */
+               meth = smp->data.meth.meth;
+               smp->data.str.str = http_known_methods[meth].name;
+               smp->data.str.len = http_known_methods[meth].len;
+               smp->flags |= SMP_F_CONST;
+               smp->type = SMP_T_STR;
+       }
+       else {
+               /* Unknown method */
+               return 0;
+       }
+       return 1;
+}
+
 /*****************************************************************/
 /*      Sample casts matrix:                                     */
 /*           sample_casts[from type][to type]                    */
@@ -614,15 +660,16 @@ static int c_str2int(struct sample *smp)
 /*****************************************************************/
 
 sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
-/*            to:  BOOL       UINT       SINT       ADDR        IPV4      IPV6        STR         BIN     */
-/* from: BOOL */ { c_none,    c_none,    c_none,    NULL,       NULL,     NULL,       c_int2str,  NULL,   },
-/*       UINT */ { c_none,    c_none,    c_none,    c_int2ip,   c_int2ip, NULL,       c_int2str,  NULL,   },
-/*       SINT */ { c_none,    c_none,    c_none,    c_int2ip,   c_int2ip, NULL,       c_int2str,  NULL,   },
-/*       ADDR */ { NULL,      NULL,      NULL,      NULL,       NULL,     NULL,       NULL,       NULL,   },
-/*       IPV4 */ { NULL,      c_ip2int,  c_ip2int,  c_none,     c_none,   c_ip2ipv6,  c_ip2str,   NULL,   },
-/*       IPV6 */ { NULL,      NULL,      NULL,      c_none,     NULL,     c_none,     c_ipv62str, NULL,   },
-/*        STR */ { c_str2int, c_str2int, c_str2int, c_str2addr, c_str2ip, c_str2ipv6, c_none,     c_none, },
-/*        BIN */ { NULL,      NULL,      NULL,      NULL,       NULL,     NULL,       c_bin2str,  c_none, },
+/*            to:  BOOL       UINT       SINT       ADDR        IPV4      IPV6        STR         BIN         METH */
+/* from: BOOL */ { c_none,    c_none,    c_none,    NULL,       NULL,     NULL,       c_int2str,  NULL,       NULL,       },
+/*       UINT */ { c_none,    c_none,    c_none,    c_int2ip,   c_int2ip, NULL,       c_int2str,  NULL,       NULL,       },
+/*       SINT */ { c_none,    c_none,    c_none,    c_int2ip,   c_int2ip, NULL,       c_int2str,  NULL,       NULL,       },
+/*       ADDR */ { NULL,      NULL,      NULL,      NULL,       NULL,     NULL,       NULL,       NULL,       NULL,       },
+/*       IPV4 */ { NULL,      c_ip2int,  c_ip2int,  c_none,     c_none,   c_ip2ipv6,  c_ip2str,   NULL,       NULL,       },
+/*       IPV6 */ { NULL,      NULL,      NULL,      c_none,     NULL,     c_none,     c_ipv62str, NULL,       NULL,       },
+/*        STR */ { c_str2int, c_str2int, c_str2int, c_str2addr, c_str2ip, c_str2ipv6, c_none,     c_none,     c_str2meth, },
+/*        BIN */ { NULL,      NULL,      NULL,      NULL,       NULL,     NULL,       c_bin2str,  c_none,     c_str2meth, },
+/*       METH */ { NULL,      NULL,      NULL,      NULL,       NULL,     NULL,       c_meth2str, c_meth2str, c_none,     },
 };
 
 /*