What HTTP Components have you created - does a replacement middleware exists?

Hi all :wave:

A lot of effort is being put into implmenting and introducing PSR-15 middlewares and move Flows own component into the middleware universe :slight_smile:

@aberl and I had a talk today and asked ourself:

What component have you been building? and Can they be replaced my already available middlewares?

So we kindly ask you to tell here, what components you have been creating and if there is equal PSR-15 middleware already in place.

Either search on packagist.org or this repository https://github.com/middlewares/ or where you happen to find your middleware :shopping_cart:

Please help by sharing and getting the word out - we wanna make this as easy a transition for all of us as possible :star_struck:

Good call.
I think a good start would be to look through our own packages (for example https://github.com/Flowpack/Flowpack.Cors)

1 Like

(Context: I built and run one website with Neos.)


I built a HTTP component that adds security-related HTTP headers.

Why here and not in the webserver configuration? As far as I understood some of these headers only make sense in a document context (i.e. an image does not need to tell the browser to disallow microphone access, but my web pages definitely want that). By adding these headers in Flow I could avoid header bloat for assets etc. and neither did my webserver configuration get too complicated / too use-case-specific.

If you want to see code, here it is: https://code.netztechniker.at/netztechniker.at/WwwScheuchenstuelAt/src/branch/master/Classes/Http/Component/SecurityHeaders.php

By following the Neos project loosely (Slack, discuss.neos.io, github, website) I already knew that changes are/were to be done in this area. During the recent update to Neos 5.3 I evaluated that again, but did not get around to find/code a replacement.

1 Like

That looks super awesome - changing that to a middleware will be a good task. I’ll ping you when we get the PR finally merged, and we can do that together to serve as a example :slight_smile:

1 Like

That’s a good example of a middleware that already exists in a similar shape.

This could help us use already existing middleware :smiley:

1 Like

Flowpack.Fullpagecache uses the old http components heavily and will need an update

1 Like

Thanks for sharing! That one is actually super easy to transform into a middleware:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class SecurityHeaders implements MiddlewareInterface
{

    public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
    {
        // allow local development
        $csp = (empty($request->getServerParams()['HTTPS']) ? '' : 'default-src https:; ')
            . 'script-src \'self\' \'unsafe-inline\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'';

        return $next->handle($request)
                ->withHeader('Content-Security-Policy', $csp)
                ->withHeader('Feature-Policy', 'microphone \'none\'; payment \'none\'')
                ->withHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
                ->withHeader('X-Frame-Options', 'sameorigin')
                ->withHeader('X-XSS-Protection', '1; mode=block')
        );
    }
}
1 Like

Our redirecthandler has one too https://github.com/neos/redirecthandler/blob/master/Classes/RedirectComponent.php. But also doesn’t look too complex.

1 Like

Yep, the hardest part is the ComponentParameters replacement, which is yet to be decided, but will likely end up as PSR-7 Request attribute.

