Forum Discussion
andreoli_4699
Nimbostratus
Jan 13, 2010HTTP::payload replace with MORE data?
Hi all, I have the following code:
when HTTP_REQUEST priority 300 {
set original_payload [HTTP::payload]
set original_length [HTTP::header value Content-Length]
if { [lindex $session_var 7] == 1 and not ( [info exists all_done] ) } {
set original_request [HTTP::request]
HTTP::uri "/lookup.asp?id=[lindex $session_var 6]"
snatpool legacy-connect_snat
pool lookup.pool
event HTTP_REQUEST disable
} elseif { [info exists all_done] and $all_done == 1 } {
lset session_var 7 2
HTTP::header replace SOFTCERT_NUM $authkey
unset all_done
}
}
when HTTP_RESPONSE priority 300 {
if { [lindex $session_var 7] == 1 and not ( [info exists all_done] ) } {
HTTP::collect 1
}
}
when HTTP_RESPONSE_DATA priority 300 {
if { [lindex $session_var 7] == 1 and not ( [info exists all_done] ) } {
set authkey [HTTP::payload]
set all_done 1
event HTTP_REQUEST enable
HTTP::header replace "Content-Length" $original_length
HTTP::payload replace 0 $original_length $original_payload
HTTP::retry $original_request
}
}
(Note that a few things, like session_var, are set by another script)
The purpose of this is to intercept a request, store the payload and length (1665 bytes) to a local variable, then take certificate information, and, by replacing the URI and doing a "pool" statement, go off and look up some data on another server. Upon return, it takes the reply data (10 bytes), stuffs it into another header, then HTTP::payload replace with what was originally gathered at the beginning. It then does a HTTP::retry with the original request.
Everything seems to be working great until I go to replace the payload, then it bombs with a "list index out of range". By playing around, it seems that since my payload went from 1665 bytes down to 10 through the lookup, it won't let me replace the payload with anything more than 10 bytes.
Does anyone have any idea how I can increase the buffer size that's allocated to this new payload so that I can replace it with the original data for my http::retry?
This is my first post, and I've been looking at this until my eyes bled, so be gentle 😉
Thanks!
Tony
15 Replies
- andreoli_4699
Nimbostratus
Thanks Aaron. I tried that, as well as hard coding the number, but it all boils down to the fact that, even though it hasn't changed in size from what was originally grabbed, the buffer has gotten smaller thanks to the "pool" lookup, and the error comes in when I try to replace with anything more than 10 bytes.
For example, if I hard code the replace with this:
HTTP::payload replace 0 10 "0123456789"
it works just fine, but as soon as I add one more byte:
HTTP::payload replace 0 11 "01234567890"
I get the list index out of range error.
Tony
I can't find a way to delete this message, so I'll caveat this with, I think I misunderstood you, and what you meant to say was go ahead and tell it the current payload length (i.e. 10) regardless of the fact that it's going to be 1665. I hadn't thought about that, I'll try and let you know.
Thanks for the pointer on the content-length. I wasn't sure so was trying to cover my bases.
Thanks!
Tony - hoolio
Cirrostratus
Can you log the [HTTP::payload length] value and try using it?when HTTP_RESPONSE_DATA priority 300 { if { [lindex $session_var 7] == 1 and not ( [info exists all_done] ) } { set authkey [HTTP::payload] set all_done 1 event HTTP_REQUEST enable log local0. "300: \[HTTP::payload length\]: [HTTP::payload length], \[HTTP::payload\]: [HTTP::payload]" HTTP::payload replace 0 [HTTP::payload length] $original_payload HTTP::retry $original_request } }
Aaron - andreoli_4699
Nimbostratus
I think that does it. I actually wrapped the payload replace on both sides with your log code, so I can see before and after:log local0. "300: \[HTTP::payload length 1\]: [HTTP::payload length], \[HTTP::payload\]: [HTTP::payload]" HTTP::payload replace 0 [HTTP::payload length] $original_payload log local0. "300: \[HTTP::payload length 2\]: [HTTP::payload length], \[HTTP::payload\]: [HTTP::payload]"
: 300: [HTTP::payload length 1]: 10, [HTTP::payload]: xxxxxxxxxx
: 300: [HTTP::payload length 2]: 1664, [HTTP::payload]:
Of course, the folks that run the server that I look-up against have it down for maintenance, so I can't check right now, but I'll let you know as soon as I do.
Thanks a lot!
Tony - hoolio
Cirrostratus
Actually... I'm not sure I follow the exact logic you're trying to implement. It's a little tricky to follow without the full rule. But to guess...
You're saving the original request headers using HTTP::request. Later, you're using HTTP::retry $original_request. This should trigger a new HTTP request with the request headers you saved from HTTP_REQUEST. What are you trying to do with the HTTP payload replace command? Are you trying to append that to the request headers and retry the request? If so, you could do this using:
append original_request $original_payload
HTTP::retry $original_request
You could also leave out the HTTP::payload replace and HTTP::header replace Content-Length commands before the HTTP::retry command.
Aaron - andreoli_4699
Nimbostratus
What happens is my original request comes in and contains a payload (a soap envelope). I take some cert info and use that to do a username/password lookup against another database (via the pool statement). That result comes back in the payload (which is why I save the original payload [soap envelope] at the beginning), I then put the username/password into the headers, put the original payload back in, and retry the original request.
The lookup server is now back online, but I'm seeing a different problem. The log lines show that the payload is now good, and the length is right, but it seems that the replace isn't actually happening. When I tcpdump the connection (all 80/tcp), the new payload is not there, all I see are headers. In fact, if I attempt to force the payload to something static (http::payload replace 0 1 "x") it's not there either.
Suggestions?
Thanks,
Tony - andreoli_4699
Nimbostratus
In fact, what I'm doing is very similar to this example: http://devcentral.f5.com/wiki/default.aspx/iRules/HTTP__request.html
With the exceptions:
1 - Instead of looking up a pool name, I'm looking up a value and inserting it into the headers
2 - There's a real payload being sent in the original connection [the soap request] that needs to be sent on the retry. - andreoli_4699
Nimbostratus
The solution ended up being the append you mentioned earlier. Once I appended the original payload back to the original request, everything worked as expected.
Thanks a lot for the help!
Tony - hoolio
Cirrostratus
That makes sense. Good to hear you got it working.
Aaron - andreoli_4699
Nimbostratus
Hi there, me again ;-) I'm hitting another snag, and have been beating my head against the wall on it.
The above is working great, but it seems that in some cases, with a soap envelope that pushes the payload beyone a single packet, things aren't working as expected. Here's what I've found:
If the soap envelope begins in the first packet (packet length=1360) then extends into subsequent packets, everything is fine.
If the soap envelope begins in the second packet (first packet=815 bytes, soap envelope begins new packet), the "HTTP::payload length" command returns zero, which blows everything else up, because HTTP::payload returns a blank string (incidentally, "HTTP::header value Content-Length" returns the correct value [3529])
I haven't been able to figure out what makes the envelope split to the second packet, as I'm just using a traffic generator, so the exact same code is running when it works as when it doesn't. Therefore, it's hit or miss as to if/when I can create a failed or successful test.
It's very odd. I tried messing with chunking, both from the command level as well as the profile definition, but that didn't seem to help.
Any suggestions would be appreciated.
Thanks,
Tony - hoolio
Cirrostratus
Hi Tony,
Can you post the actual rule you're using now?
It sounds like you've already done a great job in isolating the circumstances where the failure occurs. I'm thinking that this will be best addressed by opening a case with F5 Support. They'll be able to review tcpdumps of the problem and try to reproduce the issue.
Aaron
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
