feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS = '-W'
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/urllib3.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/urllib3.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/urllib3"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/urllib3"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 400 119.35" xmlns="http://www.w3.org/2000/svg"><path d="m23.05 31v51.88q0 7.35 1.73 11.05 3.06 6.55 12 6.56 11.48 0 15.71-9.32 2.2-5.06 2.2-13.34v-46.83h22.82v86h-21.86v-12.09c-.21.26-.74 1-1.57 2.36a15.9 15.9 0 0 1 -3 3.48 31.44 31.44 0 0 1 -10.2 6.47 34.57 34.57 0 0 1 -11.52 1.78q-19 0-25.66-13.74-3.7-7.61-3.7-22.38v-51.88z"/><path d="m140.44 29c.29 0 .93.07 1.93.12v23.06c-1.42-.16-2.68-.27-3.79-.32s-2-.08-2.68-.08q-13.58 0-18.23 8.84-2.61 5-2.61 15.32v41.12h-22.65v-86.06h21.47v15q5.2-8.61 9.08-11.76 6.3-5.24 16.41-5.24z"/><path d="m177.56 86h-22.81v-86h22.81zm-22.81 10.3h22.81v20.76h-22.81z" fill="#cb3b0f"/><path d="m210.13 86h-22.82v-86h22.82zm-22.82 10.3h22.82v20.76h-22.82z" fill="#ea9b1c"/><path d="m242.69 20.76h-22.81v-20.76h22.81zm-22.81 10.24h22.81v86h-22.81z" fill="#577a27"/><path d="m333.45 41.36q9.66 12.24 9.66 31.58 0 20-9.53 33.23t-26.58 13.18q-10.71 0-17.21-4.26-3.89-2.53-8.41-8.84v10.81h-22.18v-116.19h22.49v41.36a32.94 32.94 0 0 1 9.46-9.16q6.11-3.94 15.57-3.94 17.07 0 26.73 12.23zm-18.8 52.41q4.86-7 4.85-18.47 0-9.15-2.38-15.15-4.55-11.37-16.72-11.37-12.33 0-16.95 11.13-2.38 5.93-2.39 15.32 0 11 4.94 18.31t15 7.26a15.6 15.6 0 0 0 13.65-7.03z"/><path d="m363 49.73q.31 5.06 1.74 7.42 2.59 4.34 9.47 4.34a11.79 11.79 0 0 0 5.6-1.42q5.06-2.68 5-9.24t-5-8.6q-3.07-1.33-11.6-1.66v-9.57q7-.15 9.87-1.34 5-2.13 5-8.21a7.91 7.91 0 0 0 -2.81-6.45 10.56 10.56 0 0 0 -6.87-2.25 8.91 8.91 0 0 0 -7.3 3.12 12.32 12.32 0 0 0 -2.57 8.09h-13.53a20.75 20.75 0 0 1 7.42-17.37q5.96-4.78 16.58-4.77 10.89 0 17.33 5.17a16.55 16.55 0 0 1 6.43 13.53 14.06 14.06 0 0 1 -2.42 8.48 17.71 17.71 0 0 1 -6.55 5.41 13 13 0 0 1 7.78 4.34q3.43 3.72 3.43 11.45 0 10.59-7.3 16.38a27.25 27.25 0 0 1 -17.49 5.8q-12.07 0-19.37-5.32t-7.31-17.33z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="420" height="128" style=""><rect id="backgroundrect" width="100%" height="100%" x="0" y="0" fill="none" stroke="#dadada" class="" style="" stroke-opacity="1" opacity="0"/>
<g style="" class="currentLayer">
<title>Layer 1</title>
<path id="svg_1" d="m36.38333110809326,34.58974647521973 l0,51.88 q0,7.35 1.73,11.05 q3.06,6.55 12,6.5600000000000005 q11.48,0 15.71,-9.32 q2.2,-5.06 2.2,-13.34 l0,-46.83 l22.82,0 l0,86 l-21.86,0 l0,-12.09 c-0.21000000000000016,0.26 -0.7400000000000007,1 -1.57,2.36 a15.9,15.9 0 0 1 -3,3.48 a31.44,31.44 0 0 1 -10.2,6.47 a34.57,34.57 0 0 1 -11.52,1.78 q-19,0 -25.66,-13.74 q-3.7,-7.61 -3.7,-22.38 l0,-51.88 l23.05,0 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_2" d="m152.7476901435852,32.58974647521973 c0.29000000000000026,0 0.93,0.07 1.9300000000000002,0.12000000000000002 l0,23.06 c-1.42,-0.16000000000000017 -2.68,-0.27 -3.79,-0.32000000000000034 s-2,-0.08000000000000007 -2.68,-0.08000000000000007 q-13.58,0 -18.23,8.84 q-2.6100000000000003,5 -2.6100000000000003,15.32 l0,41.12 l-22.65,0 l0,-86.06 l21.47,0 l0,15 q5.2,-8.61 9.08,-11.76 q6.3,-5.24 16.41,-5.24 l1.07,0 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_3" fill="#cb3b0f" d="m189.8676901435852,90.61538743972778 l-22.81,0 l0,-86 l22.81,0 l0,86 zm-22.81,10.3 l22.81,0 l0,20.76 l-22.81,0 l0,-20.76 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_4" fill="#ea9b1c" d="m226.02743375778198,89.58974647521973 l-22.82,0 l0,-86 l22.82,0 l0,86 zm-22.82,10.3 l22.82,0 l0,20.76 l-22.82,0 l0,-20.76 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_5" fill="#577a27" d="m262.6899985694885,24.862566957473756 l-22.81,0 l0,-20.76 l22.81,0 l0,20.76 zm-22.81,10.24 l22.81,0 l0,86 l-22.81,0 l0,-86 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_6" d="m349.5245453694749,45.62487759993961 q9.482886925935745,12.134041987610914 9.482886925935745,31.306621402675866 q0,19.82686599282829 -9.355270435214042,32.9423378470842 t-26.092664026021957,13.065904689273841 q-10.513635504841805,0 -16.894460040926933,-4.223122456472425 q-3.8186780685186386,-2.5080985480927787 -8.255805284380912,-8.763474768830102 l0,10.71642106912369 l-21.77333664774895,0 l0,-115.18417798533594 l22.077652894854545,0 l0,41.001958873168896 a32.33605541825294,32.65484829018819 0 0 1 9.286553863286972,-9.080704624715358 q5.9979750639200216,-3.9058926005871726 15.284528927206994,-3.9058926005871726 q16.75702689707279,0 26.23991382300854,12.124128554614499 zm-18.45530788898468,51.956302334206526 q4.770893422365189,-6.939403097489901 4.76107676923275,-18.310110744376924 q0,-9.070791191718941 -2.336363445520401,-15.018850989567428 q-4.46657717525959,-11.271573316922881 -16.413444037437436,-11.271573316922881 q-12.103933312296867,0 -16.639227059483527,11.033650925008944 q-2.336363445520401,5.8786657668735876 -2.3461800986528396,15.18737935050647 q0,10.904776296055559 4.849426647424698,18.151495816434295 t14.72497969865799,7.1971523553966685 a15.313978886604309,15.464955474406066 0 0 0 13.39973152577877,-6.9691433964791445 z" class="" stroke="#ffffff" stroke-opacity="1"/>
<path id="svg_7" d="m373.7692291736603,51.26846454620361 q0.3100000000000003,5.06 1.7400000000000002,7.42 q2.59,4.34 9.47,4.34 a11.79,11.79 0 0 0 5.6,-1.42 q5.06,-2.68 5,-9.24 t-5,-8.6 q-3.07,-1.33 -11.6,-1.6600000000000001 l0,-9.57 q7,-0.15000000000000013 9.870000000000001,-1.34 q5,-2.13 5,-8.21 a7.91,7.91 0 0 0 -2.81,-6.45 a10.56,10.56 0 0 0 -6.87,-2.25 a8.91,8.91 0 0 0 -7.3,3.12 a12.32,12.32 0 0 0 -2.5700000000000003,8.09 l-13.53,0 a20.75,20.75 0 0 1 7.42,-17.37 q5.96,-4.78 16.58,-4.77 q10.89,0 17.33,5.17 a16.55,16.55 0 0 1 6.43,13.53 a14.06,14.06 0 0 1 -2.42,8.48 a17.71,17.71 0 0 1 -6.55,5.41 a13,13 0 0 1 7.78,4.34 q3.43,3.72 3.43,11.45 q0,10.59 -7.3,16.38 a27.25,27.25 0 0 1 -17.49,5.8 q-12.07,0 -19.37,-5.32 t-7.3100000000000005,-17.33 l14.47,0 z" class="" stroke="#ffffff" stroke-opacity="1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 400 119.35" xmlns="http://www.w3.org/2000/svg"><path d="m23.05 31v51.88q0 7.35 1.73 11.05 3.06 6.55 12 6.56 11.48 0 15.71-9.32 2.2-5.06 2.2-13.34v-46.83h22.82v86h-21.86v-12.09c-.21.26-.74 1-1.57 2.36a15.9 15.9 0 0 1 -3 3.48 31.44 31.44 0 0 1 -10.2 6.47 34.57 34.57 0 0 1 -11.52 1.78q-19 0-25.66-13.74-3.7-7.61-3.7-22.38v-51.88z" fill="#fff"/><path d="m140.44 29c.29 0 .93.07 1.93.12v23.06c-1.42-.16-2.68-.27-3.79-.32s-2-.08-2.68-.08q-13.58 0-18.23 8.84-2.61 5-2.61 15.32v41.12h-22.65v-86.06h21.47v15q5.2-8.61 9.08-11.76 6.3-5.24 16.41-5.24z" fill="#fff"/><path d="m177.56 86h-22.81v-86h22.81zm-22.81 10.3h22.81v20.76h-22.81z" fill="#cb3b0f"/><path d="m210.13 86h-22.82v-86h22.82zm-22.82 10.3h22.82v20.76h-22.82z" fill="#ea9b1c"/><path d="m242.69 20.76h-22.81v-20.76h22.81zm-22.81 10.24h22.81v86h-22.81z" fill="#577a27"/><path d="m333.45 41.36q9.66 12.24 9.66 31.58 0 20-9.53 33.23t-26.58 13.18q-10.71 0-17.21-4.26-3.89-2.53-8.41-8.84v10.81h-22.18v-116.19h22.49v41.36a32.94 32.94 0 0 1 9.46-9.16q6.11-3.94 15.57-3.94 17.07 0 26.73 12.23zm-18.8 52.41q4.86-7 4.85-18.47 0-9.15-2.38-15.15-4.55-11.37-16.72-11.37-12.33 0-16.95 11.13-2.38 5.93-2.39 15.32 0 11 4.94 18.31t15 7.26a15.6 15.6 0 0 0 13.65-7.03z" fill="#fff"/><path d="m363 49.73q.31 5.06 1.74 7.42 2.59 4.34 9.47 4.34a11.79 11.79 0 0 0 5.6-1.42q5.06-2.68 5-9.24t-5-8.6q-3.07-1.33-11.6-1.66v-9.57q7-.15 9.87-1.34 5-2.13 5-8.21a7.91 7.91 0 0 0 -2.81-6.45 10.56 10.56 0 0 0 -6.87-2.25 8.91 8.91 0 0 0 -7.3 3.12 12.32 12.32 0 0 0 -2.57 8.09h-13.53a20.75 20.75 0 0 1 7.42-17.37q5.96-4.78 16.58-4.77 10.89 0 17.33 5.17a16.55 16.55 0 0 1 6.43 13.53 14.06 14.06 0 0 1 -2.42 8.48 17.71 17.71 0 0 1 -6.55 5.41 13 13 0 0 1 7.78 4.34q3.43 3.72 3.43 11.45 0 10.59-7.3 16.38a27.25 27.25 0 0 1 -17.49 5.8q-12.07 0-19.37-5.32t-7.31-17.33z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,633 @@
Advanced Usage
==============
.. currentmodule:: urllib3
Customizing Pool Behavior
-------------------------
The :class:`~poolmanager.PoolManager` class automatically handles creating
:class:`~connectionpool.ConnectionPool` instances for each host as needed. By
default, it will keep a maximum of 10 :class:`~connectionpool.ConnectionPool`
instances. If you're making requests to many different hosts it might improve
performance to increase this number.
.. code-block:: python
import urllib3
http = urllib3.PoolManager(num_pools=50)
However, keep in mind that this does increase memory and socket consumption.
Similarly, the :class:`~connectionpool.ConnectionPool` class keeps a pool
of individual :class:`~connection.HTTPConnection` instances. These connections
are used during an individual request and returned to the pool when the request
is complete. By default only one connection will be saved for re-use. If you
are making many requests to the same host simultaneously it might improve
performance to increase this number.
.. code-block:: python
import urllib3
http = urllib3.PoolManager(maxsize=10)
# Alternatively
pool = urllib3.HTTPConnectionPool("google.com", maxsize=10)
The behavior of the pooling for :class:`~connectionpool.ConnectionPool` is
different from :class:`~poolmanager.PoolManager`. By default, if a new
request is made and there is no free connection in the pool then a new
connection will be created. However, this connection will not be saved if more
than ``maxsize`` connections exist. This means that ``maxsize`` does not
determine the maximum number of connections that can be open to a particular
host, just the maximum number of connections to keep in the pool. However, if you specify ``block=True`` then there can be at most ``maxsize`` connections
open to a particular host.
.. code-block:: python
http = urllib3.PoolManager(maxsize=10, block=True)
# Alternatively
pool = urllib3.HTTPConnectionPool("google.com", maxsize=10, block=True)
Any new requests will block until a connection is available from the pool.
This is a great way to prevent flooding a host with too many connections in
multi-threaded applications.
.. _stream:
.. _streaming_and_io:
Streaming and I/O
-----------------
When using ``preload_content=True`` (the default setting) the
response body will be read immediately into memory and the HTTP connection
will be released back into the pool without manual intervention.
However, when dealing with large responses it's often better to stream the response
content using ``preload_content=False``. Setting ``preload_content`` to ``False`` means
that urllib3 will only read from the socket when data is requested.
.. note:: When using ``preload_content=False``, you need to manually release
the HTTP connection back to the connection pool so that it can be re-used.
To ensure the HTTP connection is in a valid state before being re-used
all data should be read off the wire.
You can call the :meth:`~response.HTTPResponse.drain_conn` to throw away
unread data still on the wire. This call isn't necessary if data has already
been completely read from the response.
After all data is read you can call :meth:`~response.HTTPResponse.release_conn`
to release the connection into the pool.
You can call the :meth:`~response.HTTPResponse.close` to close the connection,
but this call doesnt return the connection to the pool, throws away the unread
data on the wire, and leaves the connection in an undefined protocol state.
This is desirable if you prefer not reading data from the socket to re-using the
HTTP connection.
:meth:`~response.HTTPResponse.stream` lets you iterate over chunks of the response content.
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/bytes/1024",
preload_content=False
)
for chunk in resp.stream(32):
print(chunk)
# b"\x9e\xa97'\x8e\x1eT ....
resp.release_conn()
However, you can also treat the :class:`~response.HTTPResponse` instance as
a file-like object. This allows you to do buffering:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/bytes/1024",
preload_content=False
)
print(resp.read(4))
# b"\x88\x1f\x8b\xe5"
Calls to :meth:`~response.HTTPResponse.read()` will block until more response
data is available.
.. code-block:: python
import io
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/bytes/1024",
preload_content=False
)
reader = io.BufferedReader(resp, 8)
print(reader.read(4))
# b"\xbf\x9c\xd6"
resp.release_conn()
You can use this file-like object to do things like decode the content using
:mod:`codecs`:
.. code-block:: python
import codecs
import json
import urllib3
reader = codecs.getreader("utf-8")
resp = urllib3.request(
"GET",
"https://httpbin.org/ip",
preload_content=False
)
print(json.load(reader(resp)))
# {"origin": "127.0.0.1"}
resp.release_conn()
.. _proxies:
Proxies
-------
You can use :class:`~poolmanager.ProxyManager` to tunnel requests through an
HTTP proxy:
.. code-block:: python
import urllib3
proxy = urllib3.ProxyManager("https://localhost:3128/")
proxy.request("GET", "https://google.com/")
The usage of :class:`~poolmanager.ProxyManager` is the same as
:class:`~poolmanager.PoolManager`.
You can connect to a proxy using HTTP, HTTPS or SOCKS. urllib3's behavior will
be different depending on the type of proxy you selected and the destination
you're contacting.
HTTP and HTTPS Proxies
~~~~~~~~~~~~~~~~~~~~~~
Both HTTP/HTTPS proxies support HTTP and HTTPS destinations. The only
difference between them is if you need to establish a TLS connection to the
proxy first. You can specify which proxy you need to contact by specifying the
proper proxy scheme. (i.e ``http://`` or ``https://``)
urllib3's behavior will be different depending on your proxy and destination:
* HTTP proxy + HTTP destination
Your request will be forwarded with the `absolute URI
<https://datatracker.ietf.org/doc/html/rfc9112#name-absolute-form>`_.
* HTTP proxy + HTTPS destination
A TCP tunnel will be established with a `HTTP
CONNECT <https://datatracker.ietf.org/doc/html/rfc9110#name-connect>`_. Afterward a
TLS connection will be established with the destination and your request
will be sent.
* HTTPS proxy + HTTP destination
A TLS connection will be established to the proxy and later your request
will be forwarded with the `absolute URI
<https://datatracker.ietf.org/doc/html/rfc9112#name-absolute-form>`_.
* HTTPS proxy + HTTPS destination
A TLS-in-TLS tunnel will be established. An initial TLS connection will be
established to the proxy, then an `HTTP CONNECT
<https://datatracker.ietf.org/doc/html/rfc9110#name-connect>`_ will be sent to
establish a TCP connection to the destination and finally a second TLS
connection will be established to the destination. You can customize the
:class:`ssl.SSLContext` used for the proxy TLS connection through the
``proxy_ssl_context`` argument of the :class:`~poolmanager.ProxyManager`
class.
For HTTPS proxies we also support forwarding your requests to HTTPS destinations with
an `absolute URI <https://datatracker.ietf.org/doc/html/rfc9112#name-absolute-form>`_ if the
``use_forwarding_for_https`` argument is set to ``True``. We strongly recommend you
**only use this option with trusted or corporate proxies** as the proxy will have
full visibility of your requests.
.. _https_proxy_error_http_proxy:
Your proxy appears to only use HTTP and not HTTPS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're receiving the :class:`~urllib3.exceptions.ProxyError` and it mentions
your proxy only speaks HTTP and not HTTPS here's what to do to solve your issue:
If you're using ``urllib3`` directly, make sure the URL you're passing into :class:`urllib3.ProxyManager`
starts with ``http://`` instead of ``https://``:
.. code-block:: python
# Do this:
http = urllib3.ProxyManager("http://...")
# Not this:
http = urllib3.ProxyManager("https://...")
If instead you're using ``urllib3`` through another library like Requests
there are multiple ways your proxy could be mis-configured. You need to figure out
where the configuration isn't correct and make the fix there. Some common places
to look are environment variables like ``HTTP_PROXY``, ``HTTPS_PROXY``, and ``ALL_PROXY``.
Ensure that the values for all of these environment variables starts with ``http://``
and not ``https://``:
.. code-block:: bash
# Check your existing environment variables in bash
$ env | grep "_PROXY"
HTTP_PROXY=http://127.0.0.1:8888
HTTPS_PROXY=https://127.0.0.1:8888 # <--- This setting is the problem!
# Make the fix in your current session and test your script
$ export HTTPS_PROXY="http://127.0.0.1:8888"
$ python test-proxy.py # This should now pass.
# Persist your change in your shell 'profile' (~/.bashrc, ~/.profile, ~/.bash_profile, etc)
# You may need to logout and log back in to ensure this works across all programs.
$ vim ~/.bashrc
If you're on Windows or macOS your proxy may be getting set at a system level.
To check this first ensure that the above environment variables aren't set
then run the following:
.. code-block:: bash
$ python -c 'import urllib.request; print(urllib.request.getproxies())'
If the output of the above command isn't empty and looks like this:
.. code-block:: python
{
"http": "http://127.0.0.1:8888",
"https": "https://127.0.0.1:8888" # <--- This setting is the problem!
}
Search how to configure proxies on your operating system and change the ``https://...`` URL into ``http://``.
After you make the change the return value of ``urllib.request.getproxies()`` should be:
.. code-block:: python
{ # Everything is good here! :)
"http": "http://127.0.0.1:8888",
"https": "http://127.0.0.1:8888"
}
If you still can't figure out how to configure your proxy after all these steps
please `join our community Discord <https://discord.gg/urllib3>`_ and we'll try to help you with your issue.
SOCKS Proxies
~~~~~~~~~~~~~
For SOCKS, you can use :class:`~contrib.socks.SOCKSProxyManager` to connect to
SOCKS4 or SOCKS5 proxies. In order to use SOCKS proxies you will need to
install `PySocks <https://pypi.org/project/PySocks/>`_ or install urllib3 with
the ``socks`` extra:
.. code-block:: bash
python -m pip install urllib3[socks]
Once PySocks is installed, you can use
:class:`~contrib.socks.SOCKSProxyManager`:
.. code-block:: python
from urllib3.contrib.socks import SOCKSProxyManager
proxy = SOCKSProxyManager("socks5h://localhost:8889/")
proxy.request("GET", "https://google.com/")
.. note::
It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in
your ``proxy_url`` to ensure that DNS resolution is done from the remote
server instead of client-side when connecting to a domain name.
.. _ssl_custom:
.. _custom_ssl_certificates:
Custom TLS Certificates
-----------------------
Instead of using `certifi <https://certifi.io/>`_ you can provide your
own certificate authority bundle. This is useful for cases where you've
generated your own certificates or when you're using a private certificate
authority. Just provide the full path to the certificate bundle when creating a
:class:`~poolmanager.PoolManager`:
.. code-block:: python
import urllib3
http = urllib3.PoolManager(
cert_reqs="CERT_REQUIRED",
ca_certs="/path/to/your/certificate_bundle"
)
resp = http.request("GET", "https://example.com")
When you specify your own certificate bundle only requests that can be
verified with that bundle will succeed. It's recommended to use a separate
:class:`~poolmanager.PoolManager` to make requests to URLs that do not need
the custom certificate.
.. _sni_custom:
Custom SNI Hostname
-------------------
If you want to create a connection to a host over HTTPS which uses SNI, there
are two places where the hostname is expected. It must be included in the Host
header sent, so that the server will know which host is being requested. The
hostname should also match the certificate served by the server, which is
checked by urllib3.
Normally, urllib3 takes care of setting and checking these values for you when
you connect to a host by name. However, it's sometimes useful to set a
connection's expected Host header and certificate hostname (subject),
especially when you are connecting without using name resolution. For example,
you could connect to a server by IP using HTTPS like so:
.. code-block:: python
import urllib3
pool = urllib3.HTTPSConnectionPool(
"104.154.89.105",
server_hostname="badssl.com"
)
pool.request(
"GET",
"/",
headers={"Host": "badssl.com"},
assert_same_host=False
)
Note that when you use a connection in this way, you must specify
``assert_same_host=False``.
This is useful when DNS resolution for ``example.org`` does not match the
address that you would like to use. The IP may be for a private interface, or
you may want to use a specific host under round-robin DNS.
.. _assert_hostname:
Verifying TLS against a different host
--------------------------------------
If the server you're connecting to presents a different certificate than the
hostname or the SNI hostname, you can use ``assert_hostname``:
.. code-block:: python
import urllib3
pool = urllib3.HTTPSConnectionPool(
"wrong.host.badssl.com",
assert_hostname="badssl.com",
)
pool.request("GET", "/")
.. _ssl_client:
Client Certificates
-------------------
You can also specify a client certificate. This is useful when both the server
and the client need to verify each other's identity. Typically these
certificates are issued from the same authority. To use a client certificate,
provide the full path when creating a :class:`~poolmanager.PoolManager`:
.. code-block:: python
http = urllib3.PoolManager(
cert_file="/path/to/your/client_cert.pem",
cert_reqs="CERT_REQUIRED",
ca_certs="/path/to/your/certificate_bundle"
)
If you have an encrypted client certificate private key you can use
the ``key_password`` parameter to specify a password to decrypt the key.
.. code-block:: python
http = urllib3.PoolManager(
cert_file="/path/to/your/client_cert.pem",
cert_reqs="CERT_REQUIRED",
key_file="/path/to/your/client.key",
key_password="keyfile_password"
)
If your key isn't encrypted the ``key_password`` parameter isn't required.
TLS minimum and maximum versions
--------------------------------
When the configured TLS versions by urllib3 aren't compatible with the TLS versions that
the server is willing to use you'll likely see an error like this one:
.. code-block::
SSLError(1, '[SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:1124)')
Starting in v2.0 by default urllib3 uses TLS 1.2 and later so servers that only support TLS 1.1
or earlier will not work by default with urllib3.
To fix the issue you'll need to use the ``ssl_minimum_version`` option along with the `TLSVersion enum`_
in the standard library ``ssl`` module to configure urllib3 to accept a wider range of TLS versions.
For the best security it's a good idea to set this value to the version of TLS that's being used by the
server. For example if the server requires TLS 1.0 you'd configure urllib3 like so:
.. code-block:: python
import ssl
import urllib3
http = urllib3.PoolManager(
ssl_minimum_version=ssl.TLSVersion.TLSv1
)
# This request works!
resp = http.request("GET", "https://tls-v1-0.badssl.com:1010")
.. _TLSVersion enum: https://docs.python.org/3/library/ssl.html#ssl.TLSVersion
.. _ssl_mac:
.. _certificate_validation_and_mac_os_x:
Certificate Validation and macOS
--------------------------------
Apple-provided Python and OpenSSL libraries contain a patches that make them
automatically check the system keychain's certificates. This can be
surprising if you specify custom certificates and see requests unexpectedly
succeed. For example, if you are specifying your own certificate for validation
and the server presents a different certificate you would expect the connection
to fail. However, if that server presents a certificate that is in the system
keychain then the connection will succeed.
`This article <https://hynek.me/articles/apple-openssl-verification-surprises/>`_
has more in-depth analysis and explanation.
.. _ssl_warnings:
TLS Warnings
------------
urllib3 will issue several different warnings based on the level of certificate
verification support. These warnings indicate particular situations and can
be resolved in different ways.
* :class:`~exceptions.InsecureRequestWarning`
This happens when a request is made to an HTTPS URL without certificate
verification enabled. Follow the :ref:`certificate verification <ssl>`
guide to resolve this warning.
.. _disable_ssl_warnings:
Making unverified HTTPS requests is **strongly** discouraged, however, if you
understand the risks and wish to disable these warnings, you can use :func:`~urllib3.disable_warnings`:
.. code-block:: python
import urllib3
urllib3.disable_warnings()
Alternatively you can capture the warnings with the standard :mod:`logging` module:
.. code-block:: python
logging.captureWarnings(True)
Finally, you can suppress the warnings at the interpreter level by setting the
``PYTHONWARNINGS`` environment variable or by using the
`-W flag <https://docs.python.org/3/using/cmdline.html#cmdoption-w>`_.
Brotli Encoding
---------------
Brotli is a compression algorithm created by Google with better compression
than gzip and deflate and is supported by urllib3 if the
`Brotli <https://pypi.org/Brotli>`_ package or
`brotlicffi <https://github.com/python-hyper/brotlicffi>`_ package is installed.
You may also request the package be installed via the ``urllib3[brotli]`` extra:
.. code-block:: bash
$ python -m pip install urllib3[brotli]
Here's an example using brotli encoding via the ``Accept-Encoding`` header:
.. code-block:: python
import urllib3
urllib3.request(
"GET",
"https://www.google.com/",
headers={"Accept-Encoding": "br"}
)
Zstandard Encoding
------------------
`Zstandard <https://datatracker.ietf.org/doc/html/rfc8878>`_
is a compression algorithm created by Facebook with better compression
than brotli, gzip and deflate (see `benchmarks <https://facebook.github.io/zstd/#benchmarks>`_)
and is supported by urllib3 if the `zstandard package <https://pypi.org/project/zstandard/>`_ is installed.
You may also request the package be installed via the ``urllib3[zstd]`` extra:
.. code-block:: bash
$ python -m pip install urllib3[zstd]
.. note::
Zstandard support in urllib3 requires using v0.18.0 or later of the ``zstandard`` package.
If the version installed is less than v0.18.0 then Zstandard support won't be enabled.
Here's an example using zstd encoding via the ``Accept-Encoding`` header:
.. code-block:: python
import urllib3
urllib3.request(
"GET",
"https://www.facebook.com/",
headers={"Accept-Encoding": "zstd"}
)
Decrypting Captured TLS Sessions with Wireshark
-----------------------------------------------
Python 3.8 and higher support logging of TLS pre-master secrets.
With these secrets tools like `Wireshark <https://wireshark.org>`_ can decrypt captured
network traffic.
To enable this simply define environment variable `SSLKEYLOGFILE`:
.. code-block:: bash
export SSLKEYLOGFILE=/path/to/keylogfile.txt
Then configure the key logfile in `Wireshark <https://wireshark.org>`_, see
`Wireshark TLS Decryption <https://wiki.wireshark.org/TLS#TLS_Decryption>`_ for instructions.
Custom SSL Contexts
-------------------
You can exercise fine-grained control over the urllib3 SSL configuration by
providing a :class:`ssl.SSLContext <python:ssl.SSLContext>` object. For purposes
of compatibility, we recommend you obtain one from
:func:`~urllib3.util.create_urllib3_context`.
Once you have a context object, you can mutate it to achieve whatever effect
you'd like. For example, the code below loads the default SSL certificates, sets
the :data:`ssl.OP_ENABLE_MIDDLEBOX_COMPAT<python:ssl.OP_ENABLE_MIDDLEBOX_COMPAT>`
flag that isn't set by default, and then makes a HTTPS request:
.. code-block:: python
import ssl
from urllib3 import PoolManager
from urllib3.util import create_urllib3_context
ctx = create_urllib3_context()
ctx.load_default_certs()
ctx.options |= ssl.OP_ENABLE_MIDDLEBOX_COMPAT
with PoolManager(ssl_context=ctx) as pool:
pool.request("GET", "https://www.google.com/")
Note that this is different from passing an ``options`` argument to
:func:`~urllib3.util.create_urllib3_context` because we don't overwrite
the default options: we only add a new one.

View File

@@ -0,0 +1,5 @@
=========
Changelog
=========
.. include:: ../CHANGES.rst

View File

@@ -0,0 +1,126 @@
from __future__ import annotations
import os
import sys
from datetime import date
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, root_path)
# https://docs.readthedocs.io/en/stable/builds.html#build-environment
if "READTHEDOCS" in os.environ:
import glob
if glob.glob("../changelog/*.*.rst"):
print("-- Found changes; running towncrier --", flush=True)
import subprocess
subprocess.run(
["towncrier", "--yes", "--date", "not released yet"], cwd="..", check=True
)
import urllib3
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx_copybutton",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinxext.opengraph",
]
# Open Graph metadata
ogp_title = "urllib3 documentation"
ogp_type = "website"
ogp_social_cards = {"image": "images/logo.png", "line_color": "#F09837"}
ogp_description = "urllib3 is a user-friendly HTTP client library for Python."
# Test code blocks only when explicitly specified
doctest_test_doctest_blocks = ""
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = ".rst"
# The master toctree document.
master_doc = "index"
# General information about the project.
project = "urllib3"
copyright = f"{date.today().year}, Andrey Petrov"
# The short X.Y version.
version = urllib3.__version__
# The full version, including alpha/beta/rc tags.
release = version
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "friendly"
# The base URL with a proper language and version.
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "/")
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "furo"
html_favicon = "images/favicon.png"
html_static_path = ["_static"]
html_theme_options = {
"announcement": """
<a style=\"text-decoration: none; color: white;\"
href=\"https://opencollective.com/urllib3/updates/urllib3-is-fundraising-for-http-2-support\">
<img src=\"/en/latest/_static/favicon.png\"/> urllib3 is fundraising for HTTP/2 support!
</a>
""",
"sidebar_hide_name": True,
"light_logo": "banner.svg",
"dark_logo": "dark-logo.svg",
}
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
# Show typehints as content of the function or method
autodoc_typehints = "description"
# Warn about all references to unknown targets
nitpicky = True
# Except for these ones, which we expect to point to unknown targets:
nitpick_ignore = [
("py:class", "_TYPE_SOCKS_OPTIONS"),
("py:class", "_TYPE_SOCKET_OPTIONS"),
("py:class", "_TYPE_TIMEOUT"),
("py:class", "_TYPE_FIELD_VALUE"),
("py:class", "_TYPE_BODY"),
("py:class", "_HttplibHTTPResponse"),
("py:class", "_HttplibHTTPMessage"),
("py:class", "TracebackType"),
("py:class", "email.errors.MessageDefect"),
("py:class", "MessageDefect"),
("py:class", "http.client.HTTPMessage"),
("py:class", "RequestHistory"),
("py:class", "SSLTransportType"),
("py:class", "VerifyMode"),
("py:class", "_ssl._SSLContext"),
("py:class", "urllib3._collections.HTTPHeaderDict"),
("py:class", "urllib3._collections.RecentlyUsedContainer"),
("py:class", "urllib3._request_methods.RequestMethods"),
("py:class", "urllib3.contrib.socks._TYPE_SOCKS_OPTIONS"),
("py:class", "urllib3.util.timeout._TYPE_DEFAULT"),
("py:class", "BaseHTTPConnection"),
]

