Module glean.net.http_client
This module contains a ping uploader based on the Python stdlib's http.client module.
Expand source code
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
This module contains a ping uploader based on the Python stdlib's http.client
module.
"""
import http.client
import logging
import socket
from typing import Dict, Union
import urllib.parse
from . import base_uploader
from .ping_uploader import UploadResult
log = logging.getLogger("glean")
class HttpClientUploader(base_uploader.BaseUploader):
# The timeout, in seconds, to use for all operations with the server.
_DEFAULT_TIMEOUT = 10
@classmethod
def upload(
cls, url: str, data: bytes, headers: Dict[str, str]
) -> Union[
UploadResult,
UploadResult.UNRECOVERABLE_FAILURE,
UploadResult.RECOVERABLE_FAILURE,
UploadResult.HTTP_STATUS,
]:
"""
Synchronously upload a ping to a server.
Args:
url (str): The URL path to upload the data to.
data (str): The serialized text data to send.
headers (dict of (str, str)): HTTP headers to send.
"""
parsed_url = urllib.parse.urlparse(url)
if parsed_url.scheme == "http":
conn = http.client.HTTPConnection(
parsed_url.hostname or "",
port=parsed_url.port or 80,
timeout=cls._DEFAULT_TIMEOUT,
)
elif parsed_url.scheme == "https":
conn = http.client.HTTPSConnection(
parsed_url.hostname or "",
port=parsed_url.port or 443,
timeout=cls._DEFAULT_TIMEOUT,
)
else:
# If we don't know the URL scheme, log an error and mark this as an unrecoverable
# error, like if it were a malformed URL.
log.error(f"Unknown URL scheme {parsed_url.scheme}")
return UploadResult.UNRECOVERABLE_FAILURE(0)
try:
conn.request(
"POST",
parsed_url.path,
body=data,
headers=headers,
)
response = conn.getresponse()
except http.client.InvalidURL as e:
log.error(f"Could not upload telemetry due to malformed URL: '{url}' {e}")
return UploadResult.UNRECOVERABLE_FAILURE(0)
except http.client.HTTPException as e:
log.debug(f"http.client.HTTPException while uploading ping: '{url}' {e}")
return UploadResult.RECOVERABLE_FAILURE(0)
except socket.gaierror as e:
log.debug(f"socket.gaierror while uploading ping: '{url}' {e}")
return UploadResult.RECOVERABLE_FAILURE(0)
except OSError as e:
log.debug(f"OSError while uploading ping: '{url}' {e}")
return UploadResult.RECOVERABLE_FAILURE(0)
except Exception as e:
log.error(f"Unknown Exception while uploading ping: '{url}' {e}")
return UploadResult.RECOVERABLE_FAILURE(0)
status_code = response.status
conn.close()
return UploadResult.HTTP_STATUS(status_code)
__all__ = ["HttpClientUploader"]
Classes
class HttpClientUploader (*args, **kwargs)
-
The logic for uploading pings. This leaves the actual upload implementation to the user-provided delegate.
Expand source code
class HttpClientUploader(base_uploader.BaseUploader): # The timeout, in seconds, to use for all operations with the server. _DEFAULT_TIMEOUT = 10 @classmethod def upload( cls, url: str, data: bytes, headers: Dict[str, str] ) -> Union[ UploadResult, UploadResult.UNRECOVERABLE_FAILURE, UploadResult.RECOVERABLE_FAILURE, UploadResult.HTTP_STATUS, ]: """ Synchronously upload a ping to a server. Args: url (str): The URL path to upload the data to. data (str): The serialized text data to send. headers (dict of (str, str)): HTTP headers to send. """ parsed_url = urllib.parse.urlparse(url) if parsed_url.scheme == "http": conn = http.client.HTTPConnection( parsed_url.hostname or "", port=parsed_url.port or 80, timeout=cls._DEFAULT_TIMEOUT, ) elif parsed_url.scheme == "https": conn = http.client.HTTPSConnection( parsed_url.hostname or "", port=parsed_url.port or 443, timeout=cls._DEFAULT_TIMEOUT, ) else: # If we don't know the URL scheme, log an error and mark this as an unrecoverable # error, like if it were a malformed URL. log.error(f"Unknown URL scheme {parsed_url.scheme}") return UploadResult.UNRECOVERABLE_FAILURE(0) try: conn.request( "POST", parsed_url.path, body=data, headers=headers, ) response = conn.getresponse() except http.client.InvalidURL as e: log.error(f"Could not upload telemetry due to malformed URL: '{url}' {e}") return UploadResult.UNRECOVERABLE_FAILURE(0) except http.client.HTTPException as e: log.debug(f"http.client.HTTPException while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except socket.gaierror as e: log.debug(f"socket.gaierror while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except OSError as e: log.debug(f"OSError while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except Exception as e: log.error(f"Unknown Exception while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) status_code = response.status conn.close() return UploadResult.HTTP_STATUS(status_code)
Ancestors
- BaseUploader
- PingUploader
- typing.Protocol
- typing.Generic
Static methods
def upload(url: str, data: bytes, headers: Dict[str, str]) ‑> Union[glean._uniffi.glean.UploadResult, glean._uniffi.glean.UploadResult.UNRECOVERABLE_FAILURE, glean._uniffi.glean.UploadResult.RECOVERABLE_FAILURE, glean._uniffi.glean.UploadResult.HTTP_STATUS]
-
Synchronously upload a ping to a server.
Args
url
:str
- The URL path to upload the data to.
data
:str
- The serialized text data to send.
headers (dict of (str, str)): HTTP headers to send.
Expand source code
@classmethod def upload( cls, url: str, data: bytes, headers: Dict[str, str] ) -> Union[ UploadResult, UploadResult.UNRECOVERABLE_FAILURE, UploadResult.RECOVERABLE_FAILURE, UploadResult.HTTP_STATUS, ]: """ Synchronously upload a ping to a server. Args: url (str): The URL path to upload the data to. data (str): The serialized text data to send. headers (dict of (str, str)): HTTP headers to send. """ parsed_url = urllib.parse.urlparse(url) if parsed_url.scheme == "http": conn = http.client.HTTPConnection( parsed_url.hostname or "", port=parsed_url.port or 80, timeout=cls._DEFAULT_TIMEOUT, ) elif parsed_url.scheme == "https": conn = http.client.HTTPSConnection( parsed_url.hostname or "", port=parsed_url.port or 443, timeout=cls._DEFAULT_TIMEOUT, ) else: # If we don't know the URL scheme, log an error and mark this as an unrecoverable # error, like if it were a malformed URL. log.error(f"Unknown URL scheme {parsed_url.scheme}") return UploadResult.UNRECOVERABLE_FAILURE(0) try: conn.request( "POST", parsed_url.path, body=data, headers=headers, ) response = conn.getresponse() except http.client.InvalidURL as e: log.error(f"Could not upload telemetry due to malformed URL: '{url}' {e}") return UploadResult.UNRECOVERABLE_FAILURE(0) except http.client.HTTPException as e: log.debug(f"http.client.HTTPException while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except socket.gaierror as e: log.debug(f"socket.gaierror while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except OSError as e: log.debug(f"OSError while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) except Exception as e: log.error(f"Unknown Exception while uploading ping: '{url}' {e}") return UploadResult.RECOVERABLE_FAILURE(0) status_code = response.status conn.close() return UploadResult.HTTP_STATUS(status_code)
Inherited members