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); \
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 {
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 */
/*
#include <common/chunk.h>
#include <common/mini-clist.h>
#include <types/arg.h>
+#include <types/proto_http.h>
/* input and output sample types */
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 */
};
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.
*/
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;
};
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 */
};
*/
};
+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.
* 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;
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;
}
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;
{
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
{ "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 */
#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>
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] */
/*****************************************************************/
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, },
};
/*