gabrielfalcao / HTTPretty

Intercept HTTP requests at the Python socket level. Fakes the whole socket module

Home Page:https://httpretty.readthedocs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incompatibility with boto3 S3 put_object

daveygit2050 opened this issue · comments

I'm trying to use httpretty to simulate attempting to put an object in an S3 bucket without having appropriate permissions to do so.

Here is a truncated version of what I'm doing:

import boto3
import httpretty

httpretty.enable()
httpretty.register_uri(
    httpretty.PUT,
    "https://foo-bucket.s3.amazonaws.com/foo-object",
    body="""<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>foo</RequestId>
    <HostId>foo</HostId>
</Error>""",
    status=403
)

session = boto3.Session(aws_access_key_id="foo", aws_secret_access_key="foo")
s3_client = session.client('s3')
s3_client.put_object(Bucket="foo-bucket", Key="foo-object", Body=b"foo")

Expected result
The code should raise a botocore.exceptions.ClientError exception.

Actual result
The code raises ValueError: flush of closed file. Full traceback:

Traceback (most recent call last):
  File "/home/dave/.cache/pypoetry/virtualenvs/bucket-dir-yXDMZxoY-py3.7/lib/python3.7/site-packages/botocore/httpsession.py", line 323, in send
    chunked=self._chunked(request.headers),
  File "/home/dave/.cache/pypoetry/virtualenvs/bucket-dir-yXDMZxoY-py3.7/lib/python3.7/site-packages/urllib3/connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "/home/dave/.cache/pypoetry/virtualenvs/bucket-dir-yXDMZxoY-py3.7/lib/python3.7/site-packages/urllib3/connectionpool.py", line 445, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
  File "/home/dave/.cache/pypoetry/virtualenvs/bucket-dir-yXDMZxoY-py3.7/lib/python3.7/site-packages/urllib3/connectionpool.py", line 440, in _make_request
    httplib_response = conn.getresponse()
  File "/home/dave/git/helpers/pyenv/versions/3.7.4/lib/python3.7/http/client.py", line 1352, in getresponse
    response.close()
  File "/home/dave/git/helpers/pyenv/versions/3.7.4/lib/python3.7/http/client.py", line 415, in close
    super().close() # set "closed" flag
  File "/home/dave/git/helpers/pyenv/versions/3.7.4/lib/python3.7/http/client.py", line 428, in flush
    self.fp.flush()
ValueError: flush of closed file

My assumption is that botocore is attempting to flush the socket, but httpretty has already closed it.

Note: It's possible to workaround this problem by registering a 100 response before the 403 response, but this does not accurateively represent the actual behaviour of interacting the S3 API.

@daveygit2050 thanks for reporting this and already providing such neat snippet, I'll copy it into a functional test and try to fix the issue soon.