Symfony 2.7 set header from StreamedResponse's callback - php

I have to set dynamically my Content-Type into the StreamedResponse's callback.
I wrote a code like this that it works fine on Symfony 2.3 but not on 2.7. The returned Content-Type is text/html.
function indexAction()
{
$r = new \Symfony\Component\HttpFoundation\StreamedResponse();
$r->setCallback(function() use ( & $r)
{
// ...
$r->headers->set('Content-Type', 'application/json');
// ...
});
return $r;
}
I found this commit that it can be on but i don't really understand...
https://github.com/symfony/http-foundation/commit/6a0838a26d54eff153b825e1550c1f6fa05a0941
It looks like we can now only set header outside the callback.
It works if i send headers with the native php function into the closure but it's dirty...
header('Content-Type: application/json');
if someone has a clue...
Thanks!

Streamed response made for purposes when you need long-polling connections. And so you have to know what content-type it will serve before you send any data.
When you return your Response object in action Symfony already sends headers and starts to stream output from callback function. In this moment it is not right to send another header.
P.S. I have never seen case when you really need StreamedResponse and need to set Content-Type dynamically.

To be accurate, you can use hack with replacing headers up to version 2.7.19, it was merged in 2.7.20
As #MichaelSivolobov said in his answer, I also have never seen cases when you need it
I'm sure such commits are always made for enforce better application design. When I see such cases as in your example, it's a some kind of red flag to rethink code/data flow

Related

Set Request (not Response) Headers in Laravel 5 for Non-Ajax Routes

I am actually completely baffled that this is such a difficult task to accomplish and/or find any relevant information about. My guess is that it must be something SO simple, that no one has to ask about it (except for me! :-) ), so I am hoping that someone can easily point me in the right direction...
I need to set headers in my Requests - not in my Responses (I've got that part handled), and not for Ajax routes (I've got that part handled as well). How on Earth do I accomplish this on internal app routes in Laravel 5.1?
Essentially, I need to attach an 'Authorization' header to certain Requests. (i.e.
$request->headers->set('Authorization', 'my-authorization-token');
)This line of code does not work, however. No matter where I put it. It doesn't work from middleware. It doesn't work from routes.php. It doesn't work from my controllers... it just simply does not work period. (For the sake of clarity, '$request' is 'Illuminate\Http\Request').
What am I missing? Where/How can I set request headers before a request is sent? Please help! Thanks in advance.
Some of the answers here might give you an idea, you could adapt them for the request: Where can I set headers in laravel
This also looks relevant: Laravel 5 / Lumen Request Header?
The request is sent from the client to the server (i.e. your Laravel app). So you set the request headers on the client site using Javascript.
The Laravel documentation has an example of setting the X-CSRF-TOKEN header using jQuery.
$.ajaxSetup({
headers: {
'X-MY-HEADER': 'whateveryouwant
}
});
Using VueJS it would look like this
Vue.http.headers.common['X-MY-HEADER'] = 'whateveryouwant';
You need to create a new request object and then set the header like this:
// e.g., Inside controller method
$request = new \Illuminate\Http\Request();
$request->setMethod('POST'); // or whatever your request type is
$request->header('Authorization', 'my-authorization-token');

PHP headers_list() is not showing all headers

According to the documentation: http://php.net/manual/en/function.headers-list.php, and this comment: http://php.net/manual/en/function.headers-list.php#110330, php code:
<?php var_dump(header_list()); ?>
Does not show the status headers.
This strange behavior is strange. So there are two questions:
Why? (I'm not sure if this question is opinion based, if it is, and there is no REAL explanation please omit it. I mean that sometimes opinion based questions aren't opinion based, and really have explanation, and this cannot be predict before they are asked).
I know that I can use my own function to set header, which will set header and additionally remember that this header was set. But this is kind of... workaround, as header_list() is quite sure HERE, FOR THAT. Additionally those headers are somewhere in the php engine memory so saving them second time inside script is not memory efficient. So... What is the back-door to get all headers, not as stupid as workaround below? This can be useful for example as a part of debug / developer class that is rendering all the "developer" data as html comments at the end of the page. Of course I'm omitting the content length header which is too soon to predict.
It looks like this function omit all the headers that don't have colon... Is it right?
To post more code, simple workaround to header function (linear not object, using globals and not static class just to show the idea). With the assumption that header function is omitting headers without colons (which may not be quite true...):
<?php
// Mechanism:
$headers = array();
function setHeader($header) {
header($header);
if (strpos($header, ':') === false) {
global $headers;
$headers[] = $header;
}
}
function getHeaders() {
global $headers;
return array_merge($headers, header_list());
}
// Example:
setHeader('HTTP/1.1 404 Not Found');
var_dump(getHeaders());
?>
Checking the engine source for headers_list and http_response_code, notice that the value for general headers and status code are separated:
// headers_list
SG(sapi_headers).headers
// http_response_code
SG(sapi_headers).http_response_code
But HTTP response code isn't the only header with dedicated storage: Content-Type does, too:
SG(sapi_headers).mimetype = NULL;
So what's going on here? The complete header() algorithm specifically checks for the following strings to adjust state:
HTTP/
Content-Type
Content-Length
Location
WWW-Authenticate
HTTP/ is checked specifically because that's how one set the status code explicitly before PHP 5.4: after that, http_response_code is available and is recommended for clarity. That header() was used is confusing, for the reason you're asking in this question and on general principle: the http header BNF clearly doesn't include status line:
header-field = field-name ":" OWS field-value OWS
PHP handles the others separately because they are single-value headers and/or their value matters for efficiency in later calculations.
TL;DR: HTTP/ set by header() isn't included in headers_list() because HTTP/ status lines are not headers in the strict RFC sense. But for the PHP < 5.4 limitation that header() was the only way to set HTTP/ status, it'd likely have never been a confusing issue.
It seems that only the status code is missing from the header_list.
You can get the current status code (they probably overwrite one another) using another function: http_response_code.

