FAQ
Edit report at http://pear.php.net/bugs/bug.php?id=14469&edit=1

ID: 14469
Updated by: daniel.oconnor@gmail.com
Reported By: andy dot christianson dot 2 at gmail dot com
Summary: POST Multipart Content Not Included in Request Object
-Status: Open
+Status: Feedback
Type: Bug
Package: HTTP_Server
Operating System: Mac OSX 10.5.4
Package Version: 0.4.0
PHP Version: 5.2.6
Roadmap Versions:
New Comment:

-Status: Open
+Status: Feedback
Andy/Oleg; can I get either of you to do the updated patches as actual
diffs? It's a
bit tricky for me to read them otherwise.


Previous Comments:
------------------------------------------------------------------------

[2008-11-14 12:02:31] mrsol

Here is variant under which stright not it is necessary to use the
function Driver reading from socket.
Plus is added restriction of the request.
Single that here else it is necessary to correct here is this bug
http://pear.php.net/bugs/bug.php?id=15030

-----------------------
var $ClientsInfo = array();
var $MaximalLenRequest = 51200;
var $readBuferDataSize = 256;

function __construct($hostname, $port, $driver = 'Fork'){
$this->_driver = &Net_Server::create($driver, $hostname,
$port);
$this->_driver->readEndCharacter = "\n";
$this->_driver->readBufferSize = 1;

$this->_driver->setCallbackObject($this);
}

function onReceiveData($clientId, $data){

if(empty($this->ClientsInfo[$clientId])){
$this->ClientsInfo[$clientId]['data'] = $data;
$this->ClientsInfo[$clientId]['end'] = false;
$this->ClientsInfo[$clientId]['last_content'] = 0;
$this->ClientsInfo[$clientId]['found_content_len'] = false;
$this->ClientsInfo[$clientId]['full_len'] = strlen($data);
$this->ClientsInfo[$clientId]['content_len'] = NULL;
}else{
$this->ClientsInfo[$clientId]['data'] .= $data;
if($this->ClientsInfo[$clientId]['content_len']===NULL and
strpos($data, 'Content-Length')!==false){
if(preg_match("'([^: ]+): (.+)'", $data, $regs)){
$this->ClientsInfo[$clientId]['last_content'] = $regs[2];
$this->ClientsInfo[$clientId]['content_len'] = $regs[2];
}
}
if($this->ClientsInfo[$clientId]['found_content_len']){
$this->ClientsInfo[$clientId]['last_content'] -=
strlen($data);

if($this->ClientsInfo[$clientId]['last_content']>$this->readBuferDataSize){
$this->_driver->readBufferSize = $this->readBuferDataSize;
}else{
$this->_driver->readBufferSize =
$this->ClientsInfo[$clientId]['last_content'];
}
}
if($this->ClientsInfo[$clientId]['found_content_len']!=true
and $data=="\r\n"){
$this->ClientsInfo[$clientId]['found_content_len'] = true;
$this->_driver->setEndCharacter(null);
}
$this->ClientsInfo[$clientId]['last_data'] = $data;
$this->ClientsInfo[$clientId]['full_len'] += strlen($data);

}


if($this->ClientsInfo[$clientId]['last_content']<=0 and
$this->ClientsInfo[$clientId]['found_content_len']){
$this->ClientsInfo[$clientId]['end'] = true;
}

if($this->ClientsInfo[$clientId]['end']){
$request =
&HTTP_Server_Request::parse($this->ClientsInfo[$clientId]['data']);
if($request === false){
$response = $this->handleBadRequest($clientId,
$this->ClientsInfo[$clientId]['data']);
$this->_sendResponse($clientId, $response);
}else{
$this->_serveRequest($clientId, $request);
}
}else{

if($this->ClientsInfo[$clientId]['full_len']>$this->MaximalLenRequest){
$response = $this->handleBadRequestCode($clientId,
$this->ClientsInfo[$clientId]['data'], 413);
}else{
return true;
}
}

// close the connection
$this->_driver->setEndCharacter("\n");
$this->_driver->readBufferSize = 1;
unset($ClientsInfo[$clientId]);
$this->_driver->closeConnection($clientId);
}

