Forum Discussion

spiv's avatar
spiv
Icon for Altocumulus rankAltocumulus
Aug 26, 2020

HTTP_RESPONSE - STREAM::expression to replace one string with another in HTTP data payload

I am trying to replace any instance of a certain URI whenever it occurs in the HTTP response data. It occurs within JavaScript <script> tags of the HTML document. I have the default system stream profile on the virtual server, and I'm using an iRule.

 

When I inspect the web page after in my browser, I still see the URI that I am trying to replace, even the first instance of it. Although, as I understand it from reading the content at the links below here, I am using STREAM::expression in my iRule, so I think it should replace all occurrences, not just the first. Seems to not be replacing any though.

 

https://support.f5.com/csp/article/K39394712

https://clouddocs.f5.com/api/irules/STREAM__expression.html

 

I have also checked these out:

 

https://devcentral.f5.com/s/articles/ltm-stream-profile-multiple-replacements--regular-expressions

https://clouddocs.f5.com/api/irules/STREAM__replace.html

 

Here is what I have.

 

# FQDN app.example.com resolves to ltm virtual server SNAT IP

# if URI starts with /fooportal 

# then reverse proxy to https://example.com/fooportal

# if the URI started with anything other than /fooportal

# then 307 redirect to host example.com 

# but with the originally requested path

#

#

when HTTP_REQUEST {

 

 # Disable the stream filter for client requests

 STREAM::disable

  

 # only requests to app.example.com will come to this virual server

 # app.example.com has a DNS Address record to this virtual server's SNAT IP Address

 # whereas the DNS Address record for example.com is the back-end real server address

 if { ([string tolower [HTTP::uri]] starts_with "/fooportal") } {

   HTTP::header replace Host "example.com"

   pool example.com_HTTPS_Pool

 } elseif { ([string tolower [HTTP::header host]] eq "app.example.com") } { 

   HTTP::header replace Host "example.com"

HTTP::respond 307 Location https://[HTTP::host][HTTP::uri]

 }

}

 

when HTTP_RESPONSE {

 # Disable the stream filter for server responses

 STREAM::disable

 

 # Enable the stream filter for text responses only

 if {([HTTP::status] == 200) && ([HTTP::header value Content-Type] starts_with "text")} {

  

  # Replace 'example.com' with 'app.example.com'

  STREAM::expression {@example.com/fooportal/@app.example.com/fooportal/@}

   

  # Enable the stream filter

  STREAM::enable

 

 }

}

  • spiv's avatar
    spiv
    Icon for Altocumulus rankAltocumulus

    Everything is working after adding a custom httpcompression profile to the LTM virtual server and specifying content-types for compression. I also had to tell the server to remove Accept-Encoding in the HTTP request block of the iRule, because if the server's HTTP response comes back to f5 compressed then stream cannot parse for the string we want to replace. The httpcompression profile is to compress the HTTP response before f5 sends it back to the original client.

     

    Final iRule looks like this:

     

    # If URI starts with /fooportal 

    # then reverse proxy to foo.example.com

    # If the URL started with anything other than /fooportal

    # then 307 redirect to foo.example.com 

    # but with the originally requested path

    #

    # https://clouddocs.f5.com/api/irules/STREAM.html

    # https://support.f5.com/csp/article/K39394712

    # https://clouddocs.f5.com/api/irules/STREAM__expression.html

    # https://devcentral.f5.com/s/question/0D51T00006i7fhv/understanding-stream-expression-and-compression

    # https://clouddocs.f5.com/cli/tmsh-reference/latest/modules/ltm/ltm_profile_stream.html

    # https://support.f5.com/csp/article/K15434

    # https://techdocs.f5.com/en-us/bigip-14-0-0/big-ip-local-traffic-manager-implementations-14-0-0/compressing-http-responses.html

    #

    when HTTP_REQUEST {

     # Disable the stream filter for client requests

     STREAM::disable

     if { ([string tolower [HTTP::uri]] starts_with "/fooportal") } {

       HTTP::header replace Host "foo.example.com"

       # Tell server not to compress response

        # LTM does not uncompress response content, so if the webserver has compression enabled

        # we must prevent the server from sending us a compressed response by changing the request

        # header that indicates client support for compression (on our LTM client-side we can re-

        # apply compression before the response goes across the Internet)

       HTTP::header remove Accept-Encoding

       pool foo.example.com_HTTPS_Pool

     } elseif { ([string tolower [HTTP::header host]] eq "app.foo.example.com") } { 

       HTTP::header replace Host "foo.example.com"

    HTTP::respond 307 Location https://[HTTP::host][HTTP::uri]

     }

    }

     

    when HTTP_RESPONSE {

     # Disable the stream filter for server responses

     STREAM::disable

     

     # Enable the stream filter for text responses only

     if {([HTTP::status] == 200) && ([HTTP::header value Content-Type] starts_with "text")} {

      

      # Replace 'foo' with 'app.foo'

      STREAM::expression {@foo.example.com/fooportal@app.foo.example.com/fooportal@}

       

      # Enable the stream filter

      STREAM::enable

       

      # enable compression

      COMPRESS::enable

     

     }

    }