diff --git a/library/Requests/Response/Headers.php b/library/Requests/Response/Headers.php index dc5fa0bfb..8db6a0073 100755 --- a/library/Requests/Response/Headers.php +++ b/library/Requests/Response/Headers.php @@ -10,85 +10,64 @@ * * @package Requests */ -class Requests_Response_Headers implements ArrayAccess, IteratorAggregate { +class Requests_Response_Headers extends Requests_Utility_CaseInsensitiveDictionary { /** - * Actual header data + * Get the given header * - * @var array - */ - protected $data = array(); - - /** - * Check if the given header exists + * Unlike {@see self::getValues()}, this returns a string. If there are + * multiple values, it concatenates them with a comma as per RFC2616. * - * @param string $key - * @return boolean - */ - public function offsetExists($key) { - $key = strtolower($key); - return isset($this->data[$key]); - } - - /** - * Get the given header + * Avoid using this where commas may be used unquoted in values, such as + * Set-Cookie headers. * * @param string $key * @return string Header value */ public function offsetGet($key) { $key = strtolower($key); - return isset($this->data[$key]) ? $this->data[$key] : null; + if (!isset($this->data[$key])) + return null; + + return $this->flatten($this->data[$key]); } /** - * Set the given header + * Get all values for a given header * - * @throws Requests_Exception On attempting to use headers dictionary as list (`invalidset`) - * - * @param string $key Header name - * @param string $value Header value + * @param string $key + * @return array Header values */ - public function offsetSet($key, $value) { - if ($key === null) { - throw new Requests_Exception('Headers is a dictionary, not a list', 'invalidset'); - } - + public function getValues($key) { $key = strtolower($key); + if (!isset($this->data[$key])) + return null; - if (isset($this->data[$key])) { - // RFC2616 notes that multiple headers must be able to - // be combined like this. We should use a smarter way though (arrays - // internally, e.g.) - $value = $this->data[$key] . ',' . $value; - } - - $this->data[$key] = $value; + return $this->data[$key]; } /** - * Unset the given header + * Flattens a value into a string * - * @param string $key + * Converts an array into a string by imploding values with a comma, as per + * RFC2616's rules for folding headers. + * + * @param string|array $value Value to flatten + * @return string Flattened value */ - public function offsetUnset($key) { - unset($this->data[strtolower($key)]); + public function flatten($value) { + if (is_array($value)) + $value = implode(',', $value); + + return $value; } /** - * Get an interator for the data + * Get an iterator for the data * + * Converts the internal * @return ArrayIterator */ public function getIterator() { - return new ArrayIterator($this->data); - } - - /** - * Get the headers as an array - * - * @return array Header data - */ - public function getAll() { - return $this->data; + return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten')); } } diff --git a/library/Requests/Utility/CaseInsensitiveDictionary.php b/library/Requests/Utility/CaseInsensitiveDictionary.php new file mode 100644 index 000000000..a00dc6a62 --- /dev/null +++ b/library/Requests/Utility/CaseInsensitiveDictionary.php @@ -0,0 +1,96 @@ +data[$key]); + } + + /** + * Get the value for the item + * + * @param string $key Item key + * @return string Item value + */ + public function offsetGet($key) { + $key = strtolower($key); + if (!isset($this->data[$key])) + return null; + + return $this->data[$key]; + } + + /** + * Set the given item + * + * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) + * + * @param string $key Item name + * @param string $value Item value + */ + public function offsetSet($key, $value) { + if ($key === null) { + throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); + } + + $key = strtolower($key); + + if (!isset($this->data[$key])) { + $this->data[$key] = array(); + } + + $this->data[$key][] = $value; + } + + /** + * Unset the given header + * + * @param string $key + */ + public function offsetUnset($key) { + unset($this->data[strtolower($key)]); + } + + /** + * Get an iterator for the data + * + * @return ArrayIterator + */ + public function getIterator() { + return new ArrayIterator($this->data); + } + + /** + * Get the headers as an array + * + * @return array Header data + */ + public function getAll() { + return $this->data; + } +} diff --git a/library/Requests/Utility/FilteredIterator.php b/library/Requests/Utility/FilteredIterator.php new file mode 100644 index 000000000..41e2a3d32 --- /dev/null +++ b/library/Requests/Utility/FilteredIterator.php @@ -0,0 +1,38 @@ +callback = $callback; + } + + /** + * Get the current item's value after filtering + * + * @return string + */ + public function current() { + $value = parent::current(); + $value = call_user_func($this->callback, $value); + return $value; + } +}