1# -*- coding: utf-8 -*-
2
3"""
4requests.models
5~~~~~~~~~~~~~~~
6
7This module contains the primary objects that power Requests.
8"""
9
10import collections
11import datetime
12
13from io import BytesIO, UnsupportedOperation
14from .hooks import default_hooks
15from .structures import CaseInsensitiveDict
16
17from .auth import HTTPBasicAuth
18from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar
19from .packages.urllib3.fields import RequestField
20from .packages.urllib3.filepost import encode_multipart_formdata
21from .packages.urllib3.util import parse_url
22from .packages.urllib3.exceptions import (
23    DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
24from .exceptions import (
25    HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
26    ContentDecodingError, ConnectionError, StreamConsumedError)
27from .utils import (
28    guess_filename, get_auth_from_url, requote_uri,
29    stream_decode_response_unicode, to_key_val_list, parse_header_links,
30    iter_slices, guess_json_utf, super_len, to_native_string)
31from .compat import (
32    cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
33    is_py2, chardet, builtin_str, basestring)
34from .compat import json as complexjson
35from .status_codes import codes
36
37#: The set of HTTP status codes that indicate an automatically
38#: processable redirect.
39REDIRECT_STATI = (
40    codes.moved,              # 301
41    codes.found,              # 302
42    codes.other,              # 303
43    codes.temporary_redirect, # 307
44    codes.permanent_redirect, # 308
45)
46
47DEFAULT_REDIRECT_LIMIT = 30
48CONTENT_CHUNK_SIZE = 10 * 1024
49ITER_CHUNK_SIZE = 512
50
51
52class RequestEncodingMixin(object):
53    @property
54    def path_url(self):
55        """Build the path URL to use."""
56
57        url = []
58
59        p = urlsplit(self.url)
60
61        path = p.path
62        if not path:
63            path = '/'
64
65        url.append(path)
66
67        query = p.query
68        if query:
69            url.append('?')
70            url.append(query)
71
72        return ''.join(url)
73
74    @staticmethod
75    def _encode_params(data):
76        """Encode parameters in a piece of data.
77
78        Will successfully encode parameters when passed as a dict or a list of
79        2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
80        if parameters are supplied as a dict.
81        """
82
83        if isinstance(data, (str, bytes)):
84            return data
85        elif hasattr(data, 'read'):
86            return data
87        elif hasattr(data, '__iter__'):
88            result = []
89            for k, vs in to_key_val_list(data):
90                if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
91                    vs = [vs]
92                for v in vs:
93                    if v is not None:
94                        result.append(
95                            (k.encode('utf-8') if isinstance(k, str) else k,
96                             v.encode('utf-8') if isinstance(v, str) else v))
97            return urlencode(result, doseq=True)
98        else:
99            return data
100
101    @staticmethod
102    def _encode_files(files, data):
103        """Build the body for a multipart/form-data request.
104
105        Will successfully encode files when passed as a dict or a list of
106        2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
107        if parameters are supplied as a dict.
108
109        """
110        if (not files):
111            raise ValueError("Files must be provided.")
112        elif isinstance(data, basestring):
113            raise ValueError("Data must not be a string.")
114
115        new_fields = []
116        fields = to_key_val_list(data or {})
117        files = to_key_val_list(files or {})
118
119        for field, val in fields:
120            if isinstance(val, basestring) or not hasattr(val, '__iter__'):
121                val = [val]
122            for v in val:
123                if v is not None:
124                    # Don't call str() on bytestrings: in Py3 it all goes wrong.
125                    if not isinstance(v, bytes):
126                        v = str(v)
127
128                    new_fields.append(
129                        (field.decode('utf-8') if isinstance(field, bytes) else field,
130                         v.encode('utf-8') if isinstance(v, str) else v))
131
132        for (k, v) in files:
133            # support for explicit filename
134            ft = None
135            fh = None
136            if isinstance(v, (tuple, list)):
137                if len(v) == 2:
138                    fn, fp = v
139                elif len(v) == 3:
140                    fn, fp, ft = v
141                else:
142                    fn, fp, ft, fh = v
143            else:
144                fn = guess_filename(v) or k
145                fp = v
146
147            if isinstance(fp, (str, bytes, bytearray)):
148                fdata = fp
149            else:
150                fdata = fp.read()
151
152            rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
153            rf.make_multipart(content_type=ft)
154            new_fields.append(rf)
155
156        body, content_type = encode_multipart_formdata(new_fields)
157
158        return body, content_type
159
160
161class RequestHooksMixin(object):
162    def register_hook(self, event, hook):
163        """Properly register a hook."""
164
165        if event not in self.hooks:
166            raise ValueError('Unsupported event specified, with event name "%s"' % (event))
167
168        if isinstance(hook, collections.Callable):
169            self.hooks[event].append(hook)
170        elif hasattr(hook, '__iter__'):
171            self.hooks[event].extend(h for h in hook if isinstance(h, collections.Callable))
172
173    def deregister_hook(self, event, hook):
174        """Deregister a previously registered hook.
175        Returns True if the hook existed, False if not.
176        """
177
178        try:
179            self.hooks[event].remove(hook)
180            return True
181        except ValueError:
182            return False
183
184
185class Request(RequestHooksMixin):
186    """A user-created :class:`Request <Request>` object.
187
188    Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server.
189
190    :param method: HTTP method to use.
191    :param url: URL to send.
192    :param headers: dictionary of headers to send.
193    :param files: dictionary of {filename: fileobject} files to multipart upload.
194    :param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
195    :param json: json for the body to attach to the request (if files or data is not specified).
196    :param params: dictionary of URL parameters to append to the URL.
197    :param auth: Auth handler or (user, pass) tuple.
198    :param cookies: dictionary or CookieJar of cookies to attach to this request.
199    :param hooks: dictionary of callback hooks, for internal usage.
200
201    Usage::
202
203      >>> import requests
204      >>> req = requests.Request('GET', 'http://httpbin.org/get')
205      >>> req.prepare()
206      <PreparedRequest [GET]>
207
208    """
209    def __init__(self, method=None, url=None, headers=None, files=None,
210        data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
211
212        # Default empty dicts for dict params.
213        data = [] if data is None else data
214        files = [] if files is None else files
215        headers = {} if headers is None else headers
216        params = {} if params is None else params
217        hooks = {} if hooks is None else hooks
218
219        self.hooks = default_hooks()
220        for (k, v) in list(hooks.items()):
221            self.register_hook(event=k, hook=v)
222
223        self.method = method
224        self.url = url
225        self.headers = headers
226        self.files = files
227        self.data = data
228        self.json = json
229        self.params = params
230        self.auth = auth
231        self.cookies = cookies
232
233    def __repr__(self):
234        return '<Request [%s]>' % (self.method)
235
236    def prepare(self):
237        """Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it."""
238        p = PreparedRequest()
239        p.prepare(
240            method=self.method,
241            url=self.url,
242            headers=self.headers,
243            files=self.files,
244            data=self.data,
245            json=self.json,
246            params=self.params,
247            auth=self.auth,
248            cookies=self.cookies,
249            hooks=self.hooks,
250        )
251        return p
252
253
254class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
255    """The fully mutable :class:`PreparedRequest <PreparedRequest>` object,
256    containing the exact bytes that will be sent to the server.
257
258    Generated from either a :class:`Request <Request>` object or manually.
259
260    Usage::
261
262      >>> import requests
263      >>> req = requests.Request('GET', 'http://httpbin.org/get')
264      >>> r = req.prepare()
265      <PreparedRequest [GET]>
266
267      >>> s = requests.Session()
268      >>> s.send(r)
269      <Response [200]>
270
271    """
272
273    def __init__(self):
274        #: HTTP verb to send to the server.
275        self.method = None
276        #: HTTP URL to send the request to.
277        self.url = None
278        #: dictionary of HTTP headers.
279        self.headers = None
280        # The `CookieJar` used to create the Cookie header will be stored here
281        # after prepare_cookies is called
282        self._cookies = None
283        #: request body to send to the server.
284        self.body = None
285        #: dictionary of callback hooks, for internal usage.
286        self.hooks = default_hooks()
287
288    def prepare(self, method=None, url=None, headers=None, files=None,
289        data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
290        """Prepares the entire request with the given parameters."""
291
292        self.prepare_method(method)
293        self.prepare_url(url, params)
294        self.prepare_headers(headers)
295        self.prepare_cookies(cookies)
296        self.prepare_body(data, files, json)
297        self.prepare_auth(auth, url)
298
299        # Note that prepare_auth must be last to enable authentication schemes
300        # such as OAuth to work on a fully prepared request.
301
302        # This MUST go after prepare_auth. Authenticators could add a hook
303        self.prepare_hooks(hooks)
304
305    def __repr__(self):
306        return '<PreparedRequest [%s]>' % (self.method)
307
308    def copy(self):
309        p = PreparedRequest()
310        p.method = self.method
311        p.url = self.url
312        p.headers = self.headers.copy() if self.headers is not None else None
313        p._cookies = _copy_cookie_jar(self._cookies)
314        p.body = self.body
315        p.hooks = self.hooks
316        return p
317
318    def prepare_method(self, method):
319        """Prepares the given HTTP method."""
320        self.method = method
321        if self.method is not None:
322            self.method = to_native_string(self.method.upper())
323
324    def prepare_url(self, url, params):
325        """Prepares the given HTTP URL."""
326        #: Accept objects that have string representations.
327        #: We're unable to blindly call unicode/str functions
328        #: as this will include the bytestring indicator (b'')
329        #: on python 3.x.
330        #: https://github.com/kennethreitz/requests/pull/2238
331        if isinstance(url, bytes):
332            url = url.decode('utf8')
333        else:
334            url = unicode(url) if is_py2 else str(url)
335
336        # Don't do any URL preparation for non-HTTP schemes like `mailto`,
337        # `data` etc to work around exceptions from `url_parse`, which
338        # handles RFC 3986 only.
339        if ':' in url and not url.lower().startswith('http'):
340            self.url = url
341            return
342
343        # Support for unicode domain names and paths.
344        try:
345            scheme, auth, host, port, path, query, fragment = parse_url(url)
346        except LocationParseError as e:
347            raise InvalidURL(*e.args)
348
349        if not scheme:
350            error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?")
351            error = error.format(to_native_string(url, 'utf8'))
352
353            raise MissingSchema(error)
354
355        if not host:
356            raise InvalidURL("Invalid URL %r: No host supplied" % url)
357
358        # Only want to apply IDNA to the hostname
359        try:
360            host = host.encode('idna').decode('utf-8')
361        except UnicodeError:
362            raise InvalidURL('URL has an invalid label.')
363
364        # Carefully reconstruct the network location
365        netloc = auth or ''
366        if netloc:
367            netloc += '@'
368        netloc += host
369        if port:
370            netloc += ':' + str(port)
371
372        # Bare domains aren't valid URLs.
373        if not path:
374            path = '/'
375
376        if is_py2:
377            if isinstance(scheme, str):
378                scheme = scheme.encode('utf-8')
379            if isinstance(netloc, str):
380                netloc = netloc.encode('utf-8')
381            if isinstance(path, str):
382                path = path.encode('utf-8')
383            if isinstance(query, str):
384                query = query.encode('utf-8')
385            if isinstance(fragment, str):
386                fragment = fragment.encode('utf-8')
387
388        if isinstance(params, (str, bytes)):
389            params = to_native_string(params)
390
391        enc_params = self._encode_params(params)
392        if enc_params:
393            if query:
394                query = '%s&%s' % (query, enc_params)
395            else:
396                query = enc_params
397
398        url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment]))
399        self.url = url
400
401    def prepare_headers(self, headers):
402        """Prepares the given HTTP headers."""
403
404        if headers:
405            self.headers = CaseInsensitiveDict((to_native_string(name), value) for name, value in headers.items())
406        else:
407            self.headers = CaseInsensitiveDict()
408
409    def prepare_body(self, data, files, json=None):
410        """Prepares the given HTTP body data."""
411
412        # Check if file, fo, generator, iterator.
413        # If not, run through normal process.
414
415        # Nottin' on you.
416        body = None
417        content_type = None
418        length = None
419
420        if not data and json is not None:
421            content_type = 'application/json'
422            body = complexjson.dumps(json)
423
424        is_stream = all([
425            hasattr(data, '__iter__'),
426            not isinstance(data, (basestring, list, tuple, dict))
427        ])
428
429        try:
430            length = super_len(data)
431        except (TypeError, AttributeError, UnsupportedOperation):
432            length = None
433
434        if is_stream:
435            body = data
436
437            if files:
438                raise NotImplementedError('Streamed bodies and files are mutually exclusive.')
439
440            if length:
441                self.headers['Content-Length'] = builtin_str(length)
442            else:
443                self.headers['Transfer-Encoding'] = 'chunked'
444        else:
445            # Multi-part file uploads.
446            if files:
447                (body, content_type) = self._encode_files(files, data)
448            else:
449                if data:
450                    body = self._encode_params(data)
451                    if isinstance(data, basestring) or hasattr(data, 'read'):
452                        content_type = None
453                    else:
454                        content_type = 'application/x-www-form-urlencoded'
455
456            self.prepare_content_length(body)
457
458            # Add content-type if it wasn't explicitly provided.
459            if content_type and ('content-type' not in self.headers):
460                self.headers['Content-Type'] = content_type
461
462        self.body = body
463
464    def prepare_content_length(self, body):
465        if hasattr(body, 'seek') and hasattr(body, 'tell'):
466            body.seek(0, 2)
467            self.headers['Content-Length'] = builtin_str(body.tell())
468            body.seek(0, 0)
469        elif body is not None:
470            l = super_len(body)
471            if l:
472                self.headers['Content-Length'] = builtin_str(l)
473        elif (self.method not in ('GET', 'HEAD')) and (self.headers.get('Content-Length') is None):
474            self.headers['Content-Length'] = '0'
475
476    def prepare_auth(self, auth, url=''):
477        """Prepares the given HTTP auth data."""
478
479        # If no Auth is explicitly provided, extract it from the URL first.
480        if auth is None:
481            url_auth = get_auth_from_url(self.url)
482            auth = url_auth if any(url_auth) else None
483
484        if auth:
485            if isinstance(auth, tuple) and len(auth) == 2:
486                # special-case basic HTTP auth
487                auth = HTTPBasicAuth(*auth)
488
489            # Allow auth to make its changes.
490            r = auth(self)
491
492            # Update self to reflect the auth changes.
493            self.__dict__.update(r.__dict__)
494
495            # Recompute Content-Length
496            self.prepare_content_length(self.body)
497
498    def prepare_cookies(self, cookies):
499        """Prepares the given HTTP cookie data.
500
501        This function eventually generates a ``Cookie`` header from the
502        given cookies using cookielib. Due to cookielib's design, the header
503        will not be regenerated if it already exists, meaning this function
504        can only be called once for the life of the
505        :class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls
506        to ``prepare_cookies`` will have no actual effect, unless the "Cookie"
507        header is removed beforehand."""
508
509        if isinstance(cookies, cookielib.CookieJar):
510            self._cookies = cookies
511        else:
512            self._cookies = cookiejar_from_dict(cookies)
513
514        cookie_header = get_cookie_header(self._cookies, self)
515        if cookie_header is not None:
516            self.headers['Cookie'] = cookie_header
517
518    def prepare_hooks(self, hooks):
519        """Prepares the given hooks."""
520        # hooks can be passed as None to the prepare method and to this
521        # method. To prevent iterating over None, simply use an empty list
522        # if hooks is False-y
523        hooks = hooks or []
524        for event in hooks:
525            self.register_hook(event, hooks[event])
526
527
528class Response(object):
529    """The :class:`Response <Response>` object, which contains a
530    server's response to an HTTP request.
531    """
532
533    __attrs__ = [
534        '_content', 'status_code', 'headers', 'url', 'history',
535        'encoding', 'reason', 'cookies', 'elapsed', 'request'
536    ]
537
538    def __init__(self):
539        super(Response, self).__init__()
540
541        self._content = False
542        self._content_consumed = False
543
544        #: Integer Code of responded HTTP Status, e.g. 404 or 200.
545        self.status_code = None
546
547        #: Case-insensitive Dictionary of Response Headers.
548        #: For example, ``headers['content-encoding']`` will return the
549        #: value of a ``'Content-Encoding'`` response header.
550        self.headers = CaseInsensitiveDict()
551
552        #: File-like object representation of response (for advanced usage).
553        #: Use of ``raw`` requires that ``stream=True`` be set on the request.
554        # This requirement does not apply for use internally to Requests.
555        self.raw = None
556
557        #: Final URL location of Response.
558        self.url = None
559
560        #: Encoding to decode with when accessing r.text.
561        self.encoding = None
562
563        #: A list of :class:`Response <Response>` objects from
564        #: the history of the Request. Any redirect responses will end
565        #: up here. The list is sorted from the oldest to the most recent request.
566        self.history = []
567
568        #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK".
569        self.reason = None
570
571        #: A CookieJar of Cookies the server sent back.
572        self.cookies = cookiejar_from_dict({})
573
574        #: The amount of time elapsed between sending the request
575        #: and the arrival of the response (as a timedelta).
576        #: This property specifically measures the time taken between sending
577        #: the first byte of the request and finishing parsing the headers. It
578        #: is therefore unaffected by consuming the response content or the
579        #: value of the ``stream`` keyword argument.
580        self.elapsed = datetime.timedelta(0)
581
582        #: The :class:`PreparedRequest <PreparedRequest>` object to which this
583        #: is a response.
584        self.request = None
585
586    def __getstate__(self):
587        # Consume everything; accessing the content attribute makes
588        # sure the content has been fully read.
589        if not self._content_consumed:
590            self.content
591
592        return dict(
593            (attr, getattr(self, attr, None))
594            for attr in self.__attrs__
595        )
596
597    def __setstate__(self, state):
598        for name, value in state.items():
599            setattr(self, name, value)
600
601        # pickled objects do not have .raw
602        setattr(self, '_content_consumed', True)
603        setattr(self, 'raw', None)
604
605    def __repr__(self):
606        return '<Response [%s]>' % (self.status_code)
607
608    def __bool__(self):
609        """Returns true if :attr:`status_code` is 'OK'."""
610        return self.ok
611
612    def __nonzero__(self):
613        """Returns true if :attr:`status_code` is 'OK'."""
614        return self.ok
615
616    def __iter__(self):
617        """Allows you to use a response as an iterator."""
618        return self.iter_content(128)
619
620    @property
621    def ok(self):
622        try:
623            self.raise_for_status()
624        except HTTPError:
625            return False
626        return True
627
628    @property
629    def is_redirect(self):
630        """True if this Response is a well-formed HTTP redirect that could have
631        been processed automatically (by :meth:`Session.resolve_redirects`).
632        """
633        return ('location' in self.headers and self.status_code in REDIRECT_STATI)
634
635    @property
636    def is_permanent_redirect(self):
637        """True if this Response one of the permanent versions of redirect"""
638        return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect))
639
640    @property
641    def apparent_encoding(self):
642        """The apparent encoding, provided by the chardet library"""
643        return chardet.detect(self.content)['encoding']
644
645    def iter_content(self, chunk_size=1, decode_unicode=False):
646        """Iterates over the response data.  When stream=True is set on the
647        request, this avoids reading the content at once into memory for
648        large responses.  The chunk size is the number of bytes it should
649        read into memory.  This is not necessarily the length of each item
650        returned as decoding can take place.
651
652        If decode_unicode is True, content will be decoded using the best
653        available encoding based on the response.
654        """
655
656        def generate():
657            # Special case for urllib3.
658            if hasattr(self.raw, 'stream'):
659                try:
660                    for chunk in self.raw.stream(chunk_size, decode_content=True):
661                        yield chunk
662                except ProtocolError as e:
663                    raise ChunkedEncodingError(e)
664                except DecodeError as e:
665                    raise ContentDecodingError(e)
666                except ReadTimeoutError as e:
667                    raise ConnectionError(e)
668            else:
669                # Standard file-like object.
670                while True:
671                    chunk = self.raw.read(chunk_size)
672                    if not chunk:
673                        break
674                    yield chunk
675
676            self._content_consumed = True
677
678        if self._content_consumed and isinstance(self._content, bool):
679            raise StreamConsumedError()
680        # simulate reading small chunks of the content
681        reused_chunks = iter_slices(self._content, chunk_size)
682
683        stream_chunks = generate()
684
685        chunks = reused_chunks if self._content_consumed else stream_chunks
686
687        if decode_unicode:
688            chunks = stream_decode_response_unicode(chunks, self)
689
690        return chunks
691
692    def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter=None):
693        """Iterates over the response data, one line at a time.  When
694        stream=True is set on the request, this avoids reading the
695        content at once into memory for large responses.
696
697        .. note:: This method is not reentrant safe.
698        """
699
700        pending = None
701
702        for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode):
703
704            if pending is not None:
705                chunk = pending + chunk
706
707            if delimiter:
708                lines = chunk.split(delimiter)
709            else:
710                lines = chunk.splitlines()
711
712            if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
713                pending = lines.pop()
714            else:
715                pending = None
716
717            for line in lines:
718                yield line
719
720        if pending is not None:
721            yield pending
722
723    @property
724    def content(self):
725        """Content of the response, in bytes."""
726
727        if self._content is False:
728            # Read the contents.
729            try:
730                if self._content_consumed:
731                    raise RuntimeError(
732                        'The content for this response was already consumed')
733
734                if self.status_code == 0:
735                    self._content = None
736                else:
737                    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
738
739            except AttributeError:
740                self._content = None
741
742        self._content_consumed = True
743        # don't need to release the connection; that's been handled by urllib3
744        # since we exhausted the data.
745        return self._content
746
747    @property
748    def text(self):
749        """Content of the response, in unicode.
750
751        If Response.encoding is None, encoding will be guessed using
752        ``chardet``.
753
754        The encoding of the response content is determined based solely on HTTP
755        headers, following RFC 2616 to the letter. If you can take advantage of
756        non-HTTP knowledge to make a better guess at the encoding, you should
757        set ``r.encoding`` appropriately before accessing this property.
758        """
759
760        # Try charset from content-type
761        content = None
762        encoding = self.encoding
763
764        if not self.content:
765            return str('')
766
767        # Fallback to auto-detected encoding.
768        if self.encoding is None:
769            encoding = self.apparent_encoding
770
771        # Decode unicode from given encoding.
772        try:
773            content = str(self.content, encoding, errors='replace')
774        except (LookupError, TypeError):
775            # A LookupError is raised if the encoding was not found which could
776            # indicate a misspelling or similar mistake.
777            #
778            # A TypeError can be raised if encoding is None
779            #
780            # So we try blindly encoding.
781            content = str(self.content, errors='replace')
782
783        return content
784
785    def json(self, **kwargs):
786        """Returns the json-encoded content of a response, if any.
787
788        :param \*\*kwargs: Optional arguments that ``json.loads`` takes.
789        """
790
791        if not self.encoding and len(self.content) > 3:
792            # No encoding set. JSON RFC 4627 section 3 states we should expect
793            # UTF-8, -16 or -32. Detect which one to use; If the detection or
794            # decoding fails, fall back to `self.text` (using chardet to make
795            # a best guess).
796            encoding = guess_json_utf(self.content)
797            if encoding is not None:
798                try:
799                    return complexjson.loads(
800                        self.content.decode(encoding), **kwargs
801                    )
802                except UnicodeDecodeError:
803                    # Wrong UTF codec detected; usually because it's not UTF-8
804                    # but some other 8-bit codec.  This is an RFC violation,
805                    # and the server didn't bother to tell us what codec *was*
806                    # used.
807                    pass
808        return complexjson.loads(self.text, **kwargs)
809
810    @property
811    def links(self):
812        """Returns the parsed header links of the response, if any."""
813
814        header = self.headers.get('link')
815
816        # l = MultiDict()
817        l = {}
818
819        if header:
820            links = parse_header_links(header)
821
822            for link in links:
823                key = link.get('rel') or link.get('url')
824                l[key] = link
825
826        return l
827
828    def raise_for_status(self):
829        """Raises stored :class:`HTTPError`, if one occurred."""
830
831        http_error_msg = ''
832
833        if 400 <= self.status_code < 500:
834            http_error_msg = '%s Client Error: %s for url: %s' % (self.status_code, self.reason, self.url)
835
836        elif 500 <= self.status_code < 600:
837            http_error_msg = '%s Server Error: %s for url: %s' % (self.status_code, self.reason, self.url)
838
839        if http_error_msg:
840            raise HTTPError(http_error_msg, response=self)
841
842    def close(self):
843        """Releases the connection back to the pool. Once this method has been
844        called the underlying ``raw`` object must not be accessed again.
845
846        *Note: Should not normally need to be called explicitly.*
847        """
848        if not self._content_consumed:
849            return self.raw.close()
850
851        return self.raw.release_conn()
852