View File

@@ -0,0 +1,200 @@
Contributing
============
urllib3 is a community-maintained project and we happily accept contributions.
If you wish to add a new feature or fix a bug:
#. `Check for open issues <https://github.com/urllib3/urllib3/issues>`_ or open
a fresh issue to start a discussion around a feature idea or a bug. There is
a *Contributor Friendly* tag for issues that should be ideal for people who
are not very familiar with the codebase yet.
#. Fork the `urllib3 repository on Github <https://github.com/urllib3/urllib3>`_
to start making your changes.
#. Write a test which shows that the bug was fixed or that the feature works
as expected.
#. Format your changes with black using command ``nox -rs format`` and lint your
changes using command ``nox -rs lint``.
#. Add a `changelog entry
<https://github.com/urllib3/urllib3/blob/main/changelog/README.rst>`__.
#. Send a pull request and bug the maintainer until it gets merged and published.
Setting up your development environment
---------------------------------------
In order to setup the development environment all that you need is
`nox <https://nox.thea.codes/en/stable/index.html>`_ installed in your machine::
$ python -m pip install --user --upgrade nox
Running the tests
-----------------
We use some external dependencies, multiple interpreters and code coverage
analysis while running test suite. Our ``noxfile.py`` handles much of this for
you::
$ nox --reuse-existing-virtualenvs --sessions test-3.12 test-pypy3.10
[ Nox will create virtualenv if needed, install the specified dependencies, and run the commands in order.]
Note that for nox to test different interpreters, the interpreters must be on the
``PATH`` first. Check with ``which`` to see if the interpreter is on the ``PATH``
like so::
$ which python3.12
~/.pyenv/versions/3.12.1/bin/python3.12
$ which pypy3.10
~/.pyenv/versions/pypy3.10-7.3.13/bin/pypy3.10
There is also a nox command for running all of our tests and multiple python
versions.::
$ nox --reuse-existing-virtualenvs --sessions test
Note that code coverage less than 100% is regarded as a failing run. Some
platform-specific tests are skipped unless run in that platform. To make sure
the code works in all of urllib3's supported platforms, you can run our ``nox``
suite::
$ nox --reuse-existing-virtualenvs --sessions test
[ Nox will create virtualenv if needed, install the specified dependencies, and run the commands in order.]
.......
.......
nox > Session test-3.8 was successful.
nox > Session test-3.9 was successful.
nox > Session test-3.10 was successful.
nox > Session test-3.11 was successful.
nox > Session test-3.12 was successful.
nox > Session test-3.13 was successful.
nox > Session test-pypy was successful.
Our test suite `runs continuously on GitHub Actions
<https://github.com/urllib3/urllib3/actions>`_ with every pull request.
To run specific tests or quickly re-run without nox recreating the env, do the following::
$ nox --reuse-existing-virtualenvs --sessions test-3.8 -- pyTestArgument1 pyTestArgument2 pyTestArgumentN
[ Nox will create virtualenv, install the specified dependencies, and run the commands in order.]
nox > Running session test-3.8
nox > Re-using existing virtual environment at .nox/test-3-8.
.......
.......
nox > Session test-3.8 was successful.
After the ``--`` indicator, any arguments will be passed to pytest.
To specify an exact test case the following syntax also works:
``test/dir/module_name.py::TestClassName::test_method_name``
(eg.: ``test/with_dummyserver/test_https.py::TestHTTPS::test_simple``).
The following argument is another valid example to pass to pytest: ``-k test_methode_name``.
These are useful when developing new test cases and there is no point
re-running the entire test suite every iteration. It is also possible to
further parameterize pytest for local testing.
For all valid arguments, check `the pytest documentation
<https://docs.pytest.org/en/stable/usage.html#stopping-after-the-first-or-n-failures>`_.
Getting paid for your contributions
-----------------------------------
urllib3 has a `pool of money hosted on Open Collective <https://opencollective.com/urllib3#category-BUDGET>`_
which the team uses to pay contributors for their work. **That could be you, too!** If you complete all tasks in an issue
that is marked with the `"💰 Bounty $X00" label <https://github.com/urllib3/urllib3/issues?q=is%3Aopen+is%3Aissue+label%3A%22%F0%9F%92%B0+Bounty+%24100%22%2C%22%F0%9F%92%B0+Bounty+%24200%22%2C%22%F0%9F%92%B0+Bounty+%24300%22%2C%22%F0%9F%92%B0+Bounty+%24400%22%2C%22%F0%9F%92%B0+Bounty+%24500%22+no%3Aassignee>`_ then you're eligible to be paid for your work.
- Ensure that you're able to `receive funds from Open Collective for working on OSS <https://docs.opencollective.com/help/expenses-and-getting-paid/submitting-expenses>`_.
Consider your employment contract and taxes for possible restrictions.
- If an issue is already assigned to someone on GitHub then it's likely they've
made substantial progress on the issue and will be given the bounty.
If you're interested in bounties you should look for issues which
aren't assigned to anyone.
- **Don't "claim" issues or ask whether someone is already working on an issue.**
Instead, focus on researching and working on the tasks in the issue. Once you
have made considerable progress on the tasks in an issue we can assign your
account to the issue to ensure others don't start working on it in parallel.
- If you've been assigned to an issue and haven't made progress or given an update
in over a week you will be unassigned from the issue to allow others a chance
at solving the issue.
- The amount you will be paid for the completing an issue is shown in the label (either $100, $200, $300, etc).
- If you have questions about how to create an invoice on Open Collective
`try reading their FAQ <https://docs.opencollective.com/help/expenses-and-getting-paid/expenses>`_.
- If you have a proposal to work on urllib3 that's not listed in the issue tracker please open an issue
with your proposal and our team will discuss whether we'd pay for your work on your proposal.
- If you have other questions get in contact with a maintainer in the `urllib3 Discord channel <https://discord.gg/urllib3>`_ or via email.
- The list above isn't an exhaustive list of criteria or rules for how/when money is distributed.
**The final say on whether money will be distributed is up to maintainers.**
This program is an experiment so if you have positive or negative feedback on the process you can contact the maintainers through one of the above channels.
Note that this program isn't a "bug bounty" program, we don't distribute funds to reporters of bugs or security vulnerabilities at this time.
Running local proxies
---------------------
If the feature you are developing involves a proxy, you can rely on scripts we have developed to run a proxy locally.
Run an HTTP proxy locally:
.. code-block:: bash
$ python -m dummyserver.proxy
Run an HTTPS proxy locally:
.. code-block:: bash
$ python -m dummyserver.https_proxy
Contributing to documentation
-----------------------------
You can build the docs locally using ``nox``:
.. code-block:: bash
$ nox -rs docs
While writing documentation you should follow these guidelines:
- Use the top-level ``urllib3.request()`` function for smaller code examples. For more involved examples use PoolManager, etc.
- Use double quotes for all strings. (Output, Declaration etc.)
- Use keyword arguments everywhere except for method and url. (ie ``http.request("GET", "https://example.com", headers={...})`` )
- Use HTTPS in URLs everywhere unless HTTP is needed.
- Rules for code examples and naming variables:
- ``PoolManager`` instances should be named ``http``. (ie ``http = urllib3.PoolManager(...)``)
- ``ProxyManager`` instances should be named ``proxy``.
- ``ConnectionPool`` instances should be named ``pool``.
- ``Connection`` instances should be named ``conn``.
- ``HTTPResponse`` instances should be named ``resp``.
- Only use ``example.com`` or ``httpbin.org`` for example URLs
- Comments within snippets should be useful, if what's being done is apparent
(such as parsing JSON, making a request) then it can be skipped for that section.
- Comments should always go above a code section rather than below with the exception of print
statements where the comment containing the result goes below.
- Imports should be their own section separated from the rest of the example with a line of whitespace.
- Imports should minimized if possible. Use import urllib3 instead of from urllib3 import X.
- Sort imports similarly to isort, standard library first and third-party (like urllib3) come after.
- No whitespace is required between the sections as normally would be in case of isort.
- Add print statements along with a comment below them showing the output, potentially compressed.
- This helps users using the copy-paste button immediately see the results from a script.
Releases
--------
A release candidate can be created by any contributor.
- Announce intent to release on Discord, see if anyone wants to include last minute
changes.
- Run ``towncrier build`` to update ``CHANGES.rst`` with the release notes, adjust as
necessary.
- Update ``urllib3/__init__.py`` with the proper version number
- Commit the changes to a ``release-X.Y.Z`` branch.
- Create a pull request and append ``&expand=1&template=release.md`` to the URL before
submitting in order to include our release checklist in the pull request description.
- Follow the checklist!

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<rect x="0" y="0" width="2" height="5" fill="#D03A20"></rect>
<rect x="0" y="6" width="2" height="2" fill="#D03A20"></rect>
<rect x="3" y="0" width="2" height="5" fill="#F09837"></rect>
<rect x="3" y="6" width="2" height="2" fill="#F09837"></rect>
<rect x="6" y="0" width="2" height="2" fill="#587934"></rect>
<rect x="6" y="3" width="2" height="5" fill="#587934"></rect>
</svg>

