How to generate Chunked response with a Trailer in Apache/PHP? - php

I know I can generate chunked response in PHP simply by introducing a sleep() in the output.
But is it possible to also generate a Trailer HTTP section in PHP? If not, is it possible in general in Apache 2.2?
I need it for testing purposes.

PHP will send a chunked response by default if headers are sent and no Content-Length header was specified. If you're familiar with the HTTP spec, this is the only logical thing to do since the client on the other end needs to know when the HTTP message you're sending ends so it can stop reading.
If you want to do this manually, you need to ...
Send the appropriate headers yourself and call flush()
Manually output the chunked HTTP message
So you might do something like the following. The idea is that you need to manually send your own headers and manually chunk your own message. If you simply don't send a Content-Length header, however, PHP will send a chunked message for you by default.
header("Transfer-encoding: chunked");
header("Trailer: X-My-Trailer-Header");
flush();
echo dechex(strlen($myChunk)) . "\r\n";
echo $myChunk;
echo "\r\n";
flush();
echo "0\r\n";
flush();
echo "X-My-Trailer-Header: some-value\r\n";
flush();

Related

PHP response to HEAD request

I have a PHP script that serves portions of a PDF file by byte ranges.
If an HTTP HEAD request is received, it should send back headers (including the PDF file size) but not the actual file contents. I have tried this:
header('HTTP/1.1 200 OK');
header('Content-Type: application/pdf');
header('Accept-Ranges: bytes');
header('Content-Length: '.filesize($Pathname));
die;
The problem is that something (I assume the web server == LiteSpeed) replaces the Content-Length header with Content-Length: 0 - which defeats the whole purpose.
Can anyone suggest what I should be doing? Thanks
From w3c Hypertext Transfer Protocol -- HTTP/1.1:
When a Content-Length is given in a message where a message-body is
allowed, its field value MUST exactly match the number of OCTETs in
the message-body. HTTP/1.1 user agents MUST notify the user when an
invalid length is received and detected.
And:
The Content-Length entity-header field indicates the size of the
entity-body, in decimal number of OCTETs, sent to the recipient or, in
the case of the HEAD method, the size of the entity-body that would
have been sent had the request been a GET.
So, I suppose, your code will properly work if you send real HEAD request to your server.
It's the webserver job, not yours.
In my case I left everything to the Apache webserver and nothing changed in my php code except of how the requests is being parsed
For example things like
if($_SERVER['REQUEST_METHOD'] === "GET"){
//ok
}else{
//send 400 Bad Request
}
are changed to
if($_SERVER['REQUEST_METHOD'] === "GET" || $_SERVER['REQUEST_METHOD'] === "HEAD"){
//ok
}else{
//send 400 Bad Request
}
and Apache did all the heavy lifting (striped the response body).
(don't try to ob_clean() or die("") or things like this).
related resources:
http://hc.apache.org/httpclient-3.x/methods/head.html
https://security.stackexchange.com/questions/62811/should-i-disable-http-head-requests
Apache 2.2.2 response on HEAD requests
As Lurii mentioned, the content length is affected by your request type.
With GET requests, a non-matching content length may result in a hanging client, so LiteSpeed will verify the content length before sending the header to the client.
Using a HEAD request should return the content length as expected.

Text before php header not giving errors

I'm new to development and I'm trying to learn php.
Why is it that when I use the code below, the redirection, (through the header syntax), is still taking place even though content has been output before it ?
<html>
<body>
<p>My Page</p>
</body>
</html>
<?php
$redirect_page = 'http://localhost';
$redirect = true;
echo "Some Text";
if($redirect==true){
header('Location: '.$redirect_page);
}
?>
Many thanks in advance
HTTP requires response headers to arrive strictly before the body content, like so:
HTTP/1.1 200 OK
Powered-By: PHP/7.0.0-20150527
Content-Type: text/html; charset=utf-8
<html><body>Hello world!</body></html>
For PHP to comply with that requirement, PHP must send all accumulated headers at the instant it's ready to send any body content. The answer to your question hinges on the definition of when PHP is "ready to send".
To figure that out, look at your output_buffering setting:
var_dump(ini_get('output_buffering'));
On my machine with default settings, that returns 4096, which according to the manual means that PHP will be "ready to send" when 4096 body bytes have been accumulated.
To get the page to behave as you expect (ie, not sending the headers), you need to output enough bytes to exceed the setting of output_buffering. You can either do that by reducing the output buffering setting or by emitting more body text, eg:
echo str_repeat('<div/>', 4096);
See also this SO primer.

send custom HTTP response with PHP

I want to send a custom HTTP response back to an application requesting a GET to a php script. The body is will be in binary format (octet-streams). I'm wondering if there is a simple way to do this? I am looking into the HttpResponse class in PECL but is having trouble installing it right now. I do not really need all the other functionalities that goes with it so I'm looking for something simpler.
Any help would be appreciated.
PHP has a header() function built in, so you can customise your response without requiring extra libraries:
<?php
header('Content-Type: application/octet-stream');
header('X-Powered-By: l3utterfly');
echo $binary_data;
?>
You can always set HTTP Headers using header() function, and then simply output binary data using print, echo or any other usual way. Send Content-Type http header to octet stream and it should work all right.
You can use the header function to send back whatever response you want. If you want to send back custome response codes, you could use:
<?
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
//change the code and message to whatever. But I would keep it valid codes so browsers can handle it.
//see http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
header($protocol . ' 404 Not Found');
exit();
?>
And if you want to send binary data, change the header to the correct content-type and echo the binary data.

How to stream an HTTP file upload without the Content-Length header?

Is it possible to upload a file to an apache php server without including the content-length header ?
I am trying to stream a file that I am creating on the fly as a file upload. When I don't use the content-length header I got the apache "501 Method Not Implemented".
$sock = fsockopen($host,80,$errno, $error);
fwrite($sock, "POST $resource HTTP/1.1\r\n" .
"Host: $host\r\n\r\n");
fwrite($sock,fread($readHandle,filesize($file)));
If I include the content-length it works fine.
The server is reading from php://input
According to the HTTP spec you aren't technically required to specify the Content-Length header. From RFC 2616 14.13:
Applications SHOULD use this field to indicate the transfer-length of
the message-body, unless this is prohibited by the rules in section
4.4.
However, this is a pretty standard requirement for most servers, and they'll generally send back an error response if the Content-Length header is missing or incorrectly specified. For all intents and purposes, SHOULD in this case equates to MUST.
The problem is that (especially with keep-alive connections), the server doesn't know when your request message actually ends without the Content-Length header. The other option if you're streaming a request entity body is to send a Transfer-Encoding: chunked header and manually send one chunk of the entity body at a time.
So in summary, if you want to send an entity body with your message but don't want to send a Content-Length header, your only real option is to send a chunked HTTP message. This is basically required if you want to stream that entity body and don't know its length ahead of time.
How to chunk-encode an HTTP entity body for streaming ...
Transfer-Encoding: chunked means that you're encoding the entity body of the HTTP message according to the constraints laid out in RFC2616 Sec3.6.1. This encoding format can be applied to either requests or responses (duh, they're both HTTP messages). This format is extremely useful because it allows you to start sending an HTTP message right away before you know the size of the entity body or even exactly what that entity body is going to be. In fact, this is exactly what PHP does transparently for you when you echo any output without having sent a length header like header('Content-Length: 42').
I'm not going to get into details of chunked encoding -- that's what the HTTP spec is for -- but if you want to stream a request entity body you need to do something like this:
<?php
$sock = fsockopen($host,80,$errno, $error);
$readStream = fopen('/some/file/path.txt', 'r+');
fwrite($sock, "POST /somePath HTTP/1.1\r\n" .
"Host: www.somehost.com\r\n" .
"Transfer-Encoding: chunked\r\n\r\n");
while (!feof($readStream)) {
$chunkData = fread($readStream, $chunkSize);
$chunkLength = strlen($chunkData);
$chunkData = dechex($chunkLength) . "\r\n$chunkData\r\n";
fwrite($sock, $chunkData);
}
fwrite($sock, "0\r\n\r\n");

Send HTTP headers before or after a cookie header?

I was wondering if there are any problems or difference between sending normal headers before or after sending cookie headers. Do some browsers prefer a certain order to headers? If the cookie header is to large would subsequent headers never be parsed?
setcookie("TestCookie", $value);
header("Content-type: text/javascript");
or
header('Location: http://www.example.com/');
setcookie("TestCookie", $value);
or
setcookie("SuperLargeCookie", $massive_value);
setcookie("TinyCookie", $small_value);
header("Status: 404 Not Found");
There is no difference. The Http protocol does not specify that headers are to be in a certain order. Browsers do not differentiate based on the order of headers either.
The total length of Http headers does have a limit. This limit is imposed by the server and not the browser. Typically between 8K and 16K. However this is configurable.
It really doesn't matter as long as the other HTTP headers have not been sent. setcookie() actually writes a header itself:
Set-Cookie: SuperLargeCookie=whatever; Max-Age=3600; Version=1
similar to a header() call:
Location: http://www.example.com/redirect
HTTP messages span packets all the time, so you'd be hard-pressed to overfill one unless you're jamming tons of kilobytes in there. If you need to do that, consider a better design. Browsers don't care about the order of headers since different servers (and applications) append headers all the time. Cookies are implemented as HTTP headers, so they should appear like so in the HTTP request:
Cookie: TestCookie=value\r\n
Content-type: text/javascript\r\n
\r\n
I'm not sure what the Status header is supposed to do in your example, but I don't think it's right since the webserver will set a 200 OK response code if the code executes correctly... The header function page has this examaple:
<?php
header("HTTP/1.0 404 Not Found");
?>
With the PHP header function, just make sure you're not writing any text out before issuing it. Otherwise, you could mess everything up.

Categories