Skip to content
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

BUGFIX: Throw exception when passing objects to Headers::set() #1140

Conversation

bwaidelich
Copy link
Member

According to PSR-7 (http://www.php-fig.org/psr/psr-7/) HTTP headers
can only accept values of string or string[].

This adjusts our Headers implementation to throw an exception
if an object is passed to the set() method in order to make
error handling easier.

Exceptions prove the rule so we still do allow instances of
\DateTimeInterface to be set as header value.

According to PSR-7 (http://www.php-fig.org/psr/psr-7/) HTTP headers
can only accept values of `string` or `string[]`.

This adjusts our `Headers` implementation to throw an exception
if an object is passed to the `set()` method in order to make
error handling easier.

Exceptions prove the rule so we still do allow instances of
`\DateTimeInterface` to be set as header value.
@bwaidelich
Copy link
Member Author

See #1138 for the original approach to this

@bwaidelich
Copy link
Member Author

NOTE: Right now Headers::set() won't even accept values of type integer (or any other simple type other than string). I'm not sure if that's maybe too strict?

@kdambekalns
Copy link
Member

With \DateTimeInterface I think it's good to accept it (because it must be "cast" to string in a specific way. Anything else can be cast to string without trouble by the "user of the API", so… fine with me.

public function getPreparedValuesRendersOneHeaderPerArrayItem()
{
$headers = new Headers();
$headers->set('X-Array', ['some', 'array', 123]);
Copy link
Member

Choose a reason for hiding this comment

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

Well, the 123 violates the string[] declared in the docblock, and should be rejected as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

"Eagle Eye Karsten" ;)
You're right.. we need to check every array item for its type. mäh

Copy link
Member

Choose a reason for hiding this comment

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

Could be done with an elseif ($values !== array_filter( $values, 'is_string' )) check after the other type checks.

Copy link
Member

@albe albe left a comment

Choose a reason for hiding this comment

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

See comments.

@@ -110,8 +110,10 @@ public function set($name, $values, $replaceExistingHeader = true)
$date = clone $values;
$date->setTimezone(new \DateTimeZone('GMT'));
$values = [$date->format('D, d M Y H:i:s') . ' GMT'];
} else {
} elseif (is_string($values)) {
$values = (array) $values;
Copy link
Member

Choose a reason for hiding this comment

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

I have to say, I prefer the $values = [$values]; version better, because it is more explicit. I really had to check if (array) $string; would actually end up in an array with the single string item, or for some php-ish reasons create an array of characters or something else bizarre.

public function getPreparedValuesRendersOneHeaderPerArrayItem()
{
$headers = new Headers();
$headers->set('X-Array', ['some', 'array', 123]);
Copy link
Member

Choose a reason for hiding this comment

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

Could be done with an elseif ($values !== array_filter( $values, 'is_string' )) check after the other type checks.

@bwaidelich
Copy link
Member Author

@albe @kdambekalns Thanks a lot for your feedback and sorry for the long delay.. I just rebased this and incorporated your suggestions

@bwaidelich
Copy link
Member Author

And immediately I got bitten. By the StandardsComplianceComponent of all things, that sets the Content-Length to an integer..
I still think it would be a good idea to be strict here - at least starting with the next major

@@ -560,7 +560,7 @@ public function makeStandardsCompliantRemovesMaxAgeDireciveIfExpiresHeaderIsPres
public function makeStandardsCompliantReturns304ResponseIfResourceWasNotModified()
{
$modifiedSince = \DateTime::createFromFormat(DATE_RFC2822, 'Sun, 20 May 2012 12:00:00 GMT');
$lastModified = \DateTime::createFromFormat(DATE_RFC2822, 'Fr, 18 May 2012 12:00:00 GMT');
$lastModified = \DateTime::createFromFormat(DATE_RFC2822, 'Fri, 18 May 2012 12:00:00 GMT');
Copy link
Member Author

Choose a reason for hiding this comment

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

The change got bigger than I wanted it to be. But this one is a good example why it might be worth it:
$lastModified evalutated false because the given date was invalid. The test didn't actually test what it was supposed to test. It only failed because false is no longer allowed

@kitsunet
Copy link
Member

I will revisit this for next release but we need to get there anyway.

@albe
Copy link
Member

albe commented Apr 20, 2019

Probably related to #1552 so depending on how we implement PSR-7 (with or without our own Headers implementation), this might be relevant or obsolete. Linking here to not lose track.

@kitsunet
Copy link
Member

I guess this can be closed now....

@kitsunet kitsunet closed this Aug 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants