Varnish 301 redirect displays a white page - php

We use varnish as our load balancer (among other things) but we get some strange behavior at the moment.
We have a script that gets called with some parameters, and depending on what parmas you pass, you get redirected to a different location using a 301 redirect (this it done with a php script and the header() function)
The problem is that the first time a URL is begin called the 301 redirect happens, but then the next time that same URL is called, you get a status of 200 OK, no redirect happens and just a white page is displayed.
I've added a session_start() to the top of the php script to try and stop varnish from caching the page, but nothing helped so far.
I've done some research regarding this issue, and saw that several people experience the same problem, but I wasn't able to find a solution yet.
How would I get varnish the stop caching the page?
Any help in the right direction will be appreciated.

Could you not exclude that url from the varnish cache?
Add something like the following to your default.vcl (or whatever your varnish config file is called).
sub vcl_recv {
if(req.url ~"^/thatpagethatredirects") {
return (pass);
}
}
This should stop varnish caching that url.

You could try finding the url that varnish is redirecting to and adding a query string with a randomly generated number to it.
Example:
<?php
$random_number = rand(10000, 99999999);
// This is what the redirect code MIGHT look like, but I doubt it.
header("Location: http://www.example.com/index.php?cache=$random_number");
?>
If you can find where the page is actually doing the redirecting and you add a random number query string, it should fix things. I have used this method of making sure images are not cached in the past and it always worked for me perfectly.
Oh, and if you can't find the redirect code that varnish is using itself. You could try adding this to the page that varnish loads after the 301 redirect:
<?php
$random_number = rand(10000, 99999999);
header("Location: NAME_OF_THIS_SCRIPT.php?cache=$random_number");
?>
Pretty much the same idea, just involves less hunting around. I'm not sure if this will break the load balancing function of varnish though.

This is rather awkward and is supposed to work correctly by default. Can you tell us what version of Varnish you are using and if you created a custom vcl file?
The bug was probably introduced in vcl_fetch. This should check for cacheability with checks like:
sub vcl_fetch {
...
if (req.status >= 300 ) {
return pass;
}
if ( ! obj.cacheable ) {
return pass;
}
..
}

Related

do web browsers cache redirect responses? Or laravel?

So I had built a little URL shortener with Laravel 5.4 where I have a route that does: domain.com/{urlkey} - I grab the key and look it up in my Laravel cache which is in Redis. I also have another key that tracks the # of visits - so anytime the URL is accessed i Just increment the :visits key.
Now I have been noticing when i take one of these URLs copy and paste it into a new tab... or even click it from my application it just ignores my code completely. I can put in a die() and it wont even stop! which will never trigger the cache increment on the key...
Any ideas what is going on? Probably missing something very obvious.
The simple lookup and increment is below: but I dont even think it is hitting the code? Why would this be?
Other note the domain is https - however I have tested this on both http and https
// retrieve redirect URL from cache
$redirectUrl = Cache::get('short:' . $shortKey);
// if we find the redirect in the cache - increment visits - 301 redirect
if($redirectUrl)
{
Cache::increment('short:' . $shortKey . ':visits', 1);
return redirect($redirectUrl, 301);
}
Because 301 = Moved Permanently, the browser will cache it and redirect automatically next time without calling the original page
If I am not mistaking, if you want the redirect to always go thru the original page, you need to replace the 301 with a 302 Found

Check if cookies are enabled without redirect

I need on each page check if cookies are enabled.And use this code.
<?php
setcookie('COOK_CHK',uniqid(),time()+60*60*24);
if(!isset($_COOKIE['COOK_CHK'])){
echo"Cookies are disabled!";
exit;
}
session_start();
?>
However on the first check it gives me false until i don't refresh the page.I include this code in each page so can not redirect every time i load the page as it reduces performance.However i want to use it even if javascript is disabled.Any suggestions?
Can you use javascript? If so, all it takes is a check at the navigator.cookieEnabled variable.
It works in most modern browsers. You can read more about it here: http://www.w3schools.com/jsref/prop_nav_cookieenabled.asp
It's not possible because Cookies are in the browser, and PHP send them when the page has render, so will be available just in the second page.
A possible way to fix this is using javascript.
If you really should do it in PHP, for some crazy reason, send all your request to a main controller and save the state using other method, for example, write a var into a file, then redirect and in the next redirections you'll know if the cookies are enabled without needed any other redirection. Example:
$file = 'cookie_fake_'.$userIP;
if( !isset($_COOKIE['COOK_CHK']) && !file_exists($file) ){
file_put_contents($file, 'dummy');
setcookie('COOK_CHK',uniqid(),time()+60*60*24);
header('Location:/');
exit;
}
if(!isset($_COOKIE['COOK_CHK'])){
setcookie('COOK_CHK',uniqid(),time()+60*60*24);
echo"Cookies are disabled!";
exit;
}
Then you should write something to clean old files every hour or so, of course you can use a cache layer or a database or anything like that instead of writing a file.
Edit: The previous code will be really f** up if the user enables cookies and refresh the page, now I've fixed so it works at the second time it refresh. Not perfect but... You really should do this using javascript.
Cheers.

HTTP 302 error because of a header()

