Forum Discussion

Leslie_South_55's avatar
Leslie_South_55
Icon for Nimbostratus rankNimbostratus
Oct 19, 2007

findclass AND external class AND wildcards

I am using an external class file to do URI redirects, when using speciffic URI matching it works fine:

when HTTP_REQUEST {
   log local0. "Uri is [HTTP::uri]"
  set NewURI [findclass [HTTP::uri] $::wwwredirects " "]
   log local0. "NewURI is $NewURI"
  if { $NewURI ne ""}{
    HTTP::redirect "http://[HTTP::host]$NewURI" 
   log local0. "redirecting to http://[HTTP::host]$NewURI"
    }
}

and my wwwredirects would look something like this


"/accounts/orders/ /application/query/accounts/orders"

but now I have 2 challenges to enhance this:

1) I need to be able to include wildcards (/accounts/orders/* --> /newuri/blah)

2) I need to be able to re-write the HTTP::host if needed (/accounts/newaccount/* --> https://www.host.com/register/signup.htm)

Can I do all of this (static redirects, wildcard redirects, and complete HOST and URI redirects) from one rule and one class file?

Thanks

-L
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    I don't think you can use wildcards with findclass. One option would be to loop through the class using 'foreach line $::class' and do a string comparison using 'starts_with' or 'string match' against the element of the line.

    Here's a rough, untested example:

    
    ...
    foreach line $::class {
       if {[HTTP::path] starts_with [getfield $line " " 1]}{
           HTTP::redirect "http://[HTTP::host][getfield $line " " 2]"
       }
    }

    Aaron
  • I do not undestand where the $line and the 1 and 2 come it. Are these varibles that I define or is it how I format the class file?
  • I modified your sample to look like this

     

    when HTTP_REQUEST {

     

    log local0. "URI is [HTTP::uri]"

     

    foreach line $::wwwredirects {

     

    if {[HTTP::path] starts_with [getfield $line " " 1]}{

     

    HTTP::redirect "http://[getfield $line " " 2]"

     

    log local0. "redirecting to http://[HTTP::host][HTTP::uri]"

     

    }

     

    }

     

     

     

    and the only log entry I get is

     

     

    Oct 22 15:23:57 tmm tmm[25714]: Rule rule_wwwredirecttest : URI is /accounts/orders

     

     

     

    and then a 404 error.
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Sorry, I should have included more comments...

    The format for foreach is:

    
    foreach one_line $::class_or_array {
        do something
    }

    The $::class_or_array must already exist. A single line of the class or array is assigned to the variable called one_line.

    The getfield commands return a specific field from a line. The two double quotes indicate that a space is the delineator between the fields. So 1 is the first field. 2 is for the second field.

    For an example class:

    
    class string_class  {
       "111 aaa"
       "222 bbb"
       "333 ccc"
    }

    The following rule:

    
    when RULE_INIT {
    foreach line $::string_class {
    log local0. "One Line: \$line: $line"
    log local0. "\[getfield \$line \" \" 1\]: [getfield $line " " 1]"
    log local0. "\[getfield \$line \" \" 2\]: [getfield $line " " 2]"
    }
    }

    Will return:

    
    One Line: $line: 111 aaa
    [getfield $line " " 1]: 111
    [getfield $line " " 2]: aaa
    One Line: $line: 222 bbb
    [getfield $line " " 1]: 222
    [getfield $line " " 2]: bbb
    One Line: $line: 333 ccc
    [getfield $line " " 1]: 333
    [getfield $line " " 2]: ccc

    I should have included a return command to exit the foreach loop once a match is found. Also, you're redirecting to just a URI, without a host. The example below redirects to the same Host that the client requested. I've added some more logging to help troubleshoot the issue. Can you try this and reply with the results/logs?

    
    when HTTP_REQUEST {
       log local0. "URI is [HTTP::uri]"
       foreach line $::wwwredirects {
          log local0. "Current line from the class: $line"
          if {[HTTP::path] starts_with [getfield $line " " 1]}{
             log local0. "Matched: [HTTP::path] to: [getfield $line " " 1]"
             HTTP::redirect "http://[HTTP::host][getfield $line " " 2]"
             log local0. "redirecting to http://[HTTP::host][getfield $line " " 2]"
              Break from the foreach loop once a match is found so no further checks/redirects are done
             break
          }
       }
    }

    Thanks,

    Aaron

  • I seem to be having an issue with the class. The file keeps getting un-formatted. I build the file like this:

     

     

    "/test/google/" "http://www.google.com",

     

    "/test/yahoo/" "http://www.yahoo.com",

     

    "test/msn/" "http://www.msn.com",

     

    "test/f5/" "http://www.f5.com",

     

    "test/ask" "http://www.ask.com"

     

     

    and after a b load, it looks like this

     

     

    "/test/google/",

     

    "/test/yahoo/",

     

    "http://www.ask.com",

     

    "http://www.f5.com",

     

    "http://www.google.com",

     

    "http://www.msn.com",

     

    "http://www.yahoo.com",

     

    "test/ask",

     

    "test/f5/",

     

    "test/msn/",

     

     

    so when it gets to '[getfield $line " " 2]' there is no data; I changed the log statement for the "Matched:" to look like this

     

    log local0. "Matched: [HTTP::path] to: [getfield $line " " 2]"

     

    so I could see what is was trying to redirect to as I kept redirecting to the original PATH.

     

     

    Here is the applied rule (again)

     

     

     

    when HTTP_REQUEST {

     

    log local0. "URI is [HTTP::uri]"

     

    foreach line $::wwwredirects {

     

    log local0. "Current line from the class: $line"

     

    if {[HTTP::path] starts_with [getfield $line " " 1]}{

     

    log local0. "Matched: [HTTP::path] to: [getfield $line " " 2]"

     

    log local0. "getfield-1 is $line"

     

    HTTP::redirect "[getfield $line " " 2]"

     

    log local0. "redirecting to http://[HTTP::host][HTTP::uri]"

     

    Return from the foreach loop once a match is found

     

    return

     

    }

     

    }

     

     

     

     

    and here is the log

     

     

     

    Oct 23 11:52:57 tmm tmm[17883]: Rule rule_wwwredirecttest : URI is /test/google/

     

    Oct 23 11:52:57 tmm tmm[17883]: Rule rule_wwwredirecttest : Current line from the class: /test/google/

     

    Oct 23 11:52:57 tmm tmm[17883]: Rule rule_wwwredirecttest : Matched: /test/google/ to:

     

    Oct 23 11:52:57 tmm tmm[17883]: Rule rule_wwwredirecttest : getfield-1 is /test/google/

     

    Oct 23 11:52:57 tmm tmm[17883]: Rule rule_wwwredirecttest : redirecting to http://newtest.domain.com/test/google/

     

     

     

     

    As I mention above, there is no value for getfield 2, since the class file format does not stay the way I create it...how should I edit the file so the format does not change? If I don't b load, the file format is fine.

     

     

    Thanks

     

    -L
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Can you try formatting the file with just one pair of double quotes per line?

     

     

    "/test/google/ http://www.google.com"

     

     

    Also, if you're using the starts_with command to test the URI, the first field in the class should always start with a forward slash.

     

     

    Lastly, I don't think the example I gave using starts_with wouldn't allow you to use an asterisk in the URI (the first field of the class's lines). It would in effect include an asterisk at the end of every URI. If you want to be able to apply a wildcard to only some URIs and in different positions, I think you'd have to use the string match command:

     

     

    original:

     

     

    if {[HTTP::path] starts_with [getfield $line " " 1]}{

     

     

    Updated:

     

     

    if {[string match [getfield $line " " 1] [HTTP::path]]}{

     

     

    Aaron
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    One other thing I realized: return will exit the rule. break would be better as it only exits the foreach loop.

     

     

    Aaron