I've seen a few places online where people are trying to use a substring in the path / hostname as the stick-key, and I was trying to do the same today. [1] The current solution appears to be to statically declare every path / hostname possible, but I was wondering if it was possible to make it dynamic.

I've attached a patch that allows you to extract a string from another as a conversion filter. This can be used as follows: stick on path extract_field(/, 3) # this returns baz from /foo/bar/baz (the 0th element is an empty string).
Similarly,
stick on hostname extract_field(., 1) would ensure that you correctly stick a.subdomain.domain.com and b.subdomain.domain.com.

Assumptions in the code (please tell me if these are incorrect):
* Returning 0 from a conversion filter correctly aborts the stick.
* I do not need to garbage collect the sample, after I run smp_dup (I used 'lower' as the base I started from)

PS: I hope I got the email subject right. Patch also available here: https://github.com/gja/haproxy.git, just in case this list does not allow attachments (and I am not sure if people still use git send-email)

[1] http://marc.info/?l=haproxy&m=136212840626459
--
Tejas Dinkar
http://nilenso.com
Nilenso Software LLP

>From 4b40bf6d8b1a345d839a6cd1fab132f84a97cfed Mon Sep 17 00:00:00 2001
From: Tejas Dinkar <te...@gja.in>
Date: Thu, 16 Oct 2014 00:28:40 +0530
Subject: [PATCH] stick: Allows you to extract a field from an input string

This is useful when trying to dynamically choose the stickyness based
on the path, or the hostname.

For example,
stick on path extract_field(/,3)

Will return baz from the path /foo/bar/baz
---
 src/sample.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/src/sample.c b/src/sample.c
index 3343739..dc66827 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -1386,6 +1386,35 @@ static int sample_conv_wt6(const struct arg *arg_p, 
struct sample *smp)
        return 1;
 }
 
+static int sample_conv_extract_field(const struct arg *args, struct sample 
*smp)
+{
+       char *ptr, *separator, *result;
+       unsigned int field_number;
+
+       if (!smp_dup(smp))
+               return 0;
+
+       // This chunk must be correctly terminated for strsep
+       separator = args[0].data.str.str;
+       separator[args[0].data.str.len] = '\0';
+
+       // This chunk must be correctly terminated for strsep
+       ptr = smp->data.str.str;
+       ptr[smp->data.str.len] = '\0';
+
+       for(field_number = args[1].data.uint + 1; field_number > 0; 
field_number--) {
+               if(!ptr)
+                       return 0;
+               result = strsep(&ptr, separator);
+       }
+
+       smp->data.str.len = strlen(result);
+       if(smp->data.str.str != result)
+               strcpy(smp->data.str.str, result);
+
+       return 1;
+}
+
 /************************************************************************/
 /*       All supported sample fetch functions must be declared here     */
 /************************************************************************/
@@ -1493,6 +1522,7 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, 
{
        { "djb2",   sample_conv_djb2,      ARG1(0,UINT), NULL, SMP_T_BIN,  
SMP_T_UINT },
        { "sdbm",   sample_conv_sdbm,      ARG1(0,UINT), NULL, SMP_T_BIN,  
SMP_T_UINT },
        { "wt6",    sample_conv_wt6,       ARG1(0,UINT), NULL, SMP_T_BIN,  
SMP_T_UINT },
+       { "extract_field",  sample_conv_extract_field, ARG2(2, STR, UINT),      
      NULL, SMP_T_STR,  SMP_T_STR  },
        { NULL, NULL, 0, 0, 0 },
 }};
 
-- 
1.9.3 (Apple Git-50)

Reply via email to