In Internet Explorer 10, if you press the back button it would try to fetch the previous page from the browser cache. This behavior differs from virtually every other browser including IE9 in which pressing the back button would do a full reload of the previous page instead of reusing the cache.
How do I communicate with IE10 from the website, possibly using javascript/headers etc to not do this cache utilization for the site globally?
(Note: I'm not looking for an IE10 setting to disable this. I'm looking for a solution that can be implemented in the Website and not the browser to instruct IE10 to not use this cache for the back button). Also I'm looking for a global solution that works for every page in the site...
I use PHP/Jquery for the site
so here's more information
The page is a Form. It contains some dynamically loaded info. (Let's say it contains the number of times the user submitted the form)
You click on the submit button of the form. You will then then get redirected to the form's action page.
Then you press the back button.
In every other browser, it would reload the initial form with the newly updated "number of times the user submitted the form". In IE10 however, this doesn't happen....How do I get this to happen in IE 10.
Here are some example headers:
1. When you first load the form:
Request Header
Key Value
Request GET /path/to/my/page HTTP/1.1
Accept text/html, application/xhtml+xml, */*
Accept-Language en-US
User-Agent Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
Accept-Encoding gzip, deflate
Host myhost.com
If-Modified-Since Tue, 10 Sep 2013 23:55:33 GMT
If-None-Match "1378857333"
DNT 1
Connection Keep-Alive
Cookie __utma=104299925.1011127538.1340896287.1364829735.1378764406.12; __utmz=104299925.1340896287.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); has_js=1; __utmc=104299925; __qca=P0-1247924781-1340896285157; _mkto_trk=id:601-CPX-764&token:_mch-sadfsadfze.com-1358808312889-73607; __utma=171146939.775168663.1343066079.1375907514.1378762647.41; __utmz=171146939.1343066079.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); s_stats_browser_info=%7B%22pluginInfo%22%3A%7B%22pdf%22%3A%5B%22pdf%22%2C%22application/pdf%22%2C%220%22%5D%2C%22quicktime%22%3A%5B%22qt%22%2C%22video/quicktime%22%2C%220%22%5D%2C%22realplayer%22%3A%5B%22realp%22%2C%22audio/x-pn-realaudio-plugin%22%2C%220%22%5D%2C%22wma%22%3A%5B%22wma%22%2C%22application/x-mplayer2%22%2C%220%22%5D%2C%22director%22%3A%5B%22dir%22%2C%22application/x-director%22%2C%220%22%5D%2C%22flash%22%3A%5B%22fla%22%2C%22application/x-shockwave-flash%22%2C%220%22%5D%2C%22java%22%3A%5B%22java%22%2C%22application/x-java-vm%22%2C%221%22%5D%2C%22gears%22%3A%5B%22gears%22%2C%22application/x-googlegears%22%2C%220%22%5D%2C%22silverlight%22%3A%5B%22ag%22%2C%22application/x-silverlight%22%2C%220%22%5D%7D%2C%22res%22%3A%221920x1080%22%7D; _pk_id.2.1644=19232922ec6753dc.1371502517.1.1371502630.1371502517.; SESS569093948b0206b05eb2212616da3db6=1977iogjr841af2s8l4sd1cjd0; XDEBUG_SESSION=12250; has_js=1; __utmc=171146939
Response Header:
> Key Value Response HTTP/1.1 200 OK Date Tue, 10 Sep 2013 23:55:44 GMT
> Server Apache/2.2.20 (Ubuntu) X-Powered-By PHP/5.4.15-1~tooptee10+1
> Last-Modified Tue, 10 Sep 2013 23:55:44 +0000 Cache-Control no-cache,
> must-revalidate, post-check=0, pre-check=0 ETag "1378857344"
> Keep-Alive timeout=15, max=9987 Connection Keep-Alive
> Content-Type text/html; charset=utf-8
2. When you hit the back button to go back to that form
Request Header
> Key Value
> Request GET /path/to/my/page HTTP/1.1
> Accept text/html, application/xhtml+xml, */*
> Accept-Language en-US
> User-Agent Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
> Accept-Encoding gzip, deflate
> Host myhost.com
Response Header
> Key Value Response HTTP/1.1 304 Not Modified
> X-Powered-By PHP/5.4.15-1~tooptee10+1 ETag "1378857344"
> Keep-Alive timeout=15, max=9987 Content-Type text/html; charset=utf-8
> Content-Length 117183 Expires Tue, 10 Sep 2013 22:55:36 GMT
> Last-Modified Tue, 10 Sep 2013 23:55:44 GMT
Notice that it ends up returning a 304. When I tried this in Firefox, it returned 200 instead when you press the back button.
I think the behaviour you want is a behaviour that breaks the expectation of the back button for users.
Users expect that when they press back, it returns them back to the page they were previously viewing, in the state it was in when they left it. Most modern browsers achieve this by not only caching the page, but by retaining the page state (including the Javascript context) in memory so that when returning to the page via the back button, it's in the same state it was before, including anything they wrote into forms or any Javascript they interacted with.
In most browsers you can forcibly override this by setting Cache-Control headers such as no-cache and no-store. I don't know if no-store would work in your case for IE10, or if IE10 ignores even this and just goes back to the page anyway. If it did, I don't think I'd really blame it. It's doing it in the user's interest of both being fast, and of returning back to the page as it was when it was viewed before.
I think the approach that I would take, and you don't have to agree with me, is to re-think the design. Why do you require users to hit "back" if you are not going to show them the same thing they saw when they were back there? If you want to show an updated form, why not redirect after POST back to the form, which will count as a new page load and honor your Cache-Control headers? That is what I'd do and it's become somewhat of a de-facto standard.
tl;dr it's possible, but I'm not certain, that you could do what you want with no-store, but I'd be looking at moving to redirect after POST instead so as not to rely on the back button for something other than going back to the previous state.
You may be able to set some headers in PHP
Cache-Control: private, must-revalidate, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00
Related
I am confused about cache headers.
I am trying to make the browser cache my php/html pages because they are mostly static and they would not change for a month or so.
The urls look like: example.com/article-url and in background that is a php page like /article_url.php
I tried this in PHP:
$cache_seconds = 60*60*24*30;
header("Expires: ".gmdate('D, d M Y H:i:s \G\M\T', time()+$cache_seconds));
header("Cache-Control:public, max-age=".$cache_seconds);
And in browser debug window I can see that indeed the page would expire next month:
Request URL: https://www.example.com/article-url
Request Method: GET
Status Code: 200
Referrer Policy: no-referrer-when-downgrade
cache-control: public, max-age=2592000
content-encoding: gzip
content-length: 2352
content-type: text/html
date: Mon, 25 Nov 2019 14:23:40 GMT
expires: Wed, 25 Dec 2019 14:23:40 GMT
server: nginx
status: 200
vary: Accept-Encoding
But if I access that page again, I see it was generated again, I made it print the request timestamp in footer, and I can see the page is generated again on each page load.
I was expecting browser to show exact same page from cache.
What am I doing wrong ?
I did R&D on prevention of CRLF injection in php, but i didn't find any solution in mycase, as I'm using a burp suite tool to inject some headers using CRLF characters like the below.
// Using my tool i put CRLF characters at the start of my request url
GET /%0d%0a%20HackedHeader:By_Hacker controller/action
//This generates an header for me like below
HackedHeader:By_Hacker
So i can modify all headers by doing just like above
This tool is just like a proxy server so it catches the request and gives the response and we can modify the response in the way we want.
So i'm just modifying the response by injecting some headers using CRLF characters. Now the Server responds to this request by injecting the CRLF characters in the response.
I'm just worried as header fields like Pragma, Cache-Control, Last-Modified can lead to cache poisoning attacks.
header and setcookie contain mitigations against response/header splitting, But these can't support me in fixing the above issue
Edit
When i request to mysite.com contact us page like below This is the request I captured in my tool like below
Request headers:
GET /contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
And i get the Response HTML for the above request
Now for the same request using the tool i'm adding custom headers just like below
Request Headers:
GET /%0d%0a%20Hacked_header:By_Hacker/contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Response Headers:
HTTP/1.1 302 Found
Date: Fri, 10 Jul 2015 11:51:22 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Fri, 10 Jul 2015 11:51:22 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Location: mysite.com
Hacked_header:By_Hacker/..
Vary: Accept-Encoding
Content-Length: 2
Keep-Alive: timeout=5, max=120
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
You can see the injected header Hacked_header:By_Hacker/.. in the above response
Is there anyway in php or apache server configuration to prevent such kind of headers' hack?
Not sure why all the down votes - infact, it is an interesting question :)
I can see that you have tagged CakePHP - which means your app is using Cake Framework... Excellent! If you are using Cake 3 , it is automatically strip off : %0d%0a
Alternatively, where you receive the response header, just strip off %0d%0a and you are good!
Where things like these could be applied - a 3rd party API response or say.... a Webhook response! or a badly sanitized way to handle intl.. example : lang=en to lang=fr where the GET param is directly set as response header... That would not be a wise move!
Ideally, the responses will be as GET and not in the header but either way just strip the %0d%0a and you are good.
Answering your edit.
You can see the injected header Hacked_header:By_Hacker/.. in the above response
That injected header cannot be controlled or stopped, mate. We do not have control over what the other server does.
The question is.. What do you do with the response header?
The answer is... You sanitize it, as ndm said you need to sanitize the input.. What you get as a response IS an input. As soon as you detect %0d%0a, discard the response.
Need code work?
<?php
$cr = '/\%0d/';
$lf = '/\%0a/';
$response = // whatever your response is generated in;
$cr_check = preg_match($cr , $response);
$lf_check = preg_match($lf , $response);
if (($cr_check > 0) || ($lf_check > 0)){
throw new \Exception('CRLF detected');
}
I'm trying to perfom a log-in on pinterest.com with curl. I got the following request-response-flow:
GET-Request the login form and scrape hidden fields (csrftoken)
POST-Request login credentials (mail and pw) and scraped csrftoken
Receive Session Cookie for login
Using Curl, I can see the following Headers being sent and received:
GET /login/?next=%2F HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Host: pinterest.com
Referer:
Accept: text/html,application/xhtml+xml,application/xml,*/*
Accept-Language: de-de,en-us
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Tue, 10 Apr 2012 15:03:24 GMT
ETag: "45d6a85f0ede46f13f4fc751842ce5b7"
Server: nginx/0.8.54
Set-Cookie: csrftoken=dec6cb66064f318790c6d51e3f3a9612; Max-Age=31449600; Path=/
Set-Cookie: _pinterest_sess="eJyryMwNcTXOdtI3zXcKNq0qznIxyXVxK/KqSsy3tY8vycxNtfUN8a3yc3E09nXxLPdztLVVK04tLs5MsfXNAopVpVf6VnlW+Qba2gIAuqgZIg=="; Domain=pinterest.com; HttpOnly; expires=Tue, 17-Apr-2012 15:03:24 GMT; Max-Age=1334675004; Path=/
Vary: Cookie, Accept-Encoding
Content-Length: 4496
Connection: keep-alive
So after step 1, the two cookies csrftoken and _pinterest_sess are set. But a look in the cookiejar file (I use CURLOPT_COOKIEFILE and CURLOPT_COOKIEJAR to let curl handle the cookie processing) shows the following:
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.
pinterest.com FALSE / FALSE 1365519805 csrftoken dec6cb66064f318790c6d51e3f3a9612
#HttpOnly_.pinterest.com TRUE / FALSE -1626222087 _pinterest_sess "eJyryMwNcTXOdtI3zXcKNq0qznIxyXVxK/KqSsy3tY8vycxNtfUN8a3yc3E09nXxLPdztLVVK04tLs5MsfXNAopVpVf6VnlW+Qba2gIAuqgZIg=="
First thing to note is the #HttpOnly_ in preceding the _pinterest_sess cookie line. I just assume that curl handles that just fine. But looking further, one can see that a negative value is set as expiration date: -1626222087
I don't know where that's coming from, because the cookie is set with "expires=Tue, 17-Apr-2012 15:03:24 GMT" (which is about 7 days in the future, counting from today).
On the next request, the _pinterest_sess cookie won't be set by curl:
POST /login/?next=%2F HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Host: pinterest.com
Referer: https://pinterest.com/login/?next=%2F
Cookie: csrftoken=dec6cb66064f318790c6d51e3f3a9612
Accept: text/html,application/xhtml+xml,application/xml,*/*
Accept-Language: de-de,en-us
Connection: keep-alive
Content-Length: 123
Content-Type: application/x-www-form-urlencoded
HTTP/1.1 302 FOUND
Content-Type: text/html; charset=utf-8
Date: Tue, 10 Apr 2012 15:05:26 GMT
ETag: "d41d8cd98f00b204e9800998ecf8427e"
Location: http://pinterest.com/
Server: nginx/0.8.54
Set-Cookie: _pinterest_sess="eJzLcssPCy4NTclIjvAOrjQzyywoCChISgvLDi+2tY9PrSjILEottvUN8a3yc4k09gtxrfRLt7VVK04tLs5MAYonV/qGeFb4ZkWW+4LES4tTi+KBEv4u6UZ+WYEmvlm+QOxZ6R/iWOEbEmgLAKNfJps="; Domain=pinterest.com; HttpOnly; expires=Tue, 17-Apr-2012 15:05:26 GMT; Max-Age=1334675126; Path=/
Vary: Cookie
Content-Length: 0
Connection: keep-alive
In the response, another _pinterest_sess cookie is set since curl didn't send the last one.
Currently, I don't know if I'm doing something wrong or if curl just isn't able to parse the expires value in the cookie correctly.
Any help would be greatly appreciated :)
// edit
One more thing:
According to http://opensource.apple.com/source/curl/curl-57/curl/lib/cookie.c the function curl_getdate() is used to extract the date. The documentation on that function lists some examples (http://curl.haxx.se/libcurl/c/curl_getdate.html):
Sun, 06 Nov 1994 08:49:37 GMT
Sunday, 06-Nov-94 08:49:37 GMT
Sun Nov 6 08:49:37 1994
06 Nov 1994 08:49:37 GMT
06-Nov-94 08:49:37 GMT
Nov 6 08:49:37 1994
06 Nov 1994 08:49:37
06-Nov-94 08:49:37
1994 Nov 6 08:49:37 GMT
08:49:37 06-Nov-94
Sunday 94 6 Nov 08:49:37
1994 Nov 6
06-Nov-94
Sun Nov 6 94
1994.Nov.6
Sun/Nov/6/94/GMT
Sun, 06 Nov 1994 08:49:37 CET
06 Nov 1994 08:49:37 EST
Sun, 12 Sep 2004 15:05:58 -0700
Sat, 11 Sep 2004 21:32:11 +0200
20040912 15:05:58 -0700
20040911 +0200
None of them matches the above mentioned expires date "Tue, 17-Apr-2012 15:03:24 GMT" because all examples with hyphens only use 2-digit-years..
You are experiencing an issue on your computer because of the limits of 32 bit signed integer values.
The server sets a cookie with the Max-Age of 1334675004 seconds in the future.
Max-Age=1334675004
You posted your question here # 2012-04-10 15:13:24Z. That is a UNIX timestamp of 1334070804. If you add 1334675004 to it and you take a 32 bit integer limit of 2147483647 into account while having an integer roundtrip, you'll get: -1626221485:
1334070804
+ 1334675004
------------
-1626221485
As the numbers show, it looks like that the server did misunderstood the Max-Age attribute, if you substract each values from each other there is a circa delta of 7 days in seconds (604200 = ~6.99 days, the difference is because the cookie was set earlier than you posted your question here). However Max-Age is the delta of seconds, not the absolut UNIX timestamp.
Try to raise PHP_INT_MAX with your PHP version, or compile against 64 bit, this should prevent negative numbers. However, the max-age calculation is still broken with the server. You might want to contact pinterest.com and report the problem.
Looks like pinterest.com is using Max-age incorrectly, and that's why curl is deleting this cookie.
From your example, Max-age contains timestamp for Tue, 17-Apr-2012 15:03:24 GMT, while it should contain number of seconds from request time to this date - 604800 (judging from request time - Date header)
What curl is doing is adding Max-age value to current timestamp and saving it as signed 32bit integer, hence -1626222087.
As for solution - you can try contacting pinterest and report a bug.
Actually you do not need to contact pinterest site since it is not required to send back to server cookie max age(if you will use cookie for a short period of time or you may calculate yourself correct max age). Just flip the minus sign and it will work meaning it will be send back to server. And it was not all what you have to do. Sometimes depending on login page presented you have to parce hidden fields also(where CSRF tokens resided and that have to match with the same token value in cookie). Moreover, it will sometimes require to change cookies(reset cookie values). So pinterest web site is making harder and harder to login using automated login tools and doing screen scraping. And recently they have changed how their site functions. So all the above mentioned points does not work now. Actually you do not really know when they will change how login works. You have to try and "guess" when change happens. Actually that attitude should be towards not developers but the ones who are threats to security of the system(intruders). You have to think about legality issue of above mentioned points too. Pinterest has API(although it is down right now) so it is the best and most correct way to use that API (pls see https://github.com/kellan/pinterest.api.php). There you are exchanging messages in a json format. Last option to use m.pinterest.com which is for mobile devices and it is strightforward to use like parce one login html for hidden input fields and resubmit form with correct values (to use it you are again faced with legality issues too). Please consult with pinterest site before using curl like tools or wait until pinterest api is up. Yes, there some improvements in the system like getting json responses which puts the end to screen scraping but that does not mean completely new api. Also right now they(seemingly) implemented web services, restful, api and taking ajax requests which are again steps towards to positive improvement. There are many discussions are going on the net on this matter so please refer to them for detailed info.
So I had developed a basic site, using $_SESSION superglobal variable for the logging in.
so the code basically after checking the login details are valid i store the users details into the session like so:
note I am starting the session before storing these values.
$_SESSION['myusername'] = $myusername;
$_SESSION['myuserid'] = $userid;
$_SESSION['logged_in'] = true;
$_SESSION['mystatus'] = $res['user_status'];
it all worked fine, throughout the time i made the site and tested etc.
now all of a sudden, the sessions are not working, so obviously the users cannot get access after logging in because the site is checking data which isnt in the session.
on the page I store the data like above, straight after i can use this:
echo "username".$_SESSION['myusername'];
echo "status".$_SESSION['mystatus'];
and its there. But when the user is directed to another page and i try:
<?php
session_start();
include ('functions.php');
echo "username".$_SESSION['myusername'];
echo "status".$_SESSION['mystatus']; ....
the values aren't in the session. I have checked that the session id is the same, which it is.
This has always worked, so I am really puzzled.
somebody please help.
EDIT
request header & response header from firebug (page where session appears to be empty)
Response Headersview source
Date Sat, 11 Jun 2011 15:18:48 GMT
Server Apache/2.2.3 (Red Hat)
X-Powered-By PHP/5.1.6
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Content-Length 3772
Connection close
Content-Type text/html; charset=UTF-8
Request Headersview source
Host students.ee.port.ac.uk
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-gb,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Cookie PHPSESSID=1jqqa2oeivq76h2vhtk4uflkv1
Authorization Basic ZWNlNzAxNDE6cGllczRtZTIy
So it seems you have a problem with keeping your session on a second request.
Session tracking is done via cookies, you should check (with Live HTTP Headers or firebug) the real cookie content sent by the server. In this cookie check the path setting and the server name given, check as well time validity settings, if something is wrong there the browser won't send back the cookie and you'll get a new session on each request.
The web developper Toolbar contains some nice cookie tools as well, where you can display a page containing all cookies details for a given page. If the cookie receveid is not there then the browser assume this cookie is not related to this page. Most of the time a php setting is enforcing the cookie.domain setting to something other than the used DNS.
Given the fact that you haven't changed a thing in the last few weeks and that it used to work, you should check that your server didn't run out of disk space. If it did, it may create a reference to a session but might not be able to serialize the data to disk once the page has been rendered.
This could explain why outputting the $_SESSION[...] works on the same page and why the cookie is set in the response.
Check whether the session id on the second request is the same as the one on the first request.
I'm been stuck on this problem for a while and I'm pretty sure it must be something quite simple that hopefully someone out there can shed some light on.
So, I'm currently using jQuery UI's Autocomplete plugin to reference and external PHP which gets information from a database (in an array) and sends it to a JSON output.
From my PHP file (search.php) when I do this:
echo json_encode($items);
My output (when looking at the search.php file) is this:
["Example 1","Example 2","Example 3","Example 4","Example 5"]
Which is valid JSON according to jsonlint.com
The problem is that when I use jQuery UI's Autocomplete script to reference the external search.php file, Chrome just gives me the following error:
GET http://www.example.com/search.php?term=my+search+term 404 (Not Found)
I have tried inputting the JSON code straight into the 'Source:' declaration in my jQuery, and this works fine, but it will not read the JSON from the external PHP file.
Please can someone help?
Here's my code:
HMTL
<p class="my-input">
<label for="input">Enter your input</label>
<textarea id="input" name="input"
class="validate[required]"
placeholder="Enter your input here.">
</textarea>
</p>
jQuery
$(function() {
$( "#input" ).autocomplete({
source: "http://www.example.com/search.php",
minLength: 2
});
});
PHP
header("Content-type: application/json");
// no term passed - just exit early with no response
if (empty($_GET['term'])) exit ;
$q = strtolower($_GET["term"]);
// remove slashes if they were magically added
if (get_magic_quotes_gpc()) $q = stripslashes($q);
include '../../../my-include.php';
global $globalvariable;
$items = array();
// Get info from WordPress Database and put into array
$items = $wpdb->get_col("SELECT column FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY column ASC");
// echo out the items array in JSON format to be read by my jQuery Autocomplete plugin
echo json_encode($items);
Result
In browser, when information is typed into #input
GET http://www.example.com/search.php?term=Example+1 404 (Not Found)
Update: the real PHP url is here: http://www.qwota.co.uk/wp/wp-content/themes/qwota/list-comments.php?term=Your
Please help!
UPDATE: ANSWER
The answer to my problem has been pointed out by Majid Fouladpour
The problem wasn't with my code but rather with trying to use WordPress' $wpdb global variable as (as far as I understand) it includes it's own headers, and anything outside of it's usual layout will result in a 404 error, even if the file is actually there.
I'm currently trying to get around the problem by creating my own MySQL requests and not using WordPress's global variables / headers.
PS. Majid, I'll come back and give you a 'helpful tick' once StackOverflow lets me! (I'm still a n00b.)
Are you sure the path source: "http://www.example.com/search.php" is correct?
You have to make sure that the target URL exists. If you are really using http://www.example.com/search.php then, wk, it simply does not exist, so this is why it does not work.
Update
Since you have a real URL that's working (I tested it!), here are a few steps you can take:
Make sure there's no typo. If there's one, fix it.
Make sure you can open that URL from your browser. If you cannot, then you might be having network access problems (firewall, proxy, server permission issues, etc.)
Try redirecting to another know URL, just to make sure. The 404 error is really a "not found" error. It cannot be anything else.
I think the include is the issue. As Majid pointed out... use the below include instead.
include("../../../wp-load.php");
Good luck!
Your apache server is sending wrong headers. Here is a pair of request and response:
Request
GET /wp/wp-content/themes/qwota/list-comments.php?term=this HTTP/1.1
Host: www.qwota.co.uk
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: __utma=142729525.1341149814.1305551961.1305551961.1305551961.1; __utmb=142729525.3.10.1305551961; __utmc=142729525; __utmz=142729525.1305551961.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Response headers
HTTP/1.1 404 Not Found
Date: Mon, 16 May 2011 13:28:31 GMT
Server: Apache
X-Powered-By: PHP/5.2.14
X-Pingback: http://www.qwota.co.uk/wp/xmlrpc.php
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Last-Modified: Mon, 16 May 2011 13:28:31 GMT
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Response body
["Bake 'em away... toys.","Content precedes design. Design in the absence of content is not design, it\u2019s decoration.","Hanging on in quiet desperation is the English way.","I'm a reasonable man, get off my case.","Look at me, Damien! It's all for you!","Never get out of the boat... absolutely god damn right.","That gum you like is going to come back in style.","The secret to creativity is knowing how to hide your sources.","Things could be different... but they're not.","Your eyes... they turn me."]
So, even though you receive back response from the server, it has HTTP/1.1 404 Not Found in the headers. Someone may be able to investigate this and provide a potential reason and solution.