Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Session.request doesn't have parameter return_response, contrary to what the docs say. #1280

Closed
KamilSzot opened this Issue · 19 comments

4 participants

Kamil Szot Tim Sampson Ian Cordasco Cory Benfield
Kamil Szot
def request(self, method, url,
    params=None,
    data=None,
    headers=None,
    cookies=None,
    files=None,
    auth=None,
    timeout=None,
    allow_redirects=True,
    proxies=None,
    hooks=None,
    stream=None,
    verify=None,
    cert=None):
    """Constructs a :class:`Request <Request>`, prepares it and sends it.
    Returns :class:`Response <Response>` object.

    :param method: method for the new :class:`Request` object.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary or bytes to be sent in the query
        string for the :class:`Request`.
    :param data: (optional) Dictionary or bytes to send in the body of the
        :class:`Request`.
    :param headers: (optional) Dictionary of HTTP Headers to send with the
        :class:`Request`.
    :param cookies: (optional) Dict or CookieJar object to send with the
        :class:`Request`.
    :param files: (optional) Dictionary of 'filename': file-like-objects
        for multipart encoding upload.
    :param auth: (optional) Auth tuple or callable to enable
        Basic/Digest/Custom HTTP Auth.
    :param timeout: (optional) Float describing the timeout of the
        request.
    :param allow_redirects: (optional) Boolean. Set to True by default.
    :param proxies: (optional) Dictionary mapping protocol to the URL of
        the proxy.
    :param return_response: (optional) If False, an un-sent Request object
        will returned.
    :param config: (optional) A configuration dictionary. See
        ``request.defaults`` for allowed keys and their default values.
    :param prefetch: (optional) whether to immediately download the response
        content. Defaults to ``True``.
    :param verify: (optional) if ``True``, the SSL cert will be verified.
        A CA_BUNDLE path can also be provided.
    :param cert: (optional) if String, path to ssl client cert file (.pem).
        If Tuple, ('cert', 'key') pair.
    """
Tim Sampson

Or config and presumably prefetch=> stream also. So basically it seems like the docstring hasn't been updated from pre 1.0 times

Ian Cordasco
Collaborator

This is my fault. I'll fix it

Kamil Szot

So you won't reintroduce this behavior? Could you suggest what should I do instead to achieve same thing?

Namely, I want to create request in session and inspect it and tamper with it before sending it.

I need to add to headers of the request crystallographic signature of the body of the request before sending it.

Ian Cordasco
Collaborator

I thought we had documented this, but I guess we either haven't or haven't made it prominent enough

from requests import Request, Session

unprepped = Request('GET', url, data='etc', 
         #...
)

prepared = unprepped.prepare()
sig = crystallographic_sig(prepared.body)
prepared.headers['Cystallographic-Signature'] = sig  # clearly I don't know which header key is correct, I'm just guessing
s = Session()
resp = s.send(prepared)

You can send other parameters to Session#send like you do to Session#request like stream, verify, cert, etc.

Kamil Szot

Ok. But I had made some requests previously in this session that set some cookies that I wan't to send with this new signed request.

I guess I just have to pass them manually to Request.

Ian Cordasco
Collaborator

I only created a new Session for the completeness of the example. You don't have to make a new session and if you made the rest of the requests with one session the cookies are stored on it and will be used when you call Session#send.

Kamil Szot

So you are saying that:

s = Session()
s.request('http://..')  # sets some cookies

req = Request('GET', 'http://...', ...).prepare()
s.send(req)  # cookies previously set in the session get passed along with this request
Ian Cordasco
Collaborator
Kamil Szot

From source of Session.send doesn't look like it could work. I'll try to verify that it works.

Ian Cordasco
Collaborator
Kamil Szot

I'm using the one cloned from here.

And I confirmed that this doens't work:

# -*- coding: utf-8 -*-
import requests


s = requests.Session()
s.get("http://localhost/index.php")

req = requests.Request("GET", "http://localhost/index2.php").prepare()

print s.send(req).text

index.php sets cookie, and index2.php outputs it

This works:

# -*- coding: utf-8 -*-
import requests


s = requests.Session()
s.get("http://localhost/index.php")

req = requests.Request("GET", "http://localhost/index2.php", cookies = s.cookies).prepare()

print s.send(req).text

And this works too:

# -*- coding: utf-8 -*-
import requests


s = requests.Session()
s.get("http://localhost/index.php")

print s.get("http://localhost/index2.php").text
Ian Cordasco
Collaborator

Eh, that's actually wrong. I thought someone sent a pull request to that effect but I must be remembering something else. Regardless if you session is s then when you create the Request object just pass in cookies=s.cookies.

Kamil Szot

... and all the other things that Session keeps track of.

Kamil Szot

I think that having method that creates request in session but doesn't send it just yet might be beneficial. Anyway, thank you for your help and for the great stuff you all build.

Ian Cordasco
Collaborator

It's been proposed and shot down already. Although with this, I'm (personally) starting to warm up to it.

Cory Benfield
Collaborator

The Requests-y way of doing this is to use my favourite toy, the all-powerful Transport Adapter. Observe.

from requests.adapters import HTTPAdapter

class CrystalAdapter(HTTPAdapter):
    '''
    A transport adapter that automatically applies the Crystallographic 
    signature to any request passing through it.
    '''
    def send(self, request, **kwargs):
        signature = do_crystallographic_stuff(request.body)
        request.headers['Crystallographic-Signature'] = signature

        return super(CrystalAdapter, self).send(request, **kwargs)

Then, do this:

>>> import requests
>>> from my.awesome.lib import CrystalAdapter

>>> s = requests.Session()
>>> s.mount('http://mysite.com/', CrystalAdapter())
>>> r = s.post('http://mysite.com/testytesty', data={'some': 'data'})
>>> r.request.headers['Crystallographic-Signature']
'whatever string belongs here'

This gets you a few benefits. Firstly, you can ensure that only requests going to a specific site get the signature attached. Second, you guarantee that you're signing the data on the wire, nothing else. Third, it's very object-oriented, which is always nice. =)

Kamil Szot

Awesome. But I don't think there are any examples of using adapters in the docs.

Cory Benfield
Collaborator

There aren't, but I've written one up on my blog here, and a more complicated one here. Could write another, more general one if there's interest.

Ian Cordasco
Collaborator

This is a valid report. The doc-string on Session#request is wrong. I have PR in to fix it though.

Ian Cordasco sigmavirus24 closed this issue from a commit
Ian Cordasco sigmavirus24 Closes #1280
Correct the doc-string for Session#request that I copied without thinking
about.
1abd137
meganemura meganemura referenced this issue from a commit in meganemura/requests
Kamil Szot KamilSzot Fix for the issue kennethreitz#1280 ca0aea6
meganemura meganemura referenced this issue from a commit in meganemura/requests
Kenneth Reitz Revert "Fix for the issue kennethreitz#1280"
This reverts commit ca0aea6.
54ed5ed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.