-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API / BUG - Introduce new request resolver middleware and fix broken forceWWW / forceSSL #7520
API / BUG - Introduce new request resolver middleware and fix broken forceWWW / forceSSL #7520
Conversation
* Allows events to be registered and passed through middleware. | ||
* Useful for event registered prior to the beginning of a middleware chain. | ||
*/ | ||
class RegisteredEventsMiddleware implements HTTPMiddleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have expected a DomainCanoncialisationMiddleware instead of this more abstract one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then a DomainCanoncialisationMiddleware.force_www
config option or something...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing that weirds me out about this a bit is that a "registered event" and a "middleware" are two different abstractions that do very different things, in addition to the legacy "request filter" abstraction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative approach would be to turn the forceWWW logic into its own middleware, and then add that middleware to Director instead of registering an event.
@chillu do you have any thoughts on this pr? |
I think if we were to move to a less-generic middleware, I'd probably just have a separate WWW and SSL redirect middleware, rather than trying to find a middle ground. What do you think about this @sminnee ? If we were to cater to some yet-unknown "third" redirect type, it would be hard to pre-code this into such a middleware, thus the over-generalisation of the initial solution. The question is, is "whenRequestIsAvailable" going to be useful in cases OTHER than just ssl / www redirection? In the future I'd like to implement PHP promises officially. See silverstripe/silverstripe-assets#88. I had in mind that we could shift the ssl / www redirection into the promise api eventually too. |
I agree with Sam, this adds unnecessary complexity. In my opinion, the benefits of middleware and the SS4 bootstrap is the relative simplicity and predictability of the logic flow (request in, request out). Modifying this behaviour with procedural logic (like calling Laravel has three ways you can do this: So, as a short term fix for keeping support for procedural invocation of |
Ok, let's go with the DomainCanonicalisationMiddleware |
In terms of API for the middleware, I would suggest:
Beyond the requirements of the issue at hand I would also suggest:
In terms of processing order I would do:
Outside the scope of this, but for subsites I'd probably look at a whole separate implementation of this. Additionally, if one was to build a vanity domain -> redirection mapping system, I would probably include that as a middleware that is processed prior to this one. |
I'd prefer to limit the implementation (at least for 4.0) to something that allows use of the Overall I agree with Dan that this stuff is better handled by the web server layer ( |
Director::forceSSL() would still need to work after middleware has been initialised... e.g. in Controller::init(), so we would need it still, even if we implement it at the middleware level. My intention is to retain the "if request is available" condition to determine which is activated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactoring as discussed
e06157d
to
3c3e94f
Compare
Updated and pushed... another rather major refactor, so look at it with a fresh mind from the last solution. :) |
} | ||
|
||
// Already on SSL | ||
if (Director::is_https($request)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As reported in #7492 this will provide a false positive if the SS_BASE_URL
is set to an https scheme even if the request isn't. I recommend checking against the request only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nothing to do with SS_BASE_URL; Director::is_https()
prefers the Request object before checking SS_BASE_URL.
When this line is called in CanonicalURLMiddleware, the $request will always be populated (since this middleware only activates when a request is available), so the SS_BASE_URL will never be checked by this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in that case, it shouldn't be functionally incorrect to do as you suggest, and just inline the small part of Director::is_https(). I think I see your point. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, this identified a painful flaw in Director::makeRelative(). For sites with multiple domains this method wouldn't work, meaning that Director::mockRequest() was failing in tests.
After a bit of work I've fixed and tested this, however. Now we can directly use the request instead of needing Director for getting request components.
|
||
// Check if already on www | ||
$host = Director::host($request); | ||
if (strpos($host, 'www') === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we check for www.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah true, will update.
3c3e94f
to
a21b1fb
Compare
All updated. :) |
API Introduce CanonicalURLMiddleware BUG Fix Director::makeRelative() failing on multi-domain sites
a21b1fb
to
9d3277f
Compare
Fixed up some regressions in Director::makeRelative(). I've added a note that user code should check is_site_url() BEFORE calling makeRelative(), if using un-trusted urls. |
Suggestion implemented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixes #7492
Requires silverstripe/silverstripe-cms#2007 to fix regressions in Director::makeRelative