Forum Discussion
Leslie_South_55
Nimbostratus
Oct 19, 2007findclass 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
8 Replies
- Leslie_South_55
Nimbostratus
Bump :-) - hoolio
Cirrostratus
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 - Leslie_South_55
Nimbostratus
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? - Leslie_South_55
Nimbostratus
I modified your sample to look like thiswhen 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 isOct 22 15:23:57 tmm tmm[25714]: Rule rule_wwwredirecttest : URI is /accounts/orders
and then a 404 error. - hoolio
Cirrostratus
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 - Leslie_South_55
Nimbostratus
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
Cirrostratus
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
Cirrostratus
One other thing I realized: return will exit the rule. break would be better as it only exits the foreach loop.
Aaron
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