After

Width:  |  Height:  |  Size: 516 B

View File

@@ -0,0 +1,118 @@
urllib3
=======
.. toctree::
:hidden:
:maxdepth: 3
For Enterprise <https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs>
Community Discord <https://discord.gg/urllib3>
v2-migration-guide
sponsors
user-guide
advanced-usage
reference/index
contributing
changelog
urllib3 is a powerful, *user-friendly* HTTP client for Python.
:ref:`Much of the Python ecosystem already uses <who-uses>` urllib3 and you should too.
urllib3 brings many critical features that are missing from the Python
standard libraries:
- Thread safety.
- Connection pooling.
- Client-side TLS/SSL verification.
- File uploads with multipart encoding.
- Helpers for retrying requests and dealing with HTTP redirects.
- Support for gzip, deflate, brotli, and zstd encoding.
- Proxy support for HTTP and SOCKS.
- 100% test coverage.
urllib3 is powerful and easy to use:
.. code-block:: pycon
>>> import urllib3
>>> resp = urllib3.request("GET", "https://httpbin.org/robots.txt")
>>> resp.status
200
>>> resp.data
b"User-agent: *\nDisallow: /deny\n"
For Enterprise
--------------
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
:width: 75
:alt: Tidelift
.. list-table::
:widths: 10 100
* - |tideliftlogo|_
- Professional support for urllib3 is available as part of the `Tidelift
Subscription`_. Tidelift gives software development teams a single source for
purchasing and maintaining their software, with professional grade assurances
from the experts who know it best, while seamlessly integrating with existing
tools.
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs
.. _tideliftlogo: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs
|learn-more|_ |request-a-demo|_
.. |learn-more| image:: https://raw.githubusercontent.com/urllib3/urllib3/master/docs/images/learn-more-button.png
:width: 49%
:alt: Learn more about Tidelift Subscription
.. _learn-more: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs
.. |request-a-demo| image:: https://raw.githubusercontent.com/urllib3/urllib3/master/docs/images/demo-button.png
:width: 49%
:alt: Request a Demo for the Tidelift Subscription
.. _request-a-demo: https://tidelift.com/subscription/request-a-demo?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs
Installing
----------
urllib3 can be installed with `pip <https://pip.pypa.io>`_
.. code-block:: bash
$ python -m pip install urllib3
Alternatively, you can grab the latest source code from `GitHub <https://github.com/urllib3/urllib3>`_:
.. code-block:: bash
$ git clone https://github.com/urllib3/urllib3.git
$ cd urllib3
$ pip install .
Usage
-----
The :doc:`user-guide` is the place to go to learn how to use the library and
accomplish common tasks. The more in-depth :doc:`advanced-usage` guide is the place to go for lower-level tweaking.
The :doc:`reference/index` documentation provides API-level documentation.
.. _who-uses:
Who uses urllib3?
-----------------
`urllib3 is one of the most downloaded packages on PyPI <https://pypistats.org/top>`_
and is a dependency of many popular Python packages like `Requests <https://requests.readthedocs.io>`_,
`Pip <https://pip.pypa.io>`_, and more!
License
-------
urllib3 is made available under the MIT License. For more details, see `LICENSE.txt <https://github.com/urllib3/urllib3/blob/master/LICENSE.txt>`_.
Contributing
------------
We happily welcome contributions, please see :doc:`contributing` for details.