if I validate html or register web in any serch engine, I get 302 error.
The reason is a header() function. If I take it away, everything is fine with 200 OK status.
So the main problem is that I need this redirection for web to be multilingual.
The logic is next. When user enters the web page for the first time index.php - require_once a file with a function:
function cookies() {
if (!isset($_COOKIE["lang"])){
setcookie('lang','ukr', time()+(60*60*24*31));
header('Location: index.php');
}}
cookies();
so the user sees a page already filed with a deafault language.
If there would be no redirection from require_once file the data from mysql won't be downloaded and user won't see any text.
The question: should I leave this with HTTP 302 or rebuild the whole site/logic not to have any redirects at index page???
302 is not an error. It is the status code for "Found" (aka "The document you asked for is over here"). PHP will insert this for you automatically if you add a Location header (unless insert a status manually, but you don't want a 301 here)
This is the expected response if you are telling people to go and get a different document based on their language preferences.
It is odd to redirect from index.php to index.php though. Presumably you should just return the appropriate document directly instead of redirecting.
I got it. It's actually pretty simple.
The validators don't accept cookies. So they get stuck in a an infinite loop.
You can test this:
delete all your cookies from your computer.
Disable cookies in your browser and try loading your website.
Whenever You use header("location: .... you will get a 302, it's a status and not an error, it's telling the browser that the site has redirected the page:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Read those validators and engines and see if having the 302 is a problem for whatever you are trying to do, normally it shouldn't be.
A dirty way would be to force the header, personally I don't encourage this and don't know what side-effects could it have really, but it could be a quick workaround to trick those engines:
function cookies() {
if (!isset($_COOKIE["lang"])){
setcookie('lang','ukr', time()+(60*60*24*31));
header('Location: index.php');
header('HTTP/1.1 200 OK'); // <--- Forcing the header status
}}
cookies();

301 Permanent Redirect

a website has used a "301 permanent redirect" to my site is there a way i can set code that detects this and displays a page when my website is accessed through this?
Does anyone have any idea about this?
You can get only a referer. I think you will not be able to get the http status code on server which the client gets during last request.
So my answer is NO, you cannot get the 301 status code on your server.
But you can do a little of needed magic with referer variable.
e.g. in PHP you can read this:
$_SERVER['HTTP_REFERER'];
Not much you can do. If you were doing the 301, you could set the referrer to the querystring. But since you're not, you can only grab what the request has given you.
You can try using PHP's $_SERVER['HTTP_REFERER'] to track the source URL from where your visitor comes from. I think it's a bit dodgy though and might not yield the same result in all browsers. Even PHP's documentation says 'it cannot really be trusted'.
Why do you have to use .htaccess for the redirect? You could do something like this:
Site A's index.php:
header("Location: http://siteb.com/?ref=".urlencode('http://sitea.com');
Site B's index.php:
if(isset($_GET['ref']))
{
if($_GET['ref']=='http://sitea.com')
{
// Do something
}
}
Edit:
If you can't edit Site A's code or server settings, try using:
if($_SERVER['HTTP_REFERER']=='http://sitea.com')
{
// Do something
}

Default content being added to 301 headers with PHP 5.3.5 / IIS7

On http://www.hesa.ac.uk, we are using a custom 404 handling script to redirect users from, for exmaple, http://www.hesa.ac.uk/press to the actual URL, which is an ugly CMS one: http://www.hesa.ac.uk/index.php?option=com_content&task=category&sectionid=1&id=1&Itemid=161
We're running fast-cgi.
A 301 header is sent, then a location header.
It works fine for 99% of our users but some of them are reporting 5 to 6 second loading times. This is, we think, due to a bit of stray content which is turning up in the redirection:
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found here</body>
This isn't output anywhere in the code that we can see. Here's the method which actually does the redirection:
/**
* Do the actual redirection to the win URL
*
*/
function doRedirection() {
//start output buffering to trap any content that is output by default by the headers
#ob_start();
//permanently moved header
//header( 'HTTP/1.1 301 Moved Permanently' );
//fast-cgi, so use this:
header('Status: 301 Moved Permanently', true);
#ob_end_clean(); // clear output buffer
//location header
header( "Location: ". $this->winUrl );
#ob_end_clean(); // clear output buffer
die();
}
I cannot seem to find any resource which indicates how to stop this extra bit of content being output. I have tried various variations on the method above to do the redirection.
Has anyone had a similar problem? Does anyone have any ideas?
Cheers,
G
EDIT: we've become aware that this is expected behaviour for IIs7, but IIS6 never used to do it with the same code, and whether it's expected or not, our users are complaining and this seems to be the issue.
EDIT 2: it seems that the only workable solution is to abandon this approach and instead move to IIS7's url rewriting functionality, which entails writing a C# class which clones the functionality of the PHP class then plugging that into IIS.
EDIT 3: HOWEVER, setting a content-length: 0 header might possibly help. Not tested yet though.
Turns out the problem was actually the use of the built-in PHP function getHostByAddr() within the redirection code. Client hosts which do not have their DNS records set up properly experience a 5 to 6 second delay from getHostByAddr() (under IIS7, we never had this issues with IIS6). If you find an alternative function and swap it out, the problem disppears.

Categories