Coverage for fingerprint_server_sdk/rest.py: 60%
100 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-14 10:45 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-14 10:45 +0000
1"""
2Server API
3Fingerprint Server API allows you to get, search, and update Events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios.
4Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device.
5The API also supports collection of Automation Intelligence for requests to your server in edge, pre-origin, or middleware contexts.
7The version of the OpenAPI document: 4
8Contact: support@fingerprint.com
9Generated by OpenAPI Generator (https://openapi-generator.tech)
11Do not edit the class manually.
12""" # noqa: E501
14from __future__ import annotations
16import io
17import json
18import re
19import ssl
20from typing import TYPE_CHECKING, Any, Optional, Union
22import urllib3
24from fingerprint_server_sdk.exceptions import ApiException, ApiValueError
26if TYPE_CHECKING:
27 from fingerprint_server_sdk.configuration import Configuration
29SUPPORTED_SOCKS_PROXIES = {'socks5', 'socks5h', 'socks4', 'socks4a'}
30RESTResponseType = urllib3.HTTPResponse
33def is_socks_proxy_url(url: Optional[str]) -> bool:
34 if url is None:
35 return False
36 split_section = url.split('://')
37 if len(split_section) < 2:
38 return False
39 else:
40 return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES
43class RESTResponse(io.IOBase):
44 def __init__(self, resp: urllib3.HTTPResponse) -> None:
45 self.response = resp
46 self.status = resp.status
47 self.reason = resp.reason
48 self.data: Optional[bytes] = None
50 def read(self) -> bytes:
51 if self.data is None:
52 self.data = self.response.data
53 return self.data
55 @property
56 def headers(self) -> urllib3.HTTPHeaderDict:
57 """Returns a dictionary of response headers."""
58 return self.response.headers
60 def getheaders(self) -> urllib3.HTTPHeaderDict:
61 """Returns a dictionary of the response headers; use ``headers`` instead."""
62 return self.response.headers
64 def getheader(self, name: str, default: Optional[str] = None) -> Optional[str]:
65 """Returns a given response header; use ``headers.get()`` instead."""
66 return self.response.headers.get(name, default)
69class RESTClientObject:
70 def __init__(self, configuration: Configuration) -> None:
71 # urllib3.PoolManager will pass all kw parameters to connectionpool
72 # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
73 # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
74 # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
76 # cert_reqs
77 if configuration.verify_ssl:
78 cert_reqs = ssl.CERT_REQUIRED
79 else:
80 cert_reqs = ssl.CERT_NONE
82 pool_args: dict[str, Any] = {
83 'cert_reqs': cert_reqs,
84 'ca_certs': configuration.ssl_ca_cert,
85 'cert_file': configuration.cert_file,
86 'key_file': configuration.key_file,
87 'ca_cert_data': configuration.ca_cert_data,
88 }
89 if configuration.assert_hostname is not None:
90 pool_args['assert_hostname'] = configuration.assert_hostname
92 if configuration.retries is not None:
93 pool_args['retries'] = configuration.retries
95 if configuration.tls_server_name:
96 pool_args['server_hostname'] = configuration.tls_server_name
98 if configuration.socket_options is not None:
99 pool_args['socket_options'] = configuration.socket_options
101 if configuration.connection_pool_maxsize is not None:
102 pool_args['maxsize'] = configuration.connection_pool_maxsize
104 # https pool manager
105 self.pool_manager: urllib3.PoolManager
107 if configuration.proxy:
108 if is_socks_proxy_url(configuration.proxy):
109 from urllib3.contrib.socks import SOCKSProxyManager
111 pool_args['proxy_url'] = configuration.proxy
112 pool_args['headers'] = configuration.proxy_headers
113 self.pool_manager = SOCKSProxyManager(**pool_args)
114 else:
115 pool_args['proxy_url'] = configuration.proxy
116 pool_args['proxy_headers'] = configuration.proxy_headers
117 self.pool_manager = urllib3.ProxyManager(**pool_args)
118 else:
119 self.pool_manager = urllib3.PoolManager(**pool_args)
121 def request(
122 self,
123 method: str,
124 url: str,
125 headers: Optional[dict[str, str]] = None,
126 body: Optional[Any] = None,
127 post_params: Optional[list[tuple[str, Any]]] = None,
128 _request_timeout: Optional[Union[float, tuple[float, float]]] = None,
129 ) -> RESTResponse:
130 """Perform requests.
132 :param method: http request method
133 :param url: http request url
134 :param headers: http request headers
135 :param body: request json body, for `application/json`
136 :param post_params: request post parameters,
137 `application/x-www-form-urlencoded`
138 and `multipart/form-data`
139 :param _request_timeout: timeout setting for this request. If one
140 number provided, it will be total request
141 timeout. It can also be a pair (tuple) of
142 (connection, read) timeouts.
143 """
144 method = method.upper()
145 assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH', 'OPTIONS']
147 if post_params and body:
148 raise ApiValueError('body parameter cannot be used with post_params parameter.')
150 post_params = post_params or []
151 headers = headers or {}
153 timeout = None
154 if _request_timeout:
155 if isinstance(_request_timeout, (int, float)):
156 timeout = urllib3.Timeout(total=_request_timeout)
157 elif isinstance(_request_timeout, tuple) and len(_request_timeout) == 2:
158 timeout = urllib3.Timeout(connect=_request_timeout[0], read=_request_timeout[1])
160 try:
161 # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
162 if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
163 # no content type provided or payload is json
164 content_type = headers.get('Content-Type')
165 if not content_type or re.search('json', content_type, re.IGNORECASE):
166 request_body = None
167 if body is not None:
168 request_body = json.dumps(body)
169 r = self.pool_manager.request(
170 method,
171 url,
172 body=request_body,
173 timeout=timeout,
174 headers=headers,
175 preload_content=False,
176 )
177 elif content_type == 'application/x-www-form-urlencoded':
178 r = self.pool_manager.request(
179 method,
180 url,
181 fields=post_params,
182 encode_multipart=False,
183 timeout=timeout,
184 headers=headers,
185 preload_content=False,
186 )
187 elif content_type == 'multipart/form-data':
188 # must del headers['Content-Type'], or the correct
189 # Content-Type which generated by urllib3 will be
190 # overwritten.
191 del headers['Content-Type']
192 # Ensures that dict objects are serialized
193 post_params = [
194 (a, json.dumps(b)) if isinstance(b, dict) else (a, b)
195 for a, b in post_params
196 ]
197 r = self.pool_manager.request(
198 method,
199 url,
200 fields=post_params,
201 encode_multipart=True,
202 timeout=timeout,
203 headers=headers,
204 preload_content=False,
205 )
206 # Pass a `string` parameter directly in the body to support
207 # other content types than JSON when `body` argument is
208 # provided in serialized form.
209 elif isinstance(body, (str, bytes)):
210 r = self.pool_manager.request(
211 method,
212 url,
213 body=body,
214 timeout=timeout,
215 headers=headers,
216 preload_content=False,
217 )
218 elif headers['Content-Type'].startswith('text/') and isinstance(body, bool):
219 request_body = 'true' if body else 'false'
220 r = self.pool_manager.request(
221 method,
222 url,
223 body=request_body,
224 preload_content=False,
225 timeout=timeout,
226 headers=headers,
227 )
228 else:
229 # Cannot generate the request from given parameters
230 msg = """Cannot prepare a request message for provided
231 arguments. Please check that your arguments match
232 declared content type."""
233 raise ApiException(status=0, reason=msg)
234 # For `GET`, `HEAD`
235 else:
236 r = self.pool_manager.request(
237 method, url, fields={}, timeout=timeout, headers=headers, preload_content=False
238 )
239 except urllib3.exceptions.SSLError as e:
240 msg = '\n'.join([type(e).__name__, str(e)])
241 raise ApiException(status=0, reason=msg) from e
243 return RESTResponse(r) # type: ignore[arg-type]