View File

@@ -0,0 +1,170 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\urllib3.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\urllib3.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -0,0 +1,87 @@
Pyodide, Emscripten, and PyScript
=================================
From the Pyodide documentation, `Pyodide <https://pyodide.org>`_ is a Python distribution for the browser and Node.js based on WebAssembly and `Emscripten <https://emscripten.org/>`_.
This technology also underpins the `PyScript framework <https://pyscript.net/>`_ and `Jupyterlite <https://jupyterlite.readthedocs.io/>`_, so should work in those environments too.
Starting in version 2.2.0 urllib3 supports being used in a Pyodide runtime utilizing
the `JavaScript fetch API <https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API>`_
or falling back on `XMLHttpRequest <https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest>`_
if the fetch API isn't available (such as when cross-origin isolation
isn't active). This means you can use Python libraries to make HTTP requests from your browser!
Because urllib3's Emscripten support is API-compatible, this means that
libraries that depend on urllib3 may now be usable from Emscripten and Pyodide environments, too.
.. warning::
**Support for Emscripten and Pyodide is experimental**. Report all bugs to the `urllib3 issue tracker <https://github.com/urllib3/urllib3/issues>`_.
Currently only supports browsers, does not yet support running in Node.js.
It's recommended to `run Pyodide in a Web Worker <https://pyodide.org/en/stable/usage/webworker.html#using-from-webworker>`_
in order to take full advantage of features like the fetch API which enables streaming of HTTP response bodies.
Getting started
---------------
Using urllib3 with Pyodide means you need to `get started with Pyodide first <https://pyodide.org/en/stable/usage/quickstart.html>`_.
The Pyodide project provides a `useful online REPL <https://pyodide.org/en/stable/console.html>`_ to try in your browser without
any setup or installation to test out the code examples below.
urllib3's Emscripten support is automatically enabled if ``sys.platform`` is ``"emscripten"``, so no setup is required beyond installation and importing the module.
You can install urllib3 in a Pyodide environment using micropip.
Try using the following code in a Pyodide console or ``<script>`` tag:
.. code-block:: python
import micropip
await micropip.install("urllib3")
import urllib3
resp = urllib3.request("GET", "https://httpbin.org/anything")
print(resp.status) # 200
print(resp.headers) # HTTPHeaderDict(...)
print(resp.json()) # {"headers": {"Accept": "*/*", ...}, ...}
Because `Requests <https://requests.readthedocs.io/en/latest/>`_ is built on urllib3, Requests also works out of the box:
.. code-block:: python
import micropip
await micropip.install("requests")
import requests
resp = requests.request("GET", "https://httpbin.org/anything")
print(resp.status_code) # 200
print(resp.headers)
Features
--------
Because we use JavaScript APIs under the hood, it's not possible to use all of urllib3 features.
Features which are usable with Emscripten support are:
* Requests over HTTP and HTTPS
* Timeouts
* Retries
* Streaming (with Web Workers and Cross-Origin Isolation)
* Redirects
* Decompressing response bodies
Features which don't work with Emscripten:
* Proxies, both forwarding and tunneling
* Customizing TLS and certificates (uses browsers' configuration)
* Configuring low-level socket options or source address
Streaming with Web Workers
--------------------------
To access the fetch API and do HTTP response streaming with urllib3
you must be running the code within a Web Worker and set specific HTTP headers
for the serving website to enable `Cross-Origin Isolation <https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated>`_.
You can verify whether a given environment is cross-origin isolated by evaluating the global ``crossOriginIsolated`` JavaScript property.

View File

@@ -0,0 +1,11 @@
Third-Party Modules
===================
These modules implement various extra features, that may not be ready for
prime time or that require optional third-party dependencies.
.. toctree::
emscripten
pyopenssl
socks

View File

@@ -0,0 +1,7 @@
PyOpenSSL
=========
.. automodule:: urllib3.contrib.pyopenssl
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,7 @@
SOCKS Proxies
=============
.. automodule:: urllib3.contrib.socks
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,14 @@
API Reference
=============
.. toctree::
urllib3.request
urllib3.poolmanager
urllib3.connectionpool
urllib3.connection
urllib3.exceptions
urllib3.response
urllib3.fields
urllib3.util
contrib/index

View File

@@ -0,0 +1,17 @@
Connections
===========
.. automodule:: urllib3.connection
.. autoclass:: urllib3.connection.HTTPConnection
:members:
:exclude-members: putrequest
:show-inheritance:
.. autoclass:: urllib3.connection.HTTPSConnection
:members:
:show-inheritance:
.. autoclass:: urllib3.connection.ProxyConfig
:members:
:show-inheritance:

View File

@@ -0,0 +1,21 @@
Connection Pools
================
.. automodule:: urllib3.connectionpool
.. autoclass:: urllib3.HTTPConnectionPool
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: urllib3.HTTPSConnectionPool
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: urllib3.connectionpool.ConnectionPool
:members:
:undoc-members:
:show-inheritance:
.. autofunction:: urllib3.connectionpool.connection_from_url

View File

@@ -0,0 +1,9 @@
Exceptions and Warnings
=======================
.. automodule:: urllib3.exceptions
:members:
:undoc-members:
:show-inheritance:
.. autofunction:: urllib3.disable_warnings

View File

@@ -0,0 +1,18 @@
Fields and Multipart Forms
==========================
Fields
------
.. automodule:: urllib3.fields
:members:
:undoc-members:
:show-inheritance:
Multipart Forms
---------------
.. autofunction:: urllib3.encode_multipart_formdata
.. autofunction:: urllib3.filepost.choose_boundary
.. autofunction:: urllib3.filepost.iter_field_objects

View File

@@ -0,0 +1,18 @@
Pool Manager
============
.. autoclass:: urllib3.PoolManager
:members:
:undoc-members:
:show-inheritance:
:inherited-members:
.. autoclass:: urllib3.ProxyManager
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: urllib3.poolmanager.PoolKey
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,4 @@
urllib3.request()
=================
.. autofunction:: urllib3.request

View File

@@ -0,0 +1,33 @@
Response and Decoders
=====================
Response
--------
.. autoclass:: urllib3.response.BaseHTTPResponse
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: urllib3.response.HTTPResponse
:members:
:undoc-members:
:show-inheritance:
:inherited-members: json
.. autoattribute:: auto_close
.. autoattribute:: status
.. autoattribute:: headers
Decoders
--------
Decoder classes are used for transforming compressed HTTP bodies
using the ``Content-Encoding`` into their uncompressed binary
representation.
.. autoclass:: urllib3.response.BrotliDecoder
.. autoclass:: urllib3.response.DeflateDecoder
.. autoclass:: urllib3.response.GzipDecoder
.. autoclass:: urllib3.response.ZstdDecoder
.. autoclass:: urllib3.response.MultiDecoder

View File

@@ -0,0 +1,17 @@
Utilities
=========
Useful methods for working with :mod:`http.client`, completely decoupled from
code specific to **urllib3**.
At the very core, just like its predecessors, urllib3 is built on top of
:mod:`http.client` -- the lowest level HTTP library included in the Python
standard library.
To aid the limited functionality of the :mod:`http.client` module, urllib3
provides various helper methods which are used with the higher level components
but can also be used independently.
.. automodule:: urllib3.util
:members:
:show-inheritance:

View File

@@ -0,0 +1,6 @@
-r ../dev-requirements.txt
sphinx>=7.2.6
requests
furo
sphinx-copybutton
sphinxext-opengraph

View File

@@ -0,0 +1,41 @@
Sponsors and Supporters
=======================
Please consider sponsoring urllib3 development, especially if your company
benefits from this library.
Your contribution will go towards adding new features to urllib3 and making
sure all functionality continues to meet our high quality standards.
Sponsors and Grants
-------------------
A grant for contiguous full-time development has the biggest impact for
progress. Periods of 3 to 10 days allow a contributor to tackle substantial
complex issues which are otherwise left to linger until somebody can't afford
to not fix them.
Contact `@sethmlarson <https://github.com/sethmlarson>`_ or `@shazow <https://github.com/shazow>`_
to arrange a grant for a core contributor.
We also welcome sponsorship in the form of time. We greatly appreciate companies
who encourage employees to contribute on an ongoing basis during their work hours.
Let us know and we'll be glad to add you to our sponsors list.
* `Spotify <https://engineering.atspotify.com/opensource/>`_ (June 2nd, 2022)
* `GitCoin Grants <https://gitcoin.co/grants>`_ (2019-2020), sponsored `@sethmlarson <https://github.com/sethmlarson>`_
and `@pquentin <https://github.com/pquentin>`_
* `Abbott <https://abbott.com>`_ (2018-2019), sponsored `@sethmlarson <https://github.com/sethmlarson>`_
* `Google Cloud Platform <https://cloud.google.com>`_ (2018-2019), sponsored `@theacodes <https://github.com/theacodes>`_
* `GOVCERT.LU <https://govcert.lu>`_ (October 23, 2018), sponsored `@sethmlarson <https://github.com/sethmlarson>`_
* `Akamai <https://akamai.com>`_ (2017-2018) sponsored `@haikuginger <https://github.com/haikuginger>`_
* `Hewlett Packard Enterprise <https://hpe.com>`_ (2016-2017) sponsored
`@Lukasa <https://github.com/Lukasa>`_
* `Stripe <https://stripe.com>`_ (June 23, 2014)

View File

@@ -0,0 +1,659 @@
User Guide
==========
.. currentmodule:: urllib3
Installing
----------
urllib3 can be installed with `pip <https://pip.pypa.io>`_
.. code-block:: bash
$ python -m pip install urllib3
Making Requests
---------------
First things first, import the urllib3 module:
.. code-block:: python
import urllib3
You'll need a :class:`~poolmanager.PoolManager` instance to make requests.
This object handles all of the details of connection pooling and thread safety
so that you don't have to:
.. code-block:: python
http = urllib3.PoolManager()
To make a request use :meth:`~urllib3.PoolManager.request`:
.. code-block:: python
import urllib3
# Creating a PoolManager instance for sending requests.
http = urllib3.PoolManager()
# Sending a GET request and getting back response as HTTPResponse object.
resp = http.request("GET", "https://httpbin.org/robots.txt")
# Print the returned data.
print(resp.data)
# b"User-agent: *\nDisallow: /deny\n"
``request()`` returns a :class:`~response.HTTPResponse` object, the
:ref:`response_content` section explains how to handle various responses.
You can use :meth:`~urllib3.PoolManager.request` to make requests using any
HTTP verb:
.. code-block:: python
import urllib3
http = urllib3.PoolManager()
resp = http.request(
"POST",
"https://httpbin.org/post",
fields={"hello": "world"} # Add custom form fields
)
print(resp.data)
# b"{\n "form": {\n "hello": "world"\n }, ... }
The :ref:`request_data` section covers sending other kinds of requests data,
including JSON, files, and binary data.
.. note:: For quick scripts and experiments you can also use a top-level ``urllib3.request()``.
It uses a module-global ``PoolManager`` instance.
Because of that, its side effects could be shared across dependencies relying on it.
To avoid side effects, create a new ``PoolManager`` instance and use it instead.
In addition, the method does not accept the low-level ``**urlopen_kw`` keyword arguments.
System CA certificates are loaded on default.
.. _response_content:
Response Content
----------------
The :class:`~response.HTTPResponse` object provides
:attr:`~response.HTTPResponse.status`, :attr:`~response.HTTPResponse.data`, and
:attr:`~response.HTTPResponse.headers` attributes:
.. code-block:: python
import urllib3
# Making the request (The request function returns HTTPResponse object)
resp = urllib3.request("GET", "https://httpbin.org/ip")
print(resp.status)
# 200
print(resp.data)
# b"{\n "origin": "104.232.115.37"\n}\n"
print(resp.headers)
# HTTPHeaderDict({"Content-Length": "32", ...})
.. _json_content:
JSON Content
~~~~~~~~~~~~
JSON content can be loaded by :meth:`~response.HTTPResponse.json`
method of the response:
.. code-block:: python
import urllib3
resp = urllib3.request("GET", "https://httpbin.org/ip")
print(resp.json())
# {"origin": "127.0.0.1"}
Alternatively, Custom JSON libraries such as `orjson` can be used to encode data,
retrieve data by decoding and deserializing the :attr:`~response.HTTPResponse.data`
attribute of the request:
.. code-block:: python
import orjson
import urllib3
encoded_data = orjson.dumps({"attribute": "value"})
resp = urllib3.request(method="POST", url="http://httpbin.org/post", body=encoded_data)
print(orjson.loads(resp.data)["json"])
# {'attribute': 'value'}
Binary Content
~~~~~~~~~~~~~~
The :attr:`~response.HTTPResponse.data` attribute of the response is always set
to a byte string representing the response content:
.. code-block:: python
import urllib3
resp = urllib3.request("GET", "https://httpbin.org/bytes/8")
print(resp.data)
# b"\xaa\xa5H?\x95\xe9\x9b\x11"
.. note:: For larger responses, it's sometimes better to :ref:`stream <stream>`
the response.
Using io Wrappers with Response Content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes you want to use :class:`io.TextIOWrapper` or similar objects like a CSV reader
directly with :class:`~response.HTTPResponse` data. Making these two interfaces play nice
together requires using the :attr:`~response.HTTPResponse.auto_close` attribute by setting it
to ``False``. By default HTTP responses are closed after reading all bytes, this disables that behavior:
.. code-block:: python
import io
import urllib3
resp = urllib3.request("GET", "https://example.com", preload_content=False)
resp.auto_close = False
for line in io.TextIOWrapper(resp):
print(line)
# <!doctype html>
# <html>
# <head>
# ....
# </body>
# </html>
.. _request_data:
Request Data
------------
Headers
~~~~~~~
You can specify headers as a dictionary in the ``headers`` argument in :meth:`~urllib3.PoolManager.request`:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/headers",
headers={
"X-Something": "value"
}
)
print(resp.json()["headers"])
# {"X-Something": "value", ...}
Or you can use the ``HTTPHeaderDict`` class to create multi-valued HTTP headers:
.. code-block:: python
import urllib3
# Create an HTTPHeaderDict and add headers
headers = urllib3.HTTPHeaderDict()
headers.add("Accept", "application/json")
headers.add("Accept", "text/plain")
# Make the request using the headers
resp = urllib3.request(
"GET",
"https://httpbin.org/headers",
headers=headers
)
print(resp.json()["headers"])
# {"Accept": "application/json, text/plain", ...}
Cookies
~~~~~~~
Cookies are specified using the ``Cookie`` header with a string containing
the ``;`` delimited key-value pairs:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/cookies",
headers={
"Cookie": "session=f3efe9db; id=30"
}
)
print(resp.json())
# {"cookies": {"id": "30", "session": "f3efe9db"}}
Note that the ``Cookie`` header will be stripped if the server redirects to a
different host.
Cookies provided by the server are stored in the ``Set-Cookie`` header:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/cookies/set/session/f3efe9db",
redirect=False
)
print(resp.headers["Set-Cookie"])
# session=f3efe9db; Path=/
Query Parameters
~~~~~~~~~~~~~~~~
For ``GET``, ``HEAD``, and ``DELETE`` requests, you can simply pass the
arguments as a dictionary in the ``fields`` argument to
:meth:`~urllib3.PoolManager.request`:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/get",
fields={"arg": "value"}
)
print(resp.json()["args"])
# {"arg": "value"}
For ``POST`` and ``PUT`` requests, you need to manually encode query parameters
in the URL:
.. code-block:: python
from urllib.parse import urlencode
import urllib3
# Encode the args into url grammar.
encoded_args = urlencode({"arg": "value"})
# Create a URL with args encoded.
url = "https://httpbin.org/post?" + encoded_args
resp = urllib3.request("POST", url)
print(resp.json()["args"])
# {"arg": "value"}
.. _form_data:
Form Data
~~~~~~~~~
For ``PUT`` and ``POST`` requests, urllib3 will automatically form-encode the
dictionary in the ``fields`` argument provided to
:meth:`~urllib3.PoolManager.request`:
.. code-block:: python
import urllib3
resp = urllib3.request(
"POST",
"https://httpbin.org/post",
fields={"field": "value"}
)
print(resp.json()["form"])
# {"field": "value"}
.. _json:
JSON
~~~~
To send JSON in the body of a request, provide the data in the ``json`` argument to
:meth:`~urllib3.PoolManager.request` and urllib3 will automatically encode the data
using the ``json`` module with ``UTF-8`` encoding.
In addition, when ``json`` is provided, the ``"Content-Type"`` in headers is set to
``"application/json"`` if not specified otherwise.
.. code-block:: python
import urllib3
resp = urllib3.request(
"POST",
"https://httpbin.org/post",
json={"attribute": "value"},
headers={"Content-Type": "application/json"}
)
print(resp.json())
# {'headers': {'Content-Type': 'application/json', ...},
# 'data': '{"attribute":"value"}', 'json': {'attribute': 'value'}, ...}
Files & Binary Data
~~~~~~~~~~~~~~~~~~~
For uploading files using ``multipart/form-data`` encoding you can use the same
approach as :ref:`form_data` and specify the file field as a tuple of
``(file_name, file_data)``:
.. code-block:: python
import urllib3
# Reading the text file from local storage.
with open("example.txt") as fp:
file_data = fp.read()
# Sending the request.
resp = urllib3.request(
"POST",
"https://httpbin.org/post",
fields={
"filefield": ("example.txt", file_data),
}
)
print(resp.json()["files"])
# {"filefield": "..."}
While specifying the filename is not strictly required, it's recommended in
order to match browser behavior. You can also pass a third item in the tuple
to specify the file's MIME type explicitly:
.. code-block:: python
resp = urllib3.request(
"POST",
"https://httpbin.org/post",
fields={
"filefield": ("example.txt", file_data, "text/plain"),
}
)
For sending raw binary data simply specify the ``body`` argument. It's also
recommended to set the ``Content-Type`` header:
.. code-block:: python
import urllib3
with open("/home/samad/example.jpg", "rb") as fp:
binary_data = fp.read()
resp = urllib3.request(
"POST",
"https://httpbin.org/post",
body=binary_data,
headers={"Content-Type": "image/jpeg"}
)
print(resp.json()["data"])
# data:application/octet-stream;base64,...
.. _ssl:
Certificate Verification
------------------------
.. note:: *New in version 1.25:*
HTTPS connections are now verified by default (``cert_reqs = "CERT_REQUIRED"``).
While you can disable certification verification by setting ``cert_reqs = "CERT_NONE"``, it is highly recommend to leave it on.
Unless otherwise specified urllib3 will try to load the default system certificate stores.
The most reliable cross-platform method is to use the `certifi <https://certifi.io/>`_
package which provides Mozilla's root certificate bundle:
.. code-block:: bash
$ python -m pip install certifi
Once you have certificates, you can create a :class:`~poolmanager.PoolManager`
that verifies certificates when making requests:
.. code-block:: python
import certifi
import urllib3
http = urllib3.PoolManager(
cert_reqs="CERT_REQUIRED",
ca_certs=certifi.where()
)
The :class:`~poolmanager.PoolManager` will automatically handle certificate
verification and will raise :class:`~exceptions.SSLError` if verification fails:
.. code-block:: python
import certifi
import urllib3
http = urllib3.PoolManager(
cert_reqs="CERT_REQUIRED",
ca_certs=certifi.where()
)
http.request("GET", "https://httpbin.org/")
# (No exception)
http.request("GET", "https://expired.badssl.com")
# urllib3.exceptions.SSLError ...
.. note:: You can use OS-provided certificates if desired. Just specify the full
path to the certificate bundle as the ``ca_certs`` argument instead of
``certifi.where()``. For example, most Linux systems store the certificates
at ``/etc/ssl/certs/ca-certificates.crt``. Other operating systems can
be `difficult <https://stackoverflow.com/questions/10095676/openssl-reasonable-default-for-trusted-ca-certificates>`_.
Using Timeouts
--------------
Timeouts allow you to control how long (in seconds) requests are allowed to run
before being aborted. In simple cases, you can specify a timeout as a ``float``
to :meth:`~urllib3.PoolManager.request`:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/delay/3",
timeout=4.0
)
print(type(resp))
# <class "urllib3.response.HTTPResponse">
# This request will take more time to process than timeout.
urllib3.request(
"GET",
"https://httpbin.org/delay/3",
timeout=2.5
)
# MaxRetryError caused by ReadTimeoutError
For more granular control you can use a :class:`~util.timeout.Timeout`
instance which lets you specify separate connect and read timeouts:
.. code-block:: python
import urllib3
resp = urllib3.request(
"GET",
"https://httpbin.org/delay/3",
timeout=urllib3.Timeout(connect=1.0)
)
print(type(resp))
# <urllib3.response.HTTPResponse>
urllib3.request(
"GET",
"https://httpbin.org/delay/3",
timeout=urllib3.Timeout(connect=1.0, read=2.0)
)
# MaxRetryError caused by ReadTimeoutError
If you want all requests to be subject to the same timeout, you can specify
the timeout at the :class:`~urllib3.poolmanager.PoolManager` level:
.. code-block:: python
import urllib3
http = urllib3.PoolManager(timeout=3.0)
http = urllib3.PoolManager(
timeout=urllib3.Timeout(connect=1.0, read=2.0)
)
You still override this pool-level timeout by specifying ``timeout`` to
:meth:`~urllib3.PoolManager.request`.
Retrying Requests
-----------------
urllib3 can automatically retry idempotent requests. This same mechanism also
handles redirects. You can control the retries using the ``retries`` parameter
to :meth:`~urllib3.PoolManager.request`. By default, urllib3 will retry
requests 3 times and follow up to 3 redirects.
To change the number of retries just specify an integer:
.. code-block:: python
import urllib3
urllib3.request("GET", "https://httpbin.org/ip", retries=10)
To disable all retry and redirect logic specify ``retries=False``:
.. code-block:: python
import urllib3
urllib3.request(
"GET",
"https://nxdomain.example.com",
retries=False
)
# NewConnectionError
resp = urllib3.request(
"GET",
"https://httpbin.org/redirect/1",
retries=False
)
print(resp.status)
# 302
To disable redirects but keep the retrying logic, specify ``redirect=False``:
.. code-block:: python
resp = urllib3.request(
"GET",
"https://httpbin.org/redirect/1",
redirect=False
)
print(resp.status)
# 302
For more granular control you can use a :class:`~util.retry.Retry` instance.
This class allows you far greater control of how requests are retried.
For example, to do a total of 3 retries, but limit to only 2 redirects:
.. code-block:: python
urllib3.request(
"GET",
"https://httpbin.org/redirect/3",
retries=urllib3.Retry(3, redirect=2)
)
# MaxRetryError
You can also disable exceptions for too many redirects and just return the
``302`` response:
.. code-block:: python
resp = urllib3.request(
"GET",
"https://httpbin.org/redirect/3",
retries=urllib3.Retry(
redirect=2,
raise_on_redirect=False
)
)
print(resp.status)
# 302
If you want all requests to be subject to the same retry policy, you can
specify the retry at the :class:`~urllib3.poolmanager.PoolManager` level:
.. code-block:: python
import urllib3
http = urllib3.PoolManager(retries=False)
http = urllib3.PoolManager(
retries=urllib3.Retry(5, redirect=2)
)
You still override this pool-level retry policy by specifying ``retries`` to
:meth:`~urllib3.PoolManager.request`.
Errors & Exceptions
-------------------
urllib3 wraps lower-level exceptions, for example:
.. code-block:: python
import urllib3
try:
urllib3.request("GET","https://nx.example.com", retries=False)
except urllib3.exceptions.NewConnectionError:
print("Connection failed.")
# Connection failed.
See :mod:`~urllib3.exceptions` for the full list of all exceptions.
Logging
-------
If you are using the standard library :mod:`logging` module urllib3 will
emit several logs. In some cases this can be undesirable. You can use the
standard logger interface to change the log level for urllib3's logger:
.. code-block:: python
logging.getLogger("urllib3").setLevel(logging.WARNING)