Given that, the code will look s.th. like:

    /**
     * Check if the current request match a redirect
     *
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $next
     * @return ResponseInterface
     * @throws Exception
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
    {
        $routingMatchResults = $request->getAttribute(RoutingComponent::class . ':matchResults');
        if ($routingMatchResults !== null) {
            return $next->handle($request);
        }
        $response = $this->redirectService->buildResponseIfApplicable($request);
        if ($response !== null) {
            return $response;
        }
        return $next->handle($request);
    }
1 Like

This might really be an interesting use-case to collect feedback on the breakiness and migration edge-cases. Also how to maintain a multi-major compatible package - right now it uses the class_exists() to check for Flow 5 vs 6 - how that could look for components vs middleware is something we need to think through (hopefully before the release).

Maybe the answer is, this needs to be a new major version of the package that only targets middleware (but therefore becomes cross-framework if done carefully).

1 Like

I agree that this is a good solution. Middleware will be the standard, to move closer to PSR and the PHP eco system :star_struck:

I also have a few components running in various projects, most notably one in the OIDC package (https://github.com/flownative/flow-openidconnect-client/blob/master/Classes/Http/SetJwtCookieComponent.php). I assume that it can be refactored to a middleware as well.

What nags me though (as always) is that one (a package maintainer) needs to adjust and maintain so much code due to these breaking changes. It’s always a hassle to maintain two codebases / branches which are incompatible.

So, what’s the motivation – from a user’s point of view – to drop components support? Wouldn’t it be possible to let them live side-by-side? Is it about our components being reusable in other, non-Flow projects? If so, I think that wouldn’t justify such a big break up.

2 Likes

This can be a hassle, if we change a lot of things in the HTTP Component afterwards - but since we deprecated them (the HTTP Component context etc), what support and maintanence do you expect to have for a package versioned 1.0 that uses HTTP components, if 2.0 and beyond is a middleware implementation?

Middleware has been mentioned since 2016, Alexander did the first work about one year ago (from reading issues) . We could have decided to push the topic harder and have had it in for the 6.3 LTS release - but I don’t think any time would have been better than other :slight_smile: We didn’t get it in for 6.3 LTS - so kept the LTS stable with concept known, for a longer support release.

Instead we are pushing this along with many other topic for the major 7.0 release.

To work with a framework following the PSR-* standards - “easier” adoption, due to usage of documented concept, describes in numerous of blog post, written by none-Flow users, but still they can use the concept and values.

Mentioned here RFC: PSR-15 / Replace HTTP Component completely, with Flow 7.0 - #8 by aberl - Alexander did some concept for that, but he mentiones the drawbacks, so it’s out there in the open.

The other way around - it’s about others middleware being usable by Flow. Which then (secondary?) leads to, our middlewares being usable by others :slight_smile:

circle-of-life

The problem is that if we keep support the flow processing chains and use them as three middlewares it would not be possible to place a psr middleware in between those or the other way around. We need a single definition of the processing order and we want to be able to use psr middlewares.

I see no way around the breakiness. Maybe we can provide a wrapper to add flow components as psr middlewares or the other way around but on the long run a clear cut may be the better option.

Okay, I got you. I think I need to develop a middleware myself in order to get a better understanding of what’s possible and where limits are.

I’m sorry that I didn’t do my homework and looked up the discussions and progress already made. I really appreciate all the work and certainly agree with initiatives to make Flow and Neos accessible to more people!

Looking at all the comments in the original PR (https://github.com/neos/flow-development-collection/pull/1928) I think we owe @aberl some feedback. I’m not sure if @bwaidelich had a chance to talk / write to Alex already?

Since the PR is merged I have the following question: As far as I understood the discussion, the component chain and middleware support can’t live side-by-side. Doesn’t that mean that PR 1928 is a breaking change (and should be declared as one)?

If I’m to experiment with my own middleware plugin, do I need anything else than Flow master?

Not side by side, but one after the other is perfectly fine and not breaking anything. That is also the current status as of Flow 6.3, where the middleware chain “wraps” our old component chain. So you can already write middlewares, configure them and play around with them, as long as they don’t need to run between components.

See above, even 6.3 works already to experiment :slight_smile: In master we will only remove the existing components, so you can no longer order your own components relative to existing flow components (once we are through) and that is in fact the breaking part of the change.

We could indeed keep the “ComponentChainMiddleware” that runs as the innermost middleware, so existing components could in some way still function. But that begs the question what the reason would be, when components can no longer “interact” with (wrap/interrupt) the Frameworks own http kernel layers.

I’m not sure if @bwaidelich had a chance to talk / write to Alex already?

I did have a talk with Bastian a couple weeks ago regarding the middleware change for 7.0 and he too was on the side of keeping b/c as much as possible. Since then I just found this harder to achieve than anticipated. See also my post in the other thread that @sorenmalling already mentioned RFC: PSR-15 / Replace HTTP Component completely, with Flow 7.0
I would love to have existing components simply work as a middleware without having to touch code, but right now I can’t seem to find a solution that works for all cases.
But nothing is decided yet. The current open issue for the final switch to middlewares is Convert existing HTTP Components to PSR-15 middleware · Issue #2019 · neos/flow-development-collection · GitHub

FYI: The move is going forward now with the few remaining components being replaced with middlewares hopefully right before feature freeze at the end of the week. So far it is working out pretty well, but we will need help with testing the master branch in projects after that. Especially from package maintainers. So please try to allocate a little bit of time for that in between next week and the release.

FYI: That will actually end up as
$routingMatchResults = $request->getAttribute(ServerRequestAttributes::ROUTING_RESULTS);

Also NOTE: if anyone used the ComponentParameters for passing data from a component to an “outgoing” (~postprocess, more correctly anything after “dispatch”) component, that will no longer be possible (easily). The reason is that with middlewares we can only attach metadata to the request object via attributes and pass that on, but once a middleware returns a response, the reference to the most current request is not passed on any more.
Aside from this being a strange use-case anyway (which funnily enough we did do in Flow core, but that’s taken care of), there is still a way to do this though with abusing e.g. the response headers, or introducing your own global context. But really, try to avoid this.

See Convert existing HTTP Components to PSR-15 middleware · Issue #2019 · neos/flow-development-collection · GitHub

Update everyone: All the Flow core components have been migrated to middlewares in current master as of now. The ComponentChain is still in (but disfunctional) and will be removed soon with https://github.com/neos/flow-development-collection/pull/2221 unless voices are raised against this.
So please everyone, play around with your packages on master and let us know what we can do to mitigate your pain of this breaking change.

Most likely, you will need to create a new major version of your package that targets Flow 7.0+ though. Yes, we know this will be a hassle to maintain, especially if the code inside your component is supposed to change.
So as a rule-of-thumb maybe: try to reduce the code inside the component/middleware and move the core logic into some service.

2 Likes