oscarotero / psr7-middlewares Goto Github PK
View Code? Open in Web Editor NEW[DEPRECATED] Collection of PSR-7 middlewares
License: MIT License
[DEPRECATED] Collection of PSR-7 middlewares
License: MIT License
I'm trying to use Https middleware with a Slim 3 application.
When I attach the middleware to a route, the https redirection is happening, however, the URI that I'm being redirected to is https://my-dev-site.local:80/rest/of/the/path
.
Now, I know where the 'problem' is, and I have found a seemingly easy fix for it, but I'm not sure of whether the fault lies with the Https middleware or if it is Slim's Psr\Http\Message\UriInterface implementation.
When the new URI is created with the https
scheme on Line 78 of Https.php, only the scheme of the URI is updated $uri = $uri->withScheme('https');
. This leave the port of the URI set to its original value of 80. When this newly created URI is cast to a string by the RedirectResponseTrait
, it generates a URI with a scheme of https and a port of 80. It is happening because the Slim UriInterface implementation compares the scheme and port to see if they are 'standard'. If the scheme is http and the port is 80, it does not include in port the string cast. Likewise, if the scheme is https and the port is 443 a port is not included in the string cast.
In this case, since the scheme is being changed, but not the port, Slim's Uri class is returning the non-standard https port of 80 in the string URI.
The simple solution to this is to update Https middleware to also change the port to 443. So, line 78 of Https.php becomes $uri = $uri->withScheme('https')->withPort(443)
.
If this is acceptable, I can do a pull request for this small change, but I wanted to bring it up here first to see if there could be any unforeseen consequences caused by this.
To generate uuid identifiers
A use statement needs to be added to class ContainerTrait
for the RuntimeException
like shown below:
<?php
namespace Psr7Middlewares\Utils;
use Interop\Container\ContainerInterface;
use InvalidArgumentException;
use RuntimeException;
otherwise the RunTimeException
class will not be found when thrown as it is looked up in local namespace.
Hello Oscar,
I've used the cache middleware of release 3.19, and I've a question about multi-device usage !
The cache key is specified there
https://github.com/oscarotero/psr7-middlewares/blob/master/src/Middleware/Cache.php#L121
That means the cache in PSR-6 pool is shared between all clients (desktop / mobile / tablet)
But the 304 is sent back to client device to tell it to use its device cache version.
If a desktop client create a cache in PSR-6 pool (server side) it then use it by mobile client (that sould not probably have a cache version, if it's first call)
Perharps an issue ? Or did I'm wrong and missed something !
Thanks in advance for your answer.
Laurent
@abacaphiliac While working on changes to Payload for #50 I took a closer look at the unit tests for Payload. It seems that something is going wrong there.
The callback defined in testJsonObjectPayload is never actually triggered, thus never hitting the asserts defined in there. Reason is that the Transformer throws a DomainException("Syntax Error"). Which, if you look at the JSON closely is correct: {"buz",true}}
should be {"buz":true}}
. Took quite some time to figure this one out :)
The bigger problem, and the reason I'm making this an issue instead of fixing it in a PR directly, is that we apparently run unit tests which trigger no assertions at all, and are still considered valid. I'd like to propose adding beStrictAboutTestsThatDoNotTestAnything="true"
to the phpunit.xml configuration to deal with this.
Whether it is called or not has no affect on the return of the canAddWww function as the only time an array index is used is when there are 3 values and it checks the centre one.
Unless I'm missing something.
I try to use AuraRouter with the middlewares, and it works fine if the routing exists. However, curl will not stop connection when the response is 404, 405, 406. I check the codes and find that there is no response in the code. I think we should at least add $response->getBody()->write("\n") or even better let us configure our own response message on 404, 405, 406.
oscarotero/psr7-middlewares/src/Middleware/AuraRouter.php
if (!$route) {
$failedRoute = $matcher->getFailedRoute();
switch ($failedRoute->failedRule) {
case 'Aura\Router\Rule\Allows':
return $response->withStatus(405); // 405 METHOD NOT ALLOWED
case 'Aura\Router\Rule\Accepts':
return $response->withStatus(406); // 406 NOT ACCEPTABLE
default:
return $response->withStatus(404); // 404 NOT FOUND
}
}
The new update got installed with composer update. But I got a strange 502 bad gateway error for my ajax requests.
I couldn't figure out the problem at first, so I tried to rollback some composer updates and it looks like that the problem is gone when I rolled back to the previous 3.9.3 version.
The strange thing is that normal (none-ajax) request are doing fine.
This is my dispatcher with the used middleware. Please let me know if you need more information.
$relay = new RelayBuilder();
$dispatcher = $relay->newInstance([
Middleware::FormatNegotiator(),
//Adds the php debug bar
Middleware::debugBar($debugbar),
Middleware::LeagueRoute()
->router($router) //The RouteCollection instance
]);
$response = $dispatcher(ServerRequestFactory::fromGlobals(), new Response());
(new Zend\Diactoros\Response\SapiEmitter)->emit($response);
Hi!
Thanks for the nice library. I would like to suggest some middlewares, I will make a seperate issue for each request.
It would be nice to have middleware for CSRF protection. I think the Slim-Csrf has support for psr-7. https://github.com/slimphp/Slim-Csrf
Also, I would like to build some middlewares myself to help expand the support for more middleware. But at this moment I am not sure how to do this exactly. Could you give me some tips?
I am using it like this
use Psr7Middlewares\Middleware;
$app->group('/api', function () use ($app) {
$app->get('/ping', function () {...});
})->add(
Middleware::DigestAuthentication(['me' => 'andYou'])
);
How embarrassing... trying to search issues... ignore this ๐
This class should probably create a new response instance to avoid appending to anything written to the response before an exception was thrown.
Hello,
I've recently used Csrf Middleware with PHP 5.6 and cannot run it due to generateTokens()
function.
random_bytes
is only available since PHP 7.0
I suggest to use openssl extension such as :
if (version_compare(PHP_VERSION, '7.0', 'ge')) {
$index = self::encode(random_bytes(18));
$token = self::encode(random_bytes(32));
} else {
$index = self::encode(openssl_random_pseudo_bytes(18));
$token = self::encode(openssl_random_pseudo_bytes(32));
}
What do you think of such solution ?
I am assuming that the Middleware class is basically a collection of functions, which are collected into a class instance?
$request = Middleware::setAttribute($request, self::KEY, $this->basePath);
// better as
use RequestAttributesHelperTrait;
$request = $this->setRequestAttribute($request, self::KEY, $this->basePath);
Using this as an example, it would be (IMO) better to have a set of traits to allow this functionality to be implanted into middlewares, rather than relying on a static class. Obviously backwards compatibility is an issue, so the static class can use the traits and still implement it's own methods.
When it comes to the factory method, I think an abstract factory class would be more apt, which can also have a helper trait to allow injecting itself into middleware instances that require it.
What do you think about an architectural change like this? Being that it is such a large change, it could be argued into a version release, but having a good backwards compatibility, it could be a feature release. I don't mind working on it, as I really like this codebase and want to use it, but I just can't bring myself to allow statics into my codebase :D
For example:
use Psr7Middlewares\Middleware\AuraSession;
AuraSession::setKey('_AppSession');
This allows to prevent conflicts and use static functions to get the values:
use Psr7Middlewares\Middleware\AuraSession;
function ($request, $response, $next) {
$session = $request->getAttribute('_AppSession');
//this is the same than:
$session = AuraSession::getSession($request);
}
Attention! This code is draft! not tested! Just suggestion
<?php
namespace Psr7Middlewares\Middleware;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class JsonDecoder
{
public function __invoke(ServerRequestInterface &$request, ResponseInterface $response, callable $next)
{
if (0 === strpos($request->getHeaderLine('content-type'), 'application/json')) {
// reset error
json_encode(null);
$json = $request->getBody()->getContents();
$json = json_decode($json, true);
if (JSON_ERROR_NONE != json_last_error()) {
throw new InvalidArgumentException(sprintf(
'Unable to decode data from JSON in %s: %s',
__CLASS__,
json_last_error_msg()
));
}
$method = $request->getMethod();
if ($method == 'GET') {
$request = $request->withQueryParams($json);
} else if (in_array($method, ['POST','PUT','PATCH'])) {
$request = $request->withParsedBody($json);
}
}
...
}
}
To decouple from a specific version of http-interop/http-middleware which is likely to BC until released you could use https://github.com/webimpress/http-middleware-compatibility
I have implemented into several packages and it works great. We already use it in prooph and PR's for zendframework are coming.
As far as I can see the only way to add middleware is to add it to the middleware folder.
I thought it would be nice to also add a configuration option to also include middleware from a different custom location.
This way you can also add middleware from other sources (without struggling with updates/composer). And it's easier to build/change middleware for application specific purposes.
For example: I would like to have a middleware which will check my database if a user is already connected. I don't think that is interesting for anyone else :)
The BlockSpam middleware is looking for a wrong path a default
Actually looking for :
__DIR__.'/../../../../vendor/piwik/referrer-spam-blacklist/spammers.txt'
mean
/Users/vincent/Work/hello-world/vendor/oscarotero/psr7-middlewares/src/Middleware/../../../../vendor/piwik/referrer-spam-blacklist/spammers.txt
Real path is :
__DIR__.'/../../../../piwik/referrer-spam-blacklist/spammers.txt'
mean
/Users/vincent/Work/hello-world/vendor/oscarotero/psr7-middlewares/src/Middleware/../../../../piwik/referrer-spam-blacklist/spammers.txt
Hello,
I use Slim3 and I try to use the firewall but I've an error :
use Psr7Middlewares\Middleware;
// Firewall
$app->add(Middleware::ClientIp());
$app->add(Middleware::Firewall(['37.97.90.193']));
ClientIp has launch before Firewall. Why I've this error ?
Thanks
In my adventures, I tend to find that the use case for overriding an HTTP method comes from web browsers where we all know there is poor support for anything other than POST and GET.
I'm just wondering how useful this middleware package is when solely relying on a header to do the overriding? Generally, clients that can set headers can also make requests with deliberate HTTP methods.
Would it be possible to have this upgraded to use a POST form field, and query-string parameter alongside the header?
$getUrl = "example.com?http-method-override=HEAD";
$postBody = [
"http-method-override" => "PUT"
];
It would become so much more useful in the wild with additions like this.
Can I create my own middleware like this?
class MiddlewareMy extends MiddlewareBase
{
public function handle(...)
{
}
}
I'm just wondering if this project follows semantic versioning?
I ask because in version 3.14 there was a changed introduced in the Honeypot middleware that caused the default behavior of the middleware to change.
This change caused the contact form on my website to stop working.
I only ask because if it doesn't, I need to lock my composer version to a specific version rather than doing the "standard" ^3.0 in composer. Following semantic versioning, I would not have expected to have what is in actuality a BC break when going from 3.13.1 to 3.16.1.
Thanks for this library. I really like it.
Hello,
I noticed your middleware is not compatible with Interop\Http\ServerMiddleware\MiddlewareInterface.
Will you upgrade your package?
Thanks,
Best regards,
The following array was passed to JwtAuthentication class constructor:
$options = [
"secret" => $_ENV["JWT_SECRET"],
"path" => ["/api/v1"],
"passthrough" => ["/api/v1/login"]
]
Sending an HTTP request to "http://localhost/api/v1/restricted" returns HTTP 401 Unauthorized but for some reason I am able to bypass JWT authentication by adding one or more extra slashes after the domain name. e.g. "http://localhost//api/v1/restricted"
Hello,
Actually it's not possible to activate or deactivate https middleware by passing an argument like for www middleware does :
Middleware::Www(true)
This is really useful when switching from a development to production environment.
Is it possible to add this function?
Thank you so much.
It'd be cool if in the closure for ::create() i could return an array of middlewares instead of just one new one. Example use case would be something like
Middleware::create("/admin", function() {
return [
new AuthMiddleware(),
new AdminMiddleware()
];
}
Feature
<?php
namespace Psr7Middlewares\Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Middleware to remove php information
*/
class Expose
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$response = $response->withoutHeader('X-Powered-By');
return $next($request, $response);
}
}
So I found the following issue when implementing my site. I had originally tested it on servers that were using local self-signed certs, so everything was great.
$app->add(Middleware::TrailingSlash(false)->redirect(301));
$app->add(Middleware::Https());
HTTPS
Because I moved to a system that was terminating the SSL on the load balancer the HTTPS middleware was causing infinite redirects. Its not really a bug but took me a hot second to figure out what the heck was going on.
TrailingSlash
Then because the SSL is terminated when TrailingSlash would fire, it would send the redirect back but with an http:// protocol because that is how the request came in. As far as I'm aware the following headers are somewhat of a standard for this type of situation. Do you think it would be prudent to look for these headers and if the they exist change the URI? You could maybe if just add it as a chained method that would checkHTTPSForward or something.
HTTP_X_FORWARDED_PROTO: https
HTTP_X_FORWARDED_PORT: 443
The input inserted into forms by the Honeypot middleware use type="text"
. This puts an actual text box on the page. Shouldn't it be using type="hidden"
so that it is actually hidden from real users?
I highly recommend adopting the Resolver
pattern instead of depending container-interop
. The interface looks like this:
interface Resolver
{
/**
* @param string
* @return object
*/
public function resolve($spec);
}
Although I am not sure that this can be implemented.
I use Barebones SSO for most of my projects. So it would be nice if I can implement this with middleware.
To parse the body content (json, xml, etc).
Just dropping it here: https://github.com/Ocramius/PSR7Session
Maybe interesting?
Note: requirement is PHP ^7.0 (won't be downgraded)
There are a number of configuration methods in these middleware that prevent them from being treated as immutable, for example Payload::associative
which could be written as:
public function withAssociative($setting)
{
$copy = clone $this;
$copy->associative = (bool) $setting;
return $copy;
}
Currently a page is cache only depending on its URI path, ignoring all query parameters. Which means if you have per examples query parameters to sort a table, or switch tabs, they all serve the same cached page.
Within FormatNegotiator, the negotiateHeader function call sends the hardcoded $headers as the $priority parameter to the Negotiator instance.
Therefore, if the Accept header is set to "*/*", the result will always be "html" regardless of what is specified as the default format.
//Code
Middleware::FormatNegotiator()
->defaultFormat('json')
//Request header
Accept: */*
//Result:
FormatNegotiator::getFormat($request) === "html"
Negotiator allows you to specify a list of priorities. Could this functionality be emulated in FormatNegotiator?
For example:
//Code
Middleware::FormatNegotiator()
->setPriorities(['json', 'zip'])
//Request header
Accept: */*
//Result:
FormatNegotiator::getFormat($request) === "json"
I had some recollection of this being discussed, but I don't see it in the issue
tracker, so I figure I'd raise it here. I assume there has been some discussion
on this, so at minimum, I think it would be nice to have the record of it here.
Firstly, I'm a fan of minimalism and the 'do one thing and do it right' ethos.
In my opinion, it would be nice to have this collection split into separate,
discrete packages. Things like the Authentication middleware might be grouped
together, but things of disparate concerns with varying requirements
could/should be separate.
I think the most obvious reason is that a handful of these have real
requirements (i.e. AuraRouter
), which are only listed as suggestions. The
ability to actually require the dependency (including version requirements)
seems like an obvious benefit.
Additionally, it just doesn't feel right to me to require the whole thing to
use a single component. It would be nice to glance at componser.json
and have
at least some idea of what functionality is being leveraged. It's also strange
to continually get updates which are possibly unrelated to the utilized
functionality.
I also assume (possibly without cause) that release versioning is/will-become
cumbersome with this paradigm. Given two components of unrelated concerns,
should not one be able to change it's public API and require a 1.0 release
without affecting the other?
I would register my vote for separate vendor prefix with discrete packages (eg
oscarware/aura-router
, oscarware/auth
, etc.). If absolutely necessary, they
could require a common utility package. For those desiring the "all-in-one"
paradigm, an additional package could be created which simply requires the
discrete ones.
Thoughts?
The JSON Schema middleware does not work with Slim Framework. Reason is that it relies on the Payload middleware to have getParsedBody to yield a stdClass object, using the newly added forceArray=false
option on Middleware\Payload
.
Slim's Request object has body parsing built-in. Unfortunately they force the JSON payload into an associative array (as documented in their manual) Our Payload MW currently does the following check to decide whether or not we should parse the body:
if (*!$request->getParsedBody()* && in_array($request->getMethod(), [...]
Since getParsedBody will hit Slim's version, we're basically stuck with whatever parsed body they provide. I've come up with three ways to deal with this:
Option 1: "Not our problem", have the developer deal with it in their Framework. In effect this would mean registering a custom "body parser" in Slim using registerMediaTypeParser
to overwrite the default parser for application/json
media types.
Option 2: Instead of bailing out in JSON Schema if the parsed body is not an object, do an if-array-then-cast-to-object, which will yield the stdClass we need.
Option 3: Fix it in Middleware::Payload by (optionally?) having it overwrite previously parsed bodies. Slight loss of efficiency, but ultimately it does give us more control over the request.
Would like your opinion on this before forging ahead with a PR. My preference would be option 3, under the following rationale: By adding the Payload middleware to your stack you're explicitly handing us responsibility to handle the request body, since apparently your current stack is not capable of dealing with the provided payload... it would make sense then not to rely on any previous parsed body contents.
I'll also raise this issue over at Slim to get their opinion on this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.