Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Proxy another url

Tags:

php

curl

proxy

I have a mod_rewrite rule that will send any subdomain requests to a php script which should proxy those requests to another host (internal proxy, not 302).

I'm close, in that my script works with web browsers, but curl seems not like it:

curl: (56) Received problem 2 in the chunky parser

Here is my mod_rewrite:

RewriteCond %{HTTP_HOST} ^(.*)\.example\.com$
RewriteRule ^.*$ %{DOCUMENT_ROOT}/proxy.php?__path=%1 [QSA,L]

And my proxy.php

<?php

$name = $_GET['__path'];
unset($_GET['__path']);
$path = $_SERVER['REQUEST_URI'];

$url = "http://$name.internal.example.com$path";
$ch = curl_init($url);
$headers = array();
foreach (apache_request_headers() as $key => $value) {
    $headers[] = "$key: $value";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER['REQUEST_METHOD']);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
curl_setopt($ch, CURLOPT_HEADER, TRUE);  

$data = curl_exec($ch);

list($headers, $body) = explode("\r\n\r\n", $data, 2);
$headers = explode("\r\n", $headers);
foreach ($headers as $header) {
    header($header);
}
die($body);

Any reason why curl doesn't like this but browsers are ok with it?

EDIT: It seems if I don't send the Transfer-Encoding: chunked header, everything is ok (since I'm proxying the full request, chunking isn't possible). So a follow up question: Can I act as a true middleman and send the data as I get it over the socket?

like image 948
Paul Tarjan Avatar asked Mar 04 '10 18:03

Paul Tarjan


1 Answers

Yes, you should be able send data over the network as you get it. But I suspect your problem may stem from persistent http connections. HTTP 1.0 will break the connection after the request, in your code you are creating a new CURL handle for each request, which is more like HTTP/1.0 instead of the default HTTP/1.1

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);

You may still have problems with the application layer because CURL isn't meant to act as a proxy like this. Another approach would be to modify an existing PHP HTTP Client and make sure that the forwarded requests are close enough for your needs.

No matter what approach you use, I highly recommend using WireShark for debugging. You can then dump 2 http requests and then use something like Meld to pick out the differences.

like image 63
rook Avatar answered Sep 28 '22 06:09

rook