View File

@@ -0,0 +1,399 @@
v2.0 Migration Guide
====================
**urllib3 v2.0 is now available!** Read below for how to get started and what is contained in the new major release.
**🚀 Migrating from 1.x to 2.0**
--------------------------------
We're maintaining **functional API compatibility for most users** to make the
migration an easy choice for almost everyone. Most changes are either to default
configurations, supported Python versions, or internal implementation details.
So unless you're in a specific situation you should notice no changes! 🎉
.. note::
If you have difficulty migrating to v2.0 or following this guide
you can `open an issue on GitHub <https://github.com/urllib3/urllib3/issues>`_
or reach out in `our community Discord channel <https://discord.gg/urllib3>`_.
Timeline for deprecations and breaking changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 2.x initial release schedule will look like this:
* urllib3 ``v2.0.0-alpha1`` will be released in November 2022. This release
contains **minor breaking changes and deprecation warnings for other breaking changes**.
There may be other pre-releases to address fixes before v2.0.0 is released.
* urllib3 ``v2.0.0`` will be released in early 2023 after some initial integration testing
against dependent packages and fixing of bug reports.
* urllib3 ``v2.1.0`` will be released in the summer of 2023 with **all breaking changes
being warned about in v2.0.0**.
.. warning::
Please take the ``DeprecationWarnings`` you receive when migrating from v1.x to v2.0 seriously
as they will become errors after 2.1.0 is released.
What are the important changes?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here's a short summary of which changes in urllib3 v2.0 are most important:
- Python version must be **3.7 or later** (previously supported Python 2.7, 3.5, and 3.6).
- Removed support for non-OpenSSL TLS libraries (like LibreSSL and wolfSSL).
- Removed support for OpenSSL versions older than 1.1.1.
- Removed support for Python implementations that aren't CPython or PyPy3 (previously supported Google App Engine, Jython).
- Removed the ``urllib3.contrib.ntlmpool`` module.
- Deprecated the ``urllib3.contrib.pyopenssl``, ``urllib3.contrib.securetransport`` modules, will be removed in v2.1.0.
- Deprecated the ``urllib3[secure]`` extra, will be removed in v2.1.0.
- Deprecated the ``HTTPResponse.getheaders()`` method in favor of ``HTTPResponse.headers``, will be removed in v2.1.0.
- Deprecated the ``HTTPResponse.getheader(name, default)`` method in favor of ``HTTPResponse.headers.get(name, default)``, will be removed in v2.1.0.
- Deprecated URLs without a scheme (ie 'https://') and will be raising an error in a future version of urllib3.
- Changed the default minimum TLS version to TLS 1.2 (previously was TLS 1.0).
- Removed support for verifying certificate hostnames via ``commonName``, now only ``subjectAltName`` is used.
- Removed the default set of TLS ciphers, instead now urllib3 uses the list of ciphers configured by the system.
For a full list of changes you can look at `the changelog <https://github.com/urllib3/urllib3/blob/main/CHANGES.rst>`_.
Migrating as a package maintainer?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're a maintainer of a package that uses urllib3 under the hood then this section is for you.
You may have already seen an issue opened from someone on our team about the upcoming release.
The primary goal for migrating to urllib3 v2.x should be to ensure your package supports **both urllib3 v1.26.x and v2.0 for some time**.
This is to reduce the chance that diamond dependencies are introduced into your users' dependencies which will then cause issues
with them upgrading to the latest version of **your package**.
The first step to supporting urllib3 v2.0 is to make sure the version v2.x not being excluded by ``install_requires``. You should
ensure your package allows for both urllib3 1.26.x and 2.0 to be used:
.. code-block:: python
# setup.py (setuptools)
setup(
...
install_requires=["urllib3>=1.26,<3"]
)
# pyproject.toml (hatch)
[project]
dependencies = [
"urllib3>=1.26,<3"
]
Next you should try installing urllib3 v2.0 locally and run your test suite.
.. code-block:: bash
$ python -m pip install -U --pre 'urllib3>=2.0.0a1'
Because there are many ``DeprecationWarnings`` you should ensure that you're
able to see those warnings when running your test suite. To do so you can add
the following to your test setup to ensure even ``DeprecationWarnings`` are
output to the terminal:
.. code-block:: bash
# Set PYTHONWARNING=default to show all warnings.
$ export PYTHONWARNINGS="default"
# Run your test suite and look for failures.
# Pytest automatically prints all warnings.
$ pytest tests/
or you can opt-in within your Python code:
.. code-block:: python
# You can change warning filters according to the filter rules:
# https://docs.python.org/3/library/warnings.html#warning-filter
import warnings
warnings.filterwarnings("default", category=DeprecationWarning)
Any failures or deprecation warnings you receive should be fixed as urllib3 v2.1.0 will remove all
deprecated features. Many deprecation warnings will make suggestions about what to do to avoid the deprecated feature.
Warnings will look something like this:
.. code-block:: bash
DeprecationWarning: 'ssl_version' option is deprecated and will be removed
in urllib3 v2.1.0. Instead use 'ssl_minimum_version'
Continue removing deprecation warnings until there are no more. After this you can publish a new release of your package
that supports both urllib3 v1.26.x and v2.x.
.. note::
If you're not able to support both 1.26.x and v2.0 of urllib3 at the same time with your package please
`open an issue on GitHub <https://github.com/urllib3/urllib3/issues>`_ or reach out in
`our community Discord channel <https://discord.gg/urllib3>`_.
Migrating as an application developer?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're someone who writes Python but doesn't ship as a package (things like web services, data science, tools, and more) this section is for you.
Python environments only allow for one version of a dependency to be installed per environment which means
that **all of your dependencies using urllib3 need to support v2.0 for you to upgrade**.
The best way to visualize relationships between your dependencies is using `pipdeptree <https://pypi.org/project/pipdeptree>`_ and ``$ pipdeptree --reverse``:
.. code-block:: bash
# From inside your Python environment:
$ python -m pip install pipdeptree
# We only care about packages requiring urllib3
$ pipdeptree --reverse | grep "requires: urllib3"
- botocore==1.29.8 [requires: urllib3>=1.25.4,<2]
- requests==2.28.1 [requires: urllib3>=1.21.1,<2]
Reading the output from above, there are two packages which depend on urllib3: ``botocore`` and ``requests``.
The versions of these two packages both require urllib3 that is less than v2.0 (ie ``<2``).
Because both of these packages require urllib3 before v2.0 the new version of urllib3 can't be installed
by default. There are ways to force installing the newer version of urllib3 v2.0 (ie pinning to ``urllib3==2.0.0``)
which you can do to test your application.
It's important to know that even if you don't upgrade all of your services to 2.x
immediately you will `receive security fixes on the 1.26.x release stream <#security-fixes-for-urllib3-v1-26-x>` for some time.
Security fixes for urllib3 v1.26.x
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thanks to support from `Tidelift <https://tidelift.com/subscription/pkg/pypi-urllib3>`_
we're able to continue supporting the v1.26.x release stream with
security fixes for the foreseeable future 💖
However, upgrading is still recommended as **no new feature developments or non-critical
bug fixes will be shipped to the 1.26.x release stream**.
If your organization relies on urllib3 and is interested in continuing support you can learn
more about the `Tidelift Subscription for Enterprise <https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs>`_.
**🤔 Common upgrading issues**
-------------------------------
ssl module is compiled with OpenSSL 1.0.2.k-fips
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: text
ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'.
See: https://github.com/urllib3/urllib3/issues/2168
Remediation depends on your system:
- **AWS Lambda**: Upgrade to the Python3.10 runtime as it uses OpenSSL 1.1.1. Alternatively, you can
use a `custom Docker image
<https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/>`_ and ensure you
use a Python build that uses OpenSSL 1.1.1 or later.
- **Amazon Linux 2**: Upgrade to `Amazon Linux 2023
<https://aws.amazon.com/linux/amazon-linux-2023/>`_. Alternatively, you can install OpenSSL 1.1.1
on Amazon Linux 2 using ``yum install openssl11 openssl11-devel`` and then install Python with a
tool like pyenv.
- **Red Hat Enterpritse Linux 7 (RHEL 7)**: Upgrade to RHEL 8 or RHEL 9.
- **Read the Docs**: Upgrade your `configuration file to use Ubuntu 22.04
<https://docs.readthedocs.io/en/stable/config-file/v2.html>`_ by using ``os: ubuntu-22.04`` in the
``build`` section. Feel free to use the `urllib3 configuration
<https://github.com/urllib3/urllib3/blob/2.0.0/.readthedocs.yml>`_ as an inspiration.
docker.errors.dockerexception: error while fetching server api version: request() got an unexpected keyword argument 'chunked'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upgrade to ``docker==6.1.0`` that is compatible with urllib3 2.0.
ImportError: cannot import name 'gaecontrib' from 'requests_toolbelt._compat'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To be compatible with urllib3 2.0, Requests Toolbelt released version 1.0.0 without Google App
Engine Standard Python 2.7 support. Most users that reported this issue were using the `Pyrebase
<https://github.com/thisbejim/Pyrebase>`_ library that provides an API for the Firebase API. This
library is unmaintained, but `replacements exist
<https://github.com/thisbejim/Pyrebase/issues/435>`_.
``ImportError: cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_'``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This likely happens because you're using botocore which `does not support urllib3 2.0 yet
<https://github.com/boto/botocore/issues/2921>`_. The good news is that botocore explicitly declares
in its dependencies that it only supports ``urllib3<2``. Make sure to use a recent pip. That way, pip
will install urllib3 1.26.x until botocore starts supporting urllib3 2.0.
If you're deploying to an AWS environment such as Lambda or a host using Amazon Linux 2,
you'll need to explicitly pin to ``urllib3<2`` in your project to ensure urllib3 2.0 isn't
brought into your environment. Otherwise, this may result in unintended side effects with
the default boto3 installation.
AttributeError: module 'urllib3.connectionpool' has no attribute 'VerifiedHTTPSConnection'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``VerifiedHTTPSConnection`` class has always been documented to be in the
:mod:`~urllib3.connection` module. It used to be possible to import it from
:mod:`~urllib3.connectionpool` but that was acccidental and is no longer possible due to a
refactoring in urllib3 2.0.
Note that the new name of this class is :class:`~urllib3.connection.HTTPSConnection`. It can be used
starting from urllib3 1.25.9.
AttributeError: 'HTTPResponse' object has no attribute 'strict'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``strict`` parameter is unneeded with Python 3 and should be removed.
Pinning urllib3<2
~~~~~~~~~~~~~~~~~
If the advice from the above sections did not help, you can pin urllib3 to 1.26.x by installing
``urllib3<2``. Please do **not** specify ``urllib3==1.26.15`` to make sure you continue getting
1.26.x updates!
While urllib3 1.26.x is still supported, it won't get new features or bug fixes, just security
updates. Consider opening a tracking issue to unpin urllib3 in the future to not stay on 1.26.x
indefinitely. For more details on the recommended way to handle your dependencies in general, see
`Semantic Versioning Will Not Save You <https://hynek.me/articles/semver-will-not-save-you/>`_. The
second half even uses urllib3 2.0 as an example!
**💪 User-friendly features**
-----------------------------
urllib3 has always billed itself as a **user-friendly HTTP client library**.
In the spirit of being even more user-friendly we've added two features
which should make using urllib3 for tinkering sessions, throw-away scripts,
and smaller projects a breeze!
urllib3.request()
~~~~~~~~~~~~~~~~~
Previously the highest-level API available for urllib3 was a ``PoolManager``,
but for many cases configuring a poolmanager is extra steps for no benefit.
To make using urllib3 as simple as possible we've added a top-level function
for sending requests from a global poolmanager instance:
.. code-block:: python
>>> import urllib3
>>> resp = urllib3.request("GET", "https://example.com")
>>> resp.status
200
JSON support for requests and responses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
JSON is everywhere and now it's in urllib3, too!
If you'd like to send JSON in a request body or deserialize a response body
from JSON into Python objects you can now use the new ``json=`` parameter
for requests and ``HTTPResponse.json()`` method on responses:
.. code-block:: python
import urllib3
# Send a request with a JSON body.
# This adds 'Content-Type: application/json' by default.
resp = urllib3.request(
"POST", "https://example.api.com",
json={"key": "value"}
)
# Receive a JSON body in the response.
resp = urllib3.request("GET", "https://xkcd.com/2347/info.0.json")
# There's always an XKCD...
resp.json()
{
"num": 2347,
"img": "https://imgs.xkcd.com/comics/dependency.png",
"title": "Dependency",
...
}
**✨ Optimized for Python 3.7+**
--------------------------------
In v2.0 we'll be specifically targeting
CPython 3.7+ and PyPy 7.0+ (compatible with CPython 3.7)
and dropping support for Python versions 2.7, 3.5, and 3.6.
By dropping end-of-life Python versions we're able to optimize
the codebase for Python 3.7+ by using new features to improve
performance and reduce the amount of code that needs to be executed
in order to support legacy versions.
**📜 Type-hinted APIs**
-----------------------
You're finally able to run Mypy or other type-checkers
on code using urllib3. This also means that for IDEs
that support type hints you'll receive better suggestions
from auto-complete. No more confusion with ``**kwargs``!
We've also added API interfaces like ``BaseHTTPResponse``
and ``BaseHTTPConnection`` to ensure that when you're sub-classing
an interface you're only using supported public APIs to ensure
compatibility and minimize breakages down the road.
.. note::
If you're one of the rare few who is subclassing connections
or responses you should take a closer look at detailed changes
in `the changelog <https://github.com/urllib3/urllib3/blob/main/CHANGES.rst>`_.
**🔐 Modern security by default**
---------------------------------
HTTPS requires TLS 1.2+
~~~~~~~~~~~~~~~~~~~~~~~
Greater than 95% of websites support TLS 1.2 or above.
At this point we're comfortable switching the default
minimum TLS version to be 1.2 to ensure high security
for users without breaking services.
Dropping TLS 1.0 and 1.1 by default means you
won't be vulnerable to TLS downgrade attacks
if a vulnerability in TLS 1.0 or 1.1 were discovered in
the future. Extra security for free! By dropping TLS 1.0
and TLS 1.1 we also tighten the list of ciphers we need
to support to ensure high security for data traveling
over the wire.
If you still need to use TLS 1.0 or 1.1 in your application
you can still upgrade to v2.0, you'll only need to set
``ssl_minimum_version`` to the proper value to continue using
legacy TLS versions.
Stop verifying commonName in certificates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dropping support the long deprecated ``commonName``
field on certificates in favor of only verifying
``subjectAltName`` to put us in line with browsers and
other HTTP client libraries and to improve security for our users.
Certificate verification via SSLContext
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default certificate verification is handled by urllib3
to support legacy Python versions, but now we can
rely on Python's certificate verification instead! This
should result in a speedup for verifying certificates
and means that any improvements made to certificate
verification in Python or OpenSSL will be immediately
available.