Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 533
James Hackett Avatar asked Aug 28 '12 20:08

James Hackett


People also ask

How do you find the content length of a multipart form data?

To summarize the findings: The multipart request's "Content-length" is computed from the first byte of the boundary sequence following the header section's blank line, and continues until, and includes, the last hyphen of the final boundary sequence.

Can I upload file using HTTP?

A multipart request is a HTTP request that HTTP clients construct to send files and data over to a HTTP Server. It is commonly used by browsers and HTTP clients to upload files to the server.

How does file upload work in HTTP?

To upload data to a server, the client again initiates a connection to the server and then typically sends a HTTP POST request which contains the data to be uploaded. The server knows how to handle such a request and stores the data.


1 Answers

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");
like image 134
rdlowrey Avatar answered Nov 15 '22 17:11

rdlowrey