How to use ob_* to set the content length in the header?

I am trying to create a webservice in Yii. The web service is working fine but what i am concerned about is how to use ob_start() group all together so that i could set the Content-length in the header. I read a lot about ob_* group but still i am very much confused about it.
Suppose this is the web service
public function giveTimestamp()
{
$query='select current_timestamp( );';
$record= Yii::app()->db->createCommand($query)->queryScalar();
return $record;
}
Now what I am trying to do is that I will set the content length of the header while sending this data. Now the at client side user will check if he has received the data of the told length. if not then he will send the request again otherwise there will be no request.
SO how can i use this ob_* in combination.?
To get output size in header, you need to have access to output block:
ob_start(); // enable buffering
echo 'content'; // do the output to memory
header('Content-Length: ' . ob_get_length()); // send header
ob_end_flush(); // send content of buffer and terminate it
However, I can not help you with Yii part, as I do not have experience of work with it.
There are two Yii ways of doing this.
Use afterRender to add the header. This will affect every action in a controller unless you work around that, so use cautiously. http://www.yiiframework.com/doc/api/1.1/CController#afterAction-detail
Use a custom filter and apply it as needed to all actions or select actions. I would probably go this route, as you have more flexibility in the future. Another choice is whether to use an inline filter (much like afterRender above or a class-based filter). Class-based makes it easier to apply your filter across controllers. http://www.yiiframework.com/doc/guide/1.1/en/basics.controller#filter

Trying to override Restler3 Content-Type

I'm very new to Restler3. And a very happy new user!
My object was basically to setup a EC2 which using Restlers clever routing can rewrite streaming manifests (the manifest basically tells which fragments of video/audio/subtitle to stream).
All is very good. Restler gets the Manifest, does the rewriting and easily sends it back to requestor.
Now I am trying to squeeze something else into Restler. I need Restler to respond with an MP4-header formatted XML-Subtitle-TTML chunk.
You might ask, why squeeze this onto a Restler-platform?
A. The routing in Restler makes everything so much easier.
B. Why not try it out?
So, I have managed to get Restler to do almost what I need. I simply bypass Restlers return statement. I simply echo() out the binary data to requestor. And amazingly it all works.
My only tiny problem left to sort out is Content-Type.
All my other "normal" xml-requests return "text/html" when testing with this awkward way of returning the response, using simple echo-statements of nicely handcrafted XML. So I try to override with
header('Content-type: text/xml');
Which also gets returned.
The problem is that somehow the binary response with an MP4-header gets forced by "someone" into
Content-Type: application/json; charset=utf-8
although I have set
header('Content-type: text/xml');
Any clues what I could do to override this?
Easiest way to fix headers Content-type is by adding this header and then exiting your function. And by doing the exit; cheating Restler into replying with the (maybe non-standard) Content-type.
header('Content-type: text/xml');
exit;

How does get_headers work in the background

I tryied searching for this and I belive I alredy know the answer but it's crusal that I'm not wrong, so here I go..
When calling get_headers, will I retrieve the whole file even though the function only returns the headers or will it retrieve, as expected, only the headers and nothing else?
I'm guessing the last but if I'm wrong this will cause some serious problems..
Also I noticed that there is a global setting I can change to send a HEAD request instead of the default GET request, witch is why I'm asking my self whats really going on.
Edit
Maybe this function is a better alternative? stream_get_meta_data or do they actually do the same thing?
You could also take a look at the source code, if you are familiar with C.
The function is defined here. I quickly looked over this, and it seems it is a header-only request, see line 715:
STREAM_ONLY_GET_HEADERS
GET
Requests a representation of the specified resource. Requests using
GET should only retrieve data and should have no other effect. (This
is also true of some other HTTP methods.) The W3C has published
guidance principles on this distinction, saying, "Web application
design should be informed by the above principles, but also by the
relevant limitations."
HEAD
Asks for the response identical to the one that would correspond to a
GET request, but without the response body. This is useful for
retrieving meta-information written in response headers, without
having to transport the entire content.
Wikipedia/Hypertext_Transfer_Protocol
The PHP-docs clearly states that normal get_headers() uses a GET-request, but you can force it to use HEAD instead, like this:
<?php
// By default get_headers uses a GET request to fetch the headers. If you
// want to send a HEAD request instead, you can do so using a stream context:
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
)
);
$headers = get_headers('http://example.com');
?>
Unfortunaley you're right, just read the PHP manual:
get_headers() returns an array with the headers sent by the server in response to a HTTP request.
Also take a look at the examples.
Okay, next time I should spend more attention to the question formulation.
Yeh, if the request type is set to GET (standard) you will get the whole content. You could change it to HEAD, but this is not what you want.

Categories