php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #49571 CURLOPT_POSTREDIR not implemented
Submitted: 2009-09-16 13:54 UTC Modified: 2009-09-25 12:07 UTC
From: info at pcxtra dot nl Assigned: srinatar
Status: Closed Package: Feature/Change Request
PHP Version: 5.3.0 OS: Windows XP
Private report: No CVE-ID:
 [2009-09-16 13:54 UTC] info at pcxtra dot nl
Description:
------------
I'd like to use the CURLOPT_POSTREDIR. When I try to POST data to a page it will return with 302 and CURL will redirect with POST. However I need to configure this to redirect with GET which can be configured with CURLOPT_POSTREDIR which is added in curl 7.19.1. (I'm using PHP 5.3 with Curl 7.19.4)

I also tried 
curl_setopt($ch, 161 , 0);
(also tried 1,2 and 3)
in the hope it would still work, but it didn't.

Reproduce code:
---------------
By POSTing something to an URL which returns 302 and the following settings:

curl_setopt($ch, CURLOPT_MAXREDIRS, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

It will show with curl_getinfo:
[request_header] => POST /Account/MyPortal.aspx HTTP/1.1


Expected result:
----------------
I would have expected (and wanted) 
[request_header] => GET /Account/MyPortal.aspx HTTP/1.1



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-09-17 02:11 UTC] srinatar@php.net
I am not sure, i completely understand your issue here. 

when you post data to a server returning with 302, curl will by default return with GET requests (which is non-RFC compliant)

as per HTTP/1.1 spec 10.3.3 in http://www.ietf.org/rfc/rfc2068.txt 

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: When automatically redirecting a POST request after receiving
     a 302 status code, some existing HTTP/1.0 user agents will
     erroneously change it into a GET request.


curl to provide backward compatibility will by default return with GET for post requests returning with 301/302 redirects. 

now, if you wanted to stop this behavior, and instead curl to be standards compliant ,then you need to set this CURL_POSTREDIR option.

as you mentioned, this option makes sense only when used with CURLOPT_FOLLOWLOCATION.

is this what you are looking for ?
 [2009-09-17 08:39 UTC] info at pcxtra dot nl
Thanks for you response!

You mentioned: when you post data to a server returning with 302, curl will by default return with GET requests (which is non-RFC compliant)

I also had this understanding and expected that the curl behaviour is non RFC compliant by returning with a GET after a 302. However I did not experience this. In my case it returns with another POST (according to the request_header field returned by curl_getinfo() )

All I found then is to configure this behaviour with CURLOPT_POSTREDIR which doesn't seem to be supported. 

So in fact I'm looking to the curl default behaviour that is to redirect with a GET method after a POST. And then I don't need the option CURLOPT_POSTREDIR.

Will you be able to duplicate or do I need to provide more details?
 [2009-09-18 14:51 UTC] info at pcxtra dot nl
I've completed a full running test. Please save it as curl.php and start it with curl.php?start=true. The idea is that it will do a POST to curl.php?redir=true. This page will response with 302 and redirect to curl.php?target=true. Now with CURLOPT_FOLLOWLOCATION=1 it goes wrong. I get [request_header] => POST /curl.php?redir=true HTTP/1.1 while I would expect the GET method.

<?php

$me = "http://". $_SERVER["SERVER_NAME"] . $_SERVER["SCRIPT_NAME"]; 

if( isset($_GET["redir"]) )
  header("Location: ".$me."?target=true",TRUE,302);

if( isset($_GET["target"]) ) {
  echo "done";
  exit();
}

if( isset($_GET["start"]) ) {
	$ch = curl_init( $me . "?redir=true");

	curl_setopt( $ch, CURLINFO_HEADER_OUT, 1 ); 
	curl_setopt( $ch, CURLOPT_HEADER, 1 ); 
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); 
	curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "POST"); 
	curl_setopt( $ch, CURLOPT_POST, 1 ); 
  curl_setopt( $ch, CURLOPT_POSTFIELDS, "data=somedata");

  curl_setopt($ch, CURLOPT_MAXREDIRS, 1 ); 
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 
  $content = curl_exec( $ch );

	echo '<pre style="background-color:yellow">' . htmlspecialchars( print_r(curl_getinfo( $ch ), true) ).  '</pre>';
	echo '<pre style="background-color:#eeeeee">' . htmlspecialchars( $content ).  '</pre>';
}

echo "usage: ".$me."?start=true";
?>
 [2009-09-18 14:59 UTC] info at pcxtra dot nl
I made a copy/paste failure...

instead of: Now with CURLOPT_FOLLOWLOCATION=1 it goes wrong. I
get [request_header] => POST /curl.php?redir=true HTTP/1.1 while I would expect the GET method.

it should be: Now with CURLOPT_FOLLOWLOCATION=1 it goes wrong. I
get [request_header] => POST /dev/impeng/curl.php?target=true HTTP/1.1 while I would expect the GET method.
 [2009-09-23 23:31 UTC] srinatar@php.net
hi
 hmm.. when i commented this below line  in your example
/*
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "POST"); 
*/

i was able to get curl to send a 'GET' request after post returning a redirect. 

127.0.0.1 - - [23/Sep/2009:16:25:51 -0700] "POST /curl.php?redir=true HTTP/1.1" 302 50
127.0.0.1 - - [23/Sep/2009:16:25:51 -0700] "GET /curl.php?start=true HTTP/1.1" 200 1323
127.0.0.1 - - [23/Sep/2009:16:25:51 -0700] "GET /curl.php?target=true HTTP/1.1" 200 4

similarly, when i changed the redirect to 302, i was also able to get curl to issue a 'get' request after a redirect. 

127.0.0.1 - - [23/Sep/2009:16:25:13 -0700] "POST /curl.php?redir=true HTTP/1.1" 301 50
127.0.0.1 - - [23/Sep/2009:16:25:13 -0700] "GET /curl.php?target=true HTTP/1.1" 200 4
127.0.0.1 - - [23/Sep/2009:16:25:13 -0700] "GET /curl.php?start=true HTTP/1.1" 200 1333


now, here is a simple patch against 5.3, which allows you to do
curl_setopt( $ch, CURLOPT_POSTREDIR, 3 ) and which forces curl to issue POST (or same request) after seeing a redirect. 

Index: ext/curl/interface.c
===================================================================
--- ext/curl/interface.c        (revision 288624)
+++ ext/curl/interface.c        (working copy)
@@ -747,8 +747,10 @@
        REGISTER_CURL_CONSTANT(CURLFTPSSL_CONTROL);
        REGISTER_CURL_CONSTANT(CURLFTPSSL_ALL);
 #endif
+
 #if LIBCURL_VERSION_NUM > 0x071301
        REGISTER_CURL_CONSTANT(CURLOPT_CERTINFO);
+       REGISTER_CURL_CONSTANT(CURLOPT_POSTREDIR);
 #endif
 
 /* SSH support works in 7.19.0+ using libssh2 */
@@ -1669,6 +1671,12 @@
                        }
                        error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
                        break;
+#if LIBCURL_VERSION_NUM > 0x071301
+               case CURLOPT_POSTREDIR:
+                       convert_to_long_ex(zvalue);
+                       error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, Z_LVAL_PP(zvalue) & CURL_REDIR_POST_ALL);
+                       break;
+#endif
                case CURLOPT_PRIVATE:
                case CURLOPT_URL:
                case CURLOPT_PROXY:


 [2009-09-24 18:20 UTC] svn@php.net
Automatic comment from SVN on behalf of srinatar
Revision: http://svn.php.net/viewvc/?view=revision&revision=288677
Log: - Fixed bug #49571 (CURLOPT_POSTREDIR not implemented).
 [2009-09-24 18:28 UTC] srinatar@php.net
following needs to be documented

Whenever there is a redirect request (either 301 or 302) , curl (against HTTP/1.1 spec) always follows with a GET request. However, if your applications wants compliance with HTTP/1.1 spec, and be able to issue a POST request after a POST redirect, user can use 

curl_setopt( <curl-handle>, CURLOPT_POSTREDIR, 3);

here 3 tells curl module to redirect both 301 as well as 302 requests. 

0,1,2,3 are the valid options for the last argument. 

0 -> do not set any behavior
1 -> follow redirect with the same type of request only for 301 redirects. 
2 -> follow redirect with the same type of request only for 302 redirects. 
3 -> follow redirect with the same type of request both for 301 and 302 redirects. 

for example, if users wants the ability to redirect only for 301 requests, then they could use
curl_setopt( <curl-handle>, CURLOPT_POSTREDIR, 1);
 [2009-09-24 18:29 UTC] srinatar@php.net
docs comments already provided. 
 [2009-09-24 18:45 UTC] svn@php.net
Automatic comment from SVN on behalf of srinatar
Revision: http://svn.php.net/viewvc/?view=revision&revision=288678
Log: - Rollback fix for bug #49571 (CURLOPT_POSTREDIR not implemented).
# - Features don't go into PHP 5.2
 [2009-09-25 12:07 UTC] info at pcxtra dot nl
Thanks a lot for your help! 

I can confirm that my case was indeed solved by commenting the CUSTOMREQUEST option:

/*
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "POST"); 
*/

This seems even logical when I reconsider my code as it's a custom method and kept untouched on a redirect.

Also good to see that the POSTREDIR option is implemented, at this moment I only needed the default curl behaviour and didn't test this POSTREDIR option.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Mon Apr 21 04:01:57 2014 UTC