|
Michal Koutný |
ccf7f1 |
# This work is licensed under the GNU GPLv2 or later.
|
|
Michal Koutný |
ccf7f1 |
# See the COPYING file in the top-level directory.
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
from logging import getLogger
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
import os
|
|
Michal Koutný |
ccf7f1 |
import sys
|
|
Michal Koutný |
ccf7f1 |
import urllib.parse
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
import requests
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
log = getLogger(__name__)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
class _BugzillaSession(object):
|
|
Michal Koutný |
ccf7f1 |
"""
|
|
Michal Koutný |
ccf7f1 |
Class to handle the backend agnostic 'requests' setup
|
|
Michal Koutný |
ccf7f1 |
"""
|
|
Michal Koutný |
ccf7f1 |
def __init__(self, url, user_agent,
|
|
Michal Koutný |
ccf7f1 |
sslverify, cert, tokencache, api_key,
|
|
Michal Koutný |
ccf7f1 |
is_redhat_bugzilla,
|
|
Michal Koutný |
ccf7f1 |
requests_session=None):
|
|
Michal Koutný |
ccf7f1 |
self._url = url
|
|
Michal Koutný |
ccf7f1 |
self._user_agent = user_agent
|
|
Michal Koutný |
ccf7f1 |
self._scheme = urllib.parse.urlparse(url)[0]
|
|
Michal Koutný |
ccf7f1 |
self._tokencache = tokencache
|
|
Michal Koutný |
ccf7f1 |
self._api_key = api_key
|
|
Michal Koutný |
ccf7f1 |
self._is_xmlrpc = False
|
|
Michal Koutný |
ccf7f1 |
self._use_auth_bearer = False
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
if self._scheme not in ["http", "https"]:
|
|
Michal Koutný |
ccf7f1 |
raise Exception("Invalid URL scheme: %s (%s)" % (
|
|
Michal Koutný |
ccf7f1 |
self._scheme, url))
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
self._session = requests_session
|
|
Michal Koutný |
ccf7f1 |
if not self._session:
|
|
Michal Koutný |
ccf7f1 |
self._session = requests.Session()
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
if cert:
|
|
Michal Koutný |
ccf7f1 |
self._session.cert = cert
|
|
Michal Koutný |
ccf7f1 |
if sslverify is False:
|
|
Michal Koutný |
ccf7f1 |
self._session.verify = False
|
|
Michal Koutný |
ccf7f1 |
self._session.headers["User-Agent"] = self._user_agent
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
if is_redhat_bugzilla and self._api_key:
|
|
Michal Koutný |
ccf7f1 |
self._use_auth_bearer = True
|
|
Michal Koutný |
ccf7f1 |
self._session.headers["Authorization"] = (
|
|
Michal Koutný |
ccf7f1 |
"Bearer %s" % self._api_key)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def _get_timeout(self):
|
|
Michal Koutný |
ccf7f1 |
# Default to 5 minutes. This is longer than bugzilla.redhat.com's
|
|
Michal Koutný |
ccf7f1 |
# apparent 3 minute timeout so shouldn't affect legitimate usage,
|
|
Michal Koutný |
ccf7f1 |
# but saves us from indefinite hangs
|
|
Michal Koutný |
ccf7f1 |
DEFAULT_TIMEOUT = 300
|
|
Michal Koutný |
ccf7f1 |
envtimeout = os.environ.get("PYTHONBUGZILLA_REQUESTS_TIMEOUT")
|
|
Michal Koutný |
ccf7f1 |
return float(envtimeout or DEFAULT_TIMEOUT)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def set_rest_defaults(self):
|
|
Michal Koutný |
ccf7f1 |
self._session.headers["Content-Type"] = "application/json"
|
|
Michal Koutný |
ccf7f1 |
def set_xmlrpc_defaults(self):
|
|
Michal Koutný |
ccf7f1 |
self._is_xmlrpc = True
|
|
Michal Koutný |
ccf7f1 |
self._session.headers["Content-Type"] = "text/xml"
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def get_user_agent(self):
|
|
Michal Koutný |
ccf7f1 |
return self._user_agent
|
|
Michal Koutný |
ccf7f1 |
def get_scheme(self):
|
|
Michal Koutný |
ccf7f1 |
return self._scheme
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def get_auth_params(self):
|
|
Michal Koutný |
ccf7f1 |
# bugzilla.redhat.com will error if there's auth bits in params
|
|
Michal Koutný |
ccf7f1 |
# when Authorization header is used
|
|
Michal Koutný |
ccf7f1 |
if self._use_auth_bearer:
|
|
Michal Koutný |
ccf7f1 |
return {}
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
# Don't add a token to the params list if an API key is set.
|
|
Michal Koutný |
ccf7f1 |
# Keeping API key solo means bugzilla will definitely fail
|
|
Michal Koutný |
ccf7f1 |
# if the key expires. Passing in a token could hide that
|
|
Michal Koutný |
ccf7f1 |
# fact, which could make it confusing to pinpoint the issue.
|
|
Michal Koutný |
ccf7f1 |
if self._api_key:
|
|
Michal Koutný |
ccf7f1 |
# Bugzilla 5.0 only supports api_key as a query parameter.
|
|
Michal Koutný |
ccf7f1 |
# Bugzilla 5.1+ takes it as a X-BUGZILLA-API-KEY header as well,
|
|
Michal Koutný |
ccf7f1 |
# with query param taking preference.
|
|
Michal Koutný |
ccf7f1 |
return {"Bugzilla_api_key": self._api_key}
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
token = self._tokencache.get_value(self._url)
|
|
Michal Koutný |
ccf7f1 |
if token:
|
|
Michal Koutný |
ccf7f1 |
return {"Bugzilla_token": token}
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
return {}
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def get_requests_session(self):
|
|
Michal Koutný |
ccf7f1 |
return self._session
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def request(self, *args, **kwargs):
|
|
Michal Koutný |
ccf7f1 |
timeout = self._get_timeout()
|
|
Michal Koutný |
ccf7f1 |
if "timeout" not in kwargs:
|
|
Michal Koutný |
ccf7f1 |
kwargs["timeout"] = timeout
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
response = self._session.request(*args, **kwargs)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
if self._is_xmlrpc:
|
|
Michal Koutný |
ccf7f1 |
# Yes this still appears to matter for properly decoding unicode
|
|
Michal Koutný |
ccf7f1 |
# code points in bugzilla.redhat.com content
|
|
Michal Koutný |
ccf7f1 |
response.encoding = "UTF-8"
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
try:
|
|
Michal Koutný |
ccf7f1 |
response.raise_for_status()
|
|
Michal Koutný |
ccf7f1 |
except Exception as e:
|
|
Michal Koutný |
ccf7f1 |
# Scrape the api key out of the returned exception string
|
|
Michal Koutný |
ccf7f1 |
message = str(e).replace(self._api_key or "", "")
|
|
Michal Koutný |
ccf7f1 |
raise type(e)(message).with_traceback(sys.exc_info()[2])
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
return response
|