1 # -*- coding: utf-8 -*-
7 This module contains the primary objects that power Requests.
13 from io import BytesIO, UnsupportedOperation
14 from .hooks import default_hooks
15 from .structures import CaseInsensitiveDict
17 from .auth import HTTPBasicAuth
18 from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar
19 from .packages.urllib3.fields import RequestField
20 from .packages.urllib3.filepost import encode_multipart_formdata
21 from .packages.urllib3.util import parse_url
22 from .packages.urllib3.exceptions import (
23 DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
24 from .exceptions import (
25 HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
26 ContentDecodingError, ConnectionError, StreamConsumedError)
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)
32 cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
33 is_py2, chardet, builtin_str, basestring)
34 from .compat import json as complexjson
35 from .status_codes import codes
37 #: The set of HTTP status codes that indicate an automatically
38 #: processable redirect.
43 codes.temporary_redirect, # 307
44 codes.permanent_redirect, # 308
47 DEFAULT_REDIRECT_LIMIT = 30
48 CONTENT_CHUNK_SIZE = 10 * 1024
52 class RequestEncodingMixin(object):
55 """Build the path URL to use."""
59 p = urlsplit(self.url)
75 def _encode_params(data):
76 """Encode parameters in a piece of data.
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.
83 if isinstance(data, (str, bytes)):
85 elif hasattr(data, 'read'):
87 elif hasattr(data, '__iter__'):
89 for k, vs in to_key_val_list(data):
90 if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
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)
102 def _encode_files(files, data):
103 """Build the body for a multipart/form-data request.
105 Will successfully encode files when passed as a dict or a list of
106 tuples. Order is retained if data is a list of tuples but arbitrary
107 if parameters are supplied as a dict.
108 The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype)
109 or 4-tuples (filename, fileobj, contentype, custom_headers).
113 raise ValueError("Files must be provided.")
114 elif isinstance(data, basestring):
115 raise ValueError("Data must not be a string.")
118 fields = to_key_val_list(data or {})
119 files = to_key_val_list(files or {})
121 for field, val in fields:
122 if isinstance(val, basestring) or not hasattr(val, '__iter__'):
126 # Don't call str() on bytestrings: in Py3 it all goes wrong.
127 if not isinstance(v, bytes):
131 (field.decode('utf-8') if isinstance(field, bytes) else field,
132 v.encode('utf-8') if isinstance(v, str) else v))
135 # support for explicit filename
138 if isinstance(v, (tuple, list)):
146 fn = guess_filename(v) or k
149 if isinstance(fp, (str, bytes, bytearray)):
154 rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
155 rf.make_multipart(content_type=ft)
156 new_fields.append(rf)
158 body, content_type = encode_multipart_formdata(new_fields)
160 return body, content_type
163 class RequestHooksMixin(object):
164 def register_hook(self, event, hook):
165 """Properly register a hook."""
167 if event not in self.hooks:
168 raise ValueError('Unsupported event specified, with event name "%s"' % (event))
170 if isinstance(hook, collections.Callable):
171 self.hooks[event].append(hook)
172 elif hasattr(hook, '__iter__'):
173 self.hooks[event].extend(h for h in hook if isinstance(h, collections.Callable))
175 def deregister_hook(self, event, hook):
176 """Deregister a previously registered hook.
177 Returns True if the hook existed, False if not.
181 self.hooks[event].remove(hook)
187 class Request(RequestHooksMixin):
188 """A user-created :class:`Request <Request>` object.
190 Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server.
192 :param method: HTTP method to use.
193 :param url: URL to send.
194 :param headers: dictionary of headers to send.
195 :param files: dictionary of {filename: fileobject} files to multipart upload.
196 :param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
197 :param json: json for the body to attach to the request (if files or data is not specified).
198 :param params: dictionary of URL parameters to append to the URL.
199 :param auth: Auth handler or (user, pass) tuple.
200 :param cookies: dictionary or CookieJar of cookies to attach to this request.
201 :param hooks: dictionary of callback hooks, for internal usage.
206 >>> req = requests.Request('GET', 'http://httpbin.org/get')
208 <PreparedRequest [GET]>
211 def __init__(self, method=None, url=None, headers=None, files=None,
212 data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
214 # Default empty dicts for dict params.
215 data = [] if data is None else data
216 files = [] if files is None else files
217 headers = {} if headers is None else headers
218 params = {} if params is None else params
219 hooks = {} if hooks is None else hooks
221 self.hooks = default_hooks()
222 for (k, v) in list(hooks.items()):
223 self.register_hook(event=k, hook=v)
227 self.headers = headers
233 self.cookies = cookies
236 return '<Request [%s]>' % (self.method)
239 """Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it."""
240 p = PreparedRequest()
244 headers=self.headers,
250 cookies=self.cookies,
256 class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
257 """The fully mutable :class:`PreparedRequest <PreparedRequest>` object,
258 containing the exact bytes that will be sent to the server.
260 Generated from either a :class:`Request <Request>` object or manually.
265 >>> req = requests.Request('GET', 'http://httpbin.org/get')
266 >>> r = req.prepare()
267 <PreparedRequest [GET]>
269 >>> s = requests.Session()
276 #: HTTP verb to send to the server.
278 #: HTTP URL to send the request to.
280 #: dictionary of HTTP headers.
282 # The `CookieJar` used to create the Cookie header will be stored here
283 # after prepare_cookies is called
285 #: request body to send to the server.
287 #: dictionary of callback hooks, for internal usage.
288 self.hooks = default_hooks()
290 def prepare(self, method=None, url=None, headers=None, files=None,
291 data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
292 """Prepares the entire request with the given parameters."""
294 self.prepare_method(method)
295 self.prepare_url(url, params)
296 self.prepare_headers(headers)
297 self.prepare_cookies(cookies)
298 self.prepare_body(data, files, json)
299 self.prepare_auth(auth, url)
301 # Note that prepare_auth must be last to enable authentication schemes
302 # such as OAuth to work on a fully prepared request.
304 # This MUST go after prepare_auth. Authenticators could add a hook
305 self.prepare_hooks(hooks)
308 return '<PreparedRequest [%s]>' % (self.method)
311 p = PreparedRequest()
312 p.method = self.method
314 p.headers = self.headers.copy() if self.headers is not None else None
315 p._cookies = _copy_cookie_jar(self._cookies)
320 def prepare_method(self, method):
321 """Prepares the given HTTP method."""
323 if self.method is not None:
324 self.method = to_native_string(self.method.upper())
326 def prepare_url(self, url, params):
327 """Prepares the given HTTP URL."""
328 #: Accept objects that have string representations.
329 #: We're unable to blindly call unicode/str functions
330 #: as this will include the bytestring indicator (b'')
332 #: https://github.com/kennethreitz/requests/pull/2238
333 if isinstance(url, bytes):
334 url = url.decode('utf8')
336 url = unicode(url) if is_py2 else str(url)
338 # Don't do any URL preparation for non-HTTP schemes like `mailto`,
339 # `data` etc to work around exceptions from `url_parse`, which
340 # handles RFC 3986 only.
341 if ':' in url and not url.lower().startswith('http'):
345 # Support for unicode domain names and paths.
347 scheme, auth, host, port, path, query, fragment = parse_url(url)
348 except LocationParseError as e:
349 raise InvalidURL(*e.args)
352 error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?")
353 error = error.format(to_native_string(url, 'utf8'))
355 raise MissingSchema(error)
358 raise InvalidURL("Invalid URL %r: No host supplied" % url)
360 # Only want to apply IDNA to the hostname
362 host = host.encode('idna').decode('utf-8')
364 raise InvalidURL('URL has an invalid label.')
366 # Carefully reconstruct the network location
372 netloc += ':' + str(port)
374 # Bare domains aren't valid URLs.
379 if isinstance(scheme, str):
380 scheme = scheme.encode('utf-8')
381 if isinstance(netloc, str):
382 netloc = netloc.encode('utf-8')
383 if isinstance(path, str):
384 path = path.encode('utf-8')
385 if isinstance(query, str):
386 query = query.encode('utf-8')
387 if isinstance(fragment, str):
388 fragment = fragment.encode('utf-8')
390 if isinstance(params, (str, bytes)):
391 params = to_native_string(params)
393 enc_params = self._encode_params(params)
396 query = '%s&%s' % (query, enc_params)
400 url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment]))
403 def prepare_headers(self, headers):
404 """Prepares the given HTTP headers."""
407 self.headers = CaseInsensitiveDict((to_native_string(name), value) for name, value in headers.items())
409 self.headers = CaseInsensitiveDict()
411 def prepare_body(self, data, files, json=None):
412 """Prepares the given HTTP body data."""
414 # Check if file, fo, generator, iterator.
415 # If not, run through normal process.
422 if not data and json is not None:
423 content_type = 'application/json'
424 body = complexjson.dumps(json)
427 hasattr(data, '__iter__'),
428 not isinstance(data, (basestring, list, tuple, dict))
432 length = super_len(data)
433 except (TypeError, AttributeError, UnsupportedOperation):
440 raise NotImplementedError('Streamed bodies and files are mutually exclusive.')
443 self.headers['Content-Length'] = builtin_str(length)
445 self.headers['Transfer-Encoding'] = 'chunked'
447 # Multi-part file uploads.
449 (body, content_type) = self._encode_files(files, data)
452 body = self._encode_params(data)
453 if isinstance(data, basestring) or hasattr(data, 'read'):
456 content_type = 'application/x-www-form-urlencoded'
458 self.prepare_content_length(body)
460 # Add content-type if it wasn't explicitly provided.
461 if content_type and ('content-type' not in self.headers):
462 self.headers['Content-Type'] = content_type
466 def prepare_content_length(self, body):
467 if hasattr(body, 'seek') and hasattr(body, 'tell'):
468 curr_pos = body.tell()
470 end_pos = body.tell()
471 self.headers['Content-Length'] = builtin_str(max(0, end_pos - curr_pos))
472 body.seek(curr_pos, 0)
473 elif body is not None:
476 self.headers['Content-Length'] = builtin_str(l)
477 elif (self.method not in ('GET', 'HEAD')) and (self.headers.get('Content-Length') is None):
478 self.headers['Content-Length'] = '0'
480 def prepare_auth(self, auth, url=''):
481 """Prepares the given HTTP auth data."""
483 # If no Auth is explicitly provided, extract it from the URL first.
485 url_auth = get_auth_from_url(self.url)
486 auth = url_auth if any(url_auth) else None
489 if isinstance(auth, tuple) and len(auth) == 2:
490 # special-case basic HTTP auth
491 auth = HTTPBasicAuth(*auth)
493 # Allow auth to make its changes.
496 # Update self to reflect the auth changes.
497 self.__dict__.update(r.__dict__)
499 # Recompute Content-Length
500 self.prepare_content_length(self.body)
502 def prepare_cookies(self, cookies):
503 """Prepares the given HTTP cookie data.
505 This function eventually generates a ``Cookie`` header from the
506 given cookies using cookielib. Due to cookielib's design, the header
507 will not be regenerated if it already exists, meaning this function
508 can only be called once for the life of the
509 :class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls
510 to ``prepare_cookies`` will have no actual effect, unless the "Cookie"
511 header is removed beforehand."""
513 if isinstance(cookies, cookielib.CookieJar):
514 self._cookies = cookies
516 self._cookies = cookiejar_from_dict(cookies)
518 cookie_header = get_cookie_header(self._cookies, self)
519 if cookie_header is not None:
520 self.headers['Cookie'] = cookie_header
522 def prepare_hooks(self, hooks):
523 """Prepares the given hooks."""
524 # hooks can be passed as None to the prepare method and to this
525 # method. To prevent iterating over None, simply use an empty list
526 # if hooks is False-y
529 self.register_hook(event, hooks[event])
532 class Response(object):
533 """The :class:`Response <Response>` object, which contains a
534 server's response to an HTTP request.
538 '_content', 'status_code', 'headers', 'url', 'history',
539 'encoding', 'reason', 'cookies', 'elapsed', 'request'
543 super(Response, self).__init__()
545 self._content = False
546 self._content_consumed = False
548 #: Integer Code of responded HTTP Status, e.g. 404 or 200.
549 self.status_code = None
551 #: Case-insensitive Dictionary of Response Headers.
552 #: For example, ``headers['content-encoding']`` will return the
553 #: value of a ``'Content-Encoding'`` response header.
554 self.headers = CaseInsensitiveDict()
556 #: File-like object representation of response (for advanced usage).
557 #: Use of ``raw`` requires that ``stream=True`` be set on the request.
558 # This requirement does not apply for use internally to Requests.
561 #: Final URL location of Response.
564 #: Encoding to decode with when accessing r.text.
567 #: A list of :class:`Response <Response>` objects from
568 #: the history of the Request. Any redirect responses will end
569 #: up here. The list is sorted from the oldest to the most recent request.
572 #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK".
575 #: A CookieJar of Cookies the server sent back.
576 self.cookies = cookiejar_from_dict({})
578 #: The amount of time elapsed between sending the request
579 #: and the arrival of the response (as a timedelta).
580 #: This property specifically measures the time taken between sending
581 #: the first byte of the request and finishing parsing the headers. It
582 #: is therefore unaffected by consuming the response content or the
583 #: value of the ``stream`` keyword argument.
584 self.elapsed = datetime.timedelta(0)
586 #: The :class:`PreparedRequest <PreparedRequest>` object to which this
590 def __getstate__(self):
591 # Consume everything; accessing the content attribute makes
592 # sure the content has been fully read.
593 if not self._content_consumed:
597 (attr, getattr(self, attr, None))
598 for attr in self.__attrs__
601 def __setstate__(self, state):
602 for name, value in state.items():
603 setattr(self, name, value)
605 # pickled objects do not have .raw
606 setattr(self, '_content_consumed', True)
607 setattr(self, 'raw', None)
610 return '<Response [%s]>' % (self.status_code)
613 """Returns true if :attr:`status_code` is 'OK'."""
616 def __nonzero__(self):
617 """Returns true if :attr:`status_code` is 'OK'."""
621 """Allows you to use a response as an iterator."""
622 return self.iter_content(128)
627 self.raise_for_status()
633 def is_redirect(self):
634 """True if this Response is a well-formed HTTP redirect that could have
635 been processed automatically (by :meth:`Session.resolve_redirects`).
637 return ('location' in self.headers and self.status_code in REDIRECT_STATI)
640 def is_permanent_redirect(self):
641 """True if this Response one of the permanent versions of redirect"""
642 return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect))
645 def apparent_encoding(self):
646 """The apparent encoding, provided by the chardet library"""
647 return chardet.detect(self.content)['encoding']
649 def iter_content(self, chunk_size=1, decode_unicode=False):
650 """Iterates over the response data. When stream=True is set on the
651 request, this avoids reading the content at once into memory for
652 large responses. The chunk size is the number of bytes it should
653 read into memory. This is not necessarily the length of each item
654 returned as decoding can take place.
656 If decode_unicode is True, content will be decoded using the best
657 available encoding based on the response.
661 # Special case for urllib3.
662 if hasattr(self.raw, 'stream'):
664 for chunk in self.raw.stream(chunk_size, decode_content=True):
666 except ProtocolError as e:
667 raise ChunkedEncodingError(e)
668 except DecodeError as e:
669 raise ContentDecodingError(e)
670 except ReadTimeoutError as e:
671 raise ConnectionError(e)
673 # Standard file-like object.
675 chunk = self.raw.read(chunk_size)
680 self._content_consumed = True
682 if self._content_consumed and isinstance(self._content, bool):
683 raise StreamConsumedError()
684 # simulate reading small chunks of the content
685 reused_chunks = iter_slices(self._content, chunk_size)
687 stream_chunks = generate()
689 chunks = reused_chunks if self._content_consumed else stream_chunks
692 chunks = stream_decode_response_unicode(chunks, self)
696 def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter=None):
697 """Iterates over the response data, one line at a time. When
698 stream=True is set on the request, this avoids reading the
699 content at once into memory for large responses.
701 .. note:: This method is not reentrant safe.
706 for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode):
708 if pending is not None:
709 chunk = pending + chunk
712 lines = chunk.split(delimiter)
714 lines = chunk.splitlines()
716 if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
717 pending = lines.pop()
724 if pending is not None:
729 """Content of the response, in bytes."""
731 if self._content is False:
734 if self._content_consumed:
736 'The content for this response was already consumed')
738 if self.status_code == 0:
741 self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
743 except AttributeError:
746 self._content_consumed = True
747 # don't need to release the connection; that's been handled by urllib3
748 # since we exhausted the data.
753 """Content of the response, in unicode.
755 If Response.encoding is None, encoding will be guessed using
758 The encoding of the response content is determined based solely on HTTP
759 headers, following RFC 2616 to the letter. If you can take advantage of
760 non-HTTP knowledge to make a better guess at the encoding, you should
761 set ``r.encoding`` appropriately before accessing this property.
764 # Try charset from content-type
766 encoding = self.encoding
771 # Fallback to auto-detected encoding.
772 if self.encoding is None:
773 encoding = self.apparent_encoding
775 # Decode unicode from given encoding.
777 content = str(self.content, encoding, errors='replace')
778 except (LookupError, TypeError):
779 # A LookupError is raised if the encoding was not found which could
780 # indicate a misspelling or similar mistake.
782 # A TypeError can be raised if encoding is None
784 # So we try blindly encoding.
785 content = str(self.content, errors='replace')
789 def json(self, **kwargs):
790 """Returns the json-encoded content of a response, if any.
792 :param \*\*kwargs: Optional arguments that ``json.loads`` takes.
795 if not self.encoding and len(self.content) > 3:
796 # No encoding set. JSON RFC 4627 section 3 states we should expect
797 # UTF-8, -16 or -32. Detect which one to use; If the detection or
798 # decoding fails, fall back to `self.text` (using chardet to make
800 encoding = guess_json_utf(self.content)
801 if encoding is not None:
803 return complexjson.loads(
804 self.content.decode(encoding), **kwargs
806 except UnicodeDecodeError:
807 # Wrong UTF codec detected; usually because it's not UTF-8
808 # but some other 8-bit codec. This is an RFC violation,
809 # and the server didn't bother to tell us what codec *was*
812 return complexjson.loads(self.text, **kwargs)
816 """Returns the parsed header links of the response, if any."""
818 header = self.headers.get('link')
824 links = parse_header_links(header)
827 key = link.get('rel') or link.get('url')
832 def raise_for_status(self):
833 """Raises stored :class:`HTTPError`, if one occurred."""
837 if 400 <= self.status_code < 500:
838 http_error_msg = '%s Client Error: %s for url: %s' % (self.status_code, self.reason, self.url)
840 elif 500 <= self.status_code < 600:
841 http_error_msg = '%s Server Error: %s for url: %s' % (self.status_code, self.reason, self.url)
844 raise HTTPError(http_error_msg, response=self)
847 """Releases the connection back to the pool. Once this method has been
848 called the underlying ``raw`` object must not be accessed again.
850 *Note: Should not normally need to be called explicitly.*
852 if not self._content_consumed:
853 return self.raw.close()
855 return self.raw.release_conn()