Forum Discussion

raytoles_75680's avatar
raytoles_75680
Icon for Nimbostratus rankNimbostratus
Dec 03, 2009

Header Insert of "http" or "https"

We're going to implement a virtual server to handle HTTP and HTTPS requests. The developers need us to insert the protocol into the header. We're still new to irules and I constantly fear performance issues because of irules. So I'm submitting what I have for some input.

 
 when HTTP_REQUEST { 
 if {[TCP::local_port] equals 80}{ 
 HTTP::header insert X-Forwarded-Proto "http" 
 log local0. "HTTP request from Client IP: [IP::client_addr] to [IP::local_addr]:[TCP::local_port]" 
  
  
 } elseif {[TCP::local_port] equals 443}{ 
   HTTP::header insert X-Forwarded-Proto "https" 
 log local0. "HTTPS request from Client IP: [IP::client_addr] to [IP::local_addr]:[TCP::local_port]"   
 } 
 } 
  
  
  
 

10 Replies

  • Looks good from what I can tell. The only thing I would suggest is to check for the existence of the header. This way you are not always inserting for returning connections that already have it.

     
      when HTTP_REQUEST {  
      if {([TCP::local_port] ==80) and !( [HTTP::header "X-Forwarded-Proto"] eq "http") }{  
      HTTP::header insert X-Forwarded-Proto "http"  
              log local0. "HTTP request from Client IP: [IP::client_addr] to [IP::local_addr]:[TCP::local_port]"  
             } elseif {([TCP::local_port] ==443) and !( [HTTP::header "X-Forwarded-Proto"] eq "https") } {  
              HTTP::header insert X-Forwarded-Proto "https"  
              log local0. "HTTPS request from Client IP: [IP::client_addr] to [IP::local_addr]:[TCP::local_port]"    
      }  
      }  
      

    I hope this helps

    Bhattman
  • A client wouldn't include a response header in a subsequent request, so the only time that header would exist is if the client injected it. You might actually want to remove any prior instance to ensure a malicious client couldn't forge the header.

    If the VIP is defined on port 0, you might also want to drop any non-80 or non-443 traffic. You can also do the check once in CLIENT_ACCEPTED instead of on each HTTP request:

     
     when CLIENT_ACCEPTED { 
      
         Check the requested port 
        switch [TCP::local_port] { 
           80 { 
              set proto http 
           } 
           443 { 
              set proto https 
           } 
           default { 
               Drop the request 
      drop 
           } 
        } 
     } 
     when HTTP_REQUEST { 
      
         Replace the X-Forwarded-Proto header if it exists 
          If it does not exist, a new instance will be inserted 
        HTTP::header replace X-Forwarded-Proto $proto 
     } 
     

    Aaron
  • Aaron,

     

     

    I will be using one of your irules for the HTTPandHTTPS virtual server inconjunction with the XForwardedProto irule.

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/HttpHttpsSingleVirtualServer.html

     

     

  • Everything is good but Safari is doing something weird. It's appending the url with :443 when it's an http request, looks like this http://newsite.apa.org:443. Might be because the application is doing some switching between http and https. All the rest of the browsers are working w/o any problems.
  • You could add the XForwardedProto logic to the single VIP iRule by setting the proto variable to https in this section:

     

     

    Request was to an HTTPS port, so do nothing for the clientside connection.

     

     

    And setting it to http for in this section:

     

     

    Request was to an HTTP port, not an HTTPS port, so disable client SSL profile if one is enabled on the VIP

     

     

    I'd guess that Safari is getting a redirect to http://newsite.apa.org:443 and not actually generating that request itself. You could check this by logging the Location header in redirects or by using a browser plugin to log HTTP request/response headers and payloads. If it is coming from the app, you could add a check in the HTTP_RESPONSE event to look for [HTTP::is_redirect]==1 and then rewrite the Location header value using HTTP::header replace Location $new_location.

     

     

    Aaron
  • Thank YOU kind sirs! I added the following to http_response and it resolved our Safari issue.

     
     when HTTP_RESPONSE { 
     if { [HTTP::header Location] starts_with "http://newsite.apa.org:443"} { 
     log local0. "Location [HTTP::header Location]" 
     HTTP::header replace Location "http://newsite.apa.org" 
     } 
     }   
      
     
  • It would be more efficient to only check for the Location header on redirects. Also, if you want to preserve the URI in the redirect, you should use string map:

     
     when HTTP_RESPONSE { 
        if { [HTTP::is_redirect] and [HTTP::header Location] starts_with "http://newsite.apa.org:443"} { 
           log local0. "Location [HTTP::header Location]" 
           HTTP::header replace Location "[string map "http://newsite.apa.org:443 http://newsite.apa.org" [HTTP::header Location]]" 
        } 
     } 
     

    Aaron
  • This exactly what I did once the developers returned with an issue involving the need to preserve the URI.

     

     

    Took a hint from another iRule I found on DevCentral http://devcentral.f5.com/wiki/default.aspx/iRules/RewriteHTTPRedirectPort.html.
  • I did something similar, except with the HTTP profile... i have one profile for non-ssl VS and one with ssl VS. Then each profile does a header insert that is basically SSL true or false, and the application reads this header.
  • Puli's avatar
    Puli
    Icon for Nimbostratus rankNimbostratus
    I tried the above code, but for some reason, the Location is outputed as empty in the log.

     

    Any ideas?