Question

I discovered after much painful debugging that requests to the the WP HTTP API (in this case, though wp_remote_request()) always ended up as GET method after being redirected, even if the method was something else in the initial request (in my case PURGE as used by the Varnish HTTP Purge plugin)

Normally this would apply to POST requests, where redirecting to a GET request of the same URL means completely obliterating the data being sent with the POST. In my case, using PURGE the outcome was that Apache was loading the actual URLs I was trying to purge, which wasn't what I wanted.

The point being: Pretty much never will you want this to happen. Whatever method you use to send a request, you surely want that method to be used in the end. This behavior is confusing and annoying and will probably be experienced as inexplicable bugginess for most users (in my case, the bug took me years to track down, and had been slowing down my local dev site where I don't have Varnish installed).

I'm posting this question so I can answer it myself in hopes people find it using Google in the future. The point is to be aware of this behavior so that if it is happening to you you can just find a way around it.

Was it helpful?

Solution 2

It turns out that as part of class-request->parse_response(), where redirections are handled for the various higher-level request functions (this is where it does the recursive requests for each subsequent hop) there's a weird hook thing that ends up running WP_Http->browser_redirect_compatibility() on the redirected request.

browser_redirect_compatibility() is pretty simple:

public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
        // Browser compat
        if ( $original->status_code === 302 ) {
            $options['type'] = Requests::GET;
        }
    }

Basically, it just obliterates the method you chose as soon as theres a 302 redirection, replacing it with GET. They seem to assume they are converting a POST request, but as is clear from reading it, this will apply to ANY method other than GET which ends up being a 302.

Notably though, this DOESN'T have any effect on 301 redirects, and seems to be related to an underlying crappiness of 302 as an error. You can read more about 302 and it's problems in [this previous question about a similar problem with POST requests getting converted to GET and losing their data]( Temporary redirect prevents getting $_POST array)

Affects Apache but not Nginx?

This seems relevant: My local dev environment uses MAMP and the sites is hosted through Apache, and this insane problem is triggered.

Our live site uses a Nginx->Varnish->Nginx setup, where for whatever reason, the same redirects were never 302 at all, but instead were 301 and thus worked correctly (they stayed as PURGE at the redirected location, which was the https version of the URL, rather than the http version).

So my recommendtaions to anyone having this problem:

  • Switch to Nginx completely as it seems to not use 302 for such redirects. Apache sux.
  • Look for sources of 302 errors and reconfigure your server to use 301 instead
  • Look for ways to avoid triggering redirects in the first place! (in our case, making sure the URLs were already https to start is an obvious improvement and will make our logs cleaner)

OTHER TIPS

The change of method to GET after redirect from POST, PURGE, BAN whatever, is perfectly legal and been there, and will be without Wordpress (it has nothing to do with it, really). Welcome to the World Wide Web:

Note: For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request. If this behavior is undesired, the 307 (Temporary Redirect) status code can be used instead.

As a matter of rule, don't expect a method to be kept after redirect, unless you're able to modify the client software to do so.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top