Fixes DigestAuth with Sessions

Currently if you try to use digest auth with a bad username and password, you will enter a infinite loop of 401s. I think this is due to the handle_401 method overwriting the current registered hook, which in the context of #1106 is the correct behavior. This means that we can't just count the registered hooks. 

I added a counter to the request object, but am not sure if this fits with the way the rest of the library is structured since I am not too familiar with the rest of the codebase. If you have better idea of how this should be implemented, I'd be happy to do it!


Definitely don't store the counter on the Request, that feels really weird. Putting it on the function suits me fine, particularly because it makes it really hard for end users to find and try to use. =D


In Python 2.x I don't think you can directly set attributes on instance methods. I think the counter needs to be stored at instance level, since you could foresee having multiple sessions with with multiple HTTPDigestAuth instances and you don't want to counter to be shared. We could move the handle_401 into the init, eg:

``` python
class HTTPDigestAuth(AuthBase):
    """Attaches HTTP Digest Authentication to the given Request object."""
    def __init__(self, username, password):
        # ...
        def handle_401(self, r, _num_401_calls=[1]):
          # ...
            if 'digest' in s_auth.lower() and _num_401_calls[0] < 2:
              # ...
                _num_401_calls[0] = _num_401_calls[0] + 1
              # ...
        self.handle_401 = functools.partial(handle_401, self)
```

I'm not a huge fan of this syntax though.

My other thought was to derive the state at runtime by looking at the history on the request, but the history seems to be overwritten. But, maybe I'm interpreting what the contents of request.history should be incorrectly.


Andrew you can. I write primarily in 2.6 (which is the lowest requests bothers with) and test across most everything upwards. As such, I understand your concern between requests. If you want to reset the counter after receiving a 200 or on the second (or more) call to the handler, do this before returning `r` (not `_r`, the inner return statement): 

``` python

setattr(self.handle_401, 'num_401_calls', 1)
return r
```


Someone let me know when this is ready to merge :)


Hey Ian, I  tried implementing it the way you suggested yesterday (and double checked it this morning) and it raises an AttributeError on 2.7 (and 3.2):

```
File "../requests/auth.py", line 157, in handle_401
    setattr(self.handle_401, 'num_401_calls', num_401_calls + 1)
AttributeError: 'instancemethod' object has no attribute 'num_401_calls'
```

Maybe I've made some other typo, but I don't see it.

We could store the counter on the HTTPDigestAuth instance ie: `setattr(self, 'num_401_calls', num_401_calls + 1)`


@andrewjesaitis, I have to look up where I think I did this then, because I'm getting the same thing on 2.6. :/ Sorry for the confusion.

And yeah, placing it on the auth in the pattern I mentioned above would work. Inside the if-statement you increment it by one, outside you set it to 1. That way if the auth is passed around (say in a session) it won't have incorrect counts.


No problem. I thought I was going crazy for a second... Thanks for the help! 


@kennethreitz looks good to me. :+1:


:sparkles: @sigmavirus24 has spoken! :sparkles: