-
Notifications
You must be signed in to change notification settings - Fork 195
Allow HEAD and OPTIONS requests for any matched route #413
Allow HEAD and OPTIONS requests for any matched route #413
Conversation
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.
@weierophinney It looks good for me. I haven't test it yet, just reviewed. Are you going to include some tests from #398 as well or they are redundant now?
callable $middleware, | ||
ServerRequestInterface $request, | ||
ResponseInterface $response, | ||
callable $next |
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.
Param $next
is missing in PHPDoc.
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.
Fixed; thanks!
* Returns an empty 200 response with an Allow header. | ||
* | ||
* @param Router\Route $route | ||
* @return ResponseInterface |
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.
Method always returns Response
.
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.
Fixed, thanks!
$test = $app->dispatchMiddleware($request, $response, $delegate); | ||
|
||
$this->assertInstanceOf(Response::class, $test); | ||
$this->assertEquals(200, $test->getStatusCode()); |
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 use constant also here?
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.
Yep; fixed, thanks!
@weierophinney what about shipping them as standalone, optional middlewares? |
Considering it, but need to figure out how that would work within the |
Reviewing this now. I merged your changes from that PR locally, and have a ton of failures, and I'm trying to analyze if they're due to the changes I've made, or invalid expectations. I'll keep you posted. |
@webimpress I'm reviewing the tests, and the main issue is that those that trigger the implicit HEAD/OPTIONS usage were checking for a populated response body, when it should not be; updating those tests to look for an empty string for the body makes them pass. The one I'm struggling with right now is |
Thanks, @weierophinney ! |
I've separated them out at this point locally. For the implicit options middleware, it's not a problem at all, as it's only working with the route, which is obtainable from the route result, which is obtainable as a request option. For the implicit head middleware, things get more dicey, as we need the matched middleware in the case that the route allows GET, but HEAD is only implied. This requires passing it as a constructor argument, which means it must be composed as part of routing or dispatching middleware, since this is typically marshaled from a container. Ideally, these would operate between the routing and dispatch middleware. However, I do not want to force end-users to add these to their pipeline. As such, still debating; I'll try and make a decision in the next day or two. |
If we pipe
Mhmm, why not? We already have some basic functionally such as |
@danizord Thought about this over the weekend, and I agree with you. I've updated the patch to provide optional middleware, In the skeleton, we can enable these in the default pipeline. I will also likely add some support for them into the tooling for creating a pipeline from existing configuration. I've pushed the changes at this time, but need to document them. Otherwise, the code is ready for review. |
33789f5
to
c49a520
Compare
I've rebased this patch to remove the commits that were updating the dispatch middleware to add the implicit HEAD/OPTIONS support. |
@@ -19,6 +20,7 @@ | |||
use Zend\Diactoros\Response\SapiEmitter; | |||
use Zend\Diactoros\ServerRequest; | |||
use Zend\Diactoros\ServerRequestFactory; | |||
use Zend\Diactoros\Stream; |
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.
No longer used in that class.
/** | ||
* HTTP methods that are implicitly allowed for any matched request. | ||
*/ | ||
const HTTP_METHODS_IMPLICIT = [ |
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.
Seems to be unused. Do we still need it?
Updates zend-expressive-router dependency to 1.3.2+, and related new versions of router implementations to those supporting that version. This patch adds new optional middleware, `Zend\Expressive\Middleware\ImplicitHeadMiddleware` and `ImplicitOptionsMiddleware`, that can be placed between the routing and dispatch middleware in order to handle HEAD and OPTIONS requests when they are only implicitly supported by the matched route. Each only triggers on the request method they are interested in, and then only when: - a route result is present in the request - the route result contains a route - and the route indicates the method is only implicitly supported For the implicit HEAD support, it will also check to see if GET is supported before returning a response; if so, it dispatches the next middleware layer, providing an updated request using GET as the method, and ensures that the response returned has an empty body. This patch also incorporates tests from zendframework#398, with updates for the following: - Response bodies for implicit HEAD and OPTIONS requests should be empty. - zend-expressive-aurarouter failed until version 1.1.3.
c49a520
to
833cdbe
Compare
`Generator` now does the following: - Adds dependency configuration for the implicit HEAD and OPTIONS middleware to `config/autoload/programmatic-pipeline.global.php`. - Adds entries for the implicit HEAD and OPTIONS middleware to the pipeline immediately following the routing middleware. This is to support the changes in zendframework/zend-expressive#413, and should not be merged or tagged before that functionality has been released in Expressive 1.1.
@xtreamwayz This is another one to consider for the skeleton: the |
@weierophinney I see these are using the |
There are changes pending for a 0.4.0 release of http-middleware that will impact the signatures (new namespace, and the |
Also, Stratigility provides functionality for wrapping double-pass middleware such as this to work with http-middleware, so it can still be utilized in that context; Expressive will be (eventually) doing this out-of-the-box once moving to a Stratigility version that only supports http-middleware. However, that will not happen until PSR-15 is accepted. |
@weierophinney Good to know. I guess that's Stratigility 2.0 that will be going http-middleware only. FYI, it looks like 0.4.0 dropped a couple of days ago. Not a huge fan of going from |
That was prompted by me, actually. 😄 Before this, we had:
In other words, huge inconsistencies in naming that, I felt, would lead to difficulties understanding the roles each played. I provided a number of options forward, and, ultimately, most liked having a different namespace for the server-side middleware artifacts. As you note, however, it causes us some issues with upgrading. I wasn't aware 0.4.0 had dropped, I need to see what the latest changes are, and make sure there are none others pending before we start adapting support for it. |
Hmmm... there's one open pull request on http-middleware that could still have ramifications, as it would result in at least a rename of |
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.
👍 LGTM
Documents the new middleware, both in a new feature section, and within the migration guide.
private function getResponse() | ||
{ | ||
if ($this->response) { | ||
return $this->response; |
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.
Why not check and assign it on __contructor
?
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.
There's no need to create one if the middleware does not need to return a response in the first place.
- Filenames cannot contain extra `.` characters; mkdocs will not find them if they are present. - Formatting errors due to nested bullets and attempts to have multiple paragraphs.
Replaces section on #413 under `Changes` headline.
Updates zend-expressive-router dependency to 1.3.2+, and related new versions of router implementations to those supporting that version.
This patch also introduces two new classes,
Zend\Expressive\Middleware\ImplicitHeadMiddleware
andImplicitOptionsMiddleware
. These can be placed after the routing middleware, but before the dispatch middleware, in order to handle HEAD and OPTIONS requests when the matchedRoute
does not explicitly support them. In each case, they trigger only when:RouteResult
attribute;RouteResult
composes aRoute
instance (per the changes in zend-expressive-router and the various implementations);Route
instance indicates that the method is only supported implicitly.Additionally, for routes supporting
GET
requests, theImplicitHeadMiddleware
will dispatch the next middleware in the layer, usingGET
as the request method, and ensure the returned response has an empty body.This approach ensures that if a route explicitly supports the given method, then the matched middleware is dispatched as normal.
Fixes #398