Skip to content

Commit

Permalink
Basic matching works. Except for priorization
Browse files Browse the repository at this point in the history
  • Loading branch information
Freeaqingme committed Jun 16, 2012
1 parent 4c1bad4 commit 0db935b
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 175 deletions.
166 changes: 89 additions & 77 deletions library/Zend/Http/Header/AbstractAccept.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,38 +49,36 @@ public static function fromString($headerLine)
{
$acceptHeader = new static();

if (!strpos($headerLine, ': ')) {
throw new Exception\InvalidArgumentException(
'Invalid header line for ' . $acceptHeader->getFieldName() . ' header string'
);
$fieldName = $acceptHeader->getFieldName();
$pos = strlen($fieldName)+2;
if (substr($headerLine, 0, $pos) == $fieldName . ': ') {
$headerLine = substr($headerLine, $pos);
}

list($name, $values) = explode(': ', $headerLine, 2);
$acceptHeader->values = $acceptHeader->getPayloadsFromHeaderLine($headerLine);

// check to ensure proper header type for this factory
if (strtolower($name) !== strtolower($acceptHeader->getFieldName())) {
throw new Exception\InvalidArgumentException(
'Invalid header line for ' . $acceptHeader->getFieldName() . ' header string'
);
}
return $acceptHeader;
}

public function getPayloadsFromHeaderLine($headerLine)
{
// process multiple accept values, they may be between quotes
if (!preg_match_all('/(?:[^,"]|"(?:[^\\\"]|\\\.)*")+/', $values, $values)
|| !isset($values[0])
if (!preg_match_all('/(?:[^,"]|"(?:[^\\\"]|\\\.)*")+/', $headerLine, $values)
|| !isset($values[0])
) {
throw new Exception\InvalidArgumentException(
'Invalid header line for ' . $acceptHeader->getFieldName() . ' header string'
'Invalid header line for ' . $this->getFieldName() . ' header string'
);
}

$out = array();
foreach ($values[0] as $value) {
$value = trim($value);

$payload = $acceptHeader->getPayloadValuesFromString($value);
$acceptHeader->values[] = $payload;
$out[] = $this->getPayloadValuesFromString($value);
}

return $acceptHeader;
return $out;
}

protected function getPayloadValuesFromString($mediaType)
Expand Down Expand Up @@ -172,7 +170,7 @@ protected function getFieldValueInternal(array $values)
foreach ($values as $value) {
$params = $value->params;
array_walk($params, array($this, 'assembleFieldValueParam'));
$strings[] = $value->typeString . ';'.implode(';', $params);
$strings[] = implode(';', array($value->typeString) + $params);
}

return implode(', ', $strings);
Expand Down Expand Up @@ -213,7 +211,7 @@ function($v) { return '\\' . $v[0]; },
* @param int $level
* @return Accept
*/
protected function addType($type, $priority = 1, $level = null)
protected function addType($type, $priority = 1, array $params = array())
{
if (!preg_match($this->regexAddType, $type)) {
throw new Exception\InvalidArgumentException(sprintf(
Expand All @@ -223,93 +221,107 @@ protected function addType($type, $priority = 1, $level = null)
));
}

if (!is_int($priority) && !is_float($priority) && !is_numeric($priority)) {
if (!is_int($priority) && !is_float($priority) && !is_numeric($priority)
|| $priority > 1 || $priority < 0
) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a numeric priority; received %s',
__METHOD__,
(string) $priority
));
}

if ($priority > 1 || $priority < 0) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a priority between 0 and 1; received %01.1f',
__METHOD__,
(float) $priority
));
}

if (!empty($level) && (!is_numeric($level) || $level < 0)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an integer level greater than 0; received %s',
__METHOD__,
$level
));
if ($priority != 1) {
$params = array('q' => sprintf('%01.1f', $priority)) + $params;
}

$this->types[$type] = true;

if (!empty($level)) {
$this->prioritizedValues[] = array(
'type' => $type,
'priority' => $priority,
'level' => (integer) $level
);
} else {
$this->prioritizedValues[] = array(
'type' => $type,
'priority' => $priority
);
}

$value = $type;
if (!empty($level)) {
$value .= sprintf(';level=%d', $level);
}
if ($priority < 1) {
$value .= sprintf(';q=%01.1f', $priority);
}
$this->values[] = $value;
$assembledString = $this->getFieldValueInternal(
array((object)array('typeString' => $type, 'params' => $params))
);

$this->values[] = $this->getPayloadValuesFromString($assembledString);
return $this;
}



/**
* Does the header have the requested type?
*
* @param string $type
* @return bool
*/
protected function hasType($type)
protected function hasType($matchAgainst)
{
$type = strtolower($type);
return (bool) $this->match($matchAgainst);
}

// Exact match
if (isset($this->types[$type])) {
return true;
public function match($matchAgainst)
{
if (is_string($matchAgainst)) {
$matchAgainst = $this->getPayloadsFromHeaderLine($matchAgainst);
}

// Check for media type
if (false !== strstr($type, '/')) {
// Parent type wildcard matching
$parent = substr($type, 0, strpos($type, '/'));
if (isset($this->types[$parent . '/*'])) {
return true;
}
foreach ($matchAgainst as $left) {
foreach ($this->values as $right) {
if($right->type == '*' || $left->type == '*') {
if ($res = $this->_matchParams($left, $right)) {
return $res;
}
}

if ($left->type == $right->type) {
if ((($left->subtype == $right->subtype ||
($right->subtype == '*' || $left->subtype == '*')) &&
($left->format == $right->format ||
$right->format == '*' || $left->format == '*')))
{
if ($res = $this->_matchParams($right, $left)) {
return $res;
}
}
}

// Wildcard matching
if (isset($this->types['*/*'])) {
return true;
}
} else {
if (isset($this->types['*'])) {
return true;
}
}
// No match

return false;
}

protected function _matchParams($match1, $match2)
{
foreach($match2->params as $key => $value) {
if (isset($match1->params[$key])) {
if (strpos($value, '-')) {
$values = explode('-', $value, 2);
if($values[0] > $match1->params[$key] ||
$values[1] < $match1->params[$key])
{
return false;
}
} elseif (strpos($value, '|')) {
$options = explode('|', $value);
$good = false;
foreach($options as $option) {
if($option == $match1->params[$key]) {
$good = true;
break;
}
}

if (!$good) {
return false;
}
} elseif($match1->params[$key] != $value) {
return false;
}
}

}

return $match1;
}

/**
* Get a prioritized list of types
*
Expand Down
22 changes: 11 additions & 11 deletions library/Zend/Http/Header/Accept.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
class Accept extends AbstractAccept
{
protected $regexAddType = '#^([a-zA-Z+-]+|\*)/(\*|[a-zA-Z0-9+-]+)$#';

/**
* Get field name
*
*
* @return string
*/
public function getFieldName()
Expand All @@ -44,7 +44,7 @@ public function getFieldName()

/**
* Cast to string
*
*
* @return string
*/
public function toString()
Expand All @@ -54,21 +54,21 @@ public function toString()

/**
* Add a media type, with the given priority
*
* @param string $type
* @param int|float $priority
* @param int $level
*
* @param string $type
* @param int|float $priority
* @param int $level
* @return Accept
*/
public function addMediaType($type, $priority = 1, $level = null)
public function addMediaType($type, $priority = 1, array $params = array())
{
return $this->addType($type, $priority, $level);
return $this->addType($type, $priority, $params);
}

/**
* Does the header have the requested media type?
*
* @param string $type
*
* @param string $type
* @return bool
*/
public function hasMediaType($type)
Expand Down
Loading

0 comments on commit 0db935b

Please sign in to comment.