function handleBadRequestCode($clientId, $data, $Code){
return array(
'code' => $Code
);
}

------------------------------------------------------------------------

[2008-08-12 13:31:11] achristi

...which also means that a few redundant lines can be removed. New
version (mind the line wrapping):

function onReceiveData($clientId, $data)
{
// read until double \r\n (end of HTTP headers)
while(false === strpos($data,"\r\n\r\n"))
{
$data .= $this->_driver->readFromSocket($clientId);
}

// parse request headers
$request = &HTTP_Server_Request::parse($data);

if(is_array($request->headers)
&& array_key_exists('content-type',$request->headers)
&& preg_match('/^multipart\/form-
data.*boundary=(\S+).*$/ms',
$request->headers['content-type'], $matches))
{
$boundary = "--".$matches[1]."--\r\n";

while(false === strpos($request->content,$boundary))
{
$request->content .= $this->_driver-
readFromSocket($clientId);
}
}

if ($request === false)
{
$response = $this->handleBadRequest($clientId, $data);
$this->_sendResponse($clientId, $response);
}
else
{
$this->_serveRequest($clientId, $request);
}

// close the connection
$this->_driver->closeConnection($clientId);
}

------------------------------------------------------------------------

[2008-08-12 13:27:30] achristi

I left out that the code above also relies on the following line in
HTTP_Server::__construct():

$this->_driver->readEndCharacter = "\n";

------------------------------------------------------------------------

[2008-08-12 13:26:01] achristi

Here's a very rough test case:

class MyServer extends HTTP_Server
{
public function POST($clientId, $request)
{
var_dump($request->content);
// expected output: string containing full POST message sent
from browser
// actual output: string containing a small amount of
whitespace
(\r\n?)
}
}

Also, here's a thoroughly-tested onReceiveData. I ran into some
problems with IE/Firefox on a Windows host. The following code works
perfectly, as far as I can tell, with any combination of Unix/Windows
hosts and Firefox/Safari/IE clients. The catch here is that this handles

multipart/form-data rather than any POST request. I apologize that it
is not formatted according to PEAR standards. I haven't got enough
time to do the formatting and create a proper patch at the moment.
Hopefully this will help someone and/or make its way into
HTTP_Server:

function onReceiveData($clientId, $data)
{
// read until double \r\n (end of HTTP headers)
while(false === strpos($data,"\r\n\r\n"))
{
$data .= $this->_driver->readFromSocket($clientId);
}

// parse request headers
$request = &HTTP_Server_Request::parse($data);

if(is_array($request->headers)
&& array_key_exists('content-type',$request->headers)
&& preg_match('/^multipart\/form-
data.*boundary=(\S+).*$/ms',
$request->headers['content-type'], $matches))
{
$boundary = "--".$matches[1]."--\r\n";
$originalReadEndCharacter = $this->_driver->readEndCharacter;
$this->_driver->readEndCharacter = "\n";

while(false === strpos($request->content,$boundary))
{
$request->content .= $this->_driver-
readFromSocket($clientId);
}

$this->_driver->readEndCharacter = $originalReadEndCharacter;
}

if ($request === false)
{
$response = $this->handleBadRequest($clientId, $data);
$this->_sendResponse($clientId, $response);
}
else
{
$this->_serveRequest($clientId, $request);
}

// close the connection
$this->_driver->closeConnection($clientId);
}

------------------------------------------------------------------------

[2008-08-08 23:05:12] doconnor

Hey thanks for the patch Andy!

I don't suppose you'd feel up to a very small test case to better
demonstrate this? That makes it easier for people who don't know the
package well to evaluate your patch...

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://pear.php.net/bugs/bug.php?id=14469

Search Discussions

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppear-bugs @
categoriesphp
postedAug 8, '11 at 2:17a
activeAug 8, '11 at 2:17a
posts1
users1
websitepear.php.net

1 user in discussion

Daniel Oconnor: 1 post

People

Translate

site design / logo © 2022 Grokbase