Skip to content

Streamed uploads fail against local httpbin #33

Description

@jkbrzt

Against the local httpbin It fails every time and the failuire has two flavours (see bellow).

Relevant: https://github.com/kennethreitz/requests/issues/2422

test.py

import sys
import requests


def stream():
    yield b'ham'
    yield b'spam'


def test_stream():
    r = requests.post('http://httpbin.org/post', data=stream())
    assert r.json()['data'] == 'hamspam'


def test_stream_local_httpbin(httpbin):
    r = requests.post(httpbin.url + '/post', data=stream())
    assert r.json()['data'] == 'hamspam'

body missing:

$ py.test test.py
===================================================== test session starts ======================================================
platform darwin -- Python 3.5.1, pytest-2.9.0, py-1.4.31, pluggy-0.3.1
rootdir: /private/tmp, inifile:
plugins: cov-2.2.1, httpbin-0.2.3
collected 2 items

test.py .F

=========================================================== FAILURES ===========================================================
__________________________________________________ test_stream_local_httpbin ___________________________________________________

httpbin = <Server(<class 'pytest_httpbin.serve.Server'>, started 123145309245440)>

    def test_stream_local_httpbin(httpbin):
        r = requests.post(httpbin.url + '/post', data=stream())
>       assert r.json()['data'] == 'hamspam'
E       assert '' == 'hamspam'
E         + hamspam

test.py:17: AssertionError
----------------------------------------------------- Captured stderr call -----------------------------------------------------
127.0.0.1 - - [07/Mar/2016 13:39:07] "POST /post HTTP/1.1" 200 389
============================================== 1 failed, 1 passed in 1.94 seconds ==============================================

requests.exceptions.ConnectionError: [Errno 32] Broken pipe:

$ py.test test.py
============================= test session starts =============================
platform darwin -- Python 3.5.1, pytest-2.9.0, py-1.4.31, pluggy-0.3.1
rootdir: /private/tmp, inifile:
plugins: cov-2.2.1, httpbin-0.2.3
collected 2 items

test.py .F

================================== FAILURES ===================================
__________________________ test_stream_local_httpbin __________________________

httpbin = <Server(<class 'pytest_httpbin.serve.Server'>, started 123145309245440)>

    def test_stream_local_httpbin(httpbin):
>       r = requests.post(httpbin.url + '/post', data=stream())

test.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Users/jakub/.virtualenvs/httpie/lib/python3.5/site-packages/requests/api.py:107: in post
    return request('post', url, data=data, json=json, **kwargs)
/Users/jakub/.virtualenvs/httpie/lib/python3.5/site-packages/requests/api.py:53: in request
    return session.request(method=method, url=url, **kwargs)
/Users/jakub/.virtualenvs/httpie/lib/python3.5/site-packages/requests/sessions.py:468: in request
    resp = self.send(prep, **send_kwargs)
/Users/jakub/.virtualenvs/httpie/lib/python3.5/site-packages/requests/sessions.py:576: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <requests.adapters.HTTPAdapter object at 0x103501eb8>
request = <PreparedRequest [POST]>, stream = False
timeout = <requests.packages.urllib3.util.timeout.Timeout object at 0x103521860>
verify = True, cert = None, proxies = OrderedDict()

    def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
        """Sends PreparedRequest object. Returns Response object.

            :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
            :param stream: (optional) Whether to stream the request content.
            :param timeout: (optional) How long to wait for the server to send
                data before giving up, as a float, or a :ref:`(connect timeout,
                read timeout) <timeouts>` tuple.
            :type timeout: float or tuple
            :param verify: (optional) Whether to verify SSL certificates.
            :param cert: (optional) Any user-provided SSL certificate to be trusted.
            :param proxies: (optional) The proxies dictionary to apply to the request.
            """

        conn = self.get_connection(request.url, proxies)

        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(request)

        chunked = not (request.body is None or 'Content-Length' in request.headers)

        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError as e:
                # this may raise a string formatting error.
                err = ("Invalid timeout {0}. Pass a (connect, read) "
                       "timeout tuple, or a single float to set "
                       "both timeouts to the same value".format(timeout))
                raise ValueError(err)
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)

        try:
            if not chunked:
                resp = conn.urlopen(
                    method=request.method,
                    url=url,
                    body=request.body,
                    headers=request.headers,
                    redirect=False,
                    assert_same_host=False,
                    preload_content=False,
                    decode_content=False,
                    retries=self.max_retries,
                    timeout=timeout
                )

            # Send the request.
            else:
                if hasattr(conn, 'proxy_pool'):
                    conn = conn.proxy_pool

                low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)

                try:
                    low_conn.putrequest(request.method,
                                        url,
                                        skip_accept_encoding=True)

                    for header, value in request.headers.items():
                        low_conn.putheader(header, value)

                    low_conn.endheaders()

                    for i in request.body:
                        low_conn.send(hex(len(i))[2:].encode('utf-8'))
                        low_conn.send(b'\r\n')
                        low_conn.send(i)
                        low_conn.send(b'\r\n')
                    low_conn.send(b'0\r\n\r\n')

                    # Receive the response from the server
                    try:
                        # For Python 2.7+ versions, use buffering of HTTP
                        # responses
                        r = low_conn.getresponse(buffering=True)
                    except TypeError:
                        # For compatibility with Python 2.6 versions and back
                        r = low_conn.getresponse()

                    resp = HTTPResponse.from_httplib(
                        r,
                        pool=conn,
                        connection=low_conn,
                        preload_content=False,
                        decode_content=False
                    )
                except Exception as e:
                    # If we hit any problems here, clean up the connection.
                    # Then, reraise so that we can handle the actual exception.
                    low_conn.close()
                    raise

        except (ProtocolError, socket.error) as err:
>           raise ConnectionError(err, request=request)
E           requests.exceptions.ConnectionError: [Errno 32] Broken pipe

/Users/jakub/.virtualenvs/httpie/lib/python3.5/site-packages/requests/adapters.py:426: ConnectionError
---------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Mar/2016 13:36:28] "POST /post HTTP/1.1" 200 389
===================== 1 failed, 1 passed in 2.10 seconds ======================

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions