1

Okay, I haven't been able to find a solution to this as of yet, and I need to start asking questions on SO so I can get my reputation up and hopefully help out others.

I am making a wordpress plugin that retrieves a json list of items from a remote site. Recently, the site added a redirecting check for a cookie.

Upon first request without the cookie, 302 headers are provided, pointing to a second page which also returns a 302 redirect pointing to the homepage. On this second page, however, the set-cookie headers are also provided, which prevents the homepage from redirecting yet again.

When I make a cURL request to a url on the site, however, it fails in a redirect loop.

Now, obviously the easiest solution would be to fix this on the remote server. It should not be implementing that redirect for api routes. But that at the moment is not an option for me.

I have found how to retrieve the set-cookie header value from a 2** code response, however I cannot seem to figure out how to access that value when 302 headers are provided, and cURL returns nothing but an error.

Is there a way to access the headers even when it reaches the maximum (20) redirects?

Is it possible to stop the execution after a set number of redirects?

How can I get this cookie's value so I can provide it in a final request?

D.Meganoski
  • 318
  • 1
  • 2
  • 12

3 Answers3

0

You already had problems before you started trying to add cookies into the mix. Doing a single redirect is bad for performance. Using a 302 response as a means of dissociating data presentation from data retrieval under HTTP/1,1 or later is bad (it works, but is a violation of the protocol - you should be using a 303 if you really must redirect).

Trying to set a cookie in a 3xx response will not work consistently across browsers. Setting a cookie in an Ajax response will not work consistently across browsers.

It should not be implementing that redirect for api routes

Maybe the people at the remote site are trying to prevent you leeching their content?

Fetch the homepage first in an iframe to populate the cookie and record a flag in your domain on the browser.

symcbean
  • 47,736
  • 6
  • 59
  • 94
  • No, I have full permission to access it, it's a work project. They implemented the redirect and broke the plugin they requested. It's a client so I'm not going to rag. More than likely, they will remove the redirect (eventually). I just wanted to get past it for my own learning purposes, and to continue working on other aspects of it. But I will pass on the info, I didn't know that about 3xx responses, something else to look into for me. – D.Meganoski Dec 01 '15 at 18:23
  • I'm not sure I agree with almost anything said here. 301 and 302 redirects have their uses and are WIDELY used. In my experience all browsers will handle cookies set in a 30x response just fine, as well as in Ajax responses. – drew010 Dec 01 '15 at 18:51
0

I actually found another SO question, of course after I posted, that lead me in the right direction to make this possible, HERE

I used the WebGet class to make the curl request. It has not been maintained for three years, but it still works fine.

It has a function that makes the curl request without following through on the redirect loop.

There are a lot of curl options set in that function, and curl is not returning an error in it, so I'm sure the exact solution could be simpler. HERE is a list of curl options for anyone who would like to delve deeper.

Here is how I handle each of the responses to get the final response

        $w = new WebGet();

        $cookie_file = 'cookie.txt';

        if (!file_exists($cookie_file)) {
            $cookie_file_inter = fopen($cookie_file, "w");
            fclose($cookie_file_inter);
        }

        $w->cookieFile = $cookie_file; // must exist and be writable
        $w->requestContent($url);

        $headers = $w->responseHeaders;

        if ($w->responseStatusCode == 302 && isset($headers['LOCATION'])) {
            $w->requestContent($headers['LOCATION']);
        }

        if ($w->responseStatusCode == 302 && isset($headers['LOCATION'])) {
            $w->requestContent($headers['LOCATION']);
        }

        $response = $w->cachedContent;

Of course, this is all extremely bad practice, and has severe performance implications, but there may be some rare use cases that find themselves needing to do this.

Community
  • 1
  • 1
D.Meganoski
  • 318
  • 1
  • 2
  • 12
0

If you use the cURL option CURLOPT_HEADER the data you get back from curl_exec will include the headers from each response, including the 302.

If you enable cookie handling in cURL, it should pick up the cookie set by the 302 response just fine unless you prefer to handle it manually.

I often do something like this when there could be multiple redirects:

$ch = curl_init($some_url_that_302_redirects);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, ''); // enable curl cookie handling

$result = curl_exec($ch);
// $result contains the headers from each response, plus the body of the last response

$info   = curl_getinfo($ch); // info will tell us how many redirects were followed

for ($i = 0; $i < intval($info['redirect_count']); ++$i) {
    // get headers from each response
    list($headers, $response) = explode("\r\n\r\n", $response, 2);

    // DO SOMETHING WITH $headers HERE
    // If there was a redirect, headers will be all headers from that response,
    // including Set-Cookie headers
}

list($headers, $body) = explode("\r\n\r\n", $response, 2);

// Now $headers are the headers from the final response
// $body is the content from the final response
drew010
  • 68,777
  • 11
  • 134
  • 162
  • Yep, that did it. I could retrieve the cookie I was looking for this way. The package I mentioned in my answer is a bit simpler, but doesn't actually answer the question. I'll mark yours as the answer. – D.Meganoski Dec 01 '15 at 19:02
  • @D.Meganoski Glad that code was helpful, let me know if you have any other questions. I have a pretty standard "parseHeaders" function I use that can be useful for that was well if you're interested. – drew010 Dec 01 '15 at 19:19