├── docs ├── .nojekyll ├── _themes │ ├── .gitignore │ ├── LICENSE │ └── flask_theme_support.py ├── dev │ ├── authors.rst │ └── contributing.rst ├── _static │ ├── requests-sidebar.png │ └── custom.css ├── requirements.txt ├── community │ ├── vulnerabilities.rst │ ├── updates.rst │ ├── out-there.rst │ ├── support.rst │ ├── release-process.rst │ ├── recommended.rst │ └── faq.rst ├── user │ ├── install.rst │ └── authentication.rst ├── _templates │ ├── sidebarlogo.html │ ├── sidebarintro.html │ └── hacks.html ├── index.rst ├── make.bat ├── api.rst └── Makefile ├── tests ├── testserver │ ├── __init__.py │ └── server.py ├── certs │ ├── valid │ │ ├── ca │ │ └── server │ │ │ ├── Makefile │ │ │ ├── cert.cnf │ │ │ ├── server.csr │ │ │ ├── server.key │ │ │ └── server.pem │ ├── mtls │ │ ├── client │ │ │ ├── ca │ │ │ ├── Makefile │ │ │ ├── cert.cnf │ │ │ ├── client.csr │ │ │ ├── client.key │ │ │ └── client.pem │ │ ├── Makefile │ │ └── README.md │ ├── expired │ │ ├── ca │ │ │ ├── ca.srl │ │ │ ├── Makefile │ │ │ ├── ca.cnf │ │ │ ├── ca.crt │ │ │ └── ca-private.key │ │ ├── Makefile │ │ ├── README.md │ │ └── server │ │ │ ├── Makefile │ │ │ ├── cert.cnf │ │ │ ├── server.csr │ │ │ ├── server.key │ │ │ └── server.pem │ └── README.md ├── test_packages.py ├── test_adapters.py ├── utils.py ├── __init__.py ├── test_hooks.py ├── compat.py ├── test_help.py ├── conftest.py ├── test_structures.py └── test_testserver.py ├── .coveragerc ├── NOTICE ├── ext ├── LICENSE ├── kr.png ├── ss.png ├── psf.png ├── requests-logo.ai ├── flower-of-life.jpg ├── kr-compressed.png ├── psf-compressed.png ├── requests-logo.png ├── ss-compressed.png └── requests-logo-compressed.png ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Feature_request.md │ ├── Custom.md │ └── Bug_report.md ├── dependabot.yml ├── CODE_OF_CONDUCT.md ├── workflows │ ├── lock-issues.yml │ ├── lint.yml │ ├── close-issues.yml │ ├── run-tests.yml │ ├── codeql-analysis.yml │ └── publish.yml ├── ISSUE_TEMPLATE.md ├── CONTRIBUTING.md └── SECURITY.md ├── requirements-dev.txt ├── MANIFEST.in ├── .git-blame-ignore-revs ├── pyproject.toml ├── tox.ini ├── setup.cfg ├── .gitignore ├── src └── requests │ ├── __version__.py │ ├── certs.py │ ├── hooks.py │ ├── packages.py │ ├── _internal_utils.py │ ├── compat.py │ ├── structures.py │ ├── help.py │ ├── status_codes.py │ ├── exceptions.py │ ├── __init__.py │ └── api.py ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── Makefile ├── README.md ├── setup.py ├── AUTHORS.rst └── LICENSE /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/testserver/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/certs/valid/ca: -------------------------------------------------------------------------------- 1 | ../expired/ca -------------------------------------------------------------------------------- /tests/certs/mtls/client/ca: -------------------------------------------------------------------------------- 1 | ../../expired/ca/ -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = requests/packages/* 3 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Requests 2 | Copyright 2019 Kenneth Reitz 3 | -------------------------------------------------------------------------------- /docs/_themes/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /ext/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Kenneth Reitz. All rights reserved. 2 | -------------------------------------------------------------------------------- /ext/kr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/kr.png -------------------------------------------------------------------------------- /ext/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/ss.png -------------------------------------------------------------------------------- /ext/psf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/psf.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ['https://www.python.org/psf/sponsorship/'] 2 | -------------------------------------------------------------------------------- /tests/certs/expired/ca/ca.srl: -------------------------------------------------------------------------------- 1 | 4F36C3A7E075BA6452D10EEB81E7F189FF489B83 2 | -------------------------------------------------------------------------------- /docs/dev/authors.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ======= 3 | 4 | .. include:: ../../AUTHORS.rst 5 | -------------------------------------------------------------------------------- /ext/requests-logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/requests-logo.ai -------------------------------------------------------------------------------- /ext/flower-of-life.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/flower-of-life.jpg -------------------------------------------------------------------------------- /ext/kr-compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/kr-compressed.png -------------------------------------------------------------------------------- /ext/psf-compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/psf-compressed.png -------------------------------------------------------------------------------- /ext/requests-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/requests-logo.png -------------------------------------------------------------------------------- /ext/ss-compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/ss-compressed.png -------------------------------------------------------------------------------- /ext/requests-logo-compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/ext/requests-logo-compressed.png -------------------------------------------------------------------------------- /docs/_static/requests-sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psf/requests/HEAD/docs/_static/requests-sidebar.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Pinning to avoid unexpected breakages. 2 | # Used by RTD to generate docs. 3 | Sphinx==7.2.6 4 | -------------------------------------------------------------------------------- /tests/certs/mtls/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: 4 | make -C client all 5 | 6 | clean: 7 | make -C client clean 8 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -e .[socks] 2 | pytest>=2.8.0,<9 3 | pytest-cov 4 | pytest-httpbin==2.1.0 5 | httpbin~=0.10.0 6 | trustme 7 | wheel 8 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE NOTICE HISTORY.md requirements-dev.txt 2 | recursive-include tests *.py 3 | recursive-include tests/certs * 4 | -------------------------------------------------------------------------------- /tests/certs/mtls/README.md: -------------------------------------------------------------------------------- 1 | # Certificate Examples for mTLS 2 | 3 | This has some generated certificates for mTLS utilization. The idea is to be 4 | able to have testing around how Requests handles client certificates. 5 | -------------------------------------------------------------------------------- /tests/certs/expired/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean ca server 2 | 3 | ca: 4 | make -C $@ all 5 | 6 | server: 7 | make -C $@ all 8 | 9 | all: ca server 10 | 11 | clean: 12 | make -C ca clean 13 | make -C server clean 14 | -------------------------------------------------------------------------------- /docs/community/vulnerabilities.rst: -------------------------------------------------------------------------------- 1 | Vulnerability Disclosure 2 | ======================== 3 | 4 | The latest vulnerability disclosure information can be found on GitHub in our 5 | `Security Policy `_. 6 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # You can configure git to automatically use this file with the following config: 2 | # git config --global blame.ignoreRevsFile .git-blame-ignore-revs 3 | 4 | # Add automatic code formatting to Requests 5 | 2a6f290bc09324406708a4d404a88a45d848ddf9 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: 5 | - "Feature Request" 6 | - "actions/autoclose-feat" 7 | 8 | --- 9 | 10 | Requests is not accepting feature requests at this time. 11 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.isort] 2 | profile = "black" 3 | src_paths = ["src/requests", "test"] 4 | honor_noqa = true 5 | 6 | [tool.pytest.ini_options] 7 | addopts = "--doctest-modules" 8 | doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS" 9 | minversion = "6.2" 10 | testpaths = ["tests"] 11 | -------------------------------------------------------------------------------- /tests/certs/expired/README.md: -------------------------------------------------------------------------------- 1 | # Expired Certificates and Configuration for Testing 2 | 3 | This has a valid certificate authority in [ca](./ca) and an invalid server 4 | certificate in [server](./server). 5 | 6 | This can all be regenerated with: 7 | 8 | ``` 9 | make clean 10 | make all 11 | ``` 12 | -------------------------------------------------------------------------------- /tests/test_packages.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | 4 | def test_can_access_urllib3_attribute(): 5 | requests.packages.urllib3 6 | 7 | 8 | def test_can_access_idna_attribute(): 9 | requests.packages.idna 10 | 11 | 12 | def test_can_access_chardet_attribute(): 13 | requests.packages.chardet 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Request for Help 3 | about: Guidance on using Requests. 4 | labels: 5 | - "Question/Not a bug" 6 | - "actions/autoclose-qa" 7 | 8 | --- 9 | 10 | Please refer to our [Stack Overflow tag](https://stackoverflow.com/questions/tagged/python-requests) for guidance. 11 | -------------------------------------------------------------------------------- /tests/test_adapters.py: -------------------------------------------------------------------------------- 1 | import requests.adapters 2 | 3 | 4 | def test_request_url_trims_leading_path_separators(): 5 | """See also https://github.com/psf/requests/issues/6643.""" 6 | a = requests.adapters.HTTPAdapter() 7 | p = requests.Request(method="GET", url="http://127.0.0.1:10000//v:h").prepare() 8 | assert "/v:h" == a.request_url(p, {}) 9 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{39,310,311,312,313,314}-{default, use_chardet_on_py3} 3 | 4 | [testenv] 5 | deps = -rrequirements-dev.txt 6 | extras = 7 | security 8 | socks 9 | commands = 10 | pytest {posargs:tests} 11 | 12 | [testenv:default] 13 | 14 | [testenv:use_chardet_on_py3] 15 | extras = 16 | security 17 | socks 18 | use_chardet_on_py3 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | ignore: 8 | # Ignore all patch releases as we can manually 9 | # upgrade if we run into a bug and need a fix. 10 | - dependency-name: "*" 11 | update-types: ["version-update:semver-patch"] 12 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Treat each other well 2 | 3 | Everyone participating in the _requests_ project, and in particular in the issue tracker, 4 | pull requests, and social media activity, is expected to treat other people with respect 5 | and more generally to follow the guidelines articulated in the 6 | [Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/). 7 | -------------------------------------------------------------------------------- /tests/certs/expired/ca/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | root_files = ca-private.key ca.crt 4 | 5 | ca-private.key: 6 | openssl genrsa -out ca-private.key 2048 7 | 8 | all: ca-private.key 9 | openssl req -x509 -sha256 -days 7300 -key ca-private.key -out ca.crt -config ca.cnf 10 | ln -s ca.crt cacert.pem 11 | 12 | clean: 13 | rm -f cacert.pem ca.crt ca-private.key *.csr 14 | -------------------------------------------------------------------------------- /tests/certs/README.md: -------------------------------------------------------------------------------- 1 | # Testing Certificates 2 | 3 | This is a collection of certificates useful for testing aspects of Requests' 4 | behaviour. 5 | 6 | The certificates include: 7 | 8 | * [expired](./expired) server certificate with a valid certificate authority 9 | * [mtls](./mtls) provides a valid client certificate with a 2 year validity 10 | * [valid](./valid) has a valid server certificate 11 | -------------------------------------------------------------------------------- /docs/community/updates.rst: -------------------------------------------------------------------------------- 1 | .. _updates: 2 | 3 | 4 | Community Updates 5 | ================= 6 | 7 | If you'd like to stay up to date on the community and development of Requests, 8 | there are several options: 9 | 10 | 11 | GitHub 12 | ------ 13 | 14 | The best way to track the development of Requests is through 15 | `the GitHub repo `_. 16 | 17 | 18 | .. include:: ../../HISTORY.md 19 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | license_file = LICENSE 3 | provides-extra = 4 | socks 5 | use_chardet_on_py3 6 | requires-dist = 7 | certifi>=2017.4.17 8 | charset_normalizer>=2,<4 9 | idna>=2.5,<4 10 | urllib3>=1.21.1,<3 11 | 12 | [flake8] 13 | ignore = E203, E501, W503 14 | per-file-ignores = 15 | src/requests/__init__.py:E402, F401 16 | src/requests/compat.py:E402, F401 17 | tests/compat.py:F401 18 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import os 3 | 4 | 5 | @contextlib.contextmanager 6 | def override_environ(**kwargs): 7 | save_env = dict(os.environ) 8 | for key, value in kwargs.items(): 9 | if value is None: 10 | del os.environ[key] 11 | else: 12 | os.environ[key] = value 13 | try: 14 | yield 15 | finally: 16 | os.environ.clear() 17 | os.environ.update(save_env) 18 | -------------------------------------------------------------------------------- /tests/certs/expired/server/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | server.key: 4 | openssl genrsa -out $@ 2048 5 | 6 | server.csr: server.key 7 | openssl req -key $< -new -out $@ -config cert.cnf 8 | 9 | server.pem: server.csr 10 | openssl x509 -req -CA ../ca/ca.crt -CAkey ../ca/ca-private.key -in server.csr -outform PEM -out server.pem -days 0 -CAcreateserial 11 | openssl x509 -in ../ca/ca.crt -outform PEM >> $@ 12 | 13 | all: server.pem 14 | 15 | clean: 16 | rm -f server.* 17 | -------------------------------------------------------------------------------- /tests/certs/mtls/client/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | client.key: 4 | openssl genrsa -out $@ 2048 5 | 6 | client.csr: client.key 7 | openssl req -key $< -new -out $@ -config cert.cnf 8 | 9 | client.pem: client.csr 10 | openssl x509 -req -CA ./ca/ca.crt -CAkey ./ca/ca-private.key -in client.csr -outform PEM -out client.pem -days 730 -CAcreateserial 11 | openssl x509 -in ./ca/ca.crt -outform PEM >> $@ 12 | 13 | all: client.pem 14 | 15 | clean: 16 | rm -f client.* 17 | -------------------------------------------------------------------------------- /.github/workflows/lock-issues.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | 11 | jobs: 12 | action: 13 | if: github.repository_owner == 'psf' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: dessant/lock-threads@d42e5f49803f3c4e14ffee0378e31481265dda22 # v5.0.0 17 | with: 18 | issue-lock-inactive-days: 90 19 | pr-lock-inactive-days: 90 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | MANIFEST 3 | coverage.xml 4 | nosetests.xml 5 | junit-report.xml 6 | pylint.txt 7 | toy.py 8 | .cache/ 9 | cover/ 10 | build/ 11 | docs/_build 12 | requests.egg-info/ 13 | *.pyc 14 | *.swp 15 | *.egg 16 | env/ 17 | .venv/ 18 | .eggs/ 19 | .tox/ 20 | .pytest_cache/ 21 | .vscode/ 22 | .eggs/ 23 | 24 | .workon 25 | 26 | # in case you work with IntelliJ/PyCharm 27 | .idea 28 | *.iml 29 | .python-version 30 | 31 | 32 | t.py 33 | 34 | t2.py 35 | dist 36 | 37 | /.mypy_cache/ 38 | -------------------------------------------------------------------------------- /src/requests/__version__.py: -------------------------------------------------------------------------------- 1 | # .-. .-. .-. . . .-. .-. .-. .-. 2 | # |( |- |.| | | |- `-. | `-. 3 | # ' ' `-' `-`.`-' `-' `-' ' `-' 4 | 5 | __title__ = "requests" 6 | __description__ = "Python HTTP for Humans." 7 | __url__ = "https://requests.readthedocs.io" 8 | __version__ = "2.32.5" 9 | __build__ = 0x023205 10 | __author__ = "Kenneth Reitz" 11 | __author_email__ = "me@kennethreitz.org" 12 | __license__ = "Apache-2.0" 13 | __copyright__ = "Copyright Kenneth Reitz" 14 | __cake__ = "\u2728 \U0001f370 \u2728" 15 | -------------------------------------------------------------------------------- /src/requests/certs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | requests.certs 5 | ~~~~~~~~~~~~~~ 6 | 7 | This module returns the preferred default CA certificate bundle. There is 8 | only one — the one from the certifi package. 9 | 10 | If you are packaging Requests, e.g., for a Linux distribution or a managed 11 | environment, you can change the definition of where() to return a separately 12 | packaged CA bundle. 13 | """ 14 | from certifi import where 15 | 16 | if __name__ == "__main__": 17 | print(where()) 18 | -------------------------------------------------------------------------------- /tests/certs/valid/server/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | server.key: 4 | openssl genrsa -out $@ 2048 5 | 6 | server.csr: server.key 7 | openssl req -key $< -config cert.cnf -new -out $@ 8 | 9 | server.pem: server.csr 10 | openssl x509 -req -CA ../ca/ca.crt -CAkey ../ca/ca-private.key -in server.csr -outform PEM -out server.pem -extfile cert.cnf -extensions v3_ca -days 7200 -CAcreateserial 11 | openssl x509 -in ../ca/ca.crt -outform PEM >> $@ 12 | 13 | all: server.pem 14 | 15 | clean: 16 | rm -f server.* 17 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Requests test package initialisation.""" 2 | 3 | import warnings 4 | 5 | try: 6 | from urllib3.exceptions import SNIMissingWarning 7 | 8 | # urllib3 1.x sets SNIMissingWarning to only go off once, 9 | # while this test suite requires it to always fire 10 | # so that it occurs during test_requests.test_https_warnings 11 | warnings.simplefilter("always", SNIMissingWarning) 12 | except ImportError: 13 | # urllib3 2.0 removed that warning and errors out instead 14 | SNIMissingWarning = None 15 | -------------------------------------------------------------------------------- /tests/test_hooks.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from requests import hooks 4 | 5 | 6 | def hook(value): 7 | return value[1:] 8 | 9 | 10 | @pytest.mark.parametrize( 11 | "hooks_list, result", 12 | ( 13 | (hook, "ata"), 14 | ([hook, lambda x: None, hook], "ta"), 15 | ), 16 | ) 17 | def test_hooks(hooks_list, result): 18 | assert hooks.dispatch_hook("response", {"response": hooks_list}, "Data") == result 19 | 20 | 21 | def test_default_hooks(): 22 | assert hooks.default_hooks() == {"response": []} 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Summary. 2 | 3 | ## Expected Result 4 | 5 | What you expected. 6 | 7 | ## Actual Result 8 | 9 | What happened instead. 10 | 11 | ## Reproduction Steps 12 | 13 | ```python 14 | import requests 15 | 16 | ``` 17 | 18 | ## System Information 19 | 20 | $ python -m requests.help 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | This command is only available on Requests v2.16.4 and greater. Otherwise, 27 | please provide some basic information about your system (Python version, 28 | operating system, &c). 29 | -------------------------------------------------------------------------------- /tests/certs/expired/ca/ca.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | prompt = no 4 | default_md = sha256 5 | encrypt_key = no 6 | distinguished_name = dn 7 | x509_extensions = v3_ca 8 | 9 | [dn] 10 | C = US # country code 11 | O = Python Software Foundation # organization 12 | OU = python-requests # organization unit/department 13 | CN = Self-Signed Root CA # common name / your cert name 14 | 15 | [v3_ca] 16 | basicConstraints = critical, CA:true 17 | keyUsage = critical, cRLSign, digitalSignature, keyCertSign 18 | -------------------------------------------------------------------------------- /tests/certs/expired/server/cert.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | req_extensions = v3_req 3 | distinguished_name = req_distinguished_name 4 | prompt=no 5 | 6 | [req_distinguished_name] 7 | C = US 8 | ST = DE 9 | O = Python Software Foundation 10 | OU = python-requests 11 | CN = localhost 12 | 13 | [v3_req] 14 | # Extensions to add to a certificate request 15 | basicConstraints = CA:FALSE 16 | keyUsage = digitalSignature, keyEncipherment 17 | extendedKeyUsage = serverAuth 18 | subjectAltName = @alt_names 19 | 20 | [alt_names] 21 | DNS.1 = *.localhost 22 | DNS.1 = localhost 23 | IP.1 = 127.0.0.1 24 | IP.2 = ::1 25 | -------------------------------------------------------------------------------- /tests/compat.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | try: 4 | import StringIO 5 | except ImportError: 6 | import io as StringIO 7 | 8 | try: 9 | from cStringIO import StringIO as cStringIO 10 | except ImportError: 11 | cStringIO = None 12 | 13 | 14 | def u(s): 15 | warnings.warn( 16 | ( 17 | "This helper function is no longer relevant in Python 3. " 18 | "Usage of this alias should be discontinued as it will be " 19 | "removed in a future release of Requests." 20 | ), 21 | DeprecationWarning, 22 | ) 23 | return s 24 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint code 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-24.04 11 | timeout-minutes: 10 12 | 13 | steps: 14 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 15 | - name: Set up Python 16 | uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 17 | with: 18 | python-version: "3.x" 19 | - name: Run pre-commit 20 | uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507 # v3.0.0 21 | -------------------------------------------------------------------------------- /docs/community/out-there.rst: -------------------------------------------------------------------------------- 1 | Integrations 2 | ============ 3 | 4 | Articles & Talks 5 | ================ 6 | - `Daniel Greenfeld's Review of Requests `_ 7 | - `Issac Kelly's 'Consuming Web APIs' talk `_ 8 | - `Blog post about Requests via Yum `_ 9 | - `Russian blog post introducing Requests `_ 10 | - `Sending JSON in Requests `_ 11 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: 'docs/|ext/' 2 | 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.4.0 6 | hooks: 7 | - id: check-yaml 8 | - id: debug-statements 9 | - id: end-of-file-fixer 10 | - id: trailing-whitespace 11 | - repo: https://github.com/PyCQA/isort 12 | rev: 5.12.0 13 | hooks: 14 | - id: isort 15 | - repo: https://github.com/psf/black 16 | rev: 23.7.0 17 | hooks: 18 | - id: black 19 | exclude: tests/test_lowlevel.py 20 | - repo: https://github.com/asottile/pyupgrade 21 | rev: v3.10.1 22 | hooks: 23 | - id: pyupgrade 24 | args: [--py37-plus] 25 | - repo: https://github.com/PyCQA/flake8 26 | rev: 6.1.0 27 | hooks: 28 | - id: flake8 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | 8 | 9 | ## Expected Result 10 | 11 | 12 | 13 | ## Actual Result 14 | 15 | 16 | 17 | ## Reproduction Steps 18 | 19 | ```python 20 | import requests 21 | 22 | ``` 23 | 24 | ## System Information 25 | 26 | $ python -m requests.help 27 | 28 | ```json 29 | { 30 | "paste": "here" 31 | } 32 | ``` 33 | 34 | 37 | -------------------------------------------------------------------------------- /tests/certs/mtls/client/cert.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | req_extensions = v3_req 3 | distinguished_name = req_distinguished_name 4 | prompt=no 5 | 6 | [req_distinguished_name] 7 | C = US 8 | ST = DE 9 | O = Python Software Foundation 10 | OU = python-requests 11 | CN = requests 12 | 13 | [v3_req] 14 | # Extensions to add to a certificate request 15 | basicConstraints = CA:FALSE 16 | keyUsage = digitalSignature, keyEncipherment 17 | extendedKeyUsage = clientAuth 18 | subjectAltName = @alt_names 19 | 20 | [alt_names] 21 | DNS.1 = *.localhost 22 | IP.1 = 127.0.0.1 23 | IP.2 = ::1 24 | URI.1 = spiffe://trust.python.org/v0/maintainer/sigmavirus24/project/requests/org/psf 25 | URI.2 = spiffe://trust.python.org/v1/maintainer:sigmavirus24/project:requests/org:psf 26 | URI.3 = spiffe://trust.python.org/v1/maintainer=sigmavirus24/project=requests/org=psf 27 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | 13 | # Build documentation in the "docs/" directory with Sphinx 14 | sphinx: 15 | configuration: docs/conf.py 16 | builder: "dirhtml" 17 | 18 | # Optionally build your docs in additional formats such as PDF and ePub 19 | formats: 20 | - pdf 21 | - epub 22 | 23 | # Optional but recommended, declare the Python requirements required 24 | # to build your documentation 25 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 26 | python: 27 | install: 28 | - path: . 29 | - requirements: docs/requirements.txt 30 | -------------------------------------------------------------------------------- /tests/certs/valid/server/cert.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | req_extensions = v3_req 3 | distinguished_name = req_distinguished_name 4 | prompt=no 5 | 6 | [req_distinguished_name] 7 | C = US 8 | ST = DE 9 | O = Python Software Foundation 10 | OU = python-requests 11 | CN = localhost 12 | 13 | [v3_req] 14 | # Extensions to add to a certificate request 15 | basicConstraints = critical, CA:FALSE 16 | keyUsage = critical, digitalSignature, keyEncipherment 17 | extendedKeyUsage = critical, serverAuth 18 | subjectAltName = critical, @alt_names 19 | 20 | [v3_ca] 21 | # Extensions to add to a certificate request 22 | basicConstraints = critical, CA:FALSE 23 | keyUsage = critical, digitalSignature, keyEncipherment 24 | extendedKeyUsage = critical, serverAuth 25 | subjectAltName = critical, @alt_names 26 | 27 | [alt_names] 28 | DNS.1 = *.localhost 29 | DNS.1 = localhost 30 | IP.1 = 127.0.0.1 31 | IP.2 = ::1 32 | -------------------------------------------------------------------------------- /src/requests/hooks.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.hooks 3 | ~~~~~~~~~~~~~~ 4 | 5 | This module provides the capabilities for the Requests hooks system. 6 | 7 | Available hooks: 8 | 9 | ``response``: 10 | The response generated from a Request. 11 | """ 12 | HOOKS = ["response"] 13 | 14 | 15 | def default_hooks(): 16 | return {event: [] for event in HOOKS} 17 | 18 | 19 | # TODO: response is the only one 20 | 21 | 22 | def dispatch_hook(key, hooks, hook_data, **kwargs): 23 | """Dispatches a hook dictionary on a given piece of data.""" 24 | hooks = hooks or {} 25 | hooks = hooks.get(key) 26 | if hooks: 27 | if hasattr(hooks, "__call__"): 28 | hooks = [hooks] 29 | for hook in hooks: 30 | _hook_data = hook(hook_data, **kwargs) 31 | if _hook_data is not None: 32 | hook_data = _hook_data 33 | return hook_data 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs 2 | init: 3 | python -m pip install -r requirements-dev.txt 4 | test: 5 | python -m pytest tests 6 | 7 | ci: 8 | python -m pytest tests --junitxml=report.xml 9 | 10 | test-readme: 11 | python setup.py check --restructuredtext --strict && ([ $$? -eq 0 ] && echo "README.rst and HISTORY.rst ok") || echo "Invalid markup in README.rst or HISTORY.rst!" 12 | 13 | coverage: 14 | python -m pytest --cov-config .coveragerc --verbose --cov-report term --cov-report xml --cov=src/requests tests 15 | 16 | .publishenv: 17 | python -m venv .publishenv 18 | .publishenv/bin/pip install 'twine>=1.5.0' build 19 | 20 | publish: .publishenv 21 | .publishenv/bin/python -m build 22 | .publishenv/bin/python -m twine upload --skip-existing dist/* 23 | rm -fr build dist .egg requests.egg-info 24 | 25 | docs: 26 | cd docs && make html 27 | @echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m" 28 | -------------------------------------------------------------------------------- /tests/test_help.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | from requests.help import info 4 | 5 | 6 | def test_system_ssl(): 7 | """Verify we're actually setting system_ssl when it should be available.""" 8 | assert info()["system_ssl"]["version"] != "" 9 | 10 | 11 | class VersionedPackage: 12 | def __init__(self, version): 13 | self.__version__ = version 14 | 15 | 16 | def test_idna_without_version_attribute(): 17 | """Older versions of IDNA don't provide a __version__ attribute, verify 18 | that if we have such a package, we don't blow up. 19 | """ 20 | with mock.patch("requests.help.idna", new=None): 21 | assert info()["idna"] == {"version": ""} 22 | 23 | 24 | def test_idna_with_version_attribute(): 25 | """Verify we're actually setting idna version when it should be available.""" 26 | with mock.patch("requests.help.idna", new=VersionedPackage("2.6")): 27 | assert info()["idna"] == {"version": "2.6"} 28 | -------------------------------------------------------------------------------- /docs/community/support.rst: -------------------------------------------------------------------------------- 1 | .. _support: 2 | 3 | Support 4 | ======= 5 | 6 | If you have questions or issues about Requests, there are several options: 7 | 8 | Stack Overflow 9 | -------------- 10 | 11 | If your question does not contain sensitive (possibly proprietary) 12 | information or can be properly anonymized, please ask a question on 13 | `Stack Overflow `_ 14 | and use the tag ``python-requests``. 15 | 16 | 17 | File an Issue 18 | ------------- 19 | 20 | If you notice some unexpected behaviour in Requests, or want to see support 21 | for a new feature, 22 | `file an issue on GitHub `_. 23 | 24 | 25 | Send a Tweet 26 | ------------ 27 | 28 | If your question is less than 280 characters, feel free to send a tweet to 29 | `@nateprewitt `_, 30 | `@sethmlarson `_, or 31 | `@sigmavirus24 `_. 32 | -------------------------------------------------------------------------------- /src/requests/packages.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from .compat import chardet 4 | 5 | # This code exists for backwards compatibility reasons. 6 | # I don't like it either. Just look the other way. :) 7 | 8 | for package in ("urllib3", "idna"): 9 | locals()[package] = __import__(package) 10 | # This traversal is apparently necessary such that the identities are 11 | # preserved (requests.packages.urllib3.* is urllib3.*) 12 | for mod in list(sys.modules): 13 | if mod == package or mod.startswith(f"{package}."): 14 | sys.modules[f"requests.packages.{mod}"] = sys.modules[mod] 15 | 16 | if chardet is not None: 17 | target = chardet.__name__ 18 | for mod in list(sys.modules): 19 | if mod == target or mod.startswith(f"{target}."): 20 | imported_mod = sys.modules[mod] 21 | sys.modules[f"requests.packages.{mod}"] = imported_mod 22 | mod = mod.replace(target, "chardet") 23 | sys.modules[f"requests.packages.{mod}"] = imported_mod 24 | -------------------------------------------------------------------------------- /docs/user/install.rst: -------------------------------------------------------------------------------- 1 | .. _install: 2 | 3 | Installation of Requests 4 | ======================== 5 | 6 | This part of the documentation covers the installation of Requests. 7 | The first step to using any software package is getting it properly installed. 8 | 9 | 10 | $ python -m pip install requests 11 | -------------------------------- 12 | 13 | To install Requests, simply run this simple command in your terminal of choice:: 14 | 15 | $ python -m pip install requests 16 | 17 | Get the Source Code 18 | ------------------- 19 | 20 | Requests is actively developed on GitHub, where the code is 21 | `always available `_. 22 | 23 | You can either clone the public repository:: 24 | 25 | $ git clone https://github.com/psf/requests.git 26 | 27 | Or, download the `tarball `_:: 28 | 29 | $ curl -OL https://github.com/psf/requests/tarball/main 30 | # optionally, zipball is also available (for Windows users). 31 | 32 | Once you have a copy of the source, you can embed it in your own Python 33 | package, or install it into your site-packages easily:: 34 | 35 | $ cd requests 36 | $ python -m pip install . 37 | -------------------------------------------------------------------------------- /tests/certs/expired/server/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIDHjCCAgYCAQAwbTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkRFMSMwIQYDVQQK 3 | DBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UECwwPcHl0aG9uLXJl 4 | cXVlc3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB 5 | DwAwggEKAoIBAQDcRRwk8IU1YoNu8CHzB5Vh8HP/yLfBtU69LLZq+7rDG31JlR5s 6 | lmcwLLoZ8opUQ5rg8JMRZ7toh5zB4Uc0B4Sg8RhQMSOZYBIJkXdHuqQkciR0vWnN 7 | vD/5CkWEhnj4dxE7xTbDufBlxmwAthC/u72UIsZHavAyLCBqsONa7xuTiogz/d+3 8 | G+525JrfVr05hhJpT4Ypx5YY+ABkIOuOk/XuudbGm5SquuX6BgjmgaGtDjAuE/Rn 9 | BnliIavCDrG0v3KGbG3Xxt7lFTu+98foForwGCbbQBraty27oZrzAtLltfIHlJRn 10 | jPz0JA9akNDhAihxEsTUhk2d7jFszsd0Ev7DAgMBAAGgbDBqBgkqhkiG9w0BCQ4x 11 | XTBbMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMB 12 | MCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATAN 13 | BgkqhkiG9w0BAQsFAAOCAQEAVVIxJlDrgeG0bOSufgVVRqDQx7XSd15mGlT+CynM 14 | lEFJ3Q9k98T2vRNNGVYYYZAnbdSOW9ACwWGcYm2bzIjbgZV0H2Kz0dLD/GrNuEY+ 15 | O9j6K2toFKc57G7UUkve+N74ldq+hkR4zbb6FQmTlnL2YaPp2dv5TxdMKfHEfPNf 16 | Bg8xpbXdoRc7CYW1ZACme+d2U063GVqQsrIfwGJ+BtE6aNo62T/oEm+G4Wy5iBay 17 | jNv/imwf+JKQ75bTvha9YLUg2scqdYwJj8JlBw7cvkBIHW8GydA3fX4dtV9YBbFi 18 | 8RTlWhhLgCXpYbLoDGOqF6f/MuPSIGkV1wVhCUfYA+p+Gw== 19 | -----END CERTIFICATE REQUEST----- 20 | -------------------------------------------------------------------------------- /tests/certs/valid/server/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIDKjCCAhICAQAwbTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkRFMSMwIQYDVQQK 3 | DBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UECwwPcHl0aG9uLXJl 4 | cXVlc3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB 5 | DwAwggEKAoIBAQDD3OzTz9TgOiJp/STy/au8G1EDVUuP3HWKAX5ZpkWSTYZfc7FF 6 | pgPQvBq83oh/K1+9Rw0/529N1+KeTp1i9vUBUM2wJ3EzykJP4rMFh+J/Nt6VFfJh 7 | 05pTQiHnc85l4U8Qz7fHS6Lc9EG/Yp6yDxt5OeK8QAkNYjvxVhVdpif3GlnICx1e 8 | y1EcPxb9rslERyz0eiL6+BtVbhlSvup/rz2skvaYxoh/pP1RVwbu8VtS0it046Fm 9 | U0TnIdsjrdFjHXNJ2JSs5g6FDB9QEFhYdDOonL4KMcAkXxBLYXpjJ5fj8/X4LFkU 10 | FINry+Q2zdFKYsghCxlW98hmJVJTscVWznqpAgMBAAGgeDB2BgkqhkiG9w0BCQ4x 11 | aTBnMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBYGA1UdJQEB/wQMMAoG 12 | CCsGAQUFBwMBMC8GA1UdEQEB/wQlMCOCCWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAA 13 | AAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAn8TdRWYAGL7L8JKpkX2FRMMY 14 | EuFOEeJ2UaQLRbVtb1RhkIkMT6UYulQ16K45dbFe4k8DT59/mHrTl0bJ6pqVPawa 15 | vo7vmKCrSYEz8GrImh1+i6lHaFiqbkAs1mJ6z86dZUofMYwfTPVh64ztamUqwBk7 16 | Dey+MzWUQvpTVqoaP7cLgzMy+XfcyGuWSoL6pX5XKkt4+A2wiCTsHul1sXOn4vQz 17 | 4xY96AUVnkKosXMWXvhbMkncLNH+gs+ZeQI0MekakuMa42N+0BAad3Zx60lifG3N 18 | ugyVUmvVI0Fq6QUlYp3YV6QQj3FDjbgOVsSJNh+2s4SIARJsb/k//Tddzxei7g== 19 | -----END CERTIFICATE REQUEST----- 20 | -------------------------------------------------------------------------------- /.github/workflows/close-issues.yml: -------------------------------------------------------------------------------- 1 | name: 'Autoclose Issues' 2 | 3 | on: 4 | issues: 5 | types: 6 | - labeled 7 | 8 | permissions: 9 | issues: write 10 | 11 | jobs: 12 | close_qa: 13 | if: github.event.label.name == 'actions/autoclose-qa' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - env: 17 | ISSUE_URL: ${{ github.event.issue.html_url }} 18 | GH_TOKEN: ${{ github.token }} 19 | run: | 20 | gh issue close $ISSUE_URL \ 21 | --comment "As described in the template, we won't be able to answer questions on this issue tracker. Please use [Stack Overflow](https://stackoverflow.com/)" \ 22 | --reason completed 23 | gh issue lock $ISSUE_URL --reason off_topic 24 | close_feature_request: 25 | if: github.event.label.name == 'actions/autoclose-feat' 26 | runs-on: ubuntu-latest 27 | steps: 28 | - env: 29 | ISSUE_URL: ${{ github.event.issue.html_url }} 30 | GH_TOKEN: ${{ github.token }} 31 | run: | 32 | gh issue close $ISSUE_URL \ 33 | --comment "As described in the template, Requests is not accepting feature requests" \ 34 | --reason "not planned" 35 | gh issue lock $ISSUE_URL --reason off_topic 36 | -------------------------------------------------------------------------------- /docs/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 |

2 | 4 |

5 | 6 |

7 | Requests is an elegant and simple HTTP library for Python, built for 8 | human beings. You are currently looking at the documentation of the 9 | development release. 10 |

11 | 12 |

Useful Links

13 | 30 | 31 | -------------------------------------------------------------------------------- /tests/certs/expired/ca/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDpDCCAoygAwIBAgIUQt0yyZmppkHKNx4aXRrmD5tvjbswDQYJKoZIhvcNAQEL 3 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 4 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 5 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMzI5MTM1MTQ1WhcNNDUwMzI0MTM1MTQ1WjBq 6 | MQswCQYDVQQGEwJVUzEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRp 7 | b24xGDAWBgNVBAsMD3B5dGhvbi1yZXF1ZXN0czEcMBoGA1UEAwwTU2VsZi1TaWdu 8 | ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9lSHzZ 9 | 0X+v0Zbz0g3a+o6Iwy6KQgA7dIQjf65IYJ1ZPXcL42esUntcX8PpQbLWa+bwp+FK 10 | dqlagCS2jI9dJz8Y3MnMLBmiiXvET6ub/S9u7VdtRxByoHydBEvNMKEMga64PwMe 11 | ztuZ6fX2xPmRnLQIippzfzdxDFHxbUWzjzEQEl+4EGbKX5vPi6A9yL3ofgMi4APZ 12 | C8/YoqAaqzjLIM9KZ/zqT36iQ6wsxBXAacd63L5M8lrAKfZoJeX6uYxNIIfaxQRz 13 | zVxdpVBjHJ/odqoadwKzU7YzN5Fs+6ATNvkrhlUzg1i0MyTGtCdkUIAt/hc6ZrW6 14 | /kqHpCgUwUc4Dq0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E 15 | BAMCAYYwHQYDVR0OBBYEFAhGiD3+10LBrdMW3+j/ceXMXSqcMA0GCSqGSIb3DQEB 16 | CwUAA4IBAQBRT21cyZ0Jx0JLA2ilYTLvpMsSryGyWrCOXlmRlBt1MAhmxdTRgCmu 17 | UB3UU2pfnrC16UeMVVS411lhzjowFXkXrjAqSUBRcetUIYHlpnGgDdUl4dV/X5kx 18 | HxD9VUBx/QwGeyzFhjzjeN89M2v9kPnhU/kkVfcsafwYiHdC6pwN6zeZNz7JP+GS 19 | rmI+KVpm5C+Nz6ekm3TR8rFgPIsiDTbY3qj/DNYX2+NhpU1DZfm687vhOr3Ekljx 20 | NHNu9++STEjGpirrI8EqQnK+FP2fRJ5D82YZM0d++8tmHKpY0+FRCr8//459sgun 21 | CojmhIobDa2NuF81Jx6Cc7lagCPG3/Ts 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |

8 | 10 |

11 | 12 |

13 | Requests is an elegant and simple HTTP library for Python, built for 14 | human beings. 15 |

16 | 17 |

Useful Links

18 | 35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /tests/certs/mtls/client/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEGjCCAwICAQAwbDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkRFMSMwIQYDVQQK 3 | DBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UECwwPcHl0aG9uLXJl 4 | cXVlc3RzMREwDwYDVQQDDAhyZXF1ZXN0czCCASIwDQYJKoZIhvcNAQEBBQADggEP 5 | ADCCAQoCggEBAJrdvu5kvCy5g6w67gczETk/u6K0UBmf6Mv0lqXCp3Voyt5fv6SI 6 | /OPWrFV1+m4imNe5bLM7JUoUfkqkmULsjTTh7sxVLjW226vLSYOWWy7PA+OSwUTN 7 | LjydF1dazlPedHPYdmhVShCmyoOd1pUCDQn0/4cEA/WW4mtzZImmoCf/pyAM3XAC 8 | 9RBcSSJRywOTe6n9LY6Ko0YUW94ay2M4ClVblDxswDemaAsLFuciKmi53gKx4H/l 9 | areo8p60dgubooiMbcc4E9bzp0oJpfh7xhwKeJtCNEpOik1AiiQIZtwqmkkIHvtI 10 | Go3SZ7WAQU9Eh2r+u3E6aSl+N0PMXK4Y4JsCAwEAAaCCAWcwggFjBgkqhkiG9w0B 11 | CQ4xggFUMIIBUDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggr 12 | BgEFBQcDAjCCAR8GA1UdEQSCARYwggESggsqLmxvY2FsaG9zdIcEfwAAAYcQAAAA 13 | AAAAAAAAAAAAAAAAAYZNc3BpZmZlOi8vdHJ1c3QucHl0aG9uLm9yZy92MC9tYWlu 14 | dGFpbmVyL3NpZ21hdmlydXMyNC9wcm9qZWN0L3JlcXVlc3RzL29yZy9wc2aGTXNw 15 | aWZmZTovL3RydXN0LnB5dGhvbi5vcmcvdjEvbWFpbnRhaW5lcjpzaWdtYXZpcnVz 16 | MjQvcHJvamVjdDpyZXF1ZXN0cy9vcmc6cHNmhk1zcGlmZmU6Ly90cnVzdC5weXRo 17 | b24ub3JnL3YxL21haW50YWluZXI9c2lnbWF2aXJ1czI0L3Byb2plY3Q9cmVxdWVz 18 | dHMvb3JnPXBzZjANBgkqhkiG9w0BAQsFAAOCAQEAMOwYPyq+OpMRQUAgoRjfxTQO 19 | DiqfBzCsjUsPAacLTtebbWBx8y6TkLSb+/Qn3amq3ESo4iBqKpmVwdlAS4P486GD 20 | 9f78W3zkZ29jGcnQ+XHb7WvPvzBRoXImE276F9JGqJ+9q39Cbxzh0U2+ofBx2iGY 21 | sSutzU0B/l/FKZRc8thuFoeKqHwVePLGD9p2+2nYI9I08QoGqEokTcFAq0tZ858F 22 | 9PdxBZYOKOMpnLZhiJ8qZo23v3ycBXPOjg5ILtQ9EzHoNEA5Mxx/mfNLKJ0NktZD 23 | KXANLWKbXm+w9gTcBLtCPWNeqj5DIGPsHSfq/Bmjbp/o+uOJs6oq3s5rA7WrAA== 24 | -----END CERTIFICATE REQUEST----- 25 | -------------------------------------------------------------------------------- /src/requests/_internal_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests._internal_utils 3 | ~~~~~~~~~~~~~~ 4 | 5 | Provides utility functions that are consumed internally by Requests 6 | which depend on extremely few external helpers (such as compat) 7 | """ 8 | import re 9 | 10 | from .compat import builtin_str 11 | 12 | _VALID_HEADER_NAME_RE_BYTE = re.compile(rb"^[^:\s][^:\r\n]*$") 13 | _VALID_HEADER_NAME_RE_STR = re.compile(r"^[^:\s][^:\r\n]*$") 14 | _VALID_HEADER_VALUE_RE_BYTE = re.compile(rb"^\S[^\r\n]*$|^$") 15 | _VALID_HEADER_VALUE_RE_STR = re.compile(r"^\S[^\r\n]*$|^$") 16 | 17 | _HEADER_VALIDATORS_STR = (_VALID_HEADER_NAME_RE_STR, _VALID_HEADER_VALUE_RE_STR) 18 | _HEADER_VALIDATORS_BYTE = (_VALID_HEADER_NAME_RE_BYTE, _VALID_HEADER_VALUE_RE_BYTE) 19 | HEADER_VALIDATORS = { 20 | bytes: _HEADER_VALIDATORS_BYTE, 21 | str: _HEADER_VALIDATORS_STR, 22 | } 23 | 24 | 25 | def to_native_string(string, encoding="ascii"): 26 | """Given a string object, regardless of type, returns a representation of 27 | that string in the native string type, encoding and decoding where 28 | necessary. This assumes ASCII unless told otherwise. 29 | """ 30 | if isinstance(string, builtin_str): 31 | out = string 32 | else: 33 | out = string.decode(encoding) 34 | 35 | return out 36 | 37 | 38 | def unicode_is_ascii(u_string): 39 | """Determine if unicode string only contains ASCII characters. 40 | 41 | :param str u_string: unicode string to check. Must be unicode 42 | and not Python 2 `str`. 43 | :rtype: bool 44 | """ 45 | assert isinstance(u_string, str) 46 | try: 47 | u_string.encode("ascii") 48 | return True 49 | except UnicodeEncodeError: 50 | return False 51 | -------------------------------------------------------------------------------- /tests/certs/expired/ca/ca-private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQCfZUh82dF/r9GW 3 | 89IN2vqOiMMuikIAO3SEI3+uSGCdWT13C+NnrFJ7XF/D6UGy1mvm8KfhSnapWoAk 4 | toyPXSc/GNzJzCwZool7xE+rm/0vbu1XbUcQcqB8nQRLzTChDIGuuD8DHs7bmen1 5 | 9sT5kZy0CIqac383cQxR8W1Fs48xEBJfuBBmyl+bz4ugPci96H4DIuAD2QvP2KKg 6 | Gqs4yyDPSmf86k9+okOsLMQVwGnHety+TPJawCn2aCXl+rmMTSCH2sUEc81cXaVQ 7 | Yxyf6HaqGncCs1O2MzeRbPugEzb5K4ZVM4NYtDMkxrQnZFCALf4XOma1uv5Kh6Qo 8 | FMFHOA6tAgMBAAECgf9YadXLawbJzLx0/smE5fIVHccmCYqSlmgK46XvBjaREO8H 9 | GZEJ8IvP4W09PiUzDbzMXLDCRouLZKevtZJB82nRlfjh9l5/2aho/nsytVO6+8yq 10 | sfK5LNvYQ0Aey7ItosJMJ+bL1ErphHZB+J9Jz3scYaCAC5CFMC+lREVYZEEI9QD4 11 | P2D5QbmaSeu8jmL/H3fWHjNXWDprue3W/MIf96NZa3qJew45go4TAYYMe5i757KW 12 | Ja40VNfmsgbz4uI9oDXaYL/NkWUaQP1lnh+Mfrm1YnBe2wsLcP/WuM5h0bYzJW/1 13 | ZeSrZM3fqCMW6SJyrVE1qzqvtw1xQBlrq0B6q0ECgYEA0fi4+ySFGR+mL6k5UjP1 14 | roREqQgKaLgdhOvD88EnO93Nl6tJ3Qk8LyzPUNbxe1/xTUEKMtglBKOoxCHJJZlg 15 | xXnKBAQUtlmrLFKIGe+UCD+r+wfSpS6Sl7BUDmeCSczG9dPN5vnyZA4ixUke2SCC 16 | k4Eb9Q0AHyNnbXv928r0sfkCgYEAwlZRYmGTVva6cY2YEmMrqbWy4Wxm2Zmdo+Uq 17 | Xu1RZF9a3tGzNbGsyYdeLNY7vVZoVOm1paMJCA8ScNLFtCux2jEPqwqd1OZ8OLhA 18 | 1VF3/kYtUSdqwLzWoS1RdD6mZCAHeOE+N0pone4lt3A2o8wtpHsaDA+XSTw2rHLR 19 | LVS+b1UCgYEAtezJ4Ze31pfMdrkpmCa69JVXpBj6Y9c6hGN+aWFuq/k22/WmTuRk 20 | h/9MNR+3JQ1w1l3HB1ytXkKqxBz92hz1csReG3Kpu4EfxYxQriAdY7Q/P4Z8pXAf 21 | xVwayEw439aUgIQef8UKllSFHeiH2NrJKCKSZZT5CQG06HCo+Fn1/4kCgYAYuwtY 22 | TbqGUpefY7l6fYxM6IZ/EWB1SIs7FCq0MdctwsS5nk4EAzxN2SAu7IRlr91PEP7A 23 | uWKo1+Is4WWva/ASKDQqPAuh0EL2pNv7SYbPoPabYTzAkkdt82puNJrQGxNYWrGk 24 | L5/omSnLkkghyBX23IOQDVvfQf5jK6la73HckQKBgAI+iLECAkle9HvnJ3flicau 25 | 9FAU1/9pOdM+WogSanhYQ/P2rAwRiyCIkqu62/OoZR5g4kLxWqOOmVvsK3j+gs5F 26 | FtwN7gauq06MAHnWr6qC8ZltzMsGZTVDvqSH2vgV4T1V6ovVpTBPKQ1gWtABEmpm 27 | dyfeA6HHeRAHx8VRGpL6 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/certs/expired/server/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcRRwk8IU1YoNu 3 | 8CHzB5Vh8HP/yLfBtU69LLZq+7rDG31JlR5slmcwLLoZ8opUQ5rg8JMRZ7toh5zB 4 | 4Uc0B4Sg8RhQMSOZYBIJkXdHuqQkciR0vWnNvD/5CkWEhnj4dxE7xTbDufBlxmwA 5 | thC/u72UIsZHavAyLCBqsONa7xuTiogz/d+3G+525JrfVr05hhJpT4Ypx5YY+ABk 6 | IOuOk/XuudbGm5SquuX6BgjmgaGtDjAuE/RnBnliIavCDrG0v3KGbG3Xxt7lFTu+ 7 | 98foForwGCbbQBraty27oZrzAtLltfIHlJRnjPz0JA9akNDhAihxEsTUhk2d7jFs 8 | zsd0Ev7DAgMBAAECggEAUZjCX8a/ufJ3+OE42lQdWO4fsonS1I3LENYe70u4OC2X 9 | QGpenmAq8pQnDpSj/KocliZYfLKeII9YGRRQcaw1S/9z/8TsSJVnqSa7dpVj1+J2 10 | sc43AxEw65sL/Jdp+bT169vXOTNIpBMYkDzhwH0WMemd5Pfu6c8h5RQI7Pc1knYn 11 | nPNY848qSYCWOUjZS3QmBik/gp9X//yxVCyvxB3xVnb1cpvc952D90Va6nFIWfgN 12 | ix4NgFgAvwIxCFpWI2z7JF8uBdAHPeFAx8pFukQpAzwhaEILlgt3WbvEob9CsdP5 13 | E39SUkzxiIfVM1du+hRquk9SJ/X56OSLnEjxLarSIQKBgQDyVU00yrv7lG7TJLZ5 14 | YyfE20A7eUtYdcfatTKfsxKO4KVV+p0mGsNnFhhKziuT5/xtVunbUNFEOaUfmTUP 15 | dCjy4XkDbE/ufxzIm1WTSqknUluVoJRWKmLI5gbDFxu/XGRQNLxQbMK54l3N69PT 16 | EO4kz/jqBYbd4aEmtaSx2R8JowKBgQDosUTgBGDxDE2ODPVoXc+YjReOmVHvGMKK 17 | tA+KDBEs4spxaqhH0OFh6mewx3jA4VHbcIgM50STXrq1VL/QqYclDlY9/VWzkmqp 18 | 2Ekc4NoAl3H022pgcbmXx3qapC4Z3hokNFOlbtD9xQf9NMx6c5djTKMYTBrBBWXH 19 | oFhSz6PIYQKBgQCMGqkydmvMffq89CLTd3JMq/4s5GmdUSsk1VHZZuy50kOEvAoT 20 | N7H1bZ7J0Pz83Eji5jb6Z3U1nqZK6Ib20k/CbH1Mb1ifKLp5eOU27Rly9Hiiv15D 21 | munWALe0Hy4Zqs8MWBDv5pGGasuU/F1RUB5/BgaBNoTMz2AeQzJe6Iq7RQKBgCca 22 | Ku3OLpAzNhEp4k9wfEMxaoT/BMK+EWsHiRj0oCo/zi8y8iZnVoiCwHv3eTZIZt4O 23 | Uf6BGof9QjjYjgc9hcVXXGy8Vpt/fkceXmLo8hlpWbAA8yZT1hFIZzT3Y/va09/D 24 | n07MiXgrlQUay0XEiOsZ5Mpfd5t6EblzG4SG+gnhAoGAZ+shbacxhji7cUUYJLrO 25 | 9uZJCDCZiyq8yZ+lMzX1kILQwaP6VmSvF4TzKrkrCuD2HzUYcqebko/TvckeTp/a 26 | oYC2put3zt0CHBf/keeeJwjhff19qVyE9mpZwoo7PuS5zmM7pQOLxzCyAM9MdsCz 27 | kmnbborcfh74fkfRcwXm6G8= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/certs/mtls/client/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCa3b7uZLwsuYOs 3 | Ou4HMxE5P7uitFAZn+jL9Jalwqd1aMreX7+kiPzj1qxVdfpuIpjXuWyzOyVKFH5K 4 | pJlC7I004e7MVS41ttury0mDllsuzwPjksFEzS48nRdXWs5T3nRz2HZoVUoQpsqD 5 | ndaVAg0J9P+HBAP1luJrc2SJpqAn/6cgDN1wAvUQXEkiUcsDk3up/S2OiqNGFFve 6 | GstjOApVW5Q8bMA3pmgLCxbnIipoud4CseB/5Wq3qPKetHYLm6KIjG3HOBPW86dK 7 | CaX4e8YcCnibQjRKTopNQIokCGbcKppJCB77SBqN0me1gEFPRIdq/rtxOmkpfjdD 8 | zFyuGOCbAgMBAAECggEABHa5xyNOLTfXrMIyFDELoQvOO71YxbRPQHm3UeXPb9nq 9 | Zwh5fKOaLnMEmp4A7uW+ZBFrKatdwsnebgZaiIxK8ahFesxFvbScllIQt2NBE5NR 10 | +GBFg9cqKwMYJiNu6Qnzb1dg6lbzAJHeKncFNVxOxeey6dBa0NxdgF1eG32bBiwT 11 | yIr6JO7cK5JfcExls5yxdZMZiW08quaeFMQR6Wocod2caDgJUBVbZwivEoNI3ak4 12 | /kzQaxvRoDMM8uN3LrVH2YUJgURUxSbpOLu8ycZtfg8JRArprUYI0P0OD6iDlly1 13 | 3FhJXqBEY0dWQPmZKP/Elt3ywC1oncW+AqPh9cchiQKBgQDMriOKoBrTmplw0kbo 14 | EEuxTU1A23BqcZfn2+PoUww6UxOvStL/s7iupjl3g4CXw0RgIfyOuJQldLdq7mh6 15 | W7BpK855fH2CLy1VMdIFY1umHSgJ5Bayd5NmyKdfORUw88PTFFSARYyr5DDqufWg 16 | jI77BMjqHtbyujQKspV+9U66ZwKBgQDBsi5YptfaqMdzh343G5zAtCiGCd3m9NZO 17 | atEEvgq9LKqEVwvJ/FD+3QPAS1MN+ms9KcfJ3G05VUhhEsPGRKibgcE0FNA/VBDO 18 | jS2HK6kZ1M0clC5kHmQfLZxp1q3tA5nW6zqjVFdqYzJsis7G5YxFKhnzui0lgP6V 19 | I1Io+3QvrQKBgQCK6D+sq92o8AnkfICsq6qDCKA+PO68/pyGOUAiAoKQ7qK0W0Z5 20 | TMIwnRTxHCjgViAIUehx/6hjByQXiPcU2zcNGTLGVgtjl5rfb7FGANlJEg6DL+2L 21 | bwV1QwX75OSR1U136hsy9oByg6oDEvM040+B4gxsf0OHdYEuJWa5w8eLTwKBgCJt 22 | CM+416SFWu2tp0EkJzgYzRsFpermmTBWy8+L91yoE6Zx0iaUMdEadxA2Uwyo9WZp 23 | hpjaFI+cGMEoFKOokE8TQMOA74JR7qrHbNAZcnSk3c+2hohE3oasFKC7By6Y9T69 24 | kC53TxIZj1y7TwUKx2ODmBk5fcysoJLhNDkUeBIBAoGAQ/YMeMN/pSvTDCPhubbk 25 | 9bF0SwoN6DWrzw7gzMMhHlVSPM4fjdBA+wXbhnYF7hiNan7uShtRHVhwyfj+glBz 26 | KIkDxETjxTWx5mbo3tNf8xEMsbHZBe8KPlKxizdAOvShLvkpthTCPiyqn6XTvbs4 27 | vC0zZrsQWCYT4Wbm7gcOOAU= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/certs/valid/server/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDD3OzTz9TgOiJp 3 | /STy/au8G1EDVUuP3HWKAX5ZpkWSTYZfc7FFpgPQvBq83oh/K1+9Rw0/529N1+Ke 4 | Tp1i9vUBUM2wJ3EzykJP4rMFh+J/Nt6VFfJh05pTQiHnc85l4U8Qz7fHS6Lc9EG/ 5 | Yp6yDxt5OeK8QAkNYjvxVhVdpif3GlnICx1ey1EcPxb9rslERyz0eiL6+BtVbhlS 6 | vup/rz2skvaYxoh/pP1RVwbu8VtS0it046FmU0TnIdsjrdFjHXNJ2JSs5g6FDB9Q 7 | EFhYdDOonL4KMcAkXxBLYXpjJ5fj8/X4LFkUFINry+Q2zdFKYsghCxlW98hmJVJT 8 | scVWznqpAgMBAAECggEACY98I+6uJm/QBDpuFkpZmqn+r1n3gUMynZTrFPcvyC9u 9 | krQ0AAFViFfWOkfmg8abOsMAG5FxdmxGTJHrzsvdM748/A9A0FVcHUgkku2KGcmU 10 | 3dQfa7UHgG7m9sRJW+G+mUR6ZQkFHyHxH6Vxt6FTJvyzW5sIlhWodWRNUK/unXoe 11 | 5QNIh/PM9Mkg91wKVeg8AGdY27zfuUV0KLwhV052hCSwckayi7pjYrH2xDL8fahi 12 | Z/F43N1SI6Q7PTW6izDs2KrlGyexn97jOV+cooSXXaDvivTaB2K4RoidrPt+UAW4 13 | /e1zw/LbeBvQXX4vsyC9vLO+Av1gYo2PxAZ/ezc5gQKBgQDvY/kgUud6stdMs73N 14 | Qavu9o/Ul4oeQa4fsmfUwj43OjquxpXbfV9sNTLFxFbsl5ADGkpqsR3WhP2090TK 15 | 62vkyCBiaYZjyMY6WLDATEvrpfbc74ATEzTU+r9T1rEByq/atbWPZq/zoMo8aAdg 16 | Qk2X7gQO3pTpPeEpetYG42Di+QKBgQDRc9IqPeELQugXEuI0RZ8rsfGRSFKVRelQ 17 | Rz/KpD/S8SsE7ERL0w/w5KgE0IPPbh/SYX2KYxafCqTrPWDNaoguROvUoUJQvf4a 18 | uOMTCRkqdqj8j70zaPj2ohuIIZ3GZHyaXgl/isWtuZ5OeaoY5h3r+4gk5mO41Llz 19 | YikB71SRMQKBgGBNG18BetVFNI9Kj0QO8xeCYIHpJErfqShfIJ3aNiUJa6n7gTV2 20 | zfg9vlsIjN9IaUqWPPGGprYxcc5m2mm3IwQ57a0pPkLN9dBq9U+mYbQ+Y3ylbCRA 21 | SbST2nvjlflejDezeYJikM21FSYPw0fZ5FUGDuPcbpMVrYp+O7MxrTwhAoGAcjQq 22 | xemTiWZj0iDzwfisP1D5HHRIwyepfaI7wCwquMPS5w5EduuQZ5LloipnlHTBWR7b 23 | Kte4f+N35OREofySYFgoFnoPBKNzp/Jjrf9p/2NP5NYjHaMBDMl7JZDezEwCPNFF 24 | cIukGYN6M+PWwVjHu+Ica7JLcX5b1/QP1ARBIiECgYAsdDa0CoYTVWMeqMq9GjF3 25 | BElBKCLp6iYqpElWyKTj39LCnLhzRICyYQpblM8zZgtQIvRGT8DYh2HA1Q29yPzt 26 | Rgrz9yfFACdT5gUM5D6sx7L37xbtMQQ7YYOxEAfCUZ0qnMJgpNTJ8/ECkjGJZaif 27 | CXrx6XCdvrM/evZW2JZbyg== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | try: 2 | from http.server import HTTPServer, SimpleHTTPRequestHandler 3 | except ImportError: 4 | from BaseHTTPServer import HTTPServer 5 | from SimpleHTTPServer import SimpleHTTPRequestHandler 6 | 7 | import ssl 8 | import threading 9 | 10 | import pytest 11 | 12 | from requests.compat import urljoin 13 | 14 | 15 | def prepare_url(value): 16 | # Issue #1483: Make sure the URL always has a trailing slash 17 | httpbin_url = value.url.rstrip("/") + "/" 18 | 19 | def inner(*suffix): 20 | return urljoin(httpbin_url, "/".join(suffix)) 21 | 22 | return inner 23 | 24 | 25 | @pytest.fixture 26 | def httpbin(httpbin): 27 | return prepare_url(httpbin) 28 | 29 | 30 | @pytest.fixture 31 | def httpbin_secure(httpbin_secure): 32 | return prepare_url(httpbin_secure) 33 | 34 | 35 | @pytest.fixture 36 | def nosan_server(tmp_path_factory): 37 | # delay importing until the fixture in order to make it possible 38 | # to deselect the test via command-line when trustme is not available 39 | import trustme 40 | 41 | tmpdir = tmp_path_factory.mktemp("certs") 42 | ca = trustme.CA() 43 | # only commonName, no subjectAltName 44 | server_cert = ca.issue_cert(common_name="localhost") 45 | ca_bundle = str(tmpdir / "ca.pem") 46 | ca.cert_pem.write_to_path(ca_bundle) 47 | 48 | context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) 49 | server_cert.configure_cert(context) 50 | server = HTTPServer(("localhost", 0), SimpleHTTPRequestHandler) 51 | server.socket = context.wrap_socket(server.socket, server_side=True) 52 | server_thread = threading.Thread(target=server.serve_forever) 53 | server_thread.start() 54 | 55 | yield "localhost", server.server_address[1], ca_bundle 56 | 57 | server.shutdown() 58 | server_thread.join() 59 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Modifications: 2 | 3 | Copyright (c) 2011 Kenneth Reitz. 4 | 5 | 6 | Original Project: 7 | 8 | Copyright (c) 2010 by Armin Ronacher. 9 | 10 | 11 | Some rights reserved. 12 | 13 | Redistribution and use in source and binary forms of the theme, with or 14 | without modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | * Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | * The names of the contributors may not be used to endorse or 26 | promote products derived from this software without specific 27 | prior written permission. 28 | 29 | We kindly ask you to only use these themes in an unmodified manner just 30 | for Flask and Flask-related products, not for unrelated projects. If you 31 | like the visual style and want to use it for your own projects, please 32 | consider making some larger changes to the themes (such as changing 33 | font faces, sizes, colors or margins). 34 | 35 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 36 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 39 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 42 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 43 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 45 | POSSIBILITY OF SUCH DAMAGE. 46 | -------------------------------------------------------------------------------- /docs/community/release-process.rst: -------------------------------------------------------------------------------- 1 | Release Process and Rules 2 | ========================= 3 | 4 | .. versionadded:: v2.6.2 5 | 6 | Starting with the version to be released after ``v2.6.2``, the following rules 7 | will govern and describe how the Requests core team produces a new release. 8 | 9 | Major Releases 10 | -------------- 11 | 12 | A major release will include breaking changes. When it is versioned, it will 13 | be versioned as ``vX.0.0``. For example, if the previous release was 14 | ``v10.2.7`` the next version will be ``v11.0.0``. 15 | 16 | Breaking changes are changes that break backwards compatibility with prior 17 | versions. If the project were to change the ``text`` attribute on a 18 | ``Response`` object to a method, that would only happen in a Major release. 19 | 20 | Major releases may also include miscellaneous bug fixes. The core developers of 21 | Requests are committed to providing a good user experience. This means we're 22 | also committed to preserving backwards compatibility as much as possible. Major 23 | releases will be infrequent and will need strong justifications before they are 24 | considered. 25 | 26 | Minor Releases 27 | -------------- 28 | 29 | A minor release will not include breaking changes but may include miscellaneous 30 | bug fixes. If the previous version of Requests released was ``v10.2.7`` a minor 31 | release would be versioned as ``v10.3.0``. 32 | 33 | Minor releases will be backwards compatible with releases that have the same 34 | major version number. In other words, all versions that would start with 35 | ``v10.`` should be compatible with each other. 36 | 37 | Hotfix Releases 38 | --------------- 39 | 40 | A hotfix release will only include bug fixes that were missed when the project 41 | released the previous version. If the previous version of Requests released 42 | ``v10.2.7`` the hotfix release would be versioned as ``v10.2.8``. 43 | 44 | Hotfixes will **not** include upgrades to vendored dependencies after 45 | ``v2.6.2`` 46 | 47 | Reasoning 48 | --------- 49 | 50 | In the 2.5 and 2.6 release series, the Requests core team upgraded vendored 51 | dependencies and caused a great deal of headaches for both users and the core 52 | team. To reduce this pain, we're forming a concrete set of procedures so 53 | expectations will be properly set. 54 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | timeout-minutes: 10 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14-dev", "pypy-3.10", "pypy-3.11"] 16 | os: [ubuntu-22.04, macOS-latest, windows-latest] 17 | # Pypy-3.11 can't install openssl-sys with rust 18 | # which prevents us from testing in GHA. 19 | exclude: 20 | - { python-version: "pypy-3.11", os: "windows-latest" } 21 | 22 | steps: 23 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | cache: 'pip' 29 | allow-prereleases: true 30 | - name: Install dependencies 31 | run: | 32 | make 33 | - name: Run tests 34 | run: | 35 | make ci 36 | 37 | no_chardet: 38 | name: "No Character Detection" 39 | runs-on: ubuntu-latest 40 | strategy: 41 | fail-fast: true 42 | 43 | steps: 44 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 45 | - name: 'Set up Python 3.9' 46 | uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c 47 | with: 48 | python-version: '3.9' 49 | - name: Install dependencies 50 | run: | 51 | make 52 | python -m pip uninstall -y "charset_normalizer" "chardet" 53 | - name: Run tests 54 | run: | 55 | make ci 56 | 57 | urllib3: 58 | name: 'urllib3 1.x' 59 | runs-on: 'ubuntu-latest' 60 | strategy: 61 | fail-fast: true 62 | 63 | steps: 64 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 65 | - name: 'Set up Python 3.9' 66 | uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c 67 | with: 68 | python-version: '3.9' 69 | - name: Install dependencies 70 | run: | 71 | make 72 | python -m pip install "urllib3<2" 73 | - name: Run tests 74 | run: | 75 | make ci 76 | -------------------------------------------------------------------------------- /docs/_templates/hacks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 | 35 | 81 | -------------------------------------------------------------------------------- /docs/community/recommended.rst: -------------------------------------------------------------------------------- 1 | .. _recommended: 2 | 3 | Recommended Packages and Extensions 4 | =================================== 5 | 6 | Requests has a great variety of powerful and useful third-party extensions. 7 | This page provides an overview of some of the best of them. 8 | 9 | Certifi CA Bundle 10 | ----------------- 11 | 12 | `Certifi`_ is a carefully curated collection of Root Certificates for 13 | validating the trustworthiness of SSL certificates while verifying the 14 | identity of TLS hosts. It has been extracted from the Requests project. 15 | 16 | .. _Certifi: https://github.com/certifi/python-certifi 17 | 18 | CacheControl 19 | ------------ 20 | 21 | `CacheControl`_ is an extension that adds a full HTTP cache to Requests. This 22 | makes your web requests substantially more efficient, and should be used 23 | whenever you're making a lot of web requests. 24 | 25 | .. _CacheControl: https://cachecontrol.readthedocs.io/en/latest/ 26 | 27 | Requests-Toolbelt 28 | ----------------- 29 | 30 | `Requests-Toolbelt`_ is a collection of utilities that some users of Requests may desire, 31 | but do not belong in Requests proper. This library is actively maintained 32 | by members of the Requests core team, and reflects the functionality most 33 | requested by users within the community. 34 | 35 | .. _Requests-Toolbelt: https://toolbelt.readthedocs.io/en/latest/index.html 36 | 37 | 38 | Requests-Threads 39 | ---------------- 40 | 41 | `Requests-Threads`_ is a Requests session that returns the amazing Twisted's awaitable Deferreds instead of Response objects. This allows the use of ``async``/``await`` keyword usage on Python 3, or Twisted's style of programming, if desired. 42 | 43 | .. _Requests-Threads: https://github.com/requests/requests-threads 44 | 45 | Requests-OAuthlib 46 | ----------------- 47 | 48 | `requests-oauthlib`_ makes it possible to do the OAuth dance from Requests 49 | automatically. This is useful for the large number of websites that use OAuth 50 | to provide authentication. It also provides a lot of tweaks that handle ways 51 | that specific OAuth providers differ from the standard specifications. 52 | 53 | .. _requests-oauthlib: https://requests-oauthlib.readthedocs.io/en/latest/ 54 | 55 | 56 | Betamax 57 | ------- 58 | 59 | `Betamax`_ records your HTTP interactions so the NSA does not have to. 60 | A VCR imitation designed only for Python-Requests. 61 | 62 | .. _betamax: https://github.com/betamaxpy/betamax 63 | -------------------------------------------------------------------------------- /tests/test_structures.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from requests.structures import CaseInsensitiveDict, LookupDict 4 | 5 | 6 | class TestCaseInsensitiveDict: 7 | @pytest.fixture(autouse=True) 8 | def setup(self): 9 | """CaseInsensitiveDict instance with "Accept" header.""" 10 | self.case_insensitive_dict = CaseInsensitiveDict() 11 | self.case_insensitive_dict["Accept"] = "application/json" 12 | 13 | def test_list(self): 14 | assert list(self.case_insensitive_dict) == ["Accept"] 15 | 16 | possible_keys = pytest.mark.parametrize( 17 | "key", ("accept", "ACCEPT", "aCcEpT", "Accept") 18 | ) 19 | 20 | @possible_keys 21 | def test_getitem(self, key): 22 | assert self.case_insensitive_dict[key] == "application/json" 23 | 24 | @possible_keys 25 | def test_delitem(self, key): 26 | del self.case_insensitive_dict[key] 27 | assert key not in self.case_insensitive_dict 28 | 29 | def test_lower_items(self): 30 | assert list(self.case_insensitive_dict.lower_items()) == [ 31 | ("accept", "application/json") 32 | ] 33 | 34 | def test_repr(self): 35 | assert repr(self.case_insensitive_dict) == "{'Accept': 'application/json'}" 36 | 37 | def test_copy(self): 38 | copy = self.case_insensitive_dict.copy() 39 | assert copy is not self.case_insensitive_dict 40 | assert copy == self.case_insensitive_dict 41 | 42 | @pytest.mark.parametrize( 43 | "other, result", 44 | ( 45 | ({"AccePT": "application/json"}, True), 46 | ({}, False), 47 | (None, False), 48 | ), 49 | ) 50 | def test_instance_equality(self, other, result): 51 | assert (self.case_insensitive_dict == other) is result 52 | 53 | 54 | class TestLookupDict: 55 | @pytest.fixture(autouse=True) 56 | def setup(self): 57 | """LookupDict instance with "bad_gateway" attribute.""" 58 | self.lookup_dict = LookupDict("test") 59 | self.lookup_dict.bad_gateway = 502 60 | 61 | def test_repr(self): 62 | assert repr(self.lookup_dict) == "" 63 | 64 | get_item_parameters = pytest.mark.parametrize( 65 | "key, value", 66 | ( 67 | ("bad_gateway", 502), 68 | ("not_a_key", None), 69 | ), 70 | ) 71 | 72 | @get_item_parameters 73 | def test_getitem(self, key, value): 74 | assert self.lookup_dict[key] == value 75 | 76 | @get_item_parameters 77 | def test_get(self, key, value): 78 | assert self.lookup_dict.get(key) == value 79 | -------------------------------------------------------------------------------- /src/requests/compat.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.compat 3 | ~~~~~~~~~~~~~~~ 4 | 5 | This module previously handled import compatibility issues 6 | between Python 2 and Python 3. It remains for backwards 7 | compatibility until the next major version. 8 | """ 9 | 10 | import importlib 11 | import sys 12 | 13 | # ------- 14 | # urllib3 15 | # ------- 16 | from urllib3 import __version__ as urllib3_version 17 | 18 | # Detect which major version of urllib3 is being used. 19 | try: 20 | is_urllib3_1 = int(urllib3_version.split(".")[0]) == 1 21 | except (TypeError, AttributeError): 22 | # If we can't discern a version, prefer old functionality. 23 | is_urllib3_1 = True 24 | 25 | # ------------------- 26 | # Character Detection 27 | # ------------------- 28 | 29 | 30 | def _resolve_char_detection(): 31 | """Find supported character detection libraries.""" 32 | chardet = None 33 | for lib in ("chardet", "charset_normalizer"): 34 | if chardet is None: 35 | try: 36 | chardet = importlib.import_module(lib) 37 | except ImportError: 38 | pass 39 | return chardet 40 | 41 | 42 | chardet = _resolve_char_detection() 43 | 44 | # ------- 45 | # Pythons 46 | # ------- 47 | 48 | # Syntax sugar. 49 | _ver = sys.version_info 50 | 51 | #: Python 2.x? 52 | is_py2 = _ver[0] == 2 53 | 54 | #: Python 3.x? 55 | is_py3 = _ver[0] == 3 56 | 57 | # json/simplejson module import resolution 58 | has_simplejson = False 59 | try: 60 | import simplejson as json 61 | 62 | has_simplejson = True 63 | except ImportError: 64 | import json 65 | 66 | if has_simplejson: 67 | from simplejson import JSONDecodeError 68 | else: 69 | from json import JSONDecodeError 70 | 71 | # Keep OrderedDict for backwards compatibility. 72 | from collections import OrderedDict 73 | from collections.abc import Callable, Mapping, MutableMapping 74 | from http import cookiejar as cookielib 75 | from http.cookies import Morsel 76 | from io import StringIO 77 | 78 | # -------------- 79 | # Legacy Imports 80 | # -------------- 81 | from urllib.parse import ( 82 | quote, 83 | quote_plus, 84 | unquote, 85 | unquote_plus, 86 | urldefrag, 87 | urlencode, 88 | urljoin, 89 | urlparse, 90 | urlsplit, 91 | urlunparse, 92 | ) 93 | from urllib.request import ( 94 | getproxies, 95 | getproxies_environment, 96 | parse_http_list, 97 | proxy_bypass, 98 | proxy_bypass_environment, 99 | ) 100 | 101 | builtin_str = str 102 | str = str 103 | bytes = bytes 104 | basestring = (str, bytes) 105 | numeric_types = (int, float) 106 | integer_types = (int,) 107 | -------------------------------------------------------------------------------- /tests/certs/mtls/client/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDpjCCAo6gAwIBAgIUTzbDp+B1umRS0Q7rgefxif9Im4IwDQYJKoZIhvcNAQEL 3 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 4 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 5 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIzWhcNMjcwMjE3MDAzODIzWjBs 6 | MQswCQYDVQQGEwJVUzELMAkGA1UECAwCREUxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0 7 | d2FyZSBGb3VuZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxETAPBgNV 8 | BAMMCHJlcXVlc3RzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmt2+ 9 | 7mS8LLmDrDruBzMROT+7orRQGZ/oy/SWpcKndWjK3l+/pIj849asVXX6biKY17ls 10 | szslShR+SqSZQuyNNOHuzFUuNbbbq8tJg5ZbLs8D45LBRM0uPJ0XV1rOU950c9h2 11 | aFVKEKbKg53WlQINCfT/hwQD9Zbia3NkiaagJ/+nIAzdcAL1EFxJIlHLA5N7qf0t 12 | joqjRhRb3hrLYzgKVVuUPGzAN6ZoCwsW5yIqaLneArHgf+Vqt6jynrR2C5uiiIxt 13 | xzgT1vOnSgml+HvGHAp4m0I0Sk6KTUCKJAhm3CqaSQge+0gajdJntYBBT0SHav67 14 | cTppKX43Q8xcrhjgmwIDAQABo0IwQDAdBgNVHQ4EFgQU3Ujw+VSuTzPgHqU+KFwO 15 | T4t2MHswHwYDVR0jBBgwFoAUCEaIPf7XQsGt0xbf6P9x5cxdKpwwDQYJKoZIhvcN 16 | AQELBQADggEBAEvrKXWHRRDIf26j2fH9hanx0nh+lxvI4jSWYmK0rJXZA3htEvWn 17 | gcoUspmhmLlgmRMP88lGINMjTsogUubu2j6WF/WuKxAWWvl/hUgK8NzOwOHvByPB 18 | lhO/rSNGdOWGlnaW1TVO4kI8w6c6LwzOCpY8WvOZLW+v7duLhKUdhaJMR9X77Tbt 19 | ohHkyYm0gV79izaFRpA6mdYoyHOR4gyWAKaj942doU794fT4gqQacRNifl/kUbWI 20 | lilktTLyLnmBJgrxHVBxcGe8kwnPafA1k3Gb1w7mY5BSoGKglKjutTfqR3uTjAQb 21 | vskS4SGXmsEIjLrXYWFNHyoC3pCBXWhX6Kc= 22 | -----END CERTIFICATE----- 23 | -----BEGIN CERTIFICATE----- 24 | MIIDlDCCAnygAwIBAgIUG/CTOPIQbH2BI36TyThUChQyR8wwDQYJKoZIhvcNAQEL 25 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 26 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 27 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIyWhcNNDUwMjEyMDAzODIyWjBq 28 | MQswCQYDVQQGEwJVUzEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRp 29 | b24xGDAWBgNVBAsMD3B5dGhvbi1yZXF1ZXN0czEcMBoGA1UEAwwTU2VsZi1TaWdu 30 | ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9lSHzZ 31 | 0X+v0Zbz0g3a+o6Iwy6KQgA7dIQjf65IYJ1ZPXcL42esUntcX8PpQbLWa+bwp+FK 32 | dqlagCS2jI9dJz8Y3MnMLBmiiXvET6ub/S9u7VdtRxByoHydBEvNMKEMga64PwMe 33 | ztuZ6fX2xPmRnLQIippzfzdxDFHxbUWzjzEQEl+4EGbKX5vPi6A9yL3ofgMi4APZ 34 | C8/YoqAaqzjLIM9KZ/zqT36iQ6wsxBXAacd63L5M8lrAKfZoJeX6uYxNIIfaxQRz 35 | zVxdpVBjHJ/odqoadwKzU7YzN5Fs+6ATNvkrhlUzg1i0MyTGtCdkUIAt/hc6ZrW6 36 | /kqHpCgUwUc4Dq0CAwEAAaMyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 37 | CEaIPf7XQsGt0xbf6P9x5cxdKpwwDQYJKoZIhvcNAQELBQADggEBAHMgyQNA3DQG 38 | 0l9eX8RMl4YNwhAXChU/wOTcvD+F4OsJcPqzy6QHFh1AbBBGOI9/HN7du+EiKwGZ 39 | wE+69FEsSbhSv22XidPm+kHPTguWl1eKveeWrrT5MPl9F48s14lKb/8yMEa1/ryG 40 | Iu8NQ6ZL91JbTXdkLoBDya9HZqyXjwcGkXLE8fSqTibJ7EhWS5Q3Ic7WPgUoGAum 41 | b5ygoxqhm+SEyXC2/LAktwmFawkv1SsMeYpT790VIFqJ/TVVnUl+gQ2RjSEl2WLb 42 | UO4Hwq4FZbWF9NrY6JVThLmbcr8eW6+UxWfiXHLw/qTRre4/3367QAUQRt7EuEsb 43 | KOWpOS3fbsI= 44 | -----END CERTIFICATE----- 45 | -------------------------------------------------------------------------------- /tests/certs/expired/server/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDpzCCAo+gAwIBAgIUTzbDp+B1umRS0Q7rgefxif9Im4EwDQYJKoZIhvcNAQEL 3 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 4 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 5 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIyWhcNMjUwMjE3MDAzODIyWjBt 6 | MQswCQYDVQQGEwJVUzELMAkGA1UECAwCREUxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0 7 | d2FyZSBGb3VuZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxEjAQBgNV 8 | BAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxF 9 | HCTwhTVig27wIfMHlWHwc//It8G1Tr0stmr7usMbfUmVHmyWZzAsuhnyilRDmuDw 10 | kxFnu2iHnMHhRzQHhKDxGFAxI5lgEgmRd0e6pCRyJHS9ac28P/kKRYSGePh3ETvF 11 | NsO58GXGbAC2EL+7vZQixkdq8DIsIGqw41rvG5OKiDP937cb7nbkmt9WvTmGEmlP 12 | hinHlhj4AGQg646T9e651sablKq65foGCOaBoa0OMC4T9GcGeWIhq8IOsbS/coZs 13 | bdfG3uUVO773x+gWivAYJttAGtq3LbuhmvMC0uW18geUlGeM/PQkD1qQ0OECKHES 14 | xNSGTZ3uMWzOx3QS/sMCAwEAAaNCMEAwHQYDVR0OBBYEFFK1WmMqRSzUD2isk8TL 15 | M3JfsVczMB8GA1UdIwQYMBaAFAhGiD3+10LBrdMW3+j/ceXMXSqcMA0GCSqGSIb3 16 | DQEBCwUAA4IBAQCekjxplL/AI32WtODgw7FpTXNXdyNy8PWEhn3ufL0MqiyseYOZ 17 | bIa0PAecsArlKs5hXJzB7p/hu5CZdvaCButw1jyWQBySCpeJXn3FmGdTkBvhwBHv 18 | y6npmBoy/nbLkIRNRcoLbALlfn/0iGWfmDTRblT7vRNWJmZCZCTA/+ILXJ36ItbF 19 | 3JCs3ARF6XWORuZs5Y8cNloOy2brAC/4EHnTfOZBQf8cL8CfHlcNa+nbG1j+wVNO 20 | 60e/0v9zTxa2wNzdnLBCW4rqJFJ44aGClxat5tWuypv0snA/0xrqIYWTQGXZPVT6 21 | rET47dfVbj1QxmW3sAyuy5PskZA9T7pOhcjR 22 | -----END CERTIFICATE----- 23 | -----BEGIN CERTIFICATE----- 24 | MIIDlDCCAnygAwIBAgIUG/CTOPIQbH2BI36TyThUChQyR8wwDQYJKoZIhvcNAQEL 25 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 26 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 27 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIyWhcNNDUwMjEyMDAzODIyWjBq 28 | MQswCQYDVQQGEwJVUzEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRp 29 | b24xGDAWBgNVBAsMD3B5dGhvbi1yZXF1ZXN0czEcMBoGA1UEAwwTU2VsZi1TaWdu 30 | ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9lSHzZ 31 | 0X+v0Zbz0g3a+o6Iwy6KQgA7dIQjf65IYJ1ZPXcL42esUntcX8PpQbLWa+bwp+FK 32 | dqlagCS2jI9dJz8Y3MnMLBmiiXvET6ub/S9u7VdtRxByoHydBEvNMKEMga64PwMe 33 | ztuZ6fX2xPmRnLQIippzfzdxDFHxbUWzjzEQEl+4EGbKX5vPi6A9yL3ofgMi4APZ 34 | C8/YoqAaqzjLIM9KZ/zqT36iQ6wsxBXAacd63L5M8lrAKfZoJeX6uYxNIIfaxQRz 35 | zVxdpVBjHJ/odqoadwKzU7YzN5Fs+6ATNvkrhlUzg1i0MyTGtCdkUIAt/hc6ZrW6 36 | /kqHpCgUwUc4Dq0CAwEAAaMyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 37 | CEaIPf7XQsGt0xbf6P9x5cxdKpwwDQYJKoZIhvcNAQELBQADggEBAHMgyQNA3DQG 38 | 0l9eX8RMl4YNwhAXChU/wOTcvD+F4OsJcPqzy6QHFh1AbBBGOI9/HN7du+EiKwGZ 39 | wE+69FEsSbhSv22XidPm+kHPTguWl1eKveeWrrT5MPl9F48s14lKb/8yMEa1/ryG 40 | Iu8NQ6ZL91JbTXdkLoBDya9HZqyXjwcGkXLE8fSqTibJ7EhWS5Q3Ic7WPgUoGAum 41 | b5ygoxqhm+SEyXC2/LAktwmFawkv1SsMeYpT790VIFqJ/TVVnUl+gQ2RjSEl2WLb 42 | UO4Hwq4FZbWF9NrY6JVThLmbcr8eW6+UxWfiXHLw/qTRre4/3367QAUQRt7EuEsb 43 | KOWpOS3fbsI= 44 | -----END CERTIFICATE----- 45 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [main] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [main] 14 | schedule: 15 | - cron: '0 23 * * 0' 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | analyze: 22 | permissions: 23 | actions: read # for github/codeql-action/init to get workflow details 24 | contents: read # for actions/checkout to fetch code 25 | security-events: write # for github/codeql-action/autobuild to send a status report 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | 29 | strategy: 30 | fail-fast: false 31 | 32 | 33 | steps: 34 | - name: Checkout repository 35 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 36 | with: 37 | # We must fetch at least the immediate parents so that if this is 38 | # a pull request then we can checkout the head. 39 | fetch-depth: 2 40 | 41 | # If this run was triggered by a pull request event, then checkout 42 | # the head of the pull request instead of the merge commit. 43 | - run: git checkout HEAD^2 44 | if: ${{ github.event_name == 'pull_request' }} 45 | 46 | # Initializes the CodeQL tools for scanning. 47 | - name: Initialize CodeQL 48 | uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 49 | with: 50 | languages: "python" 51 | # If you wish to specify custom queries, you can do so here or in a config file. 52 | # By default, queries listed here will override any specified in a config file. 53 | # Prefix the list here with "+" to use these queries and those in the config file. 54 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 https://git.io/JvXDl 63 | 64 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 65 | # and modify them (or add more) to build your code if your project 66 | # uses a compiled language 67 | 68 | #- run: | 69 | # make bootstrap 70 | # make release 71 | 72 | - name: Perform CodeQL Analysis 73 | uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 74 | -------------------------------------------------------------------------------- /tests/certs/valid/server/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEEDCCAvigAwIBAgIUTzbDp+B1umRS0Q7rgefxif9Im4MwDQYJKoZIhvcNAQEL 3 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 4 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 5 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIzWhcNNDQxMTA0MDAzODIzWjBt 6 | MQswCQYDVQQGEwJVUzELMAkGA1UECAwCREUxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0 7 | d2FyZSBGb3VuZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxEjAQBgNV 8 | BAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMPc 9 | 7NPP1OA6Imn9JPL9q7wbUQNVS4/cdYoBflmmRZJNhl9zsUWmA9C8GrzeiH8rX71H 10 | DT/nb03X4p5OnWL29QFQzbAncTPKQk/iswWH4n823pUV8mHTmlNCIedzzmXhTxDP 11 | t8dLotz0Qb9inrIPG3k54rxACQ1iO/FWFV2mJ/caWcgLHV7LURw/Fv2uyURHLPR6 12 | Ivr4G1VuGVK+6n+vPayS9pjGiH+k/VFXBu7xW1LSK3TjoWZTROch2yOt0WMdc0nY 13 | lKzmDoUMH1AQWFh0M6icvgoxwCRfEEthemMnl+Pz9fgsWRQUg2vL5DbN0UpiyCEL 14 | GVb3yGYlUlOxxVbOeqkCAwEAAaOBqjCBpzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB 15 | /wQEAwIFoDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATAvBgNVHREBAf8EJTAjggls 16 | b2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwHQYDVR0OBBYEFGg5Q9Ll 17 | ADkONmo02kmPg9+aiOxQMB8GA1UdIwQYMBaAFAhGiD3+10LBrdMW3+j/ceXMXSqc 18 | MA0GCSqGSIb3DQEBCwUAA4IBAQA1RlUI34tXrIdsRiALD8iLDFhh816B7qUi+F1j 19 | 3dOkTNgYw0CnQ+Vm4wrQjCEVSDQ/9sry5DOfXeGziDpFlZmQ0UuAeM1EJJD5/42l 20 | C/eKquA09+IMEq2U03GPhijrC68sFCfr5wgoB/4HmcZ1c3kLYvRaJhEK7AHDgenY 21 | knKbvuKAiRbCd584eG8HFOW7xv+YqGZ257Ic9flbarkPrazmAJg2P709w7/fP83x 22 | 7lnkPZY09jS3lcIpEdtWvzfm+anGF190hKA1yfPdO5bYPvUcEMxXdMtQ6/pbZd5i 23 | F6t95o9CPCqI/lLIn5jAf9Z+Iil3GmKefEZYIGmKJ85HGUqE 24 | -----END CERTIFICATE----- 25 | -----BEGIN CERTIFICATE----- 26 | MIIDlDCCAnygAwIBAgIUG/CTOPIQbH2BI36TyThUChQyR8wwDQYJKoZIhvcNAQEL 27 | BQAwajELMAkGA1UEBhMCVVMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 28 | ZGF0aW9uMRgwFgYDVQQLDA9weXRob24tcmVxdWVzdHMxHDAaBgNVBAMME1NlbGYt 29 | U2lnbmVkIFJvb3QgQ0EwHhcNMjUwMjE3MDAzODIyWhcNNDUwMjEyMDAzODIyWjBq 30 | MQswCQYDVQQGEwJVUzEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRp 31 | b24xGDAWBgNVBAsMD3B5dGhvbi1yZXF1ZXN0czEcMBoGA1UEAwwTU2VsZi1TaWdu 32 | ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9lSHzZ 33 | 0X+v0Zbz0g3a+o6Iwy6KQgA7dIQjf65IYJ1ZPXcL42esUntcX8PpQbLWa+bwp+FK 34 | dqlagCS2jI9dJz8Y3MnMLBmiiXvET6ub/S9u7VdtRxByoHydBEvNMKEMga64PwMe 35 | ztuZ6fX2xPmRnLQIippzfzdxDFHxbUWzjzEQEl+4EGbKX5vPi6A9yL3ofgMi4APZ 36 | C8/YoqAaqzjLIM9KZ/zqT36iQ6wsxBXAacd63L5M8lrAKfZoJeX6uYxNIIfaxQRz 37 | zVxdpVBjHJ/odqoadwKzU7YzN5Fs+6ATNvkrhlUzg1i0MyTGtCdkUIAt/hc6ZrW6 38 | /kqHpCgUwUc4Dq0CAwEAAaMyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 39 | CEaIPf7XQsGt0xbf6P9x5cxdKpwwDQYJKoZIhvcNAQELBQADggEBAHMgyQNA3DQG 40 | 0l9eX8RMl4YNwhAXChU/wOTcvD+F4OsJcPqzy6QHFh1AbBBGOI9/HN7du+EiKwGZ 41 | wE+69FEsSbhSv22XidPm+kHPTguWl1eKveeWrrT5MPl9F48s14lKb/8yMEa1/ryG 42 | Iu8NQ6ZL91JbTXdkLoBDya9HZqyXjwcGkXLE8fSqTibJ7EhWS5Q3Ic7WPgUoGAum 43 | b5ygoxqhm+SEyXC2/LAktwmFawkv1SsMeYpT790VIFqJ/TVVnUl+gQ2RjSEl2WLb 44 | UO4Hwq4FZbWF9NrY6JVThLmbcr8eW6+UxWfiXHLw/qTRre4/3367QAUQRt7EuEsb 45 | KOWpOS3fbsI= 46 | -----END CERTIFICATE----- 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Before opening any issues or proposing any pull requests, please read 4 | our [Contributor's Guide](https://requests.readthedocs.io/en/latest/dev/contributing/). 5 | 6 | To get the greatest chance of helpful responses, please also observe the 7 | following additional notes. 8 | 9 | ## Questions 10 | 11 | The GitHub issue tracker is for *bug reports* and *feature requests*. Please do 12 | not use it to ask questions about how to use Requests. These questions should 13 | instead be directed to [Stack Overflow](https://stackoverflow.com/). Make sure 14 | that your question is tagged with the `python-requests` tag when asking it on 15 | Stack Overflow, to ensure that it is answered promptly and accurately. 16 | 17 | ## Good Bug Reports 18 | 19 | Please be aware of the following things when filing bug reports: 20 | 21 | 1. Avoid raising duplicate issues. *Please* use the GitHub issue search feature 22 | to check whether your bug report or feature request has been mentioned in 23 | the past. Duplicate bug reports and feature requests are a huge maintenance 24 | burden on the limited resources of the project. If it is clear from your 25 | report that you would have struggled to find the original, that's ok, but 26 | if searching for a selection of words in your issue title would have found 27 | the duplicate then the issue will likely be closed extremely abruptly. 28 | 2. When filing bug reports about exceptions or tracebacks, please include the 29 | *complete* traceback. Partial tracebacks, or just the exception text, are 30 | not helpful. Issues that do not contain complete tracebacks may be closed 31 | without warning. 32 | 3. Make sure you provide a suitable amount of information to work with. This 33 | means you should provide: 34 | 35 | - Guidance on **how to reproduce the issue**. Ideally, this should be a 36 | *small* code sample that can be run immediately by the maintainers. 37 | Failing that, let us know what you're doing, how often it happens, what 38 | environment you're using, etc. Be thorough: it prevents us needing to ask 39 | further questions. 40 | - Tell us **what you expected to happen**. When we run your example code, 41 | what are we expecting to happen? What does "success" look like for your 42 | code? 43 | - Tell us **what actually happens**. It's not helpful for you to say "it 44 | doesn't work" or "it fails". Tell us *how* it fails: do you get an 45 | exception? A hang? A non-200 status code? How was the actual result 46 | different from your expected result? 47 | - Tell us **what version of Requests you're using**, and 48 | **how you installed it**. Different versions of Requests behave 49 | differently and have different bugs, and some distributors of Requests 50 | ship patches on top of the code we supply. 51 | 52 | If you do not provide all of these things, it will take us much longer to 53 | fix your problem. If we ask you to clarify these and you never respond, we 54 | will close your issue without fixing it. 55 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | name: "Build dists" 14 | runs-on: "ubuntu-latest" 15 | environment: 16 | name: "publish" 17 | outputs: 18 | hashes: ${{ steps.hash.outputs.hashes }} 19 | artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }} 20 | 21 | steps: 22 | - name: Harden the runner (Audit all outbound calls) 23 | uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 24 | with: 25 | egress-policy: audit 26 | 27 | - name: "Checkout repository" 28 | uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" 29 | with: 30 | persist-credentials: false 31 | 32 | - name: "Setup Python" 33 | uses: "actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c" 34 | with: 35 | python-version: "3.x" 36 | 37 | - name: "Install dependencies" 38 | run: python -m pip install build==0.8.0 39 | 40 | - name: "Build dists" 41 | run: | 42 | SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) \ 43 | python -m build 44 | 45 | - name: "Generate hashes" 46 | id: hash 47 | run: | 48 | cd dist && echo "::set-output name=hashes::$(sha256sum * | base64 -w0)" 49 | 50 | - name: "Upload dists" 51 | uses: "actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02" 52 | id: upload-artifact 53 | with: 54 | name: "dist" 55 | path: "dist/" 56 | if-no-files-found: error 57 | retention-days: 5 58 | 59 | provenance: 60 | needs: [build] 61 | permissions: 62 | actions: read 63 | contents: write 64 | id-token: write # Needed to access the workflow's OIDC identity. 65 | uses: "slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0" 66 | with: 67 | base64-subjects: "${{ needs.build.outputs.hashes }}" 68 | upload-assets: true 69 | compile-generator: true # Workaround for https://github.com/slsa-framework/slsa-github-generator/issues/1163 70 | 71 | publish: 72 | name: "Publish" 73 | if: startsWith(github.ref, 'refs/tags/') 74 | needs: ["build", "provenance"] 75 | permissions: 76 | contents: write 77 | id-token: write 78 | runs-on: "ubuntu-latest" 79 | 80 | steps: 81 | - name: Harden the runner (Audit all outbound calls) 82 | uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 83 | with: 84 | egress-policy: audit 85 | 86 | - name: "Download dists" 87 | uses: "actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0" # v5.0.0 88 | with: 89 | artifact-ids: ${{ needs.build.outputs.artifact-id }} 90 | path: "dist/" 91 | 92 | - name: "Publish dists to PyPI" 93 | uses: "pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e" 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Requests 2 | 3 | **Requests** is a simple, yet elegant, HTTP library. 4 | 5 | ```python 6 | >>> import requests 7 | >>> r = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass')) 8 | >>> r.status_code 9 | 200 10 | >>> r.headers['content-type'] 11 | 'application/json; charset=utf8' 12 | >>> r.encoding 13 | 'utf-8' 14 | >>> r.text 15 | '{"authenticated": true, ...' 16 | >>> r.json() 17 | {'authenticated': True, ...} 18 | ``` 19 | 20 | Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method! 21 | 22 | Requests is one of the most downloaded Python packages today, pulling in around `30M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `1,000,000+` repositories. You may certainly put your trust in this code. 23 | 24 | [![Downloads](https://static.pepy.tech/badge/requests/month)](https://pepy.tech/project/requests) 25 | [![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests) 26 | [![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors) 27 | 28 | ## Installing Requests and Supported Versions 29 | 30 | Requests is available on PyPI: 31 | 32 | ```console 33 | $ python -m pip install requests 34 | ``` 35 | 36 | Requests officially supports Python 3.9+. 37 | 38 | ## Supported Features & Best–Practices 39 | 40 | Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today. 41 | 42 | - Keep-Alive & Connection Pooling 43 | - International Domains and URLs 44 | - Sessions with Cookie Persistence 45 | - Browser-style TLS/SSL Verification 46 | - Basic & Digest Authentication 47 | - Familiar `dict`–like Cookies 48 | - Automatic Content Decompression and Decoding 49 | - Multi-part File Uploads 50 | - SOCKS Proxy Support 51 | - Connection Timeouts 52 | - Streaming Downloads 53 | - Automatic honoring of `.netrc` 54 | - Chunked HTTP Requests 55 | 56 | ## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io) 57 | 58 | [![Read the Docs](https://raw.githubusercontent.com/psf/requests/main/ext/ss.png)](https://requests.readthedocs.io) 59 | 60 | ## Cloning the repository 61 | 62 | When cloning the Requests repository, you may need to add the `-c 63 | fetch.fsck.badTimezone=ignore` flag to avoid an error about a bad commit timestamp (see 64 | [this issue](https://github.com/psf/requests/issues/2690) for more background): 65 | 66 | ```shell 67 | git clone -c fetch.fsck.badTimezone=ignore https://github.com/psf/requests.git 68 | ``` 69 | 70 | You can also apply this setting to your global Git config: 71 | 72 | ```shell 73 | git config --global fetch.fsck.badTimezone ignore 74 | ``` 75 | 76 | --- 77 | 78 | [![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/main/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/main/ext/psf.png)](https://www.python.org/psf) 79 | -------------------------------------------------------------------------------- /src/requests/structures.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.structures 3 | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | Data structures that power Requests. 6 | """ 7 | 8 | from collections import OrderedDict 9 | 10 | from .compat import Mapping, MutableMapping 11 | 12 | 13 | class CaseInsensitiveDict(MutableMapping): 14 | """A case-insensitive ``dict``-like object. 15 | 16 | Implements all methods and operations of 17 | ``MutableMapping`` as well as dict's ``copy``. Also 18 | provides ``lower_items``. 19 | 20 | All keys are expected to be strings. The structure remembers the 21 | case of the last key to be set, and ``iter(instance)``, 22 | ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` 23 | will contain case-sensitive keys. However, querying and contains 24 | testing is case insensitive:: 25 | 26 | cid = CaseInsensitiveDict() 27 | cid['Accept'] = 'application/json' 28 | cid['aCCEPT'] == 'application/json' # True 29 | list(cid) == ['Accept'] # True 30 | 31 | For example, ``headers['content-encoding']`` will return the 32 | value of a ``'Content-Encoding'`` response header, regardless 33 | of how the header name was originally stored. 34 | 35 | If the constructor, ``.update``, or equality comparison 36 | operations are given keys that have equal ``.lower()``s, the 37 | behavior is undefined. 38 | """ 39 | 40 | def __init__(self, data=None, **kwargs): 41 | self._store = OrderedDict() 42 | if data is None: 43 | data = {} 44 | self.update(data, **kwargs) 45 | 46 | def __setitem__(self, key, value): 47 | # Use the lowercased key for lookups, but store the actual 48 | # key alongside the value. 49 | self._store[key.lower()] = (key, value) 50 | 51 | def __getitem__(self, key): 52 | return self._store[key.lower()][1] 53 | 54 | def __delitem__(self, key): 55 | del self._store[key.lower()] 56 | 57 | def __iter__(self): 58 | return (casedkey for casedkey, mappedvalue in self._store.values()) 59 | 60 | def __len__(self): 61 | return len(self._store) 62 | 63 | def lower_items(self): 64 | """Like iteritems(), but with all lowercase keys.""" 65 | return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()) 66 | 67 | def __eq__(self, other): 68 | if isinstance(other, Mapping): 69 | other = CaseInsensitiveDict(other) 70 | else: 71 | return NotImplemented 72 | # Compare insensitively 73 | return dict(self.lower_items()) == dict(other.lower_items()) 74 | 75 | # Copy is required 76 | def copy(self): 77 | return CaseInsensitiveDict(self._store.values()) 78 | 79 | def __repr__(self): 80 | return str(dict(self.items())) 81 | 82 | 83 | class LookupDict(dict): 84 | """Dictionary lookup object.""" 85 | 86 | def __init__(self, name=None): 87 | self.name = name 88 | super().__init__() 89 | 90 | def __repr__(self): 91 | return f"" 92 | 93 | def __getitem__(self, key): 94 | # We allow fall-through here, so values default to None 95 | 96 | return self.__dict__.get(key, None) 97 | 98 | def get(self, key, default=None): 99 | return self.__dict__.get(key, default) 100 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | from codecs import open 5 | 6 | from setuptools import setup 7 | 8 | CURRENT_PYTHON = sys.version_info[:2] 9 | REQUIRED_PYTHON = (3, 9) 10 | 11 | if CURRENT_PYTHON < REQUIRED_PYTHON: 12 | sys.stderr.write( 13 | """ 14 | ========================== 15 | Unsupported Python version 16 | ========================== 17 | This version of Requests requires at least Python {}.{}, but 18 | you're trying to install it on Python {}.{}. To resolve this, 19 | consider upgrading to a supported Python version. 20 | 21 | If you can't upgrade your Python version, you'll need to 22 | pin to an older version of Requests (<2.32.0). 23 | """.format( 24 | *(REQUIRED_PYTHON + CURRENT_PYTHON) 25 | ) 26 | ) 27 | sys.exit(1) 28 | 29 | 30 | # 'setup.py publish' shortcut. 31 | if sys.argv[-1] == "publish": 32 | os.system("python setup.py sdist bdist_wheel") 33 | os.system("twine upload dist/*") 34 | sys.exit() 35 | 36 | requires = [ 37 | "charset_normalizer>=2,<4", 38 | "idna>=2.5,<4", 39 | "urllib3>=1.21.1,<3", 40 | "certifi>=2017.4.17", 41 | ] 42 | test_requirements = [ 43 | "pytest-httpbin==2.1.0", 44 | "pytest-cov", 45 | "pytest-mock", 46 | "pytest-xdist", 47 | "PySocks>=1.5.6, !=1.5.7", 48 | "pytest>=3", 49 | ] 50 | 51 | about = {} 52 | here = os.path.abspath(os.path.dirname(__file__)) 53 | with open(os.path.join(here, "src", "requests", "__version__.py"), "r", "utf-8") as f: 54 | exec(f.read(), about) 55 | 56 | with open("README.md", "r", "utf-8") as f: 57 | readme = f.read() 58 | 59 | setup( 60 | name=about["__title__"], 61 | version=about["__version__"], 62 | description=about["__description__"], 63 | long_description=readme, 64 | long_description_content_type="text/markdown", 65 | author=about["__author__"], 66 | author_email=about["__author_email__"], 67 | url=about["__url__"], 68 | packages=["requests"], 69 | package_data={"": ["LICENSE", "NOTICE"]}, 70 | package_dir={"": "src"}, 71 | include_package_data=True, 72 | python_requires=">=3.9", 73 | install_requires=requires, 74 | license=about["__license__"], 75 | zip_safe=False, 76 | classifiers=[ 77 | "Development Status :: 5 - Production/Stable", 78 | "Environment :: Web Environment", 79 | "Intended Audience :: Developers", 80 | "License :: OSI Approved :: Apache Software License", 81 | "Natural Language :: English", 82 | "Operating System :: OS Independent", 83 | "Programming Language :: Python", 84 | "Programming Language :: Python :: 3", 85 | "Programming Language :: Python :: 3.9", 86 | "Programming Language :: Python :: 3.10", 87 | "Programming Language :: Python :: 3.11", 88 | "Programming Language :: Python :: 3.12", 89 | "Programming Language :: Python :: 3.13", 90 | "Programming Language :: Python :: 3.14", 91 | "Programming Language :: Python :: 3 :: Only", 92 | "Programming Language :: Python :: Implementation :: CPython", 93 | "Programming Language :: Python :: Implementation :: PyPy", 94 | "Topic :: Internet :: WWW/HTTP", 95 | "Topic :: Software Development :: Libraries", 96 | ], 97 | tests_require=test_requirements, 98 | extras_require={ 99 | "security": [], 100 | "socks": ["PySocks>=1.5.6, !=1.5.7"], 101 | "use_chardet_on_py3": ["chardet>=3.0.2,<6"], 102 | }, 103 | project_urls={ 104 | "Documentation": "https://requests.readthedocs.io", 105 | "Source": "https://github.com/psf/requests", 106 | }, 107 | ) 108 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | body > div.document > div.sphinxsidebar > div > form > table > tbody > tr:nth-child(2) > td > select { 2 | width: 100%!important; 3 | } 4 | 5 | #python27 > a { 6 | color: white; 7 | } 8 | 9 | /* Carbon by BuySellAds */ 10 | #carbonads { 11 | display: block; 12 | overflow: hidden; 13 | margin: 1.5em 0 2em; 14 | padding: 1em; 15 | border: solid 1px #cccccc; 16 | border-radius: 2px; 17 | background-color: #eeeeee; 18 | text-align: center; 19 | line-height: 1.5; 20 | } 21 | 22 | #carbonads a { 23 | border-bottom: 0; 24 | } 25 | 26 | #carbonads span { 27 | display: block; 28 | overflow: hidden; 29 | } 30 | 31 | .carbon-img { 32 | display: block; 33 | margin: 0 auto 1em; 34 | text-align: center; 35 | } 36 | 37 | .carbon-text { 38 | display: block; 39 | margin-bottom: 1em; 40 | } 41 | 42 | .carbon-poweredby { 43 | display: block; 44 | text-transform: uppercase; 45 | letter-spacing: 1px; 46 | font-size: 10px; 47 | line-height: 1; 48 | } 49 | 50 | 51 | /* Native CPC by BuySellAds */ 52 | 53 | #native-ribbon #_custom_ { 54 | position: fixed; 55 | right: 0; 56 | bottom: 0; 57 | left: 0; 58 | box-shadow: 0 -1px 4px 1px hsla(0, 0%, 0%, .15); 59 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, 60 | Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif; 61 | transition: all .25s ease-in-out; 62 | transform: translateY(calc(100% - 35px)); 63 | 64 | flex-flow: column nowrap; 65 | } 66 | 67 | #native-ribbon #_custom_:hover { 68 | transform: translateY(0); 69 | } 70 | 71 | .native-img { 72 | margin-right: 20px; 73 | max-height: 50px; 74 | border-radius: 3px; 75 | } 76 | 77 | .native-sponsor { 78 | margin: 10px 20px; 79 | text-align: center; 80 | text-transform: uppercase; 81 | letter-spacing: .5px; 82 | font-size: 12px; 83 | transition: all .3s ease-in-out; 84 | transform-origin: left; 85 | } 86 | 87 | #native-ribbon #_custom_:hover .native-sponsor { 88 | margin: 0 20px; 89 | opacity: 0; 90 | transform: scaleY(0); 91 | } 92 | 93 | .native-flex { 94 | display: flex; 95 | padding: 10px 20px 25px; 96 | text-decoration: none; 97 | 98 | flex-flow: row nowrap; 99 | justify-content: center; 100 | align-items: center; 101 | } 102 | 103 | .native-main { 104 | display: flex; 105 | 106 | flex-flow: row nowrap; 107 | align-items: center; 108 | } 109 | 110 | .native-details { 111 | display: flex; 112 | margin-right: 30px; 113 | 114 | flex-flow: column nowrap; 115 | } 116 | 117 | .native-company { 118 | margin-bottom: 4px; 119 | text-transform: uppercase; 120 | letter-spacing: 2px; 121 | font-size: 10px; 122 | } 123 | 124 | .native-desc { 125 | letter-spacing: 1px; 126 | font-weight: 300; 127 | font-size: 14px; 128 | line-height: 1.4; 129 | } 130 | 131 | .native-cta { 132 | padding: 10px 14px; 133 | border-radius: 3px; 134 | box-shadow: 0 6px 13px 0 hsla(0, 0%, 0%, .15); 135 | text-transform: uppercase; 136 | white-space: nowrap; 137 | letter-spacing: 1px; 138 | font-weight: 400; 139 | font-size: 12px; 140 | transition: all .3s ease-in-out; 141 | transform: translateY(-1px); 142 | } 143 | 144 | .native-cta:hover { 145 | box-shadow: none; 146 | transform: translateY(1px); 147 | } 148 | 149 | @media only screen and (min-width: 320px) and (max-width: 759px) { 150 | .native-flex { 151 | padding: 5px 5px 15px; 152 | flex-direction: column; 153 | 154 | flex-wrap: wrap; 155 | } 156 | 157 | .native-img { 158 | margin: 0; 159 | display: none; 160 | } 161 | 162 | .native-details { 163 | margin: 0; 164 | } 165 | 166 | .native-main { 167 | flex-direction: column; 168 | text-align: left; 169 | 170 | flex-wrap: wrap; 171 | align-content: center; 172 | } 173 | 174 | .native-cta { 175 | display: none; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /docs/community/faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | Frequently Asked Questions 4 | ========================== 5 | 6 | This part of the documentation answers common questions about Requests. 7 | 8 | Encoded Data? 9 | ------------- 10 | 11 | Requests automatically decompresses gzip-encoded responses, and does 12 | its best to decode response content to unicode when possible. 13 | 14 | When either the `brotli `_ or `brotlicffi `_ 15 | package is installed, requests also decodes Brotli-encoded responses. 16 | 17 | You can get direct access to the raw response (and even the socket), 18 | if needed as well. 19 | 20 | 21 | Custom User-Agents? 22 | ------------------- 23 | 24 | Requests allows you to easily override User-Agent strings, along with 25 | any other HTTP Header. See :ref:`documentation about headers `. 26 | 27 | 28 | 29 | Why not Httplib2? 30 | ----------------- 31 | 32 | Chris Adams gave an excellent summary on 33 | `Hacker News `_: 34 | 35 | httplib2 is part of why you should use requests: it's far more respectable 36 | as a client but not as well documented and it still takes way too much code 37 | for basic operations. I appreciate what httplib2 is trying to do, that 38 | there's a ton of hard low-level annoyances in building a modern HTTP 39 | client, but really, just use requests instead. Kenneth Reitz is very 40 | motivated and he gets the degree to which simple things should be simple 41 | whereas httplib2 feels more like an academic exercise than something 42 | people should use to build production systems[1]. 43 | 44 | Disclosure: I'm listed in the requests AUTHORS file but can claim credit 45 | for, oh, about 0.0001% of the awesomeness. 46 | 47 | 1. http://code.google.com/p/httplib2/issues/detail?id=96 is a good example: 48 | an annoying bug which affect many people, there was a fix available for 49 | months, which worked great when I applied it in a fork and pounded a couple 50 | TB of data through it, but it took over a year to make it into trunk and 51 | even longer to make it onto PyPI where any other project which required " 52 | httplib2" would get the working version. 53 | 54 | 55 | Python 3 Support? 56 | ----------------- 57 | 58 | Yes! Requests supports all `officially supported versions of Python `_ 59 | and recent releases of PyPy. 60 | 61 | Python 2 Support? 62 | ----------------- 63 | 64 | No! As of Requests 2.28.0, Requests no longer supports Python 2.7. Users who 65 | have been unable to migrate should pin to `requests<2.28`. Full information 66 | can be found in `psf/requests#6023 `_. 67 | 68 | It is *highly* recommended users migrate to a supported Python 3.x version now since 69 | Python 2.7 is no longer receiving bug fixes or security updates as of January 1, 2020. 70 | 71 | What are "hostname doesn't match" errors? 72 | ----------------------------------------- 73 | 74 | These errors occur when :ref:`SSL certificate verification ` 75 | fails to match the certificate the server responds with to the hostname 76 | Requests thinks it's contacting. If you're certain the server's SSL setup is 77 | correct (for example, because you can visit the site with your browser) and 78 | you're using Python 2.7, a possible explanation is that you need 79 | Server-Name-Indication. 80 | 81 | `Server-Name-Indication`_, or SNI, is an official extension to SSL where the 82 | client tells the server what hostname it is contacting. This is important 83 | when servers are using `Virtual Hosting`_. When such servers are hosting 84 | more than one SSL site they need to be able to return the appropriate 85 | certificate based on the hostname the client is connecting to. 86 | 87 | Python 3 already includes native support for SNI in their SSL modules. 88 | 89 | .. _`Server-Name-Indication`: https://en.wikipedia.org/wiki/Server_Name_Indication 90 | .. _`virtual hosting`: https://en.wikipedia.org/wiki/Virtual_hosting 91 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Requests documentation master file, created by 2 | sphinx-quickstart on Sun Feb 13 23:54:25 2011. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Requests: HTTP for Humans™ 7 | ========================== 8 | 9 | Release v\ |version|. (:ref:`Installation `) 10 | 11 | 12 | .. image:: https://static.pepy.tech/badge/requests/month 13 | :target: https://pepy.tech/project/requests 14 | :alt: Requests Downloads Per Month Badge 15 | 16 | .. image:: https://img.shields.io/pypi/l/requests.svg 17 | :target: https://pypi.org/project/requests/ 18 | :alt: License Badge 19 | 20 | .. image:: https://img.shields.io/pypi/wheel/requests.svg 21 | :target: https://pypi.org/project/requests/ 22 | :alt: Wheel Support Badge 23 | 24 | .. image:: https://img.shields.io/pypi/pyversions/requests.svg 25 | :target: https://pypi.org/project/requests/ 26 | :alt: Python Version Support Badge 27 | 28 | **Requests** is an elegant and simple HTTP library for Python, built for human beings. 29 | 30 | ------------------- 31 | 32 | **Behold, the power of Requests**:: 33 | 34 | >>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) 35 | >>> r.status_code 36 | 200 37 | >>> r.headers['content-type'] 38 | 'application/json; charset=utf8' 39 | >>> r.encoding 40 | 'utf-8' 41 | >>> r.text 42 | '{"type":"User"...' 43 | >>> r.json() 44 | {'private_gists': 419, 'total_private_repos': 77, ...} 45 | 46 | See `similar code, sans Requests `_. 47 | 48 | 49 | **Requests** allows you to send HTTP/1.1 requests extremely easily. 50 | There's no need to manually add query strings to your 51 | URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling 52 | are 100% automatic, thanks to `urllib3 `_. 53 | 54 | Beloved Features 55 | ---------------- 56 | 57 | Requests is ready for today's web. 58 | 59 | - Keep-Alive & Connection Pooling 60 | - International Domains and URLs 61 | - Sessions with Cookie Persistence 62 | - Browser-style SSL Verification 63 | - Automatic Content Decoding 64 | - Basic/Digest Authentication 65 | - Elegant Key/Value Cookies 66 | - Automatic Decompression 67 | - Unicode Response Bodies 68 | - HTTP(S) Proxy Support 69 | - Multipart File Uploads 70 | - Streaming Downloads 71 | - Connection Timeouts 72 | - Chunked Requests 73 | - ``.netrc`` Support 74 | 75 | Requests officially supports Python 3.9+, and runs great on PyPy. 76 | 77 | 78 | The User Guide 79 | -------------- 80 | 81 | This part of the documentation, which is mostly prose, begins with some 82 | background information about Requests, then focuses on step-by-step 83 | instructions for getting the most out of Requests. 84 | 85 | .. toctree:: 86 | :maxdepth: 2 87 | 88 | user/install 89 | user/quickstart 90 | user/advanced 91 | user/authentication 92 | 93 | 94 | The Community Guide 95 | ------------------- 96 | 97 | This part of the documentation, which is mostly prose, details the 98 | Requests ecosystem and community. 99 | 100 | .. toctree:: 101 | :maxdepth: 2 102 | 103 | community/recommended 104 | community/faq 105 | community/out-there 106 | community/support 107 | community/vulnerabilities 108 | community/release-process 109 | 110 | .. toctree:: 111 | :maxdepth: 1 112 | 113 | community/updates 114 | 115 | The API Documentation / Guide 116 | ----------------------------- 117 | 118 | If you are looking for information on a specific function, class, or method, 119 | this part of the documentation is for you. 120 | 121 | .. toctree:: 122 | :maxdepth: 2 123 | 124 | api 125 | 126 | 127 | The Contributor Guide 128 | --------------------- 129 | 130 | If you want to contribute to the project, this part of the documentation is for 131 | you. 132 | 133 | .. toctree:: 134 | :maxdepth: 3 135 | 136 | dev/contributing 137 | dev/authors 138 | 139 | There are no more guides. You are now guideless. 140 | Good luck. 141 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Vulnerability Disclosure 2 | 3 | If you think you have found a potential security vulnerability in 4 | requests, please open a [draft Security Advisory](https://github.com/psf/requests/security/advisories/new) 5 | via GitHub. We will coordinate verification and next steps through 6 | that secure medium. 7 | 8 | If English is not your first language, please try to describe the 9 | problem and its impact to the best of your ability. For greater detail, 10 | please use your native language and we will try our best to translate it 11 | using online services. 12 | 13 | Please also include the code you used to find the problem and the 14 | shortest amount of code necessary to reproduce it. 15 | 16 | Please do not disclose this to anyone else. We will retrieve a CVE 17 | identifier if necessary and give you full credit under whatever name or 18 | alias you provide. We will only request an identifier when we have a fix 19 | and can publish it in a release. 20 | 21 | We will respect your privacy and will only publicize your involvement if 22 | you grant us permission. 23 | 24 | ## Process 25 | 26 | This following information discusses the process the requests project 27 | follows in response to vulnerability disclosures. If you are disclosing 28 | a vulnerability, this section of the documentation lets you know how we 29 | will respond to your disclosure. 30 | 31 | ### Timeline 32 | 33 | When you report an issue, one of the project members will respond to you 34 | within two days *at the outside*. In most cases responses will be 35 | faster, usually within 12 hours. This initial response will at the very 36 | least confirm receipt of the report. 37 | 38 | If we were able to rapidly reproduce the issue, the initial response 39 | will also contain confirmation of the issue. If we are not, we will 40 | often ask for more information about the reproduction scenario. 41 | 42 | Our goal is to have a fix for any vulnerability released within two 43 | weeks of the initial disclosure. This may potentially involve shipping 44 | an interim release that simply disables function while a more mature fix 45 | can be prepared, but will in the vast majority of cases mean shipping a 46 | complete release as soon as possible. 47 | 48 | Throughout the fix process we will keep you up to speed with how the fix 49 | is progressing. Once the fix is prepared, we will notify you that we 50 | believe we have a fix. Often we will ask you to confirm the fix resolves 51 | the problem in your environment, especially if we are not confident of 52 | our reproduction scenario. 53 | 54 | At this point, we will prepare for the release. We will obtain a CVE 55 | number if one is required, providing you with full credit for the 56 | discovery. We will also decide on a planned release date, and let you 57 | know when it is. This release date will *always* be on a weekday. 58 | 59 | At this point we will reach out to our major downstream packagers to 60 | notify them of an impending security-related patch so they can make 61 | arrangements. In addition, these packagers will be provided with the 62 | intended patch ahead of time, to ensure that they are able to promptly 63 | release their downstream packages. Currently the list of people we 64 | actively contact *ahead of a public release* is: 65 | 66 | - Python Maintenance Team, Red Hat (python-maint@redhat.com) 67 | - Daniele Tricoli, Debian (@eriol) 68 | 69 | We will notify these individuals at least a week ahead of our planned 70 | release date to ensure that they have sufficient time to prepare. If you 71 | believe you should be on this list, please let one of the maintainers 72 | know at one of the email addresses at the top of this article. 73 | 74 | On release day, we will push the patch to our public repository, along 75 | with an updated changelog that describes the issue and credits you. We 76 | will then issue a PyPI release containing the patch. 77 | 78 | At this point, we will publicise the release. This will involve mails to 79 | mailing lists, Tweets, and all other communication mechanisms available 80 | to the core team. 81 | 82 | We will also explicitly mention which commits contain the fix to make it 83 | easier for other distributors and users to easily patch their own 84 | versions of requests if upgrading is not an option. 85 | -------------------------------------------------------------------------------- /src/requests/help.py: -------------------------------------------------------------------------------- 1 | """Module containing bug report helper(s).""" 2 | 3 | import json 4 | import platform 5 | import ssl 6 | import sys 7 | 8 | import idna 9 | import urllib3 10 | 11 | from . import __version__ as requests_version 12 | 13 | try: 14 | import charset_normalizer 15 | except ImportError: 16 | charset_normalizer = None 17 | 18 | try: 19 | import chardet 20 | except ImportError: 21 | chardet = None 22 | 23 | try: 24 | from urllib3.contrib import pyopenssl 25 | except ImportError: 26 | pyopenssl = None 27 | OpenSSL = None 28 | cryptography = None 29 | else: 30 | import cryptography 31 | import OpenSSL 32 | 33 | 34 | def _implementation(): 35 | """Return a dict with the Python implementation and version. 36 | 37 | Provide both the name and the version of the Python implementation 38 | currently running. For example, on CPython 3.10.3 it will return 39 | {'name': 'CPython', 'version': '3.10.3'}. 40 | 41 | This function works best on CPython and PyPy: in particular, it probably 42 | doesn't work for Jython or IronPython. Future investigation should be done 43 | to work out the correct shape of the code for those platforms. 44 | """ 45 | implementation = platform.python_implementation() 46 | 47 | if implementation == "CPython": 48 | implementation_version = platform.python_version() 49 | elif implementation == "PyPy": 50 | implementation_version = "{}.{}.{}".format( 51 | sys.pypy_version_info.major, 52 | sys.pypy_version_info.minor, 53 | sys.pypy_version_info.micro, 54 | ) 55 | if sys.pypy_version_info.releaselevel != "final": 56 | implementation_version = "".join( 57 | [implementation_version, sys.pypy_version_info.releaselevel] 58 | ) 59 | elif implementation == "Jython": 60 | implementation_version = platform.python_version() # Complete Guess 61 | elif implementation == "IronPython": 62 | implementation_version = platform.python_version() # Complete Guess 63 | else: 64 | implementation_version = "Unknown" 65 | 66 | return {"name": implementation, "version": implementation_version} 67 | 68 | 69 | def info(): 70 | """Generate information for a bug report.""" 71 | try: 72 | platform_info = { 73 | "system": platform.system(), 74 | "release": platform.release(), 75 | } 76 | except OSError: 77 | platform_info = { 78 | "system": "Unknown", 79 | "release": "Unknown", 80 | } 81 | 82 | implementation_info = _implementation() 83 | urllib3_info = {"version": urllib3.__version__} 84 | charset_normalizer_info = {"version": None} 85 | chardet_info = {"version": None} 86 | if charset_normalizer: 87 | charset_normalizer_info = {"version": charset_normalizer.__version__} 88 | if chardet: 89 | chardet_info = {"version": chardet.__version__} 90 | 91 | pyopenssl_info = { 92 | "version": None, 93 | "openssl_version": "", 94 | } 95 | if OpenSSL: 96 | pyopenssl_info = { 97 | "version": OpenSSL.__version__, 98 | "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}", 99 | } 100 | cryptography_info = { 101 | "version": getattr(cryptography, "__version__", ""), 102 | } 103 | idna_info = { 104 | "version": getattr(idna, "__version__", ""), 105 | } 106 | 107 | system_ssl = ssl.OPENSSL_VERSION_NUMBER 108 | system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""} 109 | 110 | return { 111 | "platform": platform_info, 112 | "implementation": implementation_info, 113 | "system_ssl": system_ssl_info, 114 | "using_pyopenssl": pyopenssl is not None, 115 | "using_charset_normalizer": chardet is None, 116 | "pyOpenSSL": pyopenssl_info, 117 | "urllib3": urllib3_info, 118 | "chardet": chardet_info, 119 | "charset_normalizer": charset_normalizer_info, 120 | "cryptography": cryptography_info, 121 | "idna": idna_info, 122 | "requests": { 123 | "version": requests_version, 124 | }, 125 | } 126 | 127 | 128 | def main(): 129 | """Pretty-print the bug information as JSON.""" 130 | print(json.dumps(info(), sort_keys=True, indent=2)) 131 | 132 | 133 | if __name__ == "__main__": 134 | main() 135 | -------------------------------------------------------------------------------- /src/requests/status_codes.py: -------------------------------------------------------------------------------- 1 | r""" 2 | The ``codes`` object defines a mapping from common names for HTTP statuses 3 | to their numerical codes, accessible either as attributes or as dictionary 4 | items. 5 | 6 | Example:: 7 | 8 | >>> import requests 9 | >>> requests.codes['temporary_redirect'] 10 | 307 11 | >>> requests.codes.teapot 12 | 418 13 | >>> requests.codes['\o/'] 14 | 200 15 | 16 | Some codes have multiple names, and both upper- and lower-case versions of 17 | the names are allowed. For example, ``codes.ok``, ``codes.OK``, and 18 | ``codes.okay`` all correspond to the HTTP status code 200. 19 | """ 20 | 21 | from .structures import LookupDict 22 | 23 | _codes = { 24 | # Informational. 25 | 100: ("continue",), 26 | 101: ("switching_protocols",), 27 | 102: ("processing", "early-hints"), 28 | 103: ("checkpoint",), 29 | 122: ("uri_too_long", "request_uri_too_long"), 30 | 200: ("ok", "okay", "all_ok", "all_okay", "all_good", "\\o/", "✓"), 31 | 201: ("created",), 32 | 202: ("accepted",), 33 | 203: ("non_authoritative_info", "non_authoritative_information"), 34 | 204: ("no_content",), 35 | 205: ("reset_content", "reset"), 36 | 206: ("partial_content", "partial"), 37 | 207: ("multi_status", "multiple_status", "multi_stati", "multiple_stati"), 38 | 208: ("already_reported",), 39 | 226: ("im_used",), 40 | # Redirection. 41 | 300: ("multiple_choices",), 42 | 301: ("moved_permanently", "moved", "\\o-"), 43 | 302: ("found",), 44 | 303: ("see_other", "other"), 45 | 304: ("not_modified",), 46 | 305: ("use_proxy",), 47 | 306: ("switch_proxy",), 48 | 307: ("temporary_redirect", "temporary_moved", "temporary"), 49 | 308: ( 50 | "permanent_redirect", 51 | "resume_incomplete", 52 | "resume", 53 | ), # "resume" and "resume_incomplete" to be removed in 3.0 54 | # Client Error. 55 | 400: ("bad_request", "bad"), 56 | 401: ("unauthorized",), 57 | 402: ("payment_required", "payment"), 58 | 403: ("forbidden",), 59 | 404: ("not_found", "-o-"), 60 | 405: ("method_not_allowed", "not_allowed"), 61 | 406: ("not_acceptable",), 62 | 407: ("proxy_authentication_required", "proxy_auth", "proxy_authentication"), 63 | 408: ("request_timeout", "timeout"), 64 | 409: ("conflict",), 65 | 410: ("gone",), 66 | 411: ("length_required",), 67 | 412: ("precondition_failed", "precondition"), 68 | 413: ("request_entity_too_large", "content_too_large"), 69 | 414: ("request_uri_too_large", "uri_too_long"), 70 | 415: ("unsupported_media_type", "unsupported_media", "media_type"), 71 | 416: ( 72 | "requested_range_not_satisfiable", 73 | "requested_range", 74 | "range_not_satisfiable", 75 | ), 76 | 417: ("expectation_failed",), 77 | 418: ("im_a_teapot", "teapot", "i_am_a_teapot"), 78 | 421: ("misdirected_request",), 79 | 422: ("unprocessable_entity", "unprocessable", "unprocessable_content"), 80 | 423: ("locked",), 81 | 424: ("failed_dependency", "dependency"), 82 | 425: ("unordered_collection", "unordered", "too_early"), 83 | 426: ("upgrade_required", "upgrade"), 84 | 428: ("precondition_required", "precondition"), 85 | 429: ("too_many_requests", "too_many"), 86 | 431: ("header_fields_too_large", "fields_too_large"), 87 | 444: ("no_response", "none"), 88 | 449: ("retry_with", "retry"), 89 | 450: ("blocked_by_windows_parental_controls", "parental_controls"), 90 | 451: ("unavailable_for_legal_reasons", "legal_reasons"), 91 | 499: ("client_closed_request",), 92 | # Server Error. 93 | 500: ("internal_server_error", "server_error", "/o\\", "✗"), 94 | 501: ("not_implemented",), 95 | 502: ("bad_gateway",), 96 | 503: ("service_unavailable", "unavailable"), 97 | 504: ("gateway_timeout",), 98 | 505: ("http_version_not_supported", "http_version"), 99 | 506: ("variant_also_negotiates",), 100 | 507: ("insufficient_storage",), 101 | 509: ("bandwidth_limit_exceeded", "bandwidth"), 102 | 510: ("not_extended",), 103 | 511: ("network_authentication_required", "network_auth", "network_authentication"), 104 | } 105 | 106 | codes = LookupDict(name="status_codes") 107 | 108 | 109 | def _init(): 110 | for code, titles in _codes.items(): 111 | for title in titles: 112 | setattr(codes, title, code) 113 | if not title.startswith(("\\", "/")): 114 | setattr(codes, title.upper(), code) 115 | 116 | def doc(code): 117 | names = ", ".join(f"``{n}``" for n in _codes[code]) 118 | return "* %d: %s" % (code, names) 119 | 120 | global __doc__ 121 | __doc__ = ( 122 | __doc__ + "\n" + "\n".join(doc(code) for code in sorted(_codes)) 123 | if __doc__ is not None 124 | else None 125 | ) 126 | 127 | 128 | _init() 129 | -------------------------------------------------------------------------------- /src/requests/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.exceptions 3 | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | This module contains the set of Requests' exceptions. 6 | """ 7 | from urllib3.exceptions import HTTPError as BaseHTTPError 8 | 9 | from .compat import JSONDecodeError as CompatJSONDecodeError 10 | 11 | 12 | class RequestException(IOError): 13 | """There was an ambiguous exception that occurred while handling your 14 | request. 15 | """ 16 | 17 | def __init__(self, *args, **kwargs): 18 | """Initialize RequestException with `request` and `response` objects.""" 19 | response = kwargs.pop("response", None) 20 | self.response = response 21 | self.request = kwargs.pop("request", None) 22 | if response is not None and not self.request and hasattr(response, "request"): 23 | self.request = self.response.request 24 | super().__init__(*args, **kwargs) 25 | 26 | 27 | class InvalidJSONError(RequestException): 28 | """A JSON error occurred.""" 29 | 30 | 31 | class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError): 32 | """Couldn't decode the text into json""" 33 | 34 | def __init__(self, *args, **kwargs): 35 | """ 36 | Construct the JSONDecodeError instance first with all 37 | args. Then use it's args to construct the IOError so that 38 | the json specific args aren't used as IOError specific args 39 | and the error message from JSONDecodeError is preserved. 40 | """ 41 | CompatJSONDecodeError.__init__(self, *args) 42 | InvalidJSONError.__init__(self, *self.args, **kwargs) 43 | 44 | def __reduce__(self): 45 | """ 46 | The __reduce__ method called when pickling the object must 47 | be the one from the JSONDecodeError (be it json/simplejson) 48 | as it expects all the arguments for instantiation, not just 49 | one like the IOError, and the MRO would by default call the 50 | __reduce__ method from the IOError due to the inheritance order. 51 | """ 52 | return CompatJSONDecodeError.__reduce__(self) 53 | 54 | 55 | class HTTPError(RequestException): 56 | """An HTTP error occurred.""" 57 | 58 | 59 | class ConnectionError(RequestException): 60 | """A Connection error occurred.""" 61 | 62 | 63 | class ProxyError(ConnectionError): 64 | """A proxy error occurred.""" 65 | 66 | 67 | class SSLError(ConnectionError): 68 | """An SSL error occurred.""" 69 | 70 | 71 | class Timeout(RequestException): 72 | """The request timed out. 73 | 74 | Catching this error will catch both 75 | :exc:`~requests.exceptions.ConnectTimeout` and 76 | :exc:`~requests.exceptions.ReadTimeout` errors. 77 | """ 78 | 79 | 80 | class ConnectTimeout(ConnectionError, Timeout): 81 | """The request timed out while trying to connect to the remote server. 82 | 83 | Requests that produced this error are safe to retry. 84 | """ 85 | 86 | 87 | class ReadTimeout(Timeout): 88 | """The server did not send any data in the allotted amount of time.""" 89 | 90 | 91 | class URLRequired(RequestException): 92 | """A valid URL is required to make a request.""" 93 | 94 | 95 | class TooManyRedirects(RequestException): 96 | """Too many redirects.""" 97 | 98 | 99 | class MissingSchema(RequestException, ValueError): 100 | """The URL scheme (e.g. http or https) is missing.""" 101 | 102 | 103 | class InvalidSchema(RequestException, ValueError): 104 | """The URL scheme provided is either invalid or unsupported.""" 105 | 106 | 107 | class InvalidURL(RequestException, ValueError): 108 | """The URL provided was somehow invalid.""" 109 | 110 | 111 | class InvalidHeader(RequestException, ValueError): 112 | """The header value provided was somehow invalid.""" 113 | 114 | 115 | class InvalidProxyURL(InvalidURL): 116 | """The proxy URL provided is invalid.""" 117 | 118 | 119 | class ChunkedEncodingError(RequestException): 120 | """The server declared chunked encoding but sent an invalid chunk.""" 121 | 122 | 123 | class ContentDecodingError(RequestException, BaseHTTPError): 124 | """Failed to decode response content.""" 125 | 126 | 127 | class StreamConsumedError(RequestException, TypeError): 128 | """The content for this response was already consumed.""" 129 | 130 | 131 | class RetryError(RequestException): 132 | """Custom retries logic failed""" 133 | 134 | 135 | class UnrewindableBodyError(RequestException): 136 | """Requests encountered an error when trying to rewind a body.""" 137 | 138 | 139 | # Warnings 140 | 141 | 142 | class RequestsWarning(Warning): 143 | """Base warning for Requests.""" 144 | 145 | 146 | class FileModeWarning(RequestsWarning, DeprecationWarning): 147 | """A file was opened in text mode, but Requests determined its binary length.""" 148 | 149 | 150 | class RequestsDependencyWarning(RequestsWarning): 151 | """An imported dependency doesn't match the expected version range.""" 152 | -------------------------------------------------------------------------------- /docs/_themes/flask_theme_support.py: -------------------------------------------------------------------------------- 1 | # flasky extensions. flasky pygments style based on tango style 2 | from pygments.style import Style 3 | from pygments.token import Keyword, Name, Comment, String, Error, \ 4 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal 5 | 6 | 7 | class FlaskyStyle(Style): 8 | background_color = "#f8f8f8" 9 | default_style = "" 10 | 11 | styles = { 12 | # No corresponding class for the following: 13 | #Text: "", # class: '' 14 | Whitespace: "underline #f8f8f8", # class: 'w' 15 | Error: "#a40000 border:#ef2929", # class: 'err' 16 | Other: "#000000", # class 'x' 17 | 18 | Comment: "italic #8f5902", # class: 'c' 19 | Comment.Preproc: "noitalic", # class: 'cp' 20 | 21 | Keyword: "bold #004461", # class: 'k' 22 | Keyword.Constant: "bold #004461", # class: 'kc' 23 | Keyword.Declaration: "bold #004461", # class: 'kd' 24 | Keyword.Namespace: "bold #004461", # class: 'kn' 25 | Keyword.Pseudo: "bold #004461", # class: 'kp' 26 | Keyword.Reserved: "bold #004461", # class: 'kr' 27 | Keyword.Type: "bold #004461", # class: 'kt' 28 | 29 | Operator: "#582800", # class: 'o' 30 | Operator.Word: "bold #004461", # class: 'ow' - like keywords 31 | 32 | Punctuation: "bold #000000", # class: 'p' 33 | 34 | # because special names such as Name.Class, Name.Function, etc. 35 | # are not recognized as such later in the parsing, we choose them 36 | # to look the same as ordinary variables. 37 | Name: "#000000", # class: 'n' 38 | Name.Attribute: "#c4a000", # class: 'na' - to be revised 39 | Name.Builtin: "#004461", # class: 'nb' 40 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp' 41 | Name.Class: "#000000", # class: 'nc' - to be revised 42 | Name.Constant: "#000000", # class: 'no' - to be revised 43 | Name.Decorator: "#888", # class: 'nd' - to be revised 44 | Name.Entity: "#ce5c00", # class: 'ni' 45 | Name.Exception: "bold #cc0000", # class: 'ne' 46 | Name.Function: "#000000", # class: 'nf' 47 | Name.Property: "#000000", # class: 'py' 48 | Name.Label: "#f57900", # class: 'nl' 49 | Name.Namespace: "#000000", # class: 'nn' - to be revised 50 | Name.Other: "#000000", # class: 'nx' 51 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword 52 | Name.Variable: "#000000", # class: 'nv' - to be revised 53 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised 54 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised 55 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised 56 | 57 | Number: "#990000", # class: 'm' 58 | 59 | Literal: "#000000", # class: 'l' 60 | Literal.Date: "#000000", # class: 'ld' 61 | 62 | String: "#4e9a06", # class: 's' 63 | String.Backtick: "#4e9a06", # class: 'sb' 64 | String.Char: "#4e9a06", # class: 'sc' 65 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment 66 | String.Double: "#4e9a06", # class: 's2' 67 | String.Escape: "#4e9a06", # class: 'se' 68 | String.Heredoc: "#4e9a06", # class: 'sh' 69 | String.Interpol: "#4e9a06", # class: 'si' 70 | String.Other: "#4e9a06", # class: 'sx' 71 | String.Regex: "#4e9a06", # class: 'sr' 72 | String.Single: "#4e9a06", # class: 's1' 73 | String.Symbol: "#4e9a06", # class: 'ss' 74 | 75 | Generic: "#000000", # class: 'g' 76 | Generic.Deleted: "#a40000", # class: 'gd' 77 | Generic.Emph: "italic #000000", # class: 'ge' 78 | Generic.Error: "#ef2929", # class: 'gr' 79 | Generic.Heading: "bold #000080", # class: 'gh' 80 | Generic.Inserted: "#00A000", # class: 'gi' 81 | Generic.Output: "#888", # class: 'go' 82 | Generic.Prompt: "#745334", # class: 'gp' 83 | Generic.Strong: "bold #000000", # class: 'gs' 84 | Generic.Subheading: "bold #800080", # class: 'gu' 85 | Generic.Traceback: "bold #a40000", # class: 'gt' 86 | } 87 | -------------------------------------------------------------------------------- /src/requests/__init__.py: -------------------------------------------------------------------------------- 1 | # __ 2 | # /__) _ _ _ _ _/ _ 3 | # / ( (- (/ (/ (- _) / _) 4 | # / 5 | 6 | """ 7 | Requests HTTP Library 8 | ~~~~~~~~~~~~~~~~~~~~~ 9 | 10 | Requests is an HTTP library, written in Python, for human beings. 11 | Basic GET usage: 12 | 13 | >>> import requests 14 | >>> r = requests.get('https://www.python.org') 15 | >>> r.status_code 16 | 200 17 | >>> b'Python is a programming language' in r.content 18 | True 19 | 20 | ... or POST: 21 | 22 | >>> payload = dict(key1='value1', key2='value2') 23 | >>> r = requests.post('https://httpbin.org/post', data=payload) 24 | >>> print(r.text) 25 | { 26 | ... 27 | "form": { 28 | "key1": "value1", 29 | "key2": "value2" 30 | }, 31 | ... 32 | } 33 | 34 | The other HTTP methods are supported - see `requests.api`. Full documentation 35 | is at . 36 | 37 | :copyright: (c) 2017 by Kenneth Reitz. 38 | :license: Apache 2.0, see LICENSE for more details. 39 | """ 40 | 41 | import warnings 42 | 43 | import urllib3 44 | 45 | from .exceptions import RequestsDependencyWarning 46 | 47 | try: 48 | from charset_normalizer import __version__ as charset_normalizer_version 49 | except ImportError: 50 | charset_normalizer_version = None 51 | 52 | try: 53 | from chardet import __version__ as chardet_version 54 | except ImportError: 55 | chardet_version = None 56 | 57 | 58 | def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version): 59 | urllib3_version = urllib3_version.split(".") 60 | assert urllib3_version != ["dev"] # Verify urllib3 isn't installed from git. 61 | 62 | # Sometimes, urllib3 only reports its version as 16.1. 63 | if len(urllib3_version) == 2: 64 | urllib3_version.append("0") 65 | 66 | # Check urllib3 for compatibility. 67 | major, minor, patch = urllib3_version # noqa: F811 68 | major, minor, patch = int(major), int(minor), int(patch) 69 | # urllib3 >= 1.21.1 70 | assert major >= 1 71 | if major == 1: 72 | assert minor >= 21 73 | 74 | # Check charset_normalizer for compatibility. 75 | if chardet_version: 76 | major, minor, patch = chardet_version.split(".")[:3] 77 | major, minor, patch = int(major), int(minor), int(patch) 78 | # chardet_version >= 3.0.2, < 6.0.0 79 | assert (3, 0, 2) <= (major, minor, patch) < (6, 0, 0) 80 | elif charset_normalizer_version: 81 | major, minor, patch = charset_normalizer_version.split(".")[:3] 82 | major, minor, patch = int(major), int(minor), int(patch) 83 | # charset_normalizer >= 2.0.0 < 4.0.0 84 | assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0) 85 | else: 86 | warnings.warn( 87 | "Unable to find acceptable character detection dependency " 88 | "(chardet or charset_normalizer).", 89 | RequestsDependencyWarning, 90 | ) 91 | 92 | 93 | def _check_cryptography(cryptography_version): 94 | # cryptography < 1.3.4 95 | try: 96 | cryptography_version = list(map(int, cryptography_version.split("."))) 97 | except ValueError: 98 | return 99 | 100 | if cryptography_version < [1, 3, 4]: 101 | warning = "Old version of cryptography ({}) may cause slowdown.".format( 102 | cryptography_version 103 | ) 104 | warnings.warn(warning, RequestsDependencyWarning) 105 | 106 | 107 | # Check imported dependencies for compatibility. 108 | try: 109 | check_compatibility( 110 | urllib3.__version__, chardet_version, charset_normalizer_version 111 | ) 112 | except (AssertionError, ValueError): 113 | warnings.warn( 114 | "urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported " 115 | "version!".format( 116 | urllib3.__version__, chardet_version, charset_normalizer_version 117 | ), 118 | RequestsDependencyWarning, 119 | ) 120 | 121 | # Attempt to enable urllib3's fallback for SNI support 122 | # if the standard library doesn't support SNI or the 123 | # 'ssl' library isn't available. 124 | try: 125 | try: 126 | import ssl 127 | except ImportError: 128 | ssl = None 129 | 130 | if not getattr(ssl, "HAS_SNI", False): 131 | from urllib3.contrib import pyopenssl 132 | 133 | pyopenssl.inject_into_urllib3() 134 | 135 | # Check cryptography version 136 | from cryptography import __version__ as cryptography_version 137 | 138 | _check_cryptography(cryptography_version) 139 | except ImportError: 140 | pass 141 | 142 | # urllib3's DependencyWarnings should be silenced. 143 | from urllib3.exceptions import DependencyWarning 144 | 145 | warnings.simplefilter("ignore", DependencyWarning) 146 | 147 | # Set default logging handler to avoid "No handler found" warnings. 148 | import logging 149 | from logging import NullHandler 150 | 151 | from . import packages, utils 152 | from .__version__ import ( 153 | __author__, 154 | __author_email__, 155 | __build__, 156 | __cake__, 157 | __copyright__, 158 | __description__, 159 | __license__, 160 | __title__, 161 | __url__, 162 | __version__, 163 | ) 164 | from .api import delete, get, head, options, patch, post, put, request 165 | from .exceptions import ( 166 | ConnectionError, 167 | ConnectTimeout, 168 | FileModeWarning, 169 | HTTPError, 170 | JSONDecodeError, 171 | ReadTimeout, 172 | RequestException, 173 | Timeout, 174 | TooManyRedirects, 175 | URLRequired, 176 | ) 177 | from .models import PreparedRequest, Request, Response 178 | from .sessions import Session, session 179 | from .status_codes import codes 180 | 181 | logging.getLogger(__name__).addHandler(NullHandler()) 182 | 183 | # FileModeWarnings go off per the default. 184 | warnings.simplefilter("default", FileModeWarning, append=True) 185 | -------------------------------------------------------------------------------- /tests/testserver/server.py: -------------------------------------------------------------------------------- 1 | import select 2 | import socket 3 | import ssl 4 | import threading 5 | 6 | 7 | def consume_socket_content(sock, timeout=0.5): 8 | chunks = 65536 9 | content = b"" 10 | 11 | while True: 12 | more_to_read = select.select([sock], [], [], timeout)[0] 13 | if not more_to_read: 14 | break 15 | 16 | new_content = sock.recv(chunks) 17 | if not new_content: 18 | break 19 | 20 | content += new_content 21 | 22 | return content 23 | 24 | 25 | class Server(threading.Thread): 26 | """Dummy server using for unit testing""" 27 | 28 | WAIT_EVENT_TIMEOUT = 5 29 | 30 | def __init__( 31 | self, 32 | handler=None, 33 | host="localhost", 34 | port=0, 35 | requests_to_handle=1, 36 | wait_to_close_event=None, 37 | ): 38 | super().__init__() 39 | 40 | self.handler = handler or consume_socket_content 41 | self.handler_results = [] 42 | 43 | self.host = host 44 | self.port = port 45 | self.requests_to_handle = requests_to_handle 46 | 47 | self.wait_to_close_event = wait_to_close_event 48 | self.ready_event = threading.Event() 49 | self.stop_event = threading.Event() 50 | 51 | @classmethod 52 | def text_response_server(cls, text, request_timeout=0.5, **kwargs): 53 | def text_response_handler(sock): 54 | request_content = consume_socket_content(sock, timeout=request_timeout) 55 | sock.send(text.encode("utf-8")) 56 | 57 | return request_content 58 | 59 | return Server(text_response_handler, **kwargs) 60 | 61 | @classmethod 62 | def basic_response_server(cls, **kwargs): 63 | return cls.text_response_server( 64 | "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n\r\n", **kwargs 65 | ) 66 | 67 | def run(self): 68 | try: 69 | self.server_sock = self._create_socket_and_bind() 70 | # in case self.port = 0 71 | self.port = self.server_sock.getsockname()[1] 72 | self.ready_event.set() 73 | self._handle_requests() 74 | 75 | if self.wait_to_close_event: 76 | self.wait_to_close_event.wait(self.WAIT_EVENT_TIMEOUT) 77 | finally: 78 | self.ready_event.set() # just in case of exception 79 | self._close_server_sock_ignore_errors() 80 | self.stop_event.set() 81 | 82 | def _create_socket_and_bind(self): 83 | sock = socket.socket() 84 | sock.bind((self.host, self.port)) 85 | sock.listen() 86 | return sock 87 | 88 | def _close_server_sock_ignore_errors(self): 89 | try: 90 | self.server_sock.close() 91 | except OSError: 92 | pass 93 | 94 | def _handle_requests(self): 95 | for _ in range(self.requests_to_handle): 96 | sock = self._accept_connection() 97 | if not sock: 98 | break 99 | 100 | handler_result = self.handler(sock) 101 | 102 | self.handler_results.append(handler_result) 103 | sock.close() 104 | 105 | def _accept_connection(self): 106 | try: 107 | ready, _, _ = select.select( 108 | [self.server_sock], [], [], self.WAIT_EVENT_TIMEOUT 109 | ) 110 | if not ready: 111 | return None 112 | 113 | return self.server_sock.accept()[0] 114 | except OSError: 115 | return None 116 | 117 | def __enter__(self): 118 | self.start() 119 | if not self.ready_event.wait(self.WAIT_EVENT_TIMEOUT): 120 | raise RuntimeError("Timeout waiting for server to be ready.") 121 | return self.host, self.port 122 | 123 | def __exit__(self, exc_type, exc_value, traceback): 124 | if exc_type is None: 125 | self.stop_event.wait(self.WAIT_EVENT_TIMEOUT) 126 | else: 127 | if self.wait_to_close_event: 128 | # avoid server from waiting for event timeouts 129 | # if an exception is found in the main thread 130 | self.wait_to_close_event.set() 131 | 132 | # ensure server thread doesn't get stuck waiting for connections 133 | self._close_server_sock_ignore_errors() 134 | self.join() 135 | return False # allow exceptions to propagate 136 | 137 | 138 | class TLSServer(Server): 139 | def __init__( 140 | self, 141 | *, 142 | handler=None, 143 | host="localhost", 144 | port=0, 145 | requests_to_handle=1, 146 | wait_to_close_event=None, 147 | cert_chain=None, 148 | keyfile=None, 149 | mutual_tls=False, 150 | cacert=None, 151 | ): 152 | super().__init__( 153 | handler=handler, 154 | host=host, 155 | port=port, 156 | requests_to_handle=requests_to_handle, 157 | wait_to_close_event=wait_to_close_event, 158 | ) 159 | self.cert_chain = cert_chain 160 | self.keyfile = keyfile 161 | self.ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) 162 | self.ssl_context.load_cert_chain(self.cert_chain, keyfile=self.keyfile) 163 | self.mutual_tls = mutual_tls 164 | self.cacert = cacert 165 | if mutual_tls: 166 | # For simplicity, we're going to assume that the client cert is 167 | # issued by the same CA as our Server certificate 168 | self.ssl_context.verify_mode = ssl.CERT_OPTIONAL 169 | self.ssl_context.load_verify_locations(self.cacert) 170 | 171 | def _create_socket_and_bind(self): 172 | sock = socket.socket() 173 | sock = self.ssl_context.wrap_socket(sock, server_side=True) 174 | sock.bind((self.host, self.port)) 175 | sock.listen() 176 | return sock 177 | -------------------------------------------------------------------------------- /tests/test_testserver.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import threading 3 | import time 4 | 5 | import pytest 6 | from tests.testserver.server import Server 7 | 8 | import requests 9 | 10 | 11 | class TestTestServer: 12 | def test_basic(self): 13 | """messages are sent and received properly""" 14 | question = b"success?" 15 | answer = b"yeah, success" 16 | 17 | def handler(sock): 18 | text = sock.recv(1000) 19 | assert text == question 20 | sock.sendall(answer) 21 | 22 | with Server(handler) as (host, port): 23 | sock = socket.socket() 24 | sock.connect((host, port)) 25 | sock.sendall(question) 26 | text = sock.recv(1000) 27 | assert text == answer 28 | sock.close() 29 | 30 | def test_server_closes(self): 31 | """the server closes when leaving the context manager""" 32 | with Server.basic_response_server() as (host, port): 33 | sock = socket.socket() 34 | sock.connect((host, port)) 35 | 36 | sock.close() 37 | 38 | with pytest.raises(socket.error): 39 | new_sock = socket.socket() 40 | new_sock.connect((host, port)) 41 | 42 | def test_text_response(self): 43 | """the text_response_server sends the given text""" 44 | server = Server.text_response_server( 45 | "HTTP/1.1 200 OK\r\n" "Content-Length: 6\r\n" "\r\nroflol" 46 | ) 47 | 48 | with server as (host, port): 49 | r = requests.get(f"http://{host}:{port}") 50 | 51 | assert r.status_code == 200 52 | assert r.text == "roflol" 53 | assert r.headers["Content-Length"] == "6" 54 | 55 | def test_basic_response(self): 56 | """the basic response server returns an empty http response""" 57 | with Server.basic_response_server() as (host, port): 58 | r = requests.get(f"http://{host}:{port}") 59 | assert r.status_code == 200 60 | assert r.text == "" 61 | assert r.headers["Content-Length"] == "0" 62 | 63 | def test_basic_waiting_server(self): 64 | """the server waits for the block_server event to be set before closing""" 65 | block_server = threading.Event() 66 | 67 | with Server.basic_response_server(wait_to_close_event=block_server) as ( 68 | host, 69 | port, 70 | ): 71 | sock = socket.socket() 72 | sock.connect((host, port)) 73 | sock.sendall(b"send something") 74 | time.sleep(2.5) 75 | sock.sendall(b"still alive") 76 | block_server.set() # release server block 77 | 78 | def test_multiple_requests(self): 79 | """multiple requests can be served""" 80 | requests_to_handle = 5 81 | 82 | server = Server.basic_response_server(requests_to_handle=requests_to_handle) 83 | 84 | with server as (host, port): 85 | server_url = f"http://{host}:{port}" 86 | for _ in range(requests_to_handle): 87 | r = requests.get(server_url) 88 | assert r.status_code == 200 89 | 90 | # the (n+1)th request fails 91 | with pytest.raises(requests.exceptions.ConnectionError): 92 | r = requests.get(server_url) 93 | 94 | @pytest.mark.skip(reason="this fails non-deterministically under pytest-xdist") 95 | def test_request_recovery(self): 96 | """can check the requests content""" 97 | # TODO: figure out why this sometimes fails when using pytest-xdist. 98 | server = Server.basic_response_server(requests_to_handle=2) 99 | first_request = b"put your hands up in the air" 100 | second_request = b"put your hand down in the floor" 101 | 102 | with server as address: 103 | sock1 = socket.socket() 104 | sock2 = socket.socket() 105 | 106 | sock1.connect(address) 107 | sock1.sendall(first_request) 108 | sock1.close() 109 | 110 | sock2.connect(address) 111 | sock2.sendall(second_request) 112 | sock2.close() 113 | 114 | assert server.handler_results[0] == first_request 115 | assert server.handler_results[1] == second_request 116 | 117 | def test_requests_after_timeout_are_not_received(self): 118 | """the basic response handler times out when receiving requests""" 119 | server = Server.basic_response_server(request_timeout=1) 120 | 121 | with server as address: 122 | sock = socket.socket() 123 | sock.connect(address) 124 | time.sleep(1.5) 125 | sock.sendall(b"hehehe, not received") 126 | sock.close() 127 | 128 | assert server.handler_results[0] == b"" 129 | 130 | def test_request_recovery_with_bigger_timeout(self): 131 | """a biggest timeout can be specified""" 132 | server = Server.basic_response_server(request_timeout=3) 133 | data = b"bananadine" 134 | 135 | with server as address: 136 | sock = socket.socket() 137 | sock.connect(address) 138 | time.sleep(1.5) 139 | sock.sendall(data) 140 | sock.close() 141 | 142 | assert server.handler_results[0] == data 143 | 144 | def test_server_finishes_on_error(self): 145 | """the server thread exits even if an exception exits the context manager""" 146 | server = Server.basic_response_server() 147 | with pytest.raises(Exception): 148 | with server: 149 | raise Exception() 150 | 151 | assert len(server.handler_results) == 0 152 | 153 | # if the server thread fails to finish, the test suite will hang 154 | # and get killed by the jenkins timeout. 155 | 156 | def test_server_finishes_when_no_connections(self): 157 | """the server thread exits even if there are no connections""" 158 | server = Server.basic_response_server() 159 | with server: 160 | pass 161 | 162 | assert len(server.handler_results) == 0 163 | 164 | # if the server thread fails to finish, the test suite will hang 165 | # and get killed by the jenkins timeout. 166 | -------------------------------------------------------------------------------- /docs/user/authentication.rst: -------------------------------------------------------------------------------- 1 | .. _authentication: 2 | 3 | Authentication 4 | ============== 5 | 6 | This document discusses using various kinds of authentication with Requests. 7 | 8 | Many web services require authentication, and there are many different types. 9 | Below, we outline various forms of authentication available in Requests, from 10 | the simple to the complex. 11 | 12 | 13 | Basic Authentication 14 | -------------------- 15 | 16 | Many web services that require authentication accept HTTP Basic Auth. This is 17 | the simplest kind, and Requests supports it straight out of the box. 18 | 19 | Making requests with HTTP Basic Auth is very simple:: 20 | 21 | >>> from requests.auth import HTTPBasicAuth 22 | >>> basic = HTTPBasicAuth('user', 'pass') 23 | >>> requests.get('https://httpbin.org/basic-auth/user/pass', auth=basic) 24 | 25 | 26 | In fact, HTTP Basic Auth is so common that Requests provides a handy shorthand 27 | for using it:: 28 | 29 | >>> requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass')) 30 | 31 | 32 | Providing the credentials in a tuple like this is exactly the same as the 33 | ``HTTPBasicAuth`` example above. 34 | 35 | 36 | netrc Authentication 37 | ~~~~~~~~~~~~~~~~~~~~ 38 | 39 | If no authentication method is given with the ``auth`` argument, Requests will 40 | attempt to get the authentication credentials for the URL's hostname from the 41 | user's netrc file. The netrc file overrides raw HTTP authentication headers 42 | set with `headers=`. 43 | 44 | If credentials for the hostname are found, the request is sent with HTTP Basic 45 | Auth. 46 | 47 | Requests will search for the netrc file at `~/.netrc`, `~/_netrc`, or at the path 48 | specified by the `NETRC` environment variable. `~` denotes the user's home 49 | directory, which is `$HOME` on Unix based systems and `%USERPROFILE%` on Windows. 50 | 51 | Usage of netrc file can be disabled by setting `trust_env` to `False` in the 52 | Requests session:: 53 | 54 | >>> s = requests.Session() 55 | >>> s.trust_env = False 56 | >>> s.get('https://httpbin.org/basic-auth/user/pass') 57 | 58 | Digest Authentication 59 | --------------------- 60 | 61 | Another very popular form of HTTP Authentication is Digest Authentication, 62 | and Requests supports this out of the box as well:: 63 | 64 | >>> from requests.auth import HTTPDigestAuth 65 | >>> url = 'https://httpbin.org/digest-auth/auth/user/pass' 66 | >>> requests.get(url, auth=HTTPDigestAuth('user', 'pass')) 67 | 68 | 69 | 70 | OAuth 1 Authentication 71 | ---------------------- 72 | 73 | A common form of authentication for several web APIs is OAuth. The ``requests-oauthlib`` 74 | library allows Requests users to easily make OAuth 1 authenticated requests:: 75 | 76 | >>> import requests 77 | >>> from requests_oauthlib import OAuth1 78 | 79 | >>> url = 'https://api.twitter.com/1.1/account/verify_credentials.json' 80 | >>> auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET', 81 | ... 'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET') 82 | 83 | >>> requests.get(url, auth=auth) 84 | 85 | 86 | For more information on how to OAuth flow works, please see the official `OAuth`_ website. 87 | For examples and documentation on requests-oauthlib, please see the `requests_oauthlib`_ 88 | repository on GitHub 89 | 90 | OAuth 2 and OpenID Connect Authentication 91 | ----------------------------------------- 92 | 93 | The ``requests-oauthlib`` library also handles OAuth 2, the authentication mechanism 94 | underpinning OpenID Connect. See the `requests-oauthlib OAuth2 documentation`_ for 95 | details of the various OAuth 2 credential management flows: 96 | 97 | * `Web Application Flow`_ 98 | * `Mobile Application Flow`_ 99 | * `Legacy Application Flow`_ 100 | * `Backend Application Flow`_ 101 | 102 | Other Authentication 103 | -------------------- 104 | 105 | Requests is designed to allow other forms of authentication to be easily and 106 | quickly plugged in. Members of the open-source community frequently write 107 | authentication handlers for more complicated or less commonly-used forms of 108 | authentication. Some of the best have been brought together under the 109 | `Requests organization`_, including: 110 | 111 | - Kerberos_ 112 | - NTLM_ 113 | 114 | If you want to use any of these forms of authentication, go straight to their 115 | GitHub page and follow the instructions. 116 | 117 | 118 | New Forms of Authentication 119 | --------------------------- 120 | 121 | If you can't find a good implementation of the form of authentication you 122 | want, you can implement it yourself. Requests makes it easy to add your own 123 | forms of authentication. 124 | 125 | To do so, subclass :class:`AuthBase ` and implement the 126 | ``__call__()`` method:: 127 | 128 | >>> import requests 129 | >>> class MyAuth(requests.auth.AuthBase): 130 | ... def __call__(self, r): 131 | ... # Implement my authentication 132 | ... return r 133 | ... 134 | >>> url = 'https://httpbin.org/get' 135 | >>> requests.get(url, auth=MyAuth()) 136 | 137 | 138 | When an authentication handler is attached to a request, 139 | it is called during request setup. The ``__call__`` method must therefore do 140 | whatever is required to make the authentication work. Some forms of 141 | authentication will additionally add hooks to provide further functionality. 142 | 143 | Further examples can be found under the `Requests organization`_ and in the 144 | ``auth.py`` file. 145 | 146 | .. _OAuth: https://oauth.net/ 147 | .. _requests_oauthlib: https://github.com/requests/requests-oauthlib 148 | .. _requests-oauthlib OAuth2 documentation: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html 149 | .. _Web Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#web-application-flow 150 | .. _Mobile Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#mobile-application-flow 151 | .. _Legacy Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#legacy-application-flow 152 | .. _Backend Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#backend-application-flow 153 | .. _Kerberos: https://github.com/requests/requests-kerberos 154 | .. _NTLM: https://github.com/requests/requests-ntlm 155 | .. _Requests organization: https://github.com/requests 156 | -------------------------------------------------------------------------------- /src/requests/api.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.api 3 | ~~~~~~~~~~~~ 4 | 5 | This module implements the Requests API. 6 | 7 | :copyright: (c) 2012 by Kenneth Reitz. 8 | :license: Apache2, see LICENSE for more details. 9 | """ 10 | 11 | from . import sessions 12 | 13 | 14 | def request(method, url, **kwargs): 15 | """Constructs and sends a :class:`Request `. 16 | 17 | :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. 18 | :param url: URL for the new :class:`Request` object. 19 | :param params: (optional) Dictionary, list of tuples or bytes to send 20 | in the query string for the :class:`Request`. 21 | :param data: (optional) Dictionary, list of tuples, bytes, or file-like 22 | object to send in the body of the :class:`Request`. 23 | :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. 24 | :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. 25 | :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. 26 | :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. 27 | ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` 28 | or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content_type'`` is a string 29 | defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers 30 | to add for the file. 31 | :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. 32 | :param timeout: (optional) How many seconds to wait for the server to send data 33 | before giving up, as a float, or a :ref:`(connect timeout, read 34 | timeout) ` tuple. 35 | :type timeout: float or tuple 36 | :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. 37 | :type allow_redirects: bool 38 | :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. 39 | :param verify: (optional) Either a boolean, in which case it controls whether we verify 40 | the server's TLS certificate, or a string, in which case it must be a path 41 | to a CA bundle to use. Defaults to ``True``. 42 | :param stream: (optional) if ``False``, the response content will be immediately downloaded. 43 | :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. 44 | :return: :class:`Response ` object 45 | :rtype: requests.Response 46 | 47 | Usage:: 48 | 49 | >>> import requests 50 | >>> req = requests.request('GET', 'https://httpbin.org/get') 51 | >>> req 52 | 53 | """ 54 | 55 | # By using the 'with' statement we are sure the session is closed, thus we 56 | # avoid leaving sockets open which can trigger a ResourceWarning in some 57 | # cases, and look like a memory leak in others. 58 | with sessions.Session() as session: 59 | return session.request(method=method, url=url, **kwargs) 60 | 61 | 62 | def get(url, params=None, **kwargs): 63 | r"""Sends a GET request. 64 | 65 | :param url: URL for the new :class:`Request` object. 66 | :param params: (optional) Dictionary, list of tuples or bytes to send 67 | in the query string for the :class:`Request`. 68 | :param \*\*kwargs: Optional arguments that ``request`` takes. 69 | :return: :class:`Response ` object 70 | :rtype: requests.Response 71 | """ 72 | 73 | return request("get", url, params=params, **kwargs) 74 | 75 | 76 | def options(url, **kwargs): 77 | r"""Sends an OPTIONS request. 78 | 79 | :param url: URL for the new :class:`Request` object. 80 | :param \*\*kwargs: Optional arguments that ``request`` takes. 81 | :return: :class:`Response ` object 82 | :rtype: requests.Response 83 | """ 84 | 85 | return request("options", url, **kwargs) 86 | 87 | 88 | def head(url, **kwargs): 89 | r"""Sends a HEAD request. 90 | 91 | :param url: URL for the new :class:`Request` object. 92 | :param \*\*kwargs: Optional arguments that ``request`` takes. If 93 | `allow_redirects` is not provided, it will be set to `False` (as 94 | opposed to the default :meth:`request` behavior). 95 | :return: :class:`Response ` object 96 | :rtype: requests.Response 97 | """ 98 | 99 | kwargs.setdefault("allow_redirects", False) 100 | return request("head", url, **kwargs) 101 | 102 | 103 | def post(url, data=None, json=None, **kwargs): 104 | r"""Sends a POST request. 105 | 106 | :param url: URL for the new :class:`Request` object. 107 | :param data: (optional) Dictionary, list of tuples, bytes, or file-like 108 | object to send in the body of the :class:`Request`. 109 | :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. 110 | :param \*\*kwargs: Optional arguments that ``request`` takes. 111 | :return: :class:`Response ` object 112 | :rtype: requests.Response 113 | """ 114 | 115 | return request("post", url, data=data, json=json, **kwargs) 116 | 117 | 118 | def put(url, data=None, **kwargs): 119 | r"""Sends a PUT request. 120 | 121 | :param url: URL for the new :class:`Request` object. 122 | :param data: (optional) Dictionary, list of tuples, bytes, or file-like 123 | object to send in the body of the :class:`Request`. 124 | :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. 125 | :param \*\*kwargs: Optional arguments that ``request`` takes. 126 | :return: :class:`Response ` object 127 | :rtype: requests.Response 128 | """ 129 | 130 | return request("put", url, data=data, **kwargs) 131 | 132 | 133 | def patch(url, data=None, **kwargs): 134 | r"""Sends a PATCH request. 135 | 136 | :param url: URL for the new :class:`Request` object. 137 | :param data: (optional) Dictionary, list of tuples, bytes, or file-like 138 | object to send in the body of the :class:`Request`. 139 | :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. 140 | :param \*\*kwargs: Optional arguments that ``request`` takes. 141 | :return: :class:`Response ` object 142 | :rtype: requests.Response 143 | """ 144 | 145 | return request("patch", url, data=data, **kwargs) 146 | 147 | 148 | def delete(url, **kwargs): 149 | r"""Sends a DELETE request. 150 | 151 | :param url: URL for the new :class:`Request` object. 152 | :param \*\*kwargs: Optional arguments that ``request`` takes. 153 | :return: :class:`Response ` object 154 | :rtype: requests.Response 155 | """ 156 | 157 | return request("delete", url, **kwargs) 158 | -------------------------------------------------------------------------------- /docs/dev/contributing.rst: -------------------------------------------------------------------------------- 1 | .. _contributing: 2 | 3 | Contributor's Guide 4 | =================== 5 | 6 | If you're reading this, you're probably interested in contributing to Requests. 7 | Thank you very much! Open source projects live-and-die based on the support 8 | they receive from others, and the fact that you're even considering 9 | contributing to the Requests project is *very* generous of you. 10 | 11 | This document lays out guidelines and advice for contributing to this project. 12 | If you're thinking of contributing, please start by reading this document and 13 | getting a feel for how contributing to this project works. If you have any 14 | questions, feel free to reach out to either `Nate Prewitt`_, `Ian Cordasco`_, 15 | or `Seth Michael Larson`_, the primary maintainers. 16 | 17 | .. _Ian Cordasco: http://www.coglib.com/~icordasc/ 18 | .. _Nate Prewitt: https://www.nateprewitt.com/ 19 | .. _Seth Michael Larson: https://sethmlarson.dev/ 20 | 21 | The guide is split into sections based on the type of contribution you're 22 | thinking of making, with a section that covers general guidelines for all 23 | contributors. 24 | 25 | Code of Conduct 26 | --------------- 27 | 28 | The Python community is made up of members from around the globe with a diverse 29 | set of skills, personalities, and experiences. It is through these differences 30 | that our community experiences great successes and continued growth. When you're 31 | working with members of the community, follow the 32 | `Python Software Foundation Code of Conduct`_ to help steer your interactions 33 | and keep Python a positive, successful, and growing community. 34 | 35 | .. _Python Software Foundation Code of Conduct: https://policies.python.org/python.org/code-of-conduct/ 36 | 37 | .. _early-feedback: 38 | 39 | Get Early Feedback 40 | ------------------ 41 | 42 | If you are contributing, do not feel the need to sit on your contribution until 43 | it is perfectly polished and complete. It helps everyone involved for you to 44 | seek feedback as early as you possibly can. Submitting an early, unfinished 45 | version of your contribution for feedback in no way prejudices your chances of 46 | getting that contribution accepted, and can save you from putting a lot of work 47 | into a contribution that is not suitable for the project. 48 | 49 | Contribution Suitability 50 | ------------------------ 51 | 52 | Our project maintainers have the last word on whether or not a contribution is 53 | suitable for Requests. All contributions will be considered carefully, but from 54 | time to time, contributions will be rejected because they do not suit the 55 | current goals or needs of the project. 56 | 57 | If your contribution is rejected, don't despair! As long as you followed these 58 | guidelines, you will have a much better chance of getting your next 59 | contribution accepted. 60 | 61 | 62 | Code Contributions 63 | ------------------ 64 | 65 | Steps for Submitting Code 66 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 67 | 68 | When contributing code, you'll want to follow this checklist: 69 | 70 | 1. Fork the repository on GitHub. 71 | 2. Run the tests to confirm they all pass on your system. If they don't, you'll 72 | need to investigate why they fail. If you're unable to diagnose this 73 | yourself, raise it as a bug report by following the guidelines in this 74 | document: :ref:`bug-reports`. 75 | 3. Write tests that demonstrate your bug or feature. Ensure that they fail. 76 | 4. Make your change. 77 | 5. Run the entire test suite again, confirming that all tests pass *including 78 | the ones you just added*. 79 | 6. Send a GitHub Pull Request to the main repository's ``main`` branch. 80 | GitHub Pull Requests are the expected method of code collaboration on this 81 | project. 82 | 83 | The following sub-sections go into more detail on some of the points above. 84 | 85 | Code Review 86 | ~~~~~~~~~~~ 87 | 88 | Contributions will not be merged until they've been code reviewed. You should 89 | implement any code review feedback unless you strongly object to it. In the 90 | event that you object to the code review feedback, you should make your case 91 | clearly and calmly. If, after doing so, the feedback is judged to still apply, 92 | you must either apply the feedback or withdraw your contribution. 93 | 94 | Code Style 95 | ~~~~~~~~~~ 96 | 97 | Requests uses a collection of tools to ensure the code base has a consistent 98 | style as it grows. We have these orchestrated using a tool called 99 | `pre-commit`_. This can be installed locally and run over your changes prior 100 | to opening a PR, and will also be run as part of the CI approval process 101 | before a change is merged. 102 | 103 | You can find the full list of formatting requirements specified in the 104 | `.pre-commit-config.yaml`_ at the top level directory of Requests. 105 | 106 | .. _pre-commit: https://pre-commit.com/ 107 | .. _.pre-commit-config.yaml: https://github.com/psf/requests/blob/main/.pre-commit-config.yaml 108 | 109 | New Contributors 110 | ~~~~~~~~~~~~~~~~ 111 | 112 | If you are new or relatively new to Open Source, welcome! Requests aims to 113 | be a gentle introduction to the world of Open Source. If you're concerned about 114 | how best to contribute, please consider mailing a maintainer (listed above) and 115 | asking for help. 116 | 117 | Please also check the :ref:`early-feedback` section. 118 | 119 | 120 | Documentation Contributions 121 | --------------------------- 122 | 123 | Documentation improvements are always welcome! The documentation files live in 124 | the ``docs/`` directory of the codebase. They're written in 125 | `reStructuredText`_, and use `Sphinx`_ to generate the full suite of 126 | documentation. 127 | 128 | When contributing documentation, please do your best to follow the style of the 129 | documentation files. This means a soft-limit of 79 characters wide in your text 130 | files and a semi-formal, yet friendly and approachable, prose style. 131 | 132 | When presenting Python code, use single-quoted strings (``'hello'`` instead of 133 | ``"hello"``). 134 | 135 | .. _reStructuredText: http://docutils.sourceforge.net/rst.html 136 | .. _Sphinx: http://sphinx-doc.org/index.html 137 | 138 | 139 | .. _bug-reports: 140 | 141 | Bug Reports 142 | ----------- 143 | 144 | Bug reports are hugely important! Before you raise one, though, please check 145 | through the `GitHub issues`_, **both open and closed**, to confirm that the bug 146 | hasn't been reported before. Duplicate bug reports are a huge drain on the time 147 | of other contributors, and should be avoided as much as possible. 148 | 149 | .. _GitHub issues: https://github.com/psf/requests/issues 150 | 151 | 152 | Feature Requests 153 | ---------------- 154 | 155 | Requests is in a perpetual feature freeze, only the BDFL can add or approve of 156 | new features. The maintainers believe that Requests is a feature-complete 157 | piece of software at this time. 158 | 159 | One of the most important skills to have while maintaining a largely-used 160 | open source project is learning the ability to say "no" to suggested changes, 161 | while keeping an open ear and mind. 162 | 163 | If you believe there is a feature missing, feel free to raise a feature 164 | request, but please do be aware that the overwhelming likelihood is that your 165 | feature request will not be accepted. 166 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 1>NUL 2>NUL 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Requests.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Requests.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | Developer Interface 4 | =================== 5 | 6 | .. module:: requests 7 | 8 | This part of the documentation covers all the interfaces of Requests. For 9 | parts where Requests depends on external libraries, we document the most 10 | important right here and provide links to the canonical documentation. 11 | 12 | 13 | Main Interface 14 | -------------- 15 | 16 | All of Requests' functionality can be accessed by these 7 methods. 17 | They all return an instance of the :class:`Response ` object. 18 | 19 | .. autofunction:: request 20 | 21 | .. autofunction:: head 22 | .. autofunction:: get 23 | .. autofunction:: post 24 | .. autofunction:: put 25 | .. autofunction:: patch 26 | .. autofunction:: delete 27 | 28 | Exceptions 29 | ---------- 30 | 31 | .. autoexception:: requests.RequestException 32 | .. autoexception:: requests.ConnectionError 33 | .. autoexception:: requests.HTTPError 34 | .. autoexception:: requests.TooManyRedirects 35 | .. autoexception:: requests.ConnectTimeout 36 | .. autoexception:: requests.ReadTimeout 37 | .. autoexception:: requests.Timeout 38 | .. autoexception:: requests.JSONDecodeError 39 | 40 | 41 | Request Sessions 42 | ---------------- 43 | 44 | .. _sessionapi: 45 | 46 | .. autoclass:: Session 47 | :inherited-members: 48 | 49 | 50 | Lower-Level Classes 51 | ------------------- 52 | 53 | .. autoclass:: requests.Request 54 | :inherited-members: 55 | 56 | .. autoclass:: Response 57 | :inherited-members: 58 | 59 | 60 | Lower-Lower-Level Classes 61 | ------------------------- 62 | 63 | .. autoclass:: requests.PreparedRequest 64 | :inherited-members: 65 | 66 | .. autoclass:: requests.adapters.BaseAdapter 67 | :inherited-members: 68 | 69 | .. autoclass:: requests.adapters.HTTPAdapter 70 | :inherited-members: 71 | 72 | Authentication 73 | -------------- 74 | 75 | .. autoclass:: requests.auth.AuthBase 76 | .. autoclass:: requests.auth.HTTPBasicAuth 77 | .. autoclass:: requests.auth.HTTPProxyAuth 78 | .. autoclass:: requests.auth.HTTPDigestAuth 79 | 80 | 81 | 82 | Encodings 83 | --------- 84 | 85 | .. autofunction:: requests.utils.get_encodings_from_content 86 | .. autofunction:: requests.utils.get_encoding_from_headers 87 | .. autofunction:: requests.utils.get_unicode_from_response 88 | 89 | 90 | .. _api-cookies: 91 | 92 | Cookies 93 | ------- 94 | 95 | .. autofunction:: requests.utils.dict_from_cookiejar 96 | .. autofunction:: requests.utils.add_dict_to_cookiejar 97 | .. autofunction:: requests.cookies.cookiejar_from_dict 98 | 99 | .. autoclass:: requests.cookies.RequestsCookieJar 100 | :inherited-members: 101 | 102 | .. autoclass:: requests.cookies.CookieConflictError 103 | :inherited-members: 104 | 105 | 106 | 107 | Status Code Lookup 108 | ------------------ 109 | 110 | .. autoclass:: requests.codes 111 | 112 | .. automodule:: requests.status_codes 113 | 114 | 115 | Migrating to 1.x 116 | ---------------- 117 | 118 | This section details the main differences between 0.x and 1.x and is meant 119 | to ease the pain of upgrading. 120 | 121 | 122 | API Changes 123 | ~~~~~~~~~~~ 124 | 125 | * ``Response.json`` is now a callable and not a property of a response. 126 | 127 | :: 128 | 129 | import requests 130 | r = requests.get('https://api.github.com/events') 131 | r.json() # This *call* raises an exception if JSON decoding fails 132 | 133 | * The ``Session`` API has changed. Sessions objects no longer take parameters. 134 | ``Session`` is also now capitalized, but it can still be 135 | instantiated with a lowercase ``session`` for backwards compatibility. 136 | 137 | :: 138 | 139 | s = requests.Session() # formerly, session took parameters 140 | s.auth = auth 141 | s.headers.update(headers) 142 | r = s.get('https://httpbin.org/headers') 143 | 144 | * All request hooks have been removed except 'response'. 145 | 146 | * Authentication helpers have been broken out into separate modules. See 147 | requests-oauthlib_ and requests-kerberos_. 148 | 149 | .. _requests-oauthlib: https://github.com/requests/requests-oauthlib 150 | .. _requests-kerberos: https://github.com/requests/requests-kerberos 151 | 152 | * The parameter for streaming requests was changed from ``prefetch`` to 153 | ``stream`` and the logic was inverted. In addition, ``stream`` is now 154 | required for raw response reading. 155 | 156 | :: 157 | 158 | # in 0.x, passing prefetch=False would accomplish the same thing 159 | r = requests.get('https://api.github.com/events', stream=True) 160 | for chunk in r.iter_content(8192): 161 | ... 162 | 163 | * The ``config`` parameter to the requests method has been removed. Some of 164 | these options are now configured on a ``Session`` such as keep-alive and 165 | maximum number of redirects. The verbosity option should be handled by 166 | configuring logging. 167 | 168 | :: 169 | 170 | import requests 171 | import logging 172 | 173 | # Enabling debugging at http.client level (requests->urllib3->http.client) 174 | # you will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA. 175 | # the only thing missing will be the response.body which is not logged. 176 | try: # for Python 3 177 | from http.client import HTTPConnection 178 | except ImportError: 179 | from httplib import HTTPConnection 180 | HTTPConnection.debuglevel = 1 181 | 182 | logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from requests 183 | logging.getLogger().setLevel(logging.DEBUG) 184 | requests_log = logging.getLogger("urllib3") 185 | requests_log.setLevel(logging.DEBUG) 186 | requests_log.propagate = True 187 | 188 | requests.get('https://httpbin.org/headers') 189 | 190 | 191 | 192 | Licensing 193 | ~~~~~~~~~ 194 | 195 | One key difference that has nothing to do with the API is a change in the 196 | license from the ISC_ license to the `Apache 2.0`_ license. The Apache 2.0 197 | license ensures that contributions to Requests are also covered by the Apache 198 | 2.0 license. 199 | 200 | .. _ISC: https://opensource.org/licenses/ISC 201 | .. _Apache 2.0: https://opensource.org/licenses/Apache-2.0 202 | 203 | 204 | Migrating to 2.x 205 | ---------------- 206 | 207 | 208 | Compared with the 1.0 release, there were relatively few backwards 209 | incompatible changes, but there are still a few issues to be aware of with 210 | this major release. 211 | 212 | For more details on the changes in this release including new APIs, links 213 | to the relevant GitHub issues and some of the bug fixes, read Cory's blog_ 214 | on the subject. 215 | 216 | .. _blog: https://lukasa.co.uk/2013/09/Requests_20/ 217 | 218 | 219 | API Changes 220 | ~~~~~~~~~~~ 221 | 222 | * There were a couple changes to how Requests handles exceptions. 223 | ``RequestException`` is now a subclass of ``IOError`` rather than 224 | ``RuntimeError`` as that more accurately categorizes the type of error. 225 | In addition, an invalid URL escape sequence now raises a subclass of 226 | ``RequestException`` rather than a ``ValueError``. 227 | 228 | :: 229 | 230 | requests.get('http://%zz/') # raises requests.exceptions.InvalidURL 231 | 232 | Lastly, ``httplib.IncompleteRead`` exceptions caused by incorrect chunked 233 | encoding will now raise a Requests ``ChunkedEncodingError`` instead. 234 | 235 | * The proxy API has changed slightly. The scheme for a proxy URL is now 236 | required. 237 | 238 | :: 239 | 240 | proxies = { 241 | "http": "10.10.1.10:3128", # use http://10.10.1.10:3128 instead 242 | } 243 | 244 | # In requests 1.x, this was legal, in requests 2.x, 245 | # this raises requests.exceptions.MissingSchema 246 | requests.get("http://example.org", proxies=proxies) 247 | 248 | 249 | Behavioural Changes 250 | ~~~~~~~~~~~~~~~~~~~~~~~ 251 | 252 | * Keys in the ``headers`` dictionary are now native strings on all Python 253 | versions, i.e. bytestrings on Python 2 and unicode on Python 3. If the 254 | keys are not native strings (unicode on Python 2 or bytestrings on Python 3) 255 | they will be converted to the native string type assuming UTF-8 encoding. 256 | 257 | * Values in the ``headers`` dictionary should always be strings. This has 258 | been the project's position since before 1.0 but a recent change 259 | (since version 2.11.0) enforces this more strictly. It's advised to avoid 260 | passing header values as unicode when possible. 261 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | .PHONY: clean 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | .PHONY: html 55 | html: 56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 | @echo 58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 | 60 | .PHONY: dirhtml 61 | dirhtml: 62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 | @echo 64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 | 66 | .PHONY: singlehtml 67 | singlehtml: 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | .PHONY: pickle 73 | pickle: 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | .PHONY: json 79 | json: 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | .PHONY: htmlhelp 85 | htmlhelp: 86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 | @echo 88 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 | ".hhp project file in $(BUILDDIR)/htmlhelp." 90 | 91 | .PHONY: qthelp 92 | qthelp: 93 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 94 | @echo 95 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 96 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 97 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Requests.qhcp" 98 | @echo "To view the help file:" 99 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Requests.qhc" 100 | 101 | .PHONY: applehelp 102 | applehelp: 103 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 104 | @echo 105 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 106 | @echo "N.B. You won't be able to view it unless you put it in" \ 107 | "~/Library/Documentation/Help or install it in your application" \ 108 | "bundle." 109 | 110 | .PHONY: devhelp 111 | devhelp: 112 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 113 | @echo 114 | @echo "Build finished." 115 | @echo "To view the help file:" 116 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Requests" 117 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Requests" 118 | @echo "# devhelp" 119 | 120 | .PHONY: epub 121 | epub: 122 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 123 | @echo 124 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 125 | 126 | .PHONY: latex 127 | latex: 128 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 129 | @echo 130 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 131 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 132 | "(use \`make latexpdf' here to do that automatically)." 133 | 134 | .PHONY: latexpdf 135 | latexpdf: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo "Running LaTeX files through pdflatex..." 138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 | 141 | .PHONY: latexpdfja 142 | latexpdfja: 143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 144 | @echo "Running LaTeX files through platex and dvipdfmx..." 145 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 146 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 147 | 148 | .PHONY: text 149 | text: 150 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 151 | @echo 152 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 153 | 154 | .PHONY: man 155 | man: 156 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 157 | @echo 158 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 159 | 160 | .PHONY: texinfo 161 | texinfo: 162 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 163 | @echo 164 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 165 | @echo "Run \`make' in that directory to run these through makeinfo" \ 166 | "(use \`make info' here to do that automatically)." 167 | 168 | .PHONY: info 169 | info: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo "Running Texinfo files through makeinfo..." 172 | make -C $(BUILDDIR)/texinfo info 173 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 174 | 175 | .PHONY: gettext 176 | gettext: 177 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 178 | @echo 179 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 180 | 181 | .PHONY: changes 182 | changes: 183 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 184 | @echo 185 | @echo "The overview file is in $(BUILDDIR)/changes." 186 | 187 | .PHONY: linkcheck 188 | linkcheck: 189 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 190 | @echo 191 | @echo "Link check complete; look for any errors in the above output " \ 192 | "or in $(BUILDDIR)/linkcheck/output.txt." 193 | 194 | .PHONY: doctest 195 | doctest: 196 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 197 | @echo "Testing of doctests in the sources finished, look at the " \ 198 | "results in $(BUILDDIR)/doctest/output.txt." 199 | 200 | .PHONY: coverage 201 | coverage: 202 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 203 | @echo "Testing of coverage in the sources finished, look at the " \ 204 | "results in $(BUILDDIR)/coverage/python.txt." 205 | 206 | .PHONY: xml 207 | xml: 208 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 209 | @echo 210 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 211 | 212 | .PHONY: pseudoxml 213 | pseudoxml: 214 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 215 | @echo 216 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 217 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Requests was lovingly created by Kenneth Reitz. 2 | 3 | Keepers of the Crystals 4 | ``````````````````````` 5 | 6 | - Nate Prewitt `@nateprewitt `_. 7 | - Seth M. Larson `@sethmlarson `_. 8 | 9 | Previous Keepers of Crystals 10 | ```````````````````````````` 11 | - Kenneth Reitz `@kennethreitz `_, reluctant Keeper of the Master Crystal. 12 | - Cory Benfield `@lukasa `_ 13 | - Ian Cordasco `@sigmavirus24 `_. 14 | 15 | 16 | Patches and Suggestions 17 | ``````````````````````` 18 | 19 | - Various Pocoo Members 20 | - Chris Adams 21 | - Flavio Percoco Premoli 22 | - Dj Gilcrease 23 | - Justin Murphy 24 | - Rob Madole 25 | - Aram Dulyan 26 | - Johannes Gorset 27 | - 村山めがね (Megane Murayama) 28 | - James Rowe 29 | - Daniel Schauenberg 30 | - Zbigniew Siciarz 31 | - Daniele Tricoli 'Eriol' 32 | - Richard Boulton 33 | - Miguel Olivares 34 | - Alberto Paro 35 | - Jérémy Bethmont 36 | - 潘旭 (Xu Pan) 37 | - Tamás Gulácsi 38 | - Rubén Abad 39 | - Peter Manser 40 | - Jeremy Selier 41 | - Jens Diemer 42 | - Alex (`@alopatin `_) 43 | - Tom Hogans 44 | - Armin Ronacher 45 | - Shrikant Sharat Kandula 46 | - Mikko Ohtamaa 47 | - Den Shabalin 48 | - Daniel Miller 49 | - Alejandro Giacometti 50 | - Rick Mak 51 | - Johan Bergström 52 | - Josselin Jacquard 53 | - Travis N. Vaught 54 | - Fredrik Möllerstrand 55 | - Daniel Hengeveld 56 | - Dan Head 57 | - Bruno Renié 58 | - David Fischer 59 | - Joseph McCullough 60 | - Juergen Brendel 61 | - Juan Riaza 62 | - Ryan Kelly 63 | - Rolando Espinoza La fuente 64 | - Robert Gieseke 65 | - Idan Gazit 66 | - Ed Summers 67 | - Chris Van Horne 68 | - Christopher Davis 69 | - Ori Livneh 70 | - Jason Emerick 71 | - Bryan Helmig 72 | - Jonas Obrist 73 | - Lucian Ursu 74 | - Tom Moertel 75 | - Frank Kumro Jr 76 | - Chase Sterling 77 | - Marty Alchin 78 | - takluyver 79 | - Ben Toews (`@mastahyeti `_) 80 | - David Kemp 81 | - Brendon Crawford 82 | - Denis (`@Telofy `_) 83 | - Matt Giuca 84 | - Adam Tauber 85 | - Honza Javorek 86 | - Brendan Maguire 87 | - Chris Dary 88 | - Danver Braganza 89 | - Max Countryman 90 | - Nick Chadwick 91 | - Jonathan Drosdeck 92 | - Jiri Machalek 93 | - Steve Pulec 94 | - Michael Kelly 95 | - Michael Newman 96 | - Jonty Wareing 97 | - Shivaram Lingamneni 98 | - Miguel Turner 99 | - Rohan Jain (`@crodjer `_) 100 | - Justin Barber 101 | - Roman Haritonov (`@reclosedev `_) 102 | - Josh Imhoff 103 | - Arup Malakar 104 | - Danilo Bargen (`@dbrgn `_) 105 | - Torsten Landschoff 106 | - Michael Holler (`@apotheos `_) 107 | - Timnit Gebru 108 | - Sarah Gonzalez 109 | - Victoria Mo 110 | - Leila Muhtasib 111 | - Matthias Rahlf 112 | - Jakub Roztocil 113 | - Rhys Elsmore 114 | - André Graf (`@dergraf `_) 115 | - Stephen Zhuang (`@everbird `_) 116 | - Martijn Pieters 117 | - Jonatan Heyman 118 | - David Bonner (`@rascalking `_) 119 | - Vinod Chandru 120 | - Johnny Goodnow 121 | - Denis Ryzhkov 122 | - Wilfred Hughes 123 | - Dmitry Medvinsky 124 | - Bryce Boe (`@bboe `_) 125 | - Colin Dunklau (`@cdunklau `_) 126 | - Bob Carroll (`@rcarz `_) 127 | - Hugo Osvaldo Barrera (`@hobarrera `_) 128 | - Łukasz Langa 129 | - Dave Shawley 130 | - James Clarke (`@jam `_) 131 | - Kevin Burke 132 | - Flavio Curella 133 | - David Pursehouse (`@dpursehouse `_) 134 | - Jon Parise (`@jparise `_) 135 | - Alexander Karpinsky (`@homm86 `_) 136 | - Marc Schlaich (`@schlamar `_) 137 | - Park Ilsu (`@daftshady `_) 138 | - Matt Spitz (`@mattspitz `_) 139 | - Vikram Oberoi (`@voberoi `_) 140 | - Can Ibanoglu (`@canibanoglu `_) 141 | - Thomas Weißschuh (`@t-8ch `_) 142 | - Jayson Vantuyl 143 | - Pengfei.X 144 | - Kamil Madac 145 | - Michael Becker (`@beckerfuffle `_) 146 | - Erik Wickstrom (`@erikwickstrom `_) 147 | - Константин Подшумок (`@podshumok `_) 148 | - Ben Bass (`@codedstructure `_) 149 | - Jonathan Wong (`@ContinuousFunction `_) 150 | - Martin Jul (`@mjul `_) 151 | - Joe Alcorn (`@buttscicles `_) 152 | - Syed Suhail Ahmed (`@syedsuhail `_) 153 | - Scott Sadler (`@ssadler `_) 154 | - Arthur Darcet (`@arthurdarcet `_) 155 | - Ulrich Petri (`@ulope `_) 156 | - Muhammad Yasoob Ullah Khalid (`@yasoob `_) 157 | - Paul van der Linden (`@pvanderlinden `_) 158 | - Colin Dickson (`@colindickson `_) 159 | - Smiley Barry (`@smiley `_) 160 | - Shagun Sodhani (`@shagunsodhani `_) 161 | - Robin Linderborg (`@vienno `_) 162 | - Brian Samek (`@bsamek `_) 163 | - Dmitry Dygalo (`@Stranger6667 `_) 164 | - piotrjurkiewicz 165 | - Jesse Shapiro (`@haikuginger `_) 166 | - Nate Prewitt (`@nateprewitt `_) 167 | - Maik Himstedt 168 | - Michael Hunsinger 169 | - Brian Bamsch (`@bbamsch `_) 170 | - Om Prakash Kumar (`@iamprakashom `_) 171 | - Philipp Konrad (`@gardiac2002 `_) 172 | - Hussain Tamboli (`@hussaintamboli `_) 173 | - Casey Davidson (`@davidsoncasey `_) 174 | - Andrii Soldatenko (`@a_soldatenko `_) 175 | - Moinuddin Quadri (`@moin18 `_) 176 | - Matt Kohl (`@mattkohl `_) 177 | - Jonathan Vanasco (`@jvanasco `_) 178 | - David Fontenot (`@davidfontenot `_) 179 | - Shmuel Amar (`@shmuelamar `_) 180 | - Gary Wu (`@garywu `_) 181 | - Ryan Pineo (`@ryanpineo `_) 182 | - Ed Morley (`@edmorley `_) 183 | - Matt Liu (`@mlcrazy `_) 184 | - Taylor Hoff (`@PrimordialHelios `_) 185 | - Arthur Vigil (`@ahvigil `_) 186 | - Nehal J Wani (`@nehaljwani `_) 187 | - Demetrios Bairaktaris (`@DemetriosBairaktaris `_) 188 | - Darren Dormer (`@ddormer `_) 189 | - Rajiv Mayani (`@mayani `_) 190 | - Antti Kaihola (`@akaihola `_) 191 | - "Dull Bananas" (`@dullbananas `_) 192 | - Alessio Izzo (`@aless10 `_) 193 | - Sylvain Marié (`@smarie `_) 194 | - Hod Bin Noon (`@hodbn `_) 195 | - Mike Fiedler (`@miketheman `_) 196 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | --------------------------------------------------------------------------------