#1
  1. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2002
    Location
    Bay Area California
    Posts
    371
    Rep Power
    14

    Need help with RewriteRule (mod_rewrite) to redirect special files to HTTPS


    Hi all,

    I am pretty close on this and have this partially working all thanks to the great mod_rewrite sticky guide provided by jharnois!

    My premise is pretty simple:
    1. If the protocol is currently 80 and the filename the user is looking at is "signup.php", "signup_process.php" or "signup_conf.php" then force the user from HTTP to HTTPS
    2. If the protocol is currently 443 (SSL) and the filename is not one of the three aforementioned files, then redirect the user from HTTPS to HTTP.
    I was able to get both redirects functioning properly using only one of the files (signup.php). But when I try and get all fancy and add three files, I fail.

    Here is the version for #1 above that works
    PHP Code:
    <Directory "/Library/WebServer/Documents/orders">
        
    Options +FollowSymLinks
        RewriteEngine On
        RewriteCond 
    %{SERVER_PORT} ^80$
        
    RewriteRule ^signup.phphttps://%{HTTP_HOST}%{REQUEST_URI}
    </Directory
    And here is the version for #2 above that is working:
    PHP Code:
    <Directory "/Library/WebServer/Documents/orders">
        
    Options +FollowSymLinks
        RewriteEngine On
        RewriteCond 
    %{SERVER_PORT} ^443$
        
    RewriteRule !^signup.phphttps://%{HTTP_HOST}%{REQUEST_URI}
    </Directory
    When I tried to make a version that looks at all three files, I fail. Here is what I tried to do:
    PHP Code:
    <Directory "/Library/WebServer/Documents/orders">
        
    Options +FollowSymLinks
        RewriteEngine On
        RewriteCond 
    %{SERVER_PORT} ^80$
        
    RewriteCond %{REQUEST_URI} ^signup.php [OR]
        
    RewriteCond %{REQUEST_URI} ^signup_process.php [OR]
        
    RewriteCond %{REQUEST_URI} ^signup_conf.php
        RewriteRule 
    ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}
    </Directory
    I assumed I needed to use RewriteCond (conditions) to specify my three files to match (maybe this isn't the correct way). I think my problem may be in the RewriteCond usage, or in the RewriteRule where I am specifying the "^(.*)$" since I actually am not even sure what that does - I just assumed that was a catch-all or wildcard match. Or it is in how I am trying to specify the REQUEST_URI matching files. Basically I want this to do the redirect to secure HTTPS if any of the files above are matched.

    Can anyone point our where I am making my mistake and suggest a way to make this work? Much much thanks.
  2. #2
  3. Did you steal it?
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    13,961
    Rep Power
    9397
    It's not spelled out in the docs but I believe ANDing two RewriteConds has precedence over ORing. Or maybe it's the same precedence and they're left-to-right (or rather top-to-bottom). Thus you've written
    Code:
    (HTTP and signup.php) or (signup_process.php) or (signup_conf.php)
    1. Use the HTTPS flag, not the port number.
    2. The REQUEST_URI is the entire URL as requested.
    3. Put the list of files in the RewriteRule.
    Code:
    RewriteCond %{HTTPS} off
    RewriteRule ^(signup|signup_process|signup_conf).php$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
    
    RewriteCond %{HTTPS} on
    RewriteRule !^(signup|signup_process|signup_conf).php$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R]

    Comments on this post

    • jkoerber agrees : Solves my issue in a very clean and simple manner!
  4. #3
  5. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2002
    Location
    Bay Area California
    Posts
    371
    Rep Power
    14
    requinix,

    Awesome, that totally did the trick. I was wondering myself about how mod_rewrite would work with AND and OR together, but looking back at the documentation, you are correct... it does not really talk about precedence.

    I had wondered about doing the (file|file2|file3) syntax, but so few examples I have seen talk about anything other than redirecting directories, or entire servers from HTTP to HTTPS.

    But I am glad I now have everything working flawlessly on my production servers.

    You rock!
  6. #4
  7. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2002
    Location
    Bay Area California
    Posts
    371
    Rep Power
    14
    Postmortem to the prior solution... a gnarly wrinkle.

    After testing my order process fully with the new mod_rewrite directives, I realized I still had a problem. This has nothing to do with the solution provided by requinix, which worked flawlessly, it was because I hadn't fully tested the process from end-to-end and forgot about a key component.

    The problem was that all of the order data in the signup form was being lost somewhere between the passing of the data to our external merchant provider from the "signup_process.php" script and when the data was sent back from the vendor to our "create_order.php" script.

    The culprit was upon the return from the call to our "create_order.php" script by our external vendor, that call - which is supposed to be a HTTPS secure call, was being rewritten to a HTTP based URI. This caused all the POST data in the form to be lost (I am not sure why that happens, but I suppose HTTP and HTTPS protocols don't share data sessions).

    To solve the redirect issue, I went ahead and added the "create_order.php" script to my mod_rewrite directives in my httpd.conf files from above, but it didn't solve the problem. I surmised this was because the "create_order.php" script is actually in another directory, one level deeper from the main directory "/orders/" named "/orders/data_store/"

    My full processing flow (for those following this posting) is:

    signup.php => signup_process.php => [external vendor merchant site] => *create_order.php => signup_conf.php

    * means this script is one directory deeper than the main directory

    For some reason, even though the external site called the script using a fully qualified https://... URI, the prior mod_rewrite was still forcing it to be HTTP:, even though I added the name of the script to my mod_rewrite. This caused the "create_order.php" script to lose all the passed POST variables, thus killing the order process with an error.

    I am not sure why this was forcing the mod_rewrite to HTTP for the "create_order.php" script even though I had it in my http.conf file... maybe mod_rewrite in a <directory> section cannot follow hierarchical directories. That would answer the problem, but I don't know. Maybe someone can shed some light on this.

    In the end, I was able to solve my problem by adding a new directory section to my http.conf files named: <Directory "/Library/WebServer/Documents/orders/data_store">, for the subdirectory that has just the one new filename "create_order.php". This fixed the issue of the data being lost in the rewrite since it wasn't switching protocols for the create_order.php script anymore :-)

    Maybe adding a whole other <directory> section wasn't the best way to solve this problem and there is a way to reference the subdirectory where the "create_order.php" file lives using the original mod_rewrite directives. So if anyone has any comments or advice on this particular issue of the solution, I am happy to tweak my code to make it cleaner and more efficient.

    Again, much thanks for any assistance in advance.
  8. #5
  9. Did you steal it?
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    13,961
    Rep Power
    9397
    Originally Posted by jkoerber
    The culprit was upon the return from the call to our "create_order.php" script by our external vendor, that call - which is supposed to be a HTTPS secure call, was being rewritten to a HTTP based URI. This caused all the POST data in the form to be lost (I am not sure why that happens, but I suppose HTTP and HTTPS protocols don't share data sessions).
    The problem is the redirect. Technically speaking browsers should repeat the same POST request to the new URL, but in practice they do not (anymore). It actually turns from a POST with data into a GET at the new location.
    So regardless of URL rewriting, POSTed forms must always point to the right location - any redirects will kill the process.

IMN logo majestic logo threadwatch logo seochat tools logo