-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpFoundation] Add support for the 103 status code (Early Hints) and other 1XX statuses #48128
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
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
aa3684a
to
85bb5ca
Compare
Hey! I think @pascalwoerde has recently worked with this code. Maybe they can help review this? Cheers! Carsonbot |
As many Symfony devs don't know about the
|
Is that deprecation necessary? Calling |
@chalasr What would be the benefit of doing that? My proposal is very similar to how it's implemented in Go for instance. IMHO the current API is good enough and there is no need to make it more complex. @derrabus the plan is to force passing |
And why don't we make it optional right from the start? |
It's not obvious that |
Informational responses are special: they can only be composed of headers, by the spec:
https://httpwg.org/specs/rfc9110.html#status.1xx So basically, sending 1XX responses mean sending headers ahead of time. Adding a new method would just add more confusion IMHO. |
Yes, that's something I personally know but:
But maybe it's just me 🤷 hope others opinions will come.
A virtual parameter ( |
85bb5ca
to
dd18dc7
Compare
@chalasr I hope that I've found an acceptable compromise:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\WebLink\Link;
class HomepageController extends AbstractController
{
#[Route("/", name: "homepage")]
public function index(Request $request): Response
{
$response = $this->sendEarlyHints([
(new Link(href: '/style.css'))->withAttribute('as', 'stylesheet'),
(new Link(href: '/script.js'))->withAttribute('as', 'script'),
]);
// Do something slow...
return $this->render('homepage/index.html.twig', response: $response);
}
} So we have the best of both worlds. WDYT? |
Looks great! Thanks |
4d5e71d
to
2b3026f
Compare
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.
Although AbstractController is not first-class citizen anymore, it's good for discovery and we could consider moving this method to the component later if needed.
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
This sends the headers immediately to the client, right? How can I test a controller that makes use of that feature? |
Indeed. You can test using FrakenPHP and |
It would be nice to make sure that functional testing utilities are ready for this, and to patch them otherwise. Maybe even setup FrankenPHP in one of our GHA workflows? |
/** | ||
* Tracks headers already sent in informational responses | ||
*/ | ||
private array $sentHeaders; |
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.
would exposing a getter improve testability of this?
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 suggest keeping that entirely internal. WDYT?
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
701f2c1
to
065b8fb
Compare
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
Outdated
Show resolved
Hide resolved
53d4fc0
to
a631350
Compare
877a499
to
1b626cc
Compare
…d other 1XX statuses
1b626cc
to
5be52b2
Compare
Thank you @dunglas. |
// cookies | ||
foreach ($this->headers->getCookies() as $cookie) { | ||
header('Set-Cookie: '.$cookie, false, $this->statusCode); | ||
} | ||
|
||
if ($informationalResponse) { | ||
headers_send($statusCode); | ||
|
||
return $this; | ||
} |
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 personally would not send the Cookies
in the Informational Response.
As the session and so on could be changing and that handling already complex in the AbstractSessionListener
to support all kind of Runtime (Swoole, Roadrunner, ... running in the CLI context) and so would not do any set-cookie
in the early hint responses.
// cookies | |
foreach ($this->headers->getCookies() as $cookie) { | |
header('Set-Cookie: '.$cookie, false, $this->statusCode); | |
} | |
if ($informationalResponse) { | |
headers_send($statusCode); | |
return $this; | |
} | |
if ($informationalResponse) { | |
headers_send($statusCode); | |
return $this; | |
} | |
// cookies | |
foreach ($this->headers->getCookies() as $cookie) { | |
header('Set-Cookie: '.$cookie, false, $this->statusCode); | |
} |
This patch adds support for sending informational responses, including Early Hints responses if supported by the SAPI. It also allows sending other informational status codes such as 102 Processing.
According to Shopify and Cloudflare, using Early Hints, the performance improvement to the Largest Contentful Paint can go from several hundred milliseconds, and up to a second faster.
Usage:
With this patch, HttpFoundation will leverage the
headers_send()
function provided by FrankenPHP. FrankenPHP is currently the only SAPI supporting Early Hints, but other SAPI such as mod_apache will probably implement this function at some point: php/php-src#7025 (comment)The low-level API is similar to the one provided by Go: golang/go#42597
The high-level API helper in
AbstractController
is similar to Node's one: nodejs/node#44180