Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion datadog/api/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
2. `urlfetch` 3p module - Google App Engine only
"""
# stdlib
import copy
import logging
import platform
import urllib
from threading import Lock

Expand All @@ -32,6 +34,16 @@
log = logging.getLogger('datadog.api')


def _get_user_agent_header():
from datadog import version
return 'datadogpy/{version} (python {pyver}; os {os}; arch {arch})'.format(
version=version.__version__,
pyver=platform.python_version(),
os=platform.system().lower(),
arch=platform.machine().lower(),
)


def _remove_context(exc):
"""Python3: remove context from chained exceptions to prevent leaking API keys in tracebacks."""
exc.__cause__ = None
Expand Down Expand Up @@ -79,6 +91,7 @@ def request(cls, method, url, headers, params, data, timeout, proxies, verify, m
cls._session = requests.Session()
http_adapter = requests.adapters.HTTPAdapter(max_retries=max_retries)
cls._session.mount('https://', http_adapter)
cls._session.headers.update({'User-Agent': _get_user_agent_header()})

result = cls._session.request(
method, url,
Expand Down Expand Up @@ -130,12 +143,14 @@ def request(cls, method, url, headers, params, data, timeout, proxies, verify, m
url=url,
params=urllib.urlencode(params)
)
newheaders = copy.deepcopy(headers)
newheaders['User-Agent'] = _get_user_agent_header()

try:
result = urlfetch.fetch(
url=url_with_params,
method=method,
headers=headers,
headers=newheaders,
validate_certificate=validate_certificate,
deadline=timeout,
payload=data,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- datadogpy/0.38.0.dev (python 3.7.7; os darwin; arch x86_64)
method: GET
uri: https://api.datadoghq.com/api/v1/validate
response:
body:
string: '{"valid":true}'
headers:
Cache-Control:
- no-cache
Connection:
- keep-alive
Content-Length:
- '14'
Content-Security-Policy:
- frame-ancestors 'self'; report-uri https://api.datadoghq.com/csp-report
Content-Type:
- application/json
DD-POOL:
- dogweb
Date:
- Wed, 01 Jul 2020 17:22:12 GMT
Pragma:
- no-cache
Set-Cookie:
- DD-PSHARD=89; Max-Age=604800; Path=/; expires=Wed, 08-Jul-2020 17:22:12 GMT;
secure; HttpOnly
Strict-Transport-Security:
- max-age=15724800;
X-Content-Type-Options:
- nosniff
X-DD-Debug:
- SaHvyR/hQzhMjBxXmmuM76vwlwfocpgL0LhX3u6R0CFONYqUGm7Xe/7/HyTliTFX
X-DD-VERSION:
- '35.2688709'
X-Frame-Options:
- SAMEORIGIN
status:
code: 200
message: OK
version: 1
7 changes: 7 additions & 0 deletions tests/integration/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
# python
import datetime
import json
import mock
import os
import re
import time

import requests
Expand Down Expand Up @@ -959,3 +961,8 @@ def test_roles_crud(self, dog):
# check if new role is deleted successfully
res = dog.Roles.get(role_uuid)
assert "errors" in res

@mock.patch('datadog.api._return_raw_response', True)
def test_user_agent(self, dog):
_, resp = dog.api_client.APIClient.submit('GET', 'validate')
assert re.match(r'^datadogpy\/[^\s]+ \(python [^\s]+; os [^\s]+; arch [^\s]+\)$', resp.request.headers['User-Agent'])
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ envlist =
passenv = DD_TEST_CLIENT*
usedevelop = true
deps =
!integration: mock
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we move the user agent test to tests/unit instead of tests/integration we wouldn't need to change deps.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but the whole unittest suite as it is set up now replaces the RequestClient._session, so we'd have to create a completely different setup just because of this one specific test. I don't mind doing that, but this is just simpler (plus it tests the real thing).

click
freezegun
mock
pytest
pytest-vcr
python-dateutil
Expand All @@ -28,6 +28,7 @@ usedevelop = true
deps =
click
freezegun
mock
pytest
pytest-vcr
python-dateutil
Expand Down