facha
facha

Reputation: 12522

curl and redirect to ssl site

I have a piece of code that does a post http request using curl and returns an output. The website I'm making a post request to has a redirect from http to https.

When I do a post request to https port, everything works fine. when I do the same request to the http port (and get redirected to https port) I get an empty string. Please, could anyone tell me why is it not working and how to do it correctly.

The function that does a post request:

function curl_query($url, $username, $password, $payload) {
    $additionalHeaders = "";
    $process = curl_init($url);
    curl_setopt($process, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded',$additionalHeaders));
    curl_setopt($process, CURLOPT_HEADER, false);
    curl_setopt($process, CURLOPT_USERPWD, $username . ":" . $password);
    curl_setopt($process, CURLOPT_TIMEOUT, 30);
    curl_setopt($process, CURLOPT_POST, 1);
    curl_setopt($process, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($process, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($process, CURLOPT_MAXREDIRS, 4);
    curl_setopt($process, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
    $return = curl_exec($process);
    return $return;
}

A .htaccess entry that redirects a query from port 80 to port 443:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

UPDATE After some debugging I've found that after the initial POST and being redirected to a new location curl is sending a GET request. Is it possible to make it resend the initial POST to a new location?

Upvotes: 4

Views: 5664

Answers (2)

Doglas
Doglas

Reputation: 670

Use "CURLOPT_UNRESTRICTED_AUTH: true" to keep sending auth parameters to the redirected request.

Use "CURLOPT_POSTREDIR: true" to keep sending POST type request with POST parameters to the redirected request.

These options are described in @Arthur link: http://php.net/manual/en/function.curl-setopt.php

Upvotes: 0

Arthur
Arthur

Reputation: 634

Ran into the same issue today and first thought it was a bug of curl. However after digging into it a bit more I found out that RFC 2616 states the following about redirecting POST requests:

301 - Moved Permanently:

If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Note: When automatically redirecting a POST request after receiving a 301 status code, some existing HTTP/1.0 user agents will erroneously change it into a GET request.


302 - Found: > If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued. > >> Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.
303 - See Other: > The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource.
307 - Temporary Redirect > If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
source: https://www.rfc-editor.org/rfc/rfc2616#section-10.3.2 (page 62-65)

So knowing that curl cannot ask the user anything it seems reasonable that for 301 and 302 redirects POST is turned into GET (even though this is not 100% according to RFC).

Luckily since curl 7.19.1 (php 5.3.2) there is the option to force curl into keeping POST method for redirects:

CURLOPT_POSTREDIR

A bitmask of 1 (301 Moved Permanently), 2 (302 Found) and 4 (303 See Other) if the HTTP POST method should be maintained when CURLOPT_FOLLOWLOCATION is set and a specific type of redirect occurs.

http://php.net/manual/en/function.curl-setopt.php

So example:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_POSTREDIR, 7);
$response = curl_exec($ch);
curl_close($ch);

Upvotes: 2

Related Questions