10000 allow user agent to be set by caller (#1166) · LehmD/server-client-python@16b1bdd · GitHub
[go: up one dir, main page]

Skip to content

Commit 16b1bdd

Browse files
authored< 10000 /span>
allow user agent to be set by caller (tableau#1166)
1 parent 504d9d4 commit 16b1bdd

File tree

4 files changed

+67
-30
lines changed

4 files changed

+67
-30
lines changed

tableauserverclient/server/endpoint/endpoint.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from packaging.version import Version
44
from functools import wraps
55
from xml.etree.ElementTree import ParseError
6-
from typing import Any, Callable, Dict, Optional, TYPE_CHECKING
6+
from typing import Any, Callable, Dict, Optional, TYPE_CHECKING, Mapping
77

88
from .exceptions import (
99
ServerResponseError,
@@ -35,15 +35,35 @@ def __init__(self, parent_srv: "Server"):
3535
self.parent_srv = parent_srv
3636

3737
@staticmethod
38-
def _make_common_headers(auth_token, content_type):
39-
_client_version: Optional[str] = get_versions()["version"]
40-
headers = {}
38+
def set_parameters(http_options, auth_token, content, content_type, parameters) -> Dict[str, Any]:
39+
parameters = parameters or {}
40+
parameters.update(http_options)
41+
if "headers" not in parameters:
42+
parameters["headers"] = {}
43+
4144
if auth_token is not None:
42-
headers[TABLEAU_AUTH_HEADER] = auth_token
45+
parameters["headers"][TABLEAU_AUTH_HEADER] = auth_token
4346
if content_type is not None:
44-
headers[CONTENT_TYPE_HEADER] = content_type
45-
headers[USER_AGENT_HEADER] = "Tableau Server Client/{}".format(_client_version)
46-
return headers
47+
parameters["headers"][CONTENT_TYPE_HEADER] = content_type
48+
49+
Endpoint.set_user_agent(parameters)
50+
if content is not None:
51+
parameters["data"] = content
52+
return parameters or {}
53+
54+
@staticmethod
55+
def set_user_agent(parameters):
56+
if USER_AGENT_HEADER not in parameters["headers"]:
57+
if USER_AGENT_HEADER in parameters:
58+
parameters["headers"][USER_AGENT_HEADER] = parameters[USER_AGENT_HEADER]
59+
else:
60+
# only set the TSC user agent if not already populated
61+
_client_version: Optional[str] = get_versions()["version"]
62+
parameters["headers"][USER_AGENT_HEADER] = "Tableau Server Client/{}".format(_client_version)
63+
64+
# result: parameters["headers"]["User-Agent"] is set
65+
# return explicitly for testing only
66+
return parameters
4767

4868
def _make_request(
4969
self,
@@ -54,18 +74,14 @@ def _make_request(
5474
content_type: Optional[str] = None,
5575
parameters: Optional[Dict[str, Any]] = None,
5676
) -> "Response":
57-
parameters = parameters or {}
58-
if "headers" not in parameters:
59-
parameters["headers"] = {}
60-
parameters.update(self.parent_srv.http_options)
61-
parameters["headers"].update(Endpoint._make_common_headers(auth_token, content_type))
62-
63-
if content is not None:
64-
parameters["data"] = content
77+
parameters = Endpoint.set_parameters(
78+
self.parent_srv.http_options, auth_token, content, content_type, parameters
79+
)
6580

66-
logger.debug("request {}, url: {}".format(method.__name__, url))
81+
logger.debug("request {}, url: {}".format(method, url))
6782
if content:
68-
logger.debug("request content: {}".format(helpers.strings.redact_xml(content[:1000])))
83+
redacted = helpers.strings.redact_xml(content[:1000])
84+
logger.debug("request content: {}".format(redacted))
6985

7086
server_response = method(url, **parameters)
7187
self._check_status(server_response, url)

tableauserverclient/server/server.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
Fileuploads,
3232
FlowRuns,
3333
Metrics,
34+
Endpoint,
3435
)
3536
from .endpoint.exceptions import (
3637
ServerInfoEndpointNotFoundError,
@@ -62,6 +63,10 @@ def __init__(self, server_address, use_server_version=False, http_options=None,
6263
self._site_id = None
6364
self._user_id = None
6465

66+
# TODO: this needs to change to default to https, but without breaking existing code
67+
if not server_address.startswith("http://") and not server_address.startswith("https://"):
68+
server_address = "http://" + server_address
69+
6570
self._server_address: str = server_address
6671
self._session_factory = session_factory or requests.session
6772

@@ -96,21 +101,17 @@ def __init__(self, server_address, use_server_version=False, http_options=None,
96101
if http_options:
97102
self.add_http_options(http_options)
98103

99-
self.validate_server_connection()
104+
self.validate_connection_settings() # does not make an actual outgoing request
100105

101106
self.version = default_server_version
102107
if use_server_version:
103108
self.use_server_version() # this makes a server call
104109

105-
def validate_server_connection(self):
110+
def validate_connection_settings(self):
106111
try:
107-
if not self._server_address.startswith("http://") and not self._server_address.startswith("https://"):
108-
self._server_address = "http://" + self._server_address
109-
self._session.prepare_request(
110-
requests.Request("GET", url=self._server_address, params=self._http_options)
111-
)
112+
Endpoint(self).set_parameters(self._http_options, None, None, None, None)
112113
except Exception as req_ex:
113-
raise ValueError("Invalid server initialization", req_ex)
114+
raise ValueError("Server connection settings not valid", req_ex)
114115

115116
def __repr__(self):
116117
return "<TableauServerClient> [Connection: {}, {}]".format(self.baseurl, self.server_info.serverInfo)
@@ -143,10 +144,12 @@ def _set_auth(self, site_id, user_id, auth_token):
143144
self._auth_token = auth_token
144145

145146
def _get_legacy_version(self):
146-
response = self._session.get(self.server_address + "/auth?format=xml")
147+
dest = Endpoint(self)
148+
response = dest._make_request(method=self.session.get, url=self.server_address + "/auth?format=xml")
147149
try:
148150
info_xml = fromstring(response.content)
149151
except ParseError as parseError:
152+
logging.getLogger("TSC.server").info(parseError)
150153
logging.getLogger("TSC.server").info(
151154
"Could not read server version info. The server may not be running or configured."
152155
)

test/http/test_http_requests.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,20 @@ def test_http_options_not_sequence_fails(self):
8282
def test_validate_connection_http(self):
8383
url = "http://cookies.com"
8484
server = TSC.Server(url)
85-
server.validate_server_connection()
85+
server.validate_connection_settings()
8686
self.assertEqual(url, server.server_address)
8787

8888
def test_validate_connection_https(self):
8989
url = "https://cookies.com"
9090
server = TSC.Server(url)
91-
server.validate_server_connection()
91+
server.validate_connection_settings()
9292
self.assertEqual(url, server.server_address)
9393

9494
def test_validate_connection_no_protocol(self):
9595
url = "cookies.com"
9696
fixed_url = "http://cookies.com"
9797
server = TSC.Server(url)
98-
server.validate_server_connection()
98+
server.validate_connection_settings()
9999
self.assertEqual(fixed_url, server.server_address)
100100

101101

test/test_endpoint.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,21 @@ class FakeResponse(object):
3838
server_response = FakeResponse()
3939
log = endpoint.log_response_safely(server_response)
4040
self.assertTrue(log.find("[Truncated File Contents]") > 0, log)
41+
42+
def test_set_user_agent_from_options_headers(self):
43+
params = {"User-Agent": "1", "headers": {"User-Agent": "2"}}
44+
result = TSC.server.Endpoint.set_user_agent(params)
45+
# it should use the value under 'headers' if more than one is given
46+
print(result)
47+
print(result["headers"]["User-Agent"])
48+
self.assertTrue(result["headers"]["User-Agent"] == "2")
49+
50+
def test_set_user_agent_from_options(self):
51+
params = {"headers": {"User-Agent": "2"}}
52+
result = TSC.server.Endpoint.set_user_agent(params)
53+
self.assertTrue(result["headers"]["User-Agent"] == "2")
54+
55+
def test_set_user_agent_when_blank(self):
56+
params = {"headers": {}}
57+
result = TSC.server.Endpoint.set_user_agent(params)
58+
self.assertTrue(result["headers"]["User-Agent"].startswith("Tableau Server Client"))

0 commit comments

Comments
 (0)
0