Skip to content

Add HttpHeaderCollection #202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion doc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2013-10-17 Nikita V. Konstantinov

* main/Flow/HttpRequest.class.php
* main/Net/Http/HttpHeaderCollection.class.php
* test/AllTests.php
* test/main/Net/Http/HttpHeaderCollectionTest.class.php:
added HttpHeaderCollection

2013-10-15 Nikita V. Konstantinov

* main/Flow/HttpRequest.class.php:
added HttpRequest::createFromGlobals()

2013-09-03 Vasily M. Stashko

* core/DB/MySQL.class.php
Expand Down Expand Up @@ -253,7 +266,7 @@

Introducing Uncachers

2012-06-29 Nikita Konstantinov
2012-06-29 Nikita V. Konstantinov

* core/DB/PgSQL.class.php
test/core/DbConnectionTest.class.php:
Expand Down
37 changes: 26 additions & 11 deletions main/Flow/HttpRequest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class HttpRequest
// all other sh1t
private $attached = array();

private $headers = array();
private $headers = null;

/**
* @var HttpMethod
Expand All @@ -47,7 +47,6 @@ final class HttpRequest
*/
private $url = null;

//for CurlHttpClient if you need to send raw CURLOPT_POSTFIELDS
private $body = null;

/**
Expand All @@ -74,9 +73,12 @@ public static function createFromGlobals()
if (isset($_SESSION))
$request->setSession($_SESSION);

foreach ($_SERVER as $name => $value)
if (substr($name, 0, 5) === 'HTTP_')
$request->setHeaderVar(substr($name, 5), $value);
foreach ($_SERVER as $name => $value) {
if (strpos($name, 'HTTP_') === 0) {
$name = str_replace('_', '-', substr($name, 5));
$request->setHeaderVar($name, $value);
}
}

if (
$request->hasServerVar('CONTENT_TYPE')
Expand All @@ -86,6 +88,11 @@ public static function createFromGlobals()

return $request;
}

public function __construct()
{
$this->headers = new HttpHeaderCollection();
}

public function &getGet()
{
Expand Down Expand Up @@ -218,7 +225,11 @@ public function &getSession()
{
return $this->session;
}


/**
* @param string $name
* @return mixed
*/
public function getSessionVar($name)
{
return $this->session[$name];
Expand Down Expand Up @@ -278,7 +289,11 @@ public function &getAttached()
{
return $this->attached;
}


/**
* @param string $name
* @return mixed
*/
public function getAttachedVar($name)
{
return $this->attached[$name];
Expand Down Expand Up @@ -306,7 +321,7 @@ public function getByType(RequestType $type)

public function getHeaderList()
{
return $this->headers;
return $this->headers->getAll();
}

public function hasHeaderVar($name)
Expand All @@ -316,7 +331,7 @@ public function hasHeaderVar($name)

public function getHeaderVar($name)
{
return $this->headers[$name];
return $this->headers->get($name);
}

/**
Expand All @@ -333,7 +348,7 @@ public function unsetHeaderVar($name)
**/
public function setHeaderVar($name, $var)
{
$this->headers[$name] = $var;
$this->headers->set($name, $var);
return $this;
}

Expand All @@ -342,7 +357,7 @@ public function setHeaderVar($name, $var)
**/
public function setHeaders(array $headers)
{
$this->headers = $headers;
$this->headers = new HttpHeaderCollection($headers);
return $this;
}

Expand Down
110 changes: 110 additions & 0 deletions main/Net/Http/HttpHeaderCollection.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php
/***************************************************************************
* Copyright (C) 2013 by Nikita V. Konstantinov *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

/**
* @ingroup Http
**/
class HttpHeaderCollection implements IteratorAggregate
{
private $headers = array();

public function __construct(array $headers = array())
{
foreach ($headers as $name => $value)
$this->set($name, $value);
}

public function set($name, $value)
{
$this->headers[$this->normalizeName($name)]=
array_values((array) $value);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http://www.ietf.org/rfc/rfc2616.txt p.4.2 последний абзац.
Это не обязывает нас при получении $value делать explode по \r\n и ";" ?

Насколько я понимаю, с точки зрения протокола
x-foo: bar;baz

равнозначно с
x-foo: bar
x-foo: baz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Там речь про comma (","), а не semicolon (";"). Мне неясен это абзац совершенно. Если это так, то как различать значение и список значений? Экранирования нет, запятая не запрещена.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тесты показали, что популярным веб-серверам и языкам разработки пофиг на это требование.

Если возражений от сообщества нет, то предлагаю вливать.

return $this;
}

public function add($name, $value)
{
$name = $this->normalizeName($name);

if (array_key_exists($name, $this->headers))
$this->headers[$name][] = $value;
else
$this->set($name, $value);

return $this;
}

public function remove($name)
{
if (!$this->has($name)) {
throw new MissingElementException(
sprintf('Header "%s" does not exist', $name)
);
}

unset($this->headers[$this->normalizeName($name)]);

return $this;
}

public function get($name)
{
$valueList = $this->getRaw($name);

return count($valueList) > 1 ? $valueList : $valueList[0];
}

public function has($name)
{
return
array_key_exists(
$this->normalizeName($name),
$this->headers
);
}

public function getRaw($name)
{
if (!$this->has($name)) {
throw new MissingElementException(
sprintf('Header "%s" does not exist', $name)
);
}

return $this->headers[$this->normalizeName($name)];
}

public function getAll()
{
return $this->headers;
}

public function getIterator()
{
return new ArrayIterator($this->headers);
}

private function normalizeName($name)
{
return
preg_replace_callback(
'/(?<name>[^-]+)/',
function ($match) {
return
strtoupper(substr($match['name'], 0, 1))
.strtolower(substr($match['name'], 1))
;
},
$name
);
}
}
?>
1 change: 1 addition & 0 deletions test/AllTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Autoloader'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Ip'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Net'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Net'.DIRECTORY_SEPARATOR.'Http'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Utils'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Utils'.DIRECTORY_SEPARATOR.'Routers'.DIRECTORY_SEPARATOR,
ONPHP_TEST_PATH.'main'.DIRECTORY_SEPARATOR.'Utils'.DIRECTORY_SEPARATOR.'AMQP'.DIRECTORY_SEPARATOR,
Expand Down
67 changes: 67 additions & 0 deletions test/main/Net/Http/HttpHeaderCollectionTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
/***************************************************************************
* Copyright (C) 2013 by Nikita V. Konstantinov *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

class HttpHeaderCollectionTest extends TestCase
{
public function testSetter()
{
$collection =
new HttpHeaderCollection(
array('Content-Length' => 42)
);

return $collection;
}

/**
* @depends testSetter
*/
public function testAddition(HttpHeaderCollection $collection)
{
$collection->add('x-foo', 'bar')->add('x-foo', 'baz');

return $collection;
}

/**
* @depends testAddition
*/
public function testGetter(HttpHeaderCollection $collection)
{
$this->assertEquals(42, $collection->get('content-LeNgTh'));
$this->assertEquals(array(42), $collection->getRaw('content-LeNgTh'));
$this->assertEquals(array('bar', 'baz'), $collection->get('x-foo'));

return $collection;
}

/**
* @depends testGetter
*/
public function testRemoving(HttpHeaderCollection $collection)
{
$collection->remove('x-foo');

return $collection;
}

/**
* @depends testRemoving
* @expectedException MissingElementException
*/
public function testFailedRemoving(HttpHeaderCollection $collection)
{
$collection->remove('x-foo');

return $collection;
}
}
?>