html
3 TopicsAppDynamics EUM JavaScript Injection for Selective URLs
Problem this snippet solves: This code allows for the adrum.js agent to be dynamically injected into an application to support collecting EUM metrics. With this code, you can select from any number of HTTP Request headers and/or POST parameters. Additional EUM features in use: Custom GeoIP mappings based on a DataGroup User Data for Browser Snapshots, currently APM SID and Username How to use this snippet: This sample iRule assumes that the TCL variables $username and $sid have been previously created to support the UserData injection. If you don't have this information or APM available then these lines should be commented out or changed to meet your needs. Import the ltm profiles and iRule via tmsh load sys config merge <from-terminal> On your virtual, attache the Head-HTML profile as well as the iRule. Code : LTM Profiles Required: ltm html-rule tag-raise-event HTMLEvent-HeadStart-HTMLRule { description "Match an HTML tag for " match { tag-name head } } ltm profile html Head-HTML { app-service none content-detection disabled content-selection { text/html text/xhtml } defaults-from html description none rules { HTMLEvent-HeadStart-HTMLRule } } iRule to be attached to the Virtual: ltm rule SND-AppDynamics-HTML-Rule { when CLIENT_ACCEPTED { set APPDYNAMICS_EUM_DEBUG 0; } when HTTP_REQUEST { set APPDYNAMICS_EUM_APP_ID "AD-xxx-xxx-xxx-xxx" if { $APPDYNAMICS_EUM_DEBUG > 0 } {set uri [HTTP::uri]} if {[HTTP::uri] starts_with "/my/HomePage.do"} { # set enableEum 1 if { [HTTP::header Content-Type] eq "application/x-www-form-urlencoded" } { # HTTP::collect [HTTP::header Content-Length] # Only collect the first 200 bytes which should be enough to capture eventSource HTTP::collect 200 } else { if {[HTTP::uri] starts_with "/my/defaultPage"} { set enableEum 1 } } } elseif {[HTTP::uri] starts_with "/app1"} { set enableEum 1 } elseif {[HTTP::uri] starts_with "/app2"} { set enableEum 1 } when HTTP_REQUEST_DATA { set namevals [split [HTTP::payload] "&"] for {set i 0} {$i < [llength $namevals]} {incr i} { set params [split [lindex $namevals $i] "="] # log local0. " [lindex $params 0] : [lindex $params 1]" if {[lindex $params 0] equals "eventSource"} { switch -glob [lindex $params 1] { "PostParm1" - "PostParm2" - "PostParm3" { set enableEum 1 if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "FOUND HTTP DATA [lindex $params 1] TO ENABLE APPDYNAMICS EUM"; } } } break; } unset params } unset namevals } when HTTP_RESPONSE { if {[info exists enableEum]} { if { ($enableEum == 1) && ([HTTP::header "Content-Type"] starts_with "text/html") } { HTML::enable set enableEum 0 } else { HTML::disable } } else { HTML::disable } } when HTML_TAG_MATCHED { if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "uri = $uri element = [HTML::tag name] attribute id = [HTML::tag attribute id]"} switch [HTML::tag name] { "head" { if { $APPDYNAMICS_EUM_DEBUG > 0 } { log local0. "$uri info username [info exists username] info sid [info exists sid]"} if {([info exists username]) && ([info exists sid])} { # Send custom GeoIP Data to with the adrum beacon if we are on the private network set geoData [split [class match -value [IP::client_addr] equals Branch-Address-DataGroup ] "/"] if { $geoData != "" } { HTML::tag append [subst { window\["adrum-app-key"\] = "$APPDYNAMICS_EUM_APP_ID"; window\["adrum-start-time"\] = new Date().getTime(); window\["adrum-geo-resolver-url"\] = "thisdoesnotmatter"; window\["adrum-config"\] = { geo: { "country": "United States", "region": "[lindex $geoData 0]", "city": "[lindex $geoData 1]", "localIP": "[IP::client_addr]" } }; if (ADRUM) { ADRUM.command ("addUserData", "User", "$username"); } { ADRUM.command ("addUserData", "LastMRH_Session", "$sid"); } } ] } else { HTML::tag append [subst { window\["adrum-app-key"\] = "$APPDYNAMICS_EUM_APP_ID"; window\["adrum-start-time"\] = new Date().getTime(); if (ADRUM) { ADRUM.command ("addUserData", "User", "$username"); } { ADRUM.command ("addUserData", "LastMRH_Session", "$sid"); } } ] } unset geoData } } } } } Tested this on version: 11.5642Views0likes0CommentsHTML Comment Scrubber
Problem this snippet solves: HTML Commenting is very useful for documenting your site content. Unfortunately, that information can sometimes be private and it is not a desired situation to let everyone viewing your website to be able to access those comments. This iRule will perform a regular expression search on the HTTP response content and if it finds a HTML comment in the form of "!(ws)...(ws)" (ws - whitespace), it will replace all the characters with a space. I could have removed the characters from the reponse, thus shortening the payload, but by keeping the size the same that reduces the need to configure your virtual server to rechunk responses. How to use this snippet: Keep in mind that this will remove any and all content in between "!--" and "--". That includes javascript code inside a script block. I'll leave it to you all out there to modify the regexp to account for non javascript commented code blocks... Code : when HTTP_REQUEST { # Don't allow data to be chunked if { [HTTP::version] eq "1.1" } { if { [HTTP::header is_keepalive] } { HTTP::header replace "Connection" "Keep-Alive" } HTTP::version "1.0" } } when HTTP_RESPONSE { if { [HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] < 1000000} { set content_length [HTTP::header "Content-Length"] } else { set content_length 1000000 } if { $content_length > 0 } { HTTP::collect $content_length } } when HTTP_RESPONSE_DATA { # Find the HTML comments set indices [regexp -all -inline -indices {} [HTTP::payload]] # Replace the comments with spaces in the response #log local0. "Indices: $indices" foreach idx $indices { set start [lindex $idx 0] set len [expr {[lindex $idx 1] - $start + 1}] log local0. "Start: $start, Len: $len" HTTP::payload replace $start $len [string repeat " " $len] } }442Views0likes1CommentHTML Comment Scrubber with Stream Profile
Problem this snippet solves: This example uses similar logic to scrub out HTML comments as the Html Comment Scrubber rule. Instead of collecting the HTTP response payloads, it uses the stream filter to replace the strings inline. This should be more efficient than buffering the entire payload with the HTTP::collect command. How to use this snippet: The iRule requires a blank stream profile and a custom HTTP profile with Chunking set to Rechunk if you change the response content length. Code : when HTTP_REQUEST { # Prevent the server from sending chunked response data if { [HTTP::version] eq "1.1" } { # Force downgrade to HTTP 1.0, but still allow keep-alive connections. # Since HTTP 1.1 is keep-alive by default, and 1.0 is not, # we need make sure the headers reflect the keep-alive status. if { [HTTP::header is_keepalive] } { HTTP::header replace "Connection" "Keep-Alive" } } # Disable the stream filter by default STREAM::disable } when HTTP_RESPONSE { # Check if the response is HTML if {[HTTP::header "Content-Type"] contains html{ # Set the stream expression to match HTML comments and replace them with nothing STREAM::expression {###} STREAM::enable } } # STREAM_MATCHED is triggered when the stream filter find string is found when STREAM_MATCHED { # Log the string which matched the stream profile log local0. "[IP::client_addr]:[TCP::client_port]: Removed comment: [STREAM::match]" } Tested this on version: 10.0416Views0likes0Comments