Krikri::PluginHelpers::URLPreflight
URLPreflight - the failures Ansible's fetch_url reports BEFORE urllib ever opens the URL, shared by the uri and get_url plugins.
Ansible builds a request in three steps that all happen before a single byte goes out (the Ansible module's Request.open, 2.19.11):
- _configure_auth() - with use_gssapi: true the module imports
python-gssapi, and a host without it raises MissingModuleError
(fetch_url's own
except MissingModuleErrorhandler, whose result carries the message ALONE - no url, no status). - make_context() - opens ca_path (ssl.create_default_context's
cafile=), applies ciphers: (set_ciphers on the joined list) and
loads client_cert:/client_key: (load_cert_chain). A missing or
unusable file raises an OSError, an unusable cipher list an
SSLError; both are OSError subclasses, so fetch_url's
except OSErrorhandler folds them into info['msg'] = "Connection failure: <str(ex)>" with status -1. - urllib.request.Request(url) - a URL with no type at all raises ValueError("unknown url type: '<url>'"), which fetch_url re-raises through fail_json(msg=..., **info) with info = {url, status: -1}. A URL that DOES have a type but no handler (gopher://..., "127.0.0.1:80/x" - Python's type split does not require an RFC scheme) instead dies later, in urllib's own UnknownHandler, with URLError('unknown url type: <type>') - so it comes back as info['msg'] = "Request failed: <urlopen error unknown url type: <type>>" with status -1, i.e. the same info dict the OSError half below produces.
The order matters as much as the checks: make_context runs before the URL is parsed, so a task carrying BOTH a bogus ciphers: list and a scheme-less url reports the cipher failure. Each module's own module-side logic (get_url's dest/checksum skip, uri's creates:/removes: skip) runs even earlier - see the call sites.
Deliberately NOT emulated: the content-level OpenSSL errors a non-PEM (or empty) ca_path/client_cert raises ("[SSL] PEM lib (_ssl.c:4093)", "[X509: NO_CERTIFICATE_OR_CRL_FOUND] ...") - those carry CPython source line numbers and vary per interpreter build, so matching them would be guesswork. A readable file of any content passes the preflight and fails (or works) at handshake time, exactly as the real request would.
Constants
The URL types urllib's default opener actually has a handler for (urllib.request's own default handler list).
Class methods
The ciphers is the OpenSSL cipher-list string the real params join
into ("all ciphers are joined in order with ':'", get_url's own
docs) - nil or empty means "don't set them", in which case
Ansible skips set_ciphers entirely.