8000 fix behavior when url has no protocol (#1125) · LehmD/server-client-python@ca4d79e · GitHub
[go: up one dir, main page]

Skip to content

Commit ca4d79e

Browse files
authored
fix behavior when url has no protocol (tableau#1125)
* fix behavior when url has no protocol
1 parent af80100 commit ca4d79e

File tree

4 files changed

+73
-20
lines changed

4 files changed

+73
-20
lines changed

tableauserverclient/models/tableau_auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,6 @@ def credentials(self):
6565
}
6666

6767
def __repr__(self):
68-
return "<PersonalAccessToken name={} token={} site={}>".format(
68+
return "<PersonalAccessToken name={} token={}>(site={})".format(
6969
self.token_name, self.personal_access_token[:2] + "...", self.site_id
7070
)

tableauserverclient/server/endpoint/auth_endpoint.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,18 @@ def baseurl(self):
2828
def sign_in(self, auth_req):
2929
url = "{0}/{1}".format(self.baseurl, "signin")
3030
signin_req = RequestFactory.Auth.signin_req(auth_req)
31-
server_response = self.parent_srv.session.post(url, data=signin_req, **self.parent_srv.http_options)
31+
server_response = self.parent_srv.session.post(
32+
url, data=signin_req, **self.parent_srv.http_options, allow_redirects=False
33+
)
34+
# manually handle a redirect so that we send the correct POST request instead of GET
35+
# this will make e.g http://online.tableau.com work to redirect to http://east.online.tableau.com
36+
if server_response.status_code == 301:
37+
server_response = self.parent_srv.session.post(
38+
server_response.headers["Location"],
39+
data=signin_req,
40+
**self.parent_srv.http_options,
41+
allow_redirects=False,
42+
)
3243
self.parent_srv._namespace.detect(server_response.content)
3344
self._check_status(server_response, url)
3445
parsed_response = fromstring(server_response.content)

tableauserverclient/server/server.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import logging
12
import warnings
23

34
import requests
45
import urllib3
56

6-
from defusedxml.ElementTree import fromstring
7+
from defusedxml.ElementTree import fromstring, ParseError
78
from packaging.version import Version
89
from .endpoint import (
910
Sites,
@@ -61,7 +62,7 @@ def __init__(self, server_address, use_server_version=False, http_options=None,
6162
self._site_id = None
6263
self._user_id = None
6364

64-
self._server_address = server_address
65+
self._server_address: str = server_address
6566
self._session_factory = session_factory or requests.session
6667

6768
self.auth = Auth(self)
@@ -103,10 +104,13 @@ def __init__(self, server_address, use_server_version=False, http_options=None,
103104

104105
def validate_server_connection(self):
105106
try:
106-
self._session.prepare_request(requests.Request("GET", url=self._server_address, params=self._http_options))
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+
)
107112
except Exception as req_ex:
108-
warnings.warn("Invalid server initialization\n {}".format(req_ex.__str__()), UserWarning)
109-
print("==================")
113+
raise ValueError("Invalid server initialization", req_ex)
110114

111115
def __repr__(self):
112116
return "<TableauServerClient> [Connection: {}, {}]".format(self.baseurl, self.server_info.serverInfo)
@@ -140,7 +144,13 @@ def _set_auth(self, site_id, user_id, auth_token):
140144

141145
def _get_legacy_version(self):
142146
response = self._session.get(self.server_address + "/auth?format=xml")
143-
info_xml = fromstring(response.content)
147+
try:
148+
info_xml = fromstring(response.content)
149+
except ParseError as parseError:
150+
logging.getLogger("TSC.server").info(
151+
"Could not read server version info. The server may not be running or configured."
152+
)
153+
return self.version
144154
prod_version = info_xml.find(".//product_version").text
145155
version = _PRODUCT_TO_REST_VERSION.get(prod_version, "2.1") # 2.1
146156
return version
@@ -152,8 +162,6 @@ def _determine_highest_version(self):
152162
version = self.server_info.get().rest_api_version
153163
except ServerInfoEndpointNotFoundError:
154164
version = self._get_legacy_version()
155-
except BaseException:
156-
version = self._get_legacy_version()
157165

158166
self.version = old_version
159167

@@ -164,8 +172,6 @@ def use_server_version(self):
164172

165173
def use_highest_version(self):
166174
self.use_server_version()
167-
import warnings
168-
169175
warnings.warn("use use_server_version instead", DeprecationWarning)
170176

171177
def check_at_least_version(self, target: str):

test/http/test_http_requests.py

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,58 @@
11
import tableauserverclient as TSC
22
import unittest
33
import requests
4+
import requests_mock
45

5-
from requests_mock import adapter, mock
6+
from unittest import mock
67
from requests.exceptions import MissingSchema
78

89

10+
# This method will be used by the mock to replace requests.get
11+
def mocked_requests_get(*args, **kwargs):
12+
class MockResponse:
13+
def __init__(self, status_code):
14+
self.content = (
15+
"<xml>"
16+
"<version version='0.31'>"
17+
"<api_version>0.31</api_version>"
18+
"<server_api_version>0.31</server_api_version>"
19+
"<product_version>2022.3</product_version>"
20+
"</version>"
21+
"</xml>"
22+
)
23+
self.status_code = status_code
24+
25+
return MockResponse(200)
26+
27+
928
class ServerTests(unittest.TestCase):
1029
def test_init_server_model_empty_throws(self):
1130
with self.assertRaises(TypeError):
1231
server = TSC.Server()
1332

14-
def test_init_server_model_bad_server_name_complains(self):
15-
# by default, it will just set the version to 2.3
33+
def test_init_server_model_no_protocol_defaults_htt(self):
1634
server = TSC.Server("fake-url")
1735

1836
def test_init_server_model_valid_server_name_works(self):
19-
# by default, it will just set the version to 2.3
2037
server = TSC.Server("http://fake-url")
2138

2239
def test_init_server_model_valid_https_server_name_works(self):
2340
# by default, it will just set the version to 2.3
2441
server = TSC.Server("https://fake-url")
2542

2643
def test_init_server_model_bad_server_name_not_version_check(self):
27-
# by default, it will just set the version to 2.3
2844
server = TSC.Server("fake-url", use_server_version=False)
2945

3046
def test_init_server_model_bad_server_name_do_version_check(self):
31-
with self.assertRaises(MissingSchema):
47+
with self.assertRaises(requests.exceptions.ConnectionError):
3248
server = TSC.Server("fake-url", use_server_version=True)
3349

3450
def test_init_server_model_bad_server_name_not_version_check_random_options(self):
35-
# by default, it will just set the version to 2.3
51+
# with self.assertRaises(MissingSchema):
3652
server = TSC.Server("fake-url", use_server_version=False, http_options={"foo": 1})
3753

3854
def test_init_server_model_bad_server_name_not_version_check_real_options(self):
55+
# with self.assertRaises(ValueError):
3956
server = TSC.Server("fake-url", use_server_version=False, http_options={"verify": False})
4057

4158
def test_http_options_skip_ssl_works(self):
@@ -62,6 +79,25 @@ def test_http_options_not_sequence_fails(self):
6279
with self.assertRaises(ValueError):
6380
server.add_http_options({1, 2, 3})
6481

82+
def test_validate_connection_http(self):
83+
url = "http://cookies.com"
84+
server = TSC.Server(url)
85+
server.validate_server_connection()
86+
self.assertEqual(url, server.server_address)
87+
88+
def test_validate_connection_https(self):
89+
url = "https://cookies.com"
90+
server = TSC.Server(url)
91+
server.validate_server_connection()
92+
self.assertEqual(url, server.server_address)
93+
94+
def test_validate_connection_no_protocol(self):
95+
url = "cookies.com"
96+
fixed_url = "http://cookies.com"
97+
server = TSC.Server(url)
98+
server.validate_server_connection()
99+
self.assertEqual(fixed_url, server.server_address)
100+
65101

66102
class SessionTests(unittest.TestCase):
67103
test_header = {"x-test": "true"}
@@ -74,6 +110,6 @@ def session_factory():
74110

75111
def test_session_factory_adds_headers(self):
76112
test_request_bin = "http://capture-this-with-mock.com"
77-
with mock() as m:
113+
with requests_mock.mock() as m:
78114
m.get(url="http://capture-this-with-mock.com/api/2.4/serverInfo", request_headers=SessionTests.test_header)
79115
server = TSC.Server(test_request_bin, use_server_version=True, session_factory=SessionTests.session_factory)

0 commit comments

Comments
 (0)
0