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

file mode validation cannot be implemented according to PSR-17 #42

Merged
merged 2 commits into from
Jun 26, 2019
Merged

Conversation

Tobion
Copy link
Contributor

@Tobion Tobion commented Jun 6, 2019

the psr-17 spec requires to have different exceptions for invalid modes and other file opening errors:

@throws \RuntimeException If the file cannot be opened.
@throws \InvalidArgumentException If the mode is invalid.

How is it expected to be implemented? I can't figure out a way to implement this because the accepted modes depend on the OS. And the error message that are returned also depend on the OS. See https://github.com/guzzle/psr7/pull/274/files#r291236165
On travis for example it say No such file or directory although the mode is wrong. So we cannot distinguish between wrong mode or a different failure unless we hardcode the modes. But that would be pointless and would also be against the PSR-17 spec which says it must accept anything that fopen can accept. So it can't be hardcoded.
Diactoros also does not seem to implement this behavior. So did anybody find a solution or is the spec not implementable?

Response from Woody Gilk

yeah that is really bad on our part, i think you should just ignore InvalidArgumentException and only deal with RuntimeException the InvalidArgumentException was intended for packages that want to validate the mode
for instance, if a StreamFactory only wanted to support readable streams, it has the option to throw InvalidArgumentException for any mode that is not $mode = 'r'

Tobion added 2 commits June 6, 2019 17:49
the psr-17 spec requires to have different exceptions for invalid modes and other file opening errors:
```
@throws \RuntimeException If the file cannot be opened.
@throws \InvalidArgumentException If the mode is invalid.
```

How is it expected to be implemented? I can't figure out a way to implement this because the accepted modes depend on the OS. And the error message that are returned also depend on the OS. See https://github.com/guzzle/psr7/pull/274/files#r291236165
On travis for example it say `No such file or directory` although the mode is wrong. So we cannot distinguish between wrong mode or a different failure unless we hardcode the modes. But that would be pointless and would also be against the PSR-17 spec which says it must accept anything that `fopen` can accept. So it can't be hardcoded.
Diactoros also does not seem to implement this behavior. So did anybody find a solution or is the spec not implementable?

Response from Woody Gilk

> yeah that is really bad on our part, i think you should just ignore `InvalidArgumentException` and only deal with `RuntimeException` the `InvalidArgumentException` was intended for packages that *want* to validate the mode
> for instance, if a StreamFactory only wanted to support readable streams, it has the option to throw `InvalidArgumentException` for any mode that is not `$mode = 'r'`
@Zegnat
Copy link
Contributor

Zegnat commented Jun 8, 2019

So we cannot distinguish between wrong mode or a different failure unless we hardcode the modes. But that would be pointless and would also be against the PSR-17 spec which says it must accept anything that fopen can accept. So it can't be hardcoded.

It can specifically be hard-coded, because that is exactly what PHP does. They do a very straight-forward check on modes, and also seem to do this without caring about the filesystem it is running on:

	switch (mode[0]) {
		case 'r':
			flags = 0;
			break;
		case 'w':
			flags = O_TRUNC|O_CREAT;
			break;
		case 'a':
			flags = O_CREAT|O_APPEND;
			break;
		case 'x':
			flags = O_CREAT|O_EXCL;
			break;
		case 'c':
			flags = O_CREAT;
			break;
		default:
			/* unknown mode */
			return FAILURE;
	}

If your PSR-17 implementation uses fopen() to implement StreamFactoryInterface::createStreamFromFile you know exactly what modes PHP will support, and you can throw the exception for all others. I implemented this for Nyholm/psr7 as follows:

        $resource = @\fopen($filename, $mode);
        if (false === $resource) {
            if (0 === \strlen($mode) || false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'])) {
                throw new \InvalidArgumentException('The mode '.$mode.' is invalid.');
            }

Of course if your implementation is not using fopen() you will need a different check. The interface isn’t really clear on whether different implementations may support different modes.

I am open for comments as to why this would not be a solution. But I fully believe the spec to be implementable as I did for Nyholm/psr7. As such, I would be against this proposed change to the tests.

Tobion added a commit to guzzle/psr7 that referenced this pull request Jun 9, 2019
@Tobion
Copy link
Contributor Author

Tobion commented Jun 9, 2019

@Zegnat thanks for the pointer. I've used your suggestion to make Guzzle pass the tests.

But I don't think it's a good idea to require PSR-17 implementation to basically depend on an implementation detail in PHP. Either the spec is self-contained and lists the valid modes itself, or it forwards to php fopen but then shouldn't require validation in the spec.
What I also don't get is why PHP has this code: https://github.com/php/php-src/blob/18e4b4bd44298e78a5b558f1331d14c78b5a7de9/main/streams/plain_wrapper.c#L1015
But invalid modes don't actually trigger this warning in PHP userland code. This would definitely help debugging.

@shadowhand shadowhand merged commit 92d8b91 into http-interop:master Jun 26, 2019
@shadowhand
Copy link
Collaborator

I left this PR open for several days to allow for additional comments. None received, so I am merging.

Thanks @Tobion .

@shadowhand
Copy link
Collaborator

Released in version 0.6.0.

@Tobion Tobion deleted the patch-1 branch June 26, 2019 17:56
tuupola added a commit to tuupola/http-factory that referenced this pull request Aug 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants