Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

401 redirect magically results in a 302 redirect

I'm using the Redirect class to send non-logged-in users to the login page, with a 401 status code:

return Redirect::to('login', 401);

This sends the correct location header, but the status code is set to 302.


I've traced it all the way to the base Response class in

laravel/vendor/Symfony/Component/HttpFoundation/Response.php

and it's calling:

$this->setStatusCode($status);

with the correct 401 code.


I also tried dumping the object:

var_dump( Redirect::to('login', 401)->foundation );

and I can see the protected statusCode property is correctly set to 401.


Still, the generated response's HTTP status code is set to 302.

What gives? Am I using it wrong?


P.S. I also posted this on Laravel's forums, to no avail.

like image 340
Joseph Silber Avatar asked Nov 20 '12 23:11

Joseph Silber


1 Answers

This is not because of laravel, you can reproduce this with just (php 5.4 in windows):

<?php
header("HTTP/1.1 401 Unauthorized");
header("Location: http://www.google.com");

It appears php sets it to 302:

$ php-cgi "test.php"
Status: 302 Moved Temporarily
Location: http://www.google.com
Content-type: text/html; charset=UTF-8

In PHP source code main/SAPI.C:

} else if (!STRCASECMP(header_line, "Location")) {
    if ((SG(sapi_headers).http_response_code < 300 ||
        SG(sapi_headers).http_response_code > 307) &&
        SG(sapi_headers).http_response_code != 201) {
        /* Return a Found Redirect if one is not already specified */
        if (http_response_code) { /* user specified redirect code */
            sapi_update_response_code(http_response_code TSRMLS_CC);
        } else if (SG(request_info).proto_num > 1000 && 
           SG(request_info).request_method && 
           strcmp(SG(request_info).request_method, "HEAD") &&
           strcmp(SG(request_info).request_method, "GET")) {
            sapi_update_response_code(303 TSRMLS_CC);
        } else {
            sapi_update_response_code(302 TSRMLS_CC);
        }
    }

As you can see, when you do header() with "Location", the http status code is modified to 302

You can make it work if you do it the other way around:

<?php
header("Location: http://www.google.com");
header("HTTP/1.1 401 Unauthorized");

This will give:

$ php-cgi "test.php"
Status: 401 Unauthorized
Location: http://www.google.com
Content-type: text/html; charset=UTF-8

But laravel sets the location after setting status, so the status is set back to 302 anyway. But this is a moot point, even if you successfully set status to 401 with a location header, the redirect is not followed by browsers.

like image 162
Esailija Avatar answered Sep 23 '22 22:09

Esailija