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]"   
 } 
 } 
  
  
  
 
  • 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
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    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.
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    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" 
     } 
     }   
      
     
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    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?