Cookies not persisted when set via functional API.

Cookies set as part of a call to `Session.request()` (or any of the top level methods that call it) are _not_ persisted, including on redirects.

Expected behaviour:

``` python
>>> s = requests.Session()
>>> r = s.get('http://httpbin.org/redirect/1', cookies={'Hi': 'There'})
>>> print r.request.headers['Cookie']
'hi=there'
```

Actual behaviour:

``` python
>>> s = requests.Session()
>>> r = s.get('http://httpbin.org/redirect/1', cookies={'Hi': 'There'})
>>> print r.request.headers['Cookie']
KeyError: 'cookie'
```

And, a super extra bonus bug:

``` python
>>> r.history[0].request.headers['Cookie']
KeyError: 'cookie'
```

even though we definitely sent the cookie on the first request.


In the hope of getting more contributors, I'm going to leave my diagnosis of the bug up here for a little while before I take a pass at fixing it.

The specific problem in this bug is that we don't add cookies on a prepared request to the Session unless they were set by the server. There are three possible scopes for this fix:
1. Only fix up the occurrences of this bug in the top-level functions, e.g `requests.request()`. This _must_ be fixed, because otherwise cookies are stupid for these functions. The logic behind this restriction is that if you want cookies on all requests in a session, you should set them on the `Session` object.
2. Add all cookies set through the functional API to the correct `Session` object. It's not entirely clear that this is the right thing to do: these cookies should probably have been set on the `Session`.
3. Do something 'magic' for redirects.

As for the super-extra bonus bug, the offending lines of code are these in `SessionRedirectMixin.resolve_redirects()`:

``` python
headers = prepared_request.headers
try:
    del headers['Cookie']
except KeyError:
    pass
```

combined with the implementation of `PreparedRequest.copy()`:

``` python
def copy(self):
    p = PreparedRequest()
    p.method = self.method
    p.url = self.url
    p.headers = self.headers
    p.body = self.body
    p.hooks = self.hooks
    return p
```

Nice little teachable lesson about python's mutable data structures right there.


@Lukasa I will try on it.
I think implementing deepcopy of models.PreparedRequest and call req.deepcopy() instead of req.copy() will fix super extra bonus bug easily. Is there any expectable drawback of using deepcopy?


@daftshady It's unnecessary. =) `PreparedRequest.copy()` should just make sure it calls `req.headers.copy()` to get the new head dict. =)


@Lukasa It' s strange.. I think even if PreparedRequest.copy creates new object, as you know,  assignment like this (p.headers = self.headers) only make shallow copy of CaseInsensitiveDict. so the change in new `p` created by copy() can affect origin so that extra bonus bug happens.
Anyway, i will try another way to fix it if you think deepcopy is not suitable =)


Assignment like that does not make a shallow copy. =) It doesn't make a copy at all, instead both names point to the same object. That's why `CaseInsensitiveDict.copy()` is enough: it returns a new object which is a shallow copy of the original dictionary.

To try to clear this up, observe the following:

``` python
# Create two dictionaries.
>>> a = {'first': 'dict'}
>>> b = {'second': 'dict'}

# Assign C to A using equals, create D using copy().
>>> c = a
>>> d = b.copy()

# Observe that A and C are the same objects, while B and D are not.
>>> a is c
True
>>> b is d
False

# This means that any change that affects A will also affect C. This is our bonus bug.
>>> a['third'] = 'value'
>>> a
{'third': 'value', 'first': 'dict'}
>>> c
{'third': 'value', 'first': 'dict'}

# But changes that affect B do not affect D.
>>> b['fourth'] = 'value'
>>> b
{'second': 'dict', 'fourth': 'value'
>>> d
{'second': 'dict'}
```


@Lukasa I understand. I misunderstood that you are saying 'p.headers = self.headers' is just enough.
As you said, `CaseInsensitiveDict.copy()` works correctly. So just fixing it to 'p.headers = self.headers.copy() is enough, not deepcopy.

In your example, if

> > > b = {'first' : [1,2,3]}
> > > d = b.copy()
> > > b is d
> > > False
> > > b['first'].append(4)
> > > b
> > > {'first' : [1,2,3,4]}
> > > d
> > > {'first' : [1,2,3,4]}
> > > Changes that affect B can affect D in this case.

But, as you said, `CaseInsensitiveDict.copy()` is just enough to fix extra bonus bug.
Sorry for my carelessness =)


Not a problem. =D Glad we're on the same page.