Forum Discussion

coreyva's avatar
coreyva
Icon for Nimbostratus rankNimbostratus
Jan 31, 2012

STREAM::expression regex

I'm in the process of writing an irule to correct for some bad code in one of our applications. The app in question has multiple bad links with tildes in it.

Example bad code

img src="~/0.jpg" width="60" height="80"

img src="/images/~/1.jpg" width="60" height="80"

img src="/foo/bar/~2.jpg" width="60" height="80"

img src="/~/3.jpg" width="60" height="80"

img src="/foo/bar/~/images/4.jpg" width="60" height="80"

This should be corrected to

img src="/0.jpg"

img src="/1.jpg"

img src="/foo/bar/~2.jpg"

img src="/3.jpg"

img src="/images/4.jpg"

Note I'm not concerned about fixing this one as it should generate a 404.

img src="/foo/bar/~2.jpg"

This is a snippet of my irule

when HTTP_RESPONSE {

Disable the stream filter by default

STREAM::disable

Enable the stream filter for text responses only

if {[HTTP::header value Content-Type] contains "text"}{

Replace '".*~/' with '/'

STREAM::expression {@src="\~/@src="/@ @src="/\~/@src="/@ @src="/.*/\~/@src="/@}

Enable the stream filter for this response only

STREAM::enable

}

}

When I test my regex with expresso 'src="/.*/\~/' works fine, but I'm not able to come up with the correct regex within the irule after many variations.

Any help would be appreciated.

  • Hi coreyva,

    The curly braces prevent character interpretation. Can you try this:

     

    
           Replace '".*~/' with '/'
          STREAM::expression {@src="~/@src="http://devcentral.f5.com/@ @src="http://devcentral.f5.com/~/@src="http://devcentral.f5.com/@ @src="http://devcentral.f5.com/.*/~/@src="http://devcentral.f5.com/@}
    

     

    If that doesn't work, can you try a simple find/replace string to make sure the response is being parsed correctly (ie, it's not compressed)? If it's compressed, you should either disable compression on the servers or remove the Accept-Encoding header from the requests in the iRule.

    Also, you should move STREAM::disable to HTTP_REQUEST to prevent the stream filter from being enabled on a subsequent HTTP request.

    Aaron

  • Thanks for the reply. I do have STREAM::disable in the HTTP_REQUEST as well, just didn't post that portion. My bad.

     

     

    I should have clarified what I was trying to resolve with my regex. I'm want to be able to strip everything before the ~ even if it is multiple levels deep. Unfortunately I don't know the exact depth that the tilde could occur. So while I could continue adding depths to your example, I'd like to find a cleaner way. If not then I'll just do a few depths and see if that doesn't resolve the issue.

     

     

    On a side note, what tag should I use for HTML so that you can see the code rather than it trying to render it?
  • You can use [ code ] [/ code] tags without the spaces. If you're using more than one set of code tags click reply on a post instead of using the quick reply box at the bottom of the post.

     

     

    Once you post the HTML snippets you're trying to handle, I'll take another look at the stream expression.

     

     

    Aaron
  • Thanks. I stripped the <> off as well in my original message, so you should be able to see the html now.
  • I don't think you need to rewrite this:

    img src="~/0.jpg"

    to the fully qualified URL of this:

    img src="http://devcentral.f5.com/0.jpg"

    as a local URI of /0.jpg should be rendered using the same hostname the client made the request to.

    You might be able to get away with just replacing any instance of ~/ with /. Or maybe /~/ with / and ~/ with / STREAM::expression {@/~/@/@ @~/@@}

     

    
    when HTTP_REQUEST {
        Disable the stream filter by default
       STREAM::disable
    }
    when HTTP_RESPONSE {
         Disable the stream filter by default
        STREAM::disable
         Enable the stream filter for text responses only
        if {[HTTP::header value Content-Type] contains "text"}{
             Replace '~/' with '/'
            STREAM::expression {@~/@/@}
             Enable the stream filter for this response only
            STREAM::enable
        }
    }

     

    Or if you want to make the matching more specific and only look within img src tags, you could use something like this:

     

    
    when HTTP_REQUEST {
        Disable the stream filter by default
       STREAM::disable
    }
    when HTTP_RESPONSE {
         Disable the stream filter by default
        STREAM::disable
         Enable the stream filter for text responses only
        if {[HTTP::header value Content-Type] contains "text"}{
             Match on img src tags with a ~/ in them
            STREAM::expression {@]*?~/@@}
             Enable the stream filter for this response only
            STREAM::enable
        }
    }
    when STREAM_MATCHED {
        log local0. "Matched: [STREAM::match], replacing with [string map {~/ /} [STREAM::match]]"
        switch -glob [STREAM::match] {
            "*~/*" {
                 Replace ~/ with /
                STREAM::replace [string map {~/ /} [STREAM::match]]
            }
        }
    }

     

    If neither of these approaches work, can you reply with the debug logging from /var/log/ltm and give more detail on what hostname the client is requesting and how you want to rewrite the response content?

    Aaron