Forum Discussion
irule to insert action parameter inside Content-Type header for xml request
Hello
we have a lot of xml services using soap version 1.2, im facing issue regarding validate soap action header using xml profile.
To summarize, while SOAP 1.1 would have these HTTP headers:
Content-Type: text/xml
SOAPAction: "http://example.com/ticker"
A SOAP 1.2 message would have the following:
Content-Type: application/soap+_xml; action="http://example.com/ticker"
our client software is not sending action parameter inside Content-Type header and it's to hard to apply changes on the code level
http header is look like this: Content-Type: application/soap+_xml; charset=utf-8
so i want to insert action parameter inside Content-Type header to be: Content-Type: application/soap+_xml; charset=utf-8; action=";
sample of the request
POST /xxyyzz/Service.svc HTTP/1.1
Content-Type: application/soap xml; charset=utf-8
Host:
Content-Length:
Expect: 100-continue
Accept-Encoding: gzip, deflate
X-Forwarded-For:
http://tempuri.org/IACHService/SendEchoResponse
`
so i want to match string after "Action s:mustUnderstand="1">[http://tempuri.org/IACHService/"](http://tempuri.org/IACHService/); then inject it to http header to be look like this
if:
` http://tempuri.org/IACHService/Something
Content-Type: application/soap xml; charset=utf-8; action=http://tempuri.org/IACHService/Something
- youssef1Cumulonimbus
Hi,
Can you begin with trying this irule please (we will optimize it later):
when HTTP_REQUEST { set capture 0 if { [HTTP::header exists Content-length] and [HTTP::method] equals "POST" } { set capture 1 HTTP::collect [HTTP::header Content-Length] } } when HTTP_REQUEST_DATA { if {$capture} { set payload [HTTP::payload] regexp {^.*([^\"]+)<\/a:Action>.*$} $capture -> action log local0. "action: $action" } }
- Mohanad_313515Nimbostratus
i think we need to double quotes
action=";
Hi Mohanad,
the iRule below should do the trick for your.
It uses the STREAM profile to search on POST-Request for the regex pattern:
[^<|\r\n|\n]*
If a match is found the
event will be triggered to read (or even manipulate) the string value of the regex match.STREAM_MATCHED
The action value get then extracted and stored into the
via the$action_value
command.[URI::basename]
The iRule will finally replace the
header of the ongoing HTTP request based on the just extracted action value...Content-Type
when HTTP_REQUEST { if { ( [HTTP::method] eq "POST" ) and ( [HTTP::path] ends_with "/Service.svc" ) } then { set stream_action 1 STREAM::expression {@[^<|\r\n|\n]*@@} STREAM::enable } else { set stream_action 0 STREAM::disable } } when STREAM_MATCHED { set stream_action 2 set action_value [URI::basename [STREAM::match]] log local0.debug "Found the action = $action_value" STREAM::replace } when HTTP_REQUEST_SEND { clientside { if { $stream_action == 0 } then { Let the request pass... } elseif { $stream_action == 1 } then { HTTP::header insert "Transfer-Encoding" "chunked" } else { HTTP::header remove "Content-Type" HTTP::header insert "Content-Type" "application/soap xml; charset=utf-8; action=http://tempuri.org/IACHService/$action_value" HTTP::header insert "Transfer-Encoding" "chunked" log local0.debug "New Header Value: [HTTP::header value "Content-Type"]" } } }
Note: You need to assign the default STREAM profile to your virtual server.
Cheers, Kai
Hi Mohanad,
the iRule below uses a
approach, to intercept and buffer the POST request destined to your web service. If the entire POST-Body (or a maximum of X bytes amount) has been buffered, the iRule will use a combination of theHTTP::collect
,[getfield]
and[substr]
commands to extract the last portion of the URL defined in the[URI::basename]
XML element. If a action value could be extracted, the iRule will replace the Content-Type HTTP-Header with a new value including the extracted action value. Once the HTTP-Header has been changed, the request is released from the buffer and send to your web service...Action
when RULE_INIT { Defining the maximum HTTP::collect size set static::maximum_http_collect_size 1048576 ; Its 1 Mbyte per POST request. This should be lowered if possible } when HTTP_REQUEST { if { ( [HTTP::method] eq "POST" ) and ( [HTTP::path] ends_with "/Service.svc" ) } then { if { not [string is integer [HTTP::header value "Content-Length"]] } then { Skipping the malformated Content-Length header... } elseif { [HTTP::header value "Content-Length"] >= $static::maximum_post_collect_size } then { Collecting the HTTP payload until maximum size has been reached HTTP::collect $static::maximum_http_collect_size } elseif { [HTTP::header value "Content-Length"] > 0 } then { Collecting the full HTTP payload. HTTP::collect [HTTP::header value "Content-Length"] } } } when HTTP_REQUEST_DATA { set action_value [URI::basename [substr [getfield [HTTP::payload] "" 2] 0 "<"]] log local0.debug "Found the action = $action_value" if { $action_value ne "" } then { HTTP::header remove "Content-Type" HTTP::header insert "Content-Type" "application/soap xml; charset=utf-8; action=http://tempuri.org/IACHService/$action_value" log local0.debug "New Header Value: [HTTP::header value "Content-Type"]" } }
Note: I'm sorry if I've wasted some of your valuable time with my previous
approach. Well, theSTREAM_MATCH
approach is still superior in my opinion, since it does not need to buffer the entire payload into LTMs memory. But unfortunately it changes the ongoing request slightly, which may have certain side effects within your application which we don't know yet. TheSTREAM_MATCH
approach is not bad at all. If you tweak the maximum collect size to a minimum (e.g. just a few kbyte), the impact to buffer portions of the request could be minimized to an acceptable degree.HTTP::collect
Cheers, Kai
- Stanislas_Piro2Cumulonimbus
Try this code:
when HTTP_REQUEST { if { [set capture [expr {([HTTP::header exists Content-length] and [HTTP::method] equals "POST") and ([HTTP::header Content-Type] contains "soap")}]] } { HTTP::collect [HTTP::header Content-Length] } } when HTTP_REQUEST_DATA { if {$capture} { HTTP::header remove "Content-Type" HTTP::header insert "Content-Type" "application/soap xml; charset=utf-8; action=\"[string trim [findstr [HTTP::payload] "" 31 ""] ]\"" } }
Recent Discussions
Related Content
* 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