I'm having issues with a client site.
The issue is that there seems to be a redirect on a URL which doesn't exist/has no content:
www.henparty-houses.com/liverpool
Yet if we changed the end URL to another with no content / does not exist we get the correct page load (i.e. page doesn't exist).
www.henparty-houses.com/leeds
===
There seems to be some sort of redirect on the /liverpool URL.
The issue is when a page is create, ending with the URL /liverpool - it is not possible to use this URL as wordpress think's it's already in use / taken.
I might be missing something obvious or some sort of error, but I need to somehow clear the /liverpool URL so content can be used, and ensure when a page with content is created using /liverpool there is no redirect!
Can someone please help?
---- when checking this redirect, here is the output. I've checked clourflare and can't see any redirects setup:
Results:
www.henparty-houses.com/liverpool
HTTP/1.1 301 Moved Permanently
Date: Fri, 25 Sep 2020 10:08:36 GMT
Content-Type: text/html; charset=iso-8859-1
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d440b3cca7954a48bdc3f84b50e73ea7a1601028515; expires=Sun, 25-Oct-20 10:08:35 GMT; path=/; domain=.henparty-houses.com; HttpOnly; SameSite=Lax
Location: https://www.henparty-houses.com/liverpool
Cache-Control: max-age=0
Expires: Fri, 25 Sep 2020 10:08:36 GMT
Host-Header: b7440e60b07ee7b8044761568fab26e8
X-Proxy-Cache: MISS
CF-Cache-Status: DYNAMIC
cf-request-id: 05665580120000ed6fcaa52200000001
Server: cloudflare
CF-RAY: 5d83f1e01a84ed6f-SJC
https://www.henparty-houses.com/liverpool
HTTP/2 302
date: Fri, 25 Sep 2020 10:08:39 GMT
content-type: text/html; charset=UTF-8
set-cookie: __cfduid=d974040f170c5090b9a4e61af9590d1b61601028518; expires=Sun, 25-Oct-20 10:08:38 GMT; path=/; domain=.henparty-houses.com; HttpOnly; SameSite=Lax
x-cache-enabled: True
p3p: CP="ALL DSP NID CURa ADMa DEVa HISa OTPa OUR NOR NAV DEM"
x-redirect-by: WordPress
location: https://www.henparty-houses.com
cache-control: max-age=0
expires: Fri, 25 Sep 2020 10:08:38 GMT
host-header: b7440e60b07ee7b8044761568fab26e8
x-proxy-cache: MISS
cf-cache-status: DYNAMIC
cf-request-id: 05665588c800009623ca33e200000001
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 5d83f1ee09ee9623-SJC
https://www.henparty-houses.com
HTTP/2 200
date: Fri, 25 Sep 2020 10:08:41 GMT
content-type: text/html; charset=UTF-8
set-cookie: __cfduid=d63a3cce54fa1ecc1e3d8bbf7c7415b8d1601028519; expires=Sun, 25-Oct-20 10:08:39 GMT; path=/; domain=.henparty-houses.com; HttpOnly; SameSite=Lax
x-cache-enabled: True
p3p: CP="ALL DSP NID CURa ADMa DEVa HISa OTPa OUR NOR NAV DEM"
link: ; rel="https://api.w.org/", ; rel="alternate"; type="application/json", ; rel=shortlink
vary: Accept-Encoding
cache-control: max-age=0
expires: Fri, 25 Sep 2020 10:08:40 GMT
host-header: b7440e60b07ee7b8044761568fab26e8
x-proxy-cache: MISS
cf-cache-status: DYNAMIC
cf-request-id: 0566558f4e0000930a5d2f8200000001
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 5d83f1f87ede930a-SJC
I don't think you're going to find the answer looking in your .htaccess files. As you can see from the headers, the redirect is being issued by WordPress itself.
x-redirect-by: WordPress
If you go to your WordPress installation directory, you can use the following command to find the function that sets this header.
grep --line-number --with-filename --fixed-strings -i -R 'x-redirect-by' .
The result is pretty short:
./wp-includes/pluggable.php:1284: * Filters the X-Redirect-By header.
./wp-includes/pluggable.php:1296: header( "X-Redirect-By: $x_redirect_by" );
Unsurprisingly, the function that sets this header is called wp_redirect.
In short, the problem is probably not the server configuration. What I think is happening is that one of your pages' slug is set to liverpool.
Normally, when WordPress receives a request for a page that doesn't exist (triggering a 404 error), it first attempts to redirect the request to a "canonical" URL (see this post). These canonical URLs are called "slugs".
If one of your existing pages has a slug set to liverpool, this would trigger the URL canonicalization process. It's therefore possible that maybe that page is set to hidden, or is manually redirecting the user because it requires the user to be logged in, or a myriad of other things. Either way, a manual redirect is the reason for the 302 redirect. The best way to find out what exactly is going on is to find the page with that particular slug.
The reason I'm inclined to believe the page exists right now is that a 302 means Found. If a page had previously used a slug of liverpool and then changed it, the proper response would have been a 301 Moved Permanently with a redirect to the current version of the page. My thinking is that a page exists with a slug of liverpool that is purposefully redirecting the client to the main page. The solution, therefore, is most likely tracking that one page down.
You can speed this process up significantly by accessing the database directly, rather than via the user interface. The wp_posts table contains most of the page content (see the WordPress documentation for a more in-depth explanation), and the wp_postmeta table contains post metadata.
I would start by running a query like this (I'm assuming you're using MariaDB or MySQL, but a Postgres or whatever query would be analogous, if not identical).
SELECT `wp_posts`.`post_name` FROM `wp_posts` WHERE `wp_posts`.`post_name` LIKE '%liverpool%';
This query should get you close. If you can't find anything there, you might want to check the wp_postmeta table. Depending on how large the site's database is, it might actually be easier to just go page by page in the UI and check by hand, since a lot of entries are either serialized objects, HTML, or just generally hard to visually parse.
SELECT `wp_postmeta`.* FROM `wp_postmeta`;
You can use another LIKE clause here, obviously, which might be helpful to try first, before running this one. Keep in mind it might take a while to run though since it has to filter the results based on a wildcard match, so it might be helpful to run this basic query first so you have all the results, then the specific query on another console, so you can try to go through the output while the other query executes. I'm not sure how fast the hardware you're on is, but I speak from personal experience lol.
I would start by running the following query on any tables you're working with so you can get a handle of the table structure.
DESCRIBE `wp_postmeta`;
DESCRIBE `wp_posts`;
You can also do SHOW TABLES to actually see all of the tables in the database you're working with.
You should also take a look at this post. In particular, note where it says you can disable redirects by adding the remove_action( 'template_redirect', 'wp_old_slug_redirect');. I'm not personally familiar with that functionality, but if you look at the wp_redirect function definition ($WORDPRESS_INSTALL_DIR/wp-includes/pluggable.php, line 1246), you can see the function applies filters elsewhere defined.
Note also that the function specifically checks to make sure the status code is between 300 and 399, meaning something is changing the status code from 404 to 302.
Here is the function definition, for your convenience and edification.
/**
* Redirects to another page.
*
* Note: wp_redirect() does not exit automatically, and should almost always be
* followed by a call to `exit;`:
*
* wp_redirect( $url );
* exit;
*
* Exiting can also be selectively manipulated by using wp_redirect() as a conditional
* in conjunction with the {#see 'wp_redirect'} and {#see 'wp_redirect_location'} filters:
*
* if ( wp_redirect( $url ) ) {
* exit;
* }
*
* #since 1.5.1
* #since 5.1.0 The `$x_redirect_by` parameter was added.
* #since 5.4.0 On invalid status codes, wp_die() is called.
*
* #global bool $is_IIS
*
* #param string $location The path or URL to redirect to.
* #param int $status Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
* #param string $x_redirect_by Optional. The application doing the redirect. Default 'WordPress'.
* #return bool False if the redirect was cancelled, true otherwise.
*/
function wp_redirect( $location, $status = 302, $x_redirect_by = 'WordPress' ) {
global $is_IIS;
/**
* Filters the redirect location.
*
* #since 2.1.0
*
* #param string $location The path or URL to redirect to.
* #param int $status The HTTP response status code to use.
*/
$location = apply_filters( 'wp_redirect', $location, $status );
/**
* Filters the redirect HTTP response status code to use.
*
* #since 2.3.0
*
* #param int $status The HTTP response status code to use.
* #param string $location The path or URL to redirect to.
*/
$status = apply_filters( 'wp_redirect_status', $status, $location );
if ( ! $location ) {
return false;
}
if ( $status < 300 || 399 < $status ) {
wp_die( __( 'HTTP redirect status code must be a redirection code, 3xx.' ) );
}
$location = wp_sanitize_redirect( $location );
if ( ! $is_IIS && 'cgi-fcgi' !== PHP_SAPI ) {
status_header( $status ); // This causes problems on IIS and some FastCGI setups.
}
/**
* Filters the X-Redirect-By header.
*
* Allows applications to identify themselves when they're doing a redirect.
*
* #since 5.1.0
*
* #param string $x_redirect_by The application doing the redirect.
* #param int $status Status code to use.
* #param string $location The path to redirect to.
*/
$x_redirect_by = apply_filters( 'x_redirect_by', $x_redirect_by, $status, $location );
if ( is_string( $x_redirect_by ) ) {
header( "X-Redirect-By: $x_redirect_by" );
}
header( "Location: $location", true, $status );
return true;
}
Related
I am using a react app served using Nginx. I am trying to make a request to an external API, that requires a HMAC signature in the auth header, and also needs a date header set.
The API requires to use the following format: Thu, 07 May 2020 15:38:19 GMT in the request header. I tried using date_gmt which provides Thursday, 07-May-2020 15:38:19 UTC. To format it, I've explored map directives and the <!--config> type html tags, to no avail.
How can I get around this?
Try this in the location directive that you're using to proxy:
if ($date_gmt ~ "^(?<day>(\w{3}))\w+, (?<date>(\d{2}))-(?<month>(\w{3}))-(?<yeartime>(\d{4} \d{2}:\d{2}:\d{2})) UTC$") {
set $day $day;
set $date $date;
set $month $month;
set $yeartime $yeartime;
}
proxy_set_header Date "$day, $date $month $yeartime GMT";
i'm new to go, and i'm trying to do a redirect after login.
for the router, i'm using Mux:
router.HandleFunc("/login", pages.Login).Methods("POST")
and the Login func contains these lines:
if errorFlag {
http.Redirect(rw, rq, "/", http.StatusNotAcceptable)
} else {
http.Redirect(rw, rq, "/", http.StatusOK)
}
thing is, i'm getting the correct status according to the errorFlag, but the page is not redirected! the headers also seem to be set correctly ("Location:/")
but instead of redirecting, the page just stays blank and remains under "/login"
i've tested it on Chrome & FF.
these are the response headers:
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Thu, 14 Jan 2016 16:52:34 GMT
Location:localhost:8000/
Set-Cookie:user=MTQ1Mjc5MDM1N...; Path=/; Expires=Sat, 13 Feb 2016 16:52:34 UTC; Max-Age=2592000
anyone every encountered this before?
Update
As suggested below, this change works:
if errorFlag {
http.Redirect(rw, rq, "/", http.StatusTemporaryRedirect)
} else {
http.Redirect(rw, rq, "/", http.StatusFound)
}
thanks!
Use a 3xx status code to redirect the client (http.StatusFound, http.StatusMovedPermanently, http.StatusSeeOther, ...). The Location header is not sufficient to cause a redirect.
You are trying to redirect POST method so neither 301 (StatusMovedPermanently) nor 302 (StatusFound) should work according to W3.org.
Try returning 303 (StatusSeeOther) if you want to redirect with GET method. Try returning status 307 (StatusTemporaryRedirect) if you want to redirect with the same method as in the request.
Details here: https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect
I'm working on an API and I can't get Sf2 to catch the "Date" parameter from the request header... Demo is below. I'm testing my API via Postman.
$date = $this->request->headers->get('Date');
$auth = $this->request->headers->get('Authorization');
echo $date; // NULL
echo $auth; // whatever i pased.
A very strange behaviour indeed ! Could anyone know why ?
The Date header is a restricted one and it's not possible to overwrite it unless you use the Interceptor Chrome Extension (see this official link for details).
This is a list of restricted headers:
Accept-Charset
Accept-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
Cookie
Content-Transfer-Encoding
Date
Expect
Host
Keep-Alive
Origin
Referer
TE
Trailer
Transfer-Encoding
Upgrade
User-Agent
Via
That's why you're getting an empty header.
change
$date = $this->request->headers->get('Date');
to
$date = $this->request->headers->get('X-Date');
I am doing this:
domain.com/route-name/?do-something=1
..which sets a cookie and then redirects to this using a 302 redirect:
domain.com/route-name/
It allows an action to take place regardless of the page viewing (cookie stores a setting for the user).
I am using the default Symfony2 reverse-proxy cache and all is well, but I need to prevent both the above requests from caching.
I am using this to perform the redirect:
// $event being a listener, usually a request listener
$response = new RedirectResponse($url, 302);
$this->event->setResponse($response);
I've tried things like this but nothing seems to work:
$response->setCache(array('max_age' => 0));
header("Cache-Control: no-cache");
So how do I stop it caching those pages?
You have to make sure you are sending the following headers with the RedirectResponse ( if the GET parameter is set ) AND with your regular Response for the route:
Cache-Control: private, max-age=0, must-revalidate, no-store;
Achieve what you want like this:
$response->setPrivate();
$response->setMaxAge(0);
$response->setSharedMaxAge(0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);
private is important and missing in coma's answer.
The difference is that with Cache-Control: private you are not allowing proxies to cache the data that travels through them.
Try this on your response:
$response->headers->addCacheControlDirective('no-cache', true);
$response->headers->addCacheControlDirective('max-age', 0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);
You can use annotations too:
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html
And take a look at:
Why both no-cache and no-store should be used in HTTP response?
I have an action method that I want to cache:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="index")]
public ActionResult Index()
{
return View();
}
With this approach:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
context.Response.Cache.SetOmitVaryStar(true);
context.Response.Cache.VaryByHeaders["Cookie"] = true;
if (User.Identity.IsAuthenticated)
{
Debug.Print("Authenticated");
context.Response.Cache.SetNoServerCaching();
context.Response.Cache.SetCacheability(HttpCacheability.Private);
return null;
}
else
{
Debug.Print("Non authenticated");
return custom;
}
}
The idea was to keep a cached version of the page for non-authenticated users, but avoid caching for authenticated ones.
I thought it will always return a Vary:Cookie HTTP header, but it is not.
Doing a test with Fiddler and issuing twice the same request, in the first HTTP call it goes good:
HTTP/1.1 200 OK
Cache-Control: public, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: Cookie
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:37 GMT
Content-Length: 441
But in the second one, it overwrites the header:
HTTP/1.1 200 OK
Cache-Control: public, max-age=297
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:39 GMT
Content-Length: 441
So, as far as I know, browsers won't cache the request even if it is public, since Vary:* means that the request has been generated with parameters that are not in the URL nor in the HTTP headers. Is there a way to fix this?
Regards.
UPDATE:
In a similar way, when I send two identical authenticated requests, the first call gets the private modifier, but not the Vary header:
HTTP/1.1 200 OK
Cache-Control: private, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:43:14 GMT
Last-Modified: Thu, 09 Feb 2012 12:38:14 GMT
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:38:14 GMT
Content-Length: 443
But the second one gets the same response that a non-authenticated request:
HTTP/1.1 200 OK
Cache-Control: public, max-age=298
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:44:32 GMT
Last-Modified: Thu, 09 Feb 2012 12:39:32 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:39:33 GMT
Content-Length: 443
I have uploaded a test project showing the issue so may be you want to give it a try.
Please be aware that there is an IHttpModule that sets a request as authenticated or not depending on if the request has a cookie or not, this is not a "real life" approach, it is just for testing purposes.
The project contains only a web page with a link to itself, a link that logs you in, and another link that logs you out:
LogIn : Sends a cookie in a HTTP 302 redirection to the home page again.
LogOut: Sends a expired cookie in a HTTP 302 recirection to the home page again.
The expected/ideal behaviour would be:
User access Index, and get the page from the server. The page show date "A".
User access Index again, and the browser shows the cached version.The page show date "A".
Clean browser cache.
User access Index again, and the browser shows the server cached version. The page show date "A".
User clicks login, and the broswer gets a new page, that show date "B".
User clicks logout, and the browser gets the server cached page. The page show date "A" again.
But this is the behaviour so far:
User access Index, and get the page from the server. The page show date "A".
User access Index again, and the browser shows the cached version.The page show date "A".
Clean browser cache.
User access Index again, and the browser shows the server cached version. The page show date "A".
User clicks login, and the broswer gets a new page, that show date "B".
User clicks logout, and the browser should get the server cached page, but it does not. The page show date "B" again from the browser cache. This is because the lack of the Vary header in the authenticated response.
I don't know if I get something wrong about caching, just missing some detail or the OutputCache does not work very well, but I would appreciate any guidance.
Cheers.
UPDATE 2:
My intention is to use the HTTP cache semantics to:
Allow browsers and proxys to cache the "public" version of the page.
Allow browsers to cache the "authenticated" version of the page for its user.
If I change the OutputCache declaration to do the caching only on the server and prevent the downstream and client caching:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]
it behaves as expected, but the downstream and client cache is prevented, and that is not what I want.
I don't think the [OutputCache] attribute is what you want, the VaryByCustom method is basically saying that I want to cache different versions based on these parameters, it doesn't really have an option for Do Not Cache and the majority of the code in the attribute is built around server based caching.
That being said the documentation on MSDN for custom caching seems to indicate you need to return a string to vary on based on the authentication state:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if(custom == "user") return "User:" + context.Request.User.Identity.Name;
return base.GetVaryByCustomString(context, custom);
}
And then use the user literal in the VaryByCustom:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="user")]
public ActionResult Index()
{
return View();
}
So basically this would result in a cache being built for anonymous (assuming the anonymous identity is empty string or something) and every user on the server, and a Vary: * sent to the client I believe. Obviously not ideal what you are looking for.
If you really just want to cache the unauthenticated version using HTTP caching I would recommend not using the OutputCacheAttribute and using something more custom.
You could easily just write in your own custom attribute something like what you have for your GetVaryByCustomString implementation (this is just some pseudo code, would need more than this):
public class HttpCacheUnauthenticatedAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if(!filterContext.HttpContext.Request.IsAuthenticated) {
//TODO: set unauthenticated caching values and vary here
}
}
}
And then tag your action method with it:
[HttpCacheUnauthenticated]
public ActionResult Index()
{
return View();
}
Sort of wrestling with something similar myself. Have you tried in the web.config to the setting omitVaryStar=true
https://msdn.microsoft.com/en-us/library/ms228124(v=vs.100).aspx
I am using a custom cache provider and in this case there is a simple solution for this.
On the BeginRequest, based on the user authentication status, we set a context information to not run cache:
HttpContext.Current.Items["NoCache"] = "1";
And then on our GetVaryBy method we return null if this information is set:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (HttpContext.Current.Items["NoCache"] != null)
return null;
// remaining code here
}
And then on the cache methods, we can test the same. For instance:
public override object Add(string key, object entry, DateTime utcExpiry)
{
if (HttpContext.Current.Items["NoCache"] != null)
return null;
// remaining code here
}