[7.x] Add the 'X-Elastic-Client-Meta' header
Co-authored-by: Seth Michael Larson <[email protected]>
This commit is contained in:
co-authored by
Seth Michael Larson
parent
2e06989ca1
commit
b894e359df
@@ -21,6 +21,7 @@ import gzip
|
||||
import io
|
||||
import re
|
||||
from platform import python_version
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
try:
|
||||
@@ -65,6 +66,8 @@ class Connection(object):
|
||||
:arg cloud_id: The Cloud ID from ElasticCloud. Convenient way to connect to cloud instances.
|
||||
:arg opaque_id: Send this value in the 'X-Opaque-Id' HTTP header
|
||||
For tracing all requests made by this transport.
|
||||
:arg meta_header: If True will send the 'X-Elastic-Client-Meta' HTTP header containing
|
||||
simple client metadata. Setting to False will disable the header. Defaults to True.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -79,6 +82,7 @@ class Connection(object):
|
||||
cloud_id=None,
|
||||
api_key=None,
|
||||
opaque_id=None,
|
||||
meta_header=True,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
@@ -148,6 +152,10 @@ class Connection(object):
|
||||
self.url_prefix = url_prefix
|
||||
self.timeout = timeout
|
||||
|
||||
if not isinstance(meta_header, bool):
|
||||
raise TypeError("meta_header must be of type bool")
|
||||
self.meta_header = meta_header
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (self.__class__.__name__, self.host)
|
||||
|
||||
@@ -329,3 +337,25 @@ class Connection(object):
|
||||
s = "{0}:{1}".format(api_key[0], api_key[1]).encode("utf-8")
|
||||
return "ApiKey " + binascii.b2a_base64(s).rstrip(b"\r\n").decode("utf-8")
|
||||
return "ApiKey " + api_key
|
||||
|
||||
|
||||
def _python_to_meta_version(version):
|
||||
"""Transforms a Python package version to one
|
||||
compatible with 'X-Elastic-Client-Meta'. Essentially
|
||||
replaces any pre-release information with a 'p' suffix.
|
||||
"""
|
||||
version, version_pre = re.match(r"^([0-9.]+)(.*)$", version).groups()
|
||||
if version_pre:
|
||||
version += "p"
|
||||
return version
|
||||
|
||||
|
||||
def _get_client_meta_header(client_meta=()):
|
||||
"""Builds an 'X-Elastic-Client-Meta' HTTP header"""
|
||||
es_version = _python_to_meta_version(__versionstr__)
|
||||
py_version = python_version() + ("p" if sys.version_info[3] != "final" else "")
|
||||
# First three values have to be 'service', 'language', 'transport'
|
||||
client_meta = (("es", es_version), ("py", py_version), ("t", es_version)) + tuple(
|
||||
client_meta
|
||||
)
|
||||
return ",".join("%s=%s" % (k, v) for k, v in client_meta)
|
||||
|
||||
@@ -21,13 +21,13 @@ from typing import (
|
||||
Union,
|
||||
Optional,
|
||||
Mapping,
|
||||
MutableMapping,
|
||||
Tuple,
|
||||
List,
|
||||
NoReturn,
|
||||
Dict,
|
||||
Sequence,
|
||||
Any,
|
||||
AnyStr,
|
||||
Collection,
|
||||
)
|
||||
|
||||
@@ -44,6 +44,7 @@ class Connection(object):
|
||||
host: str
|
||||
url_prefix: str
|
||||
timeout: Optional[Union[float, int]]
|
||||
meta_header: bool
|
||||
def __init__(
|
||||
self,
|
||||
host: str = ...,
|
||||
@@ -56,6 +57,7 @@ class Connection(object):
|
||||
cloud_id: Optional[str] = ...,
|
||||
api_key: Optional[Union[Tuple[str, str], List[str], str]] = ...,
|
||||
opaque_id: Optional[str] = ...,
|
||||
meta_header: bool = ...,
|
||||
**kwargs: Any
|
||||
) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
@@ -77,11 +79,11 @@ class Connection(object):
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
params: Optional[Mapping[str, Any]] = ...,
|
||||
params: Optional[MutableMapping[str, Any]] = ...,
|
||||
body: Optional[bytes] = ...,
|
||||
timeout: Optional[Union[int, float]] = ...,
|
||||
ignore: Collection[int] = ...,
|
||||
headers: Optional[Mapping[str, str]] = ...,
|
||||
headers: Optional[MutableMapping[str, str]] = ...,
|
||||
) -> Tuple[int, Mapping[str, str], str]: ...
|
||||
def log_request_success(
|
||||
self,
|
||||
|
||||
@@ -25,7 +25,7 @@ try:
|
||||
except ImportError:
|
||||
REQUESTS_AVAILABLE = False
|
||||
|
||||
from .base import Connection
|
||||
from .base import Connection, _get_client_meta_header, _python_to_meta_version
|
||||
from ..exceptions import (
|
||||
ConnectionError,
|
||||
ImproperlyConfigured,
|
||||
@@ -142,13 +142,25 @@ class RequestsHttpConnection(Connection):
|
||||
url = self.base_url + url
|
||||
headers = headers or {}
|
||||
if params:
|
||||
url = "%s?%s" % (url, urlencode(params or {}))
|
||||
# Pop client metadata from parameters, if any.
|
||||
client_meta = params.pop("_client_meta", ())
|
||||
else:
|
||||
client_meta = ()
|
||||
if params:
|
||||
url = "%s?%s" % (url, urlencode(params))
|
||||
|
||||
orig_body = body
|
||||
if self.http_compress and body:
|
||||
body = self._gzip_compress(body)
|
||||
headers["content-encoding"] = "gzip"
|
||||
|
||||
# Create meta header for requests
|
||||
if self.meta_header:
|
||||
client_meta = (
|
||||
("rq", _python_to_meta_version(requests.__version__)),
|
||||
) + client_meta
|
||||
headers["x-elastic-client-meta"] = _get_client_meta_header(client_meta)
|
||||
|
||||
start = time.time()
|
||||
request = requests.Request(method=method, headers=headers, url=url, data=body)
|
||||
prepared_request = self.session.prepare_request(request)
|
||||
|
||||
@@ -37,5 +37,6 @@ class RequestsHttpConnection(Connection):
|
||||
cloud_id: Optional[str] = ...,
|
||||
api_key: Optional[Any] = ...,
|
||||
opaque_id: Optional[str] = ...,
|
||||
meta_header: bool = ...,
|
||||
**kwargs: Any
|
||||
) -> None: ...
|
||||
|
||||
@@ -22,7 +22,7 @@ from urllib3.exceptions import ReadTimeoutError, SSLError as UrllibSSLError # t
|
||||
from urllib3.util.retry import Retry # type: ignore
|
||||
import warnings
|
||||
|
||||
from .base import Connection
|
||||
from .base import Connection, _get_client_meta_header, _python_to_meta_version
|
||||
from ..exceptions import (
|
||||
ConnectionError,
|
||||
ImproperlyConfigured,
|
||||
@@ -216,8 +216,14 @@ class Urllib3HttpConnection(Connection):
|
||||
self, method, url, params=None, body=None, timeout=None, ignore=(), headers=None
|
||||
):
|
||||
url = self.url_prefix + url
|
||||
# Pop client metadata from parameters, if any.
|
||||
if params:
|
||||
client_meta = tuple(params.pop("_client_meta", ()))
|
||||
else:
|
||||
client_meta = ()
|
||||
if params:
|
||||
url = "%s?%s" % (url, urlencode(params))
|
||||
|
||||
full_url = self.host + url
|
||||
|
||||
start = time.time()
|
||||
@@ -242,6 +248,15 @@ class Urllib3HttpConnection(Connection):
|
||||
body = self._gzip_compress(body)
|
||||
request_headers["content-encoding"] = "gzip"
|
||||
|
||||
# Create meta header for urllib3
|
||||
if self.meta_header:
|
||||
client_meta = (
|
||||
("ur", _python_to_meta_version(urllib3.__version__)),
|
||||
) + client_meta
|
||||
request_headers["x-elastic-client-meta"] = _get_client_meta_header(
|
||||
client_meta
|
||||
)
|
||||
|
||||
response = self.pool.urlopen(
|
||||
method, url, body, retries=Retry(False), headers=request_headers, **kw
|
||||
)
|
||||
|
||||
@@ -51,5 +51,6 @@ class Urllib3HttpConnection(Connection):
|
||||
cloud_id: Optional[str] = ...,
|
||||
api_key: Optional[Any] = ...,
|
||||
opaque_id: Optional[str] = ...,
|
||||
meta_header: bool = ...,
|
||||
**kwargs: Any
|
||||
) -> None: ...
|
||||
|
||||
Reference in New Issue
Block a user