-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhttp_client.py
184 lines (147 loc) · 6.35 KB
/
http_client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
"""Helper utilities for making HTTP requests to the Volatility API.
This module provides functions for making HTTP requests to the Volatility API
with error handling and response processing.
"""
import requests
import logging
from typing import List, Dict, Optional, Any
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class HttpClient:
"""
Handle HTTP requests with built-in error handling.
Args:
timeout: Request timeout in seconds, defaults to DEFAULT_TIMEOUT
"""
DEFAULT_TIMEOUT = 30
def __init__(self, timeout: int = DEFAULT_TIMEOUT):
"""
Initialize HTTP client with specified timeout.
Args:
timeout: Request timeout in seconds
"""
self.timeout = timeout
@staticmethod
def _handle_request_error(e: Exception) -> List[str]:
"""
Handle exceptions during HTTP requests and return error message.
Args:
e: Exception that occurred during request
Returns:
List[str]: List containing error message
"""
error_msg = f"Request failed: {str(e)}"
logger.error(error_msg, exc_info=True)
return [error_msg]
@staticmethod
def _process_response(response: requests.Response) -> List[str]:
"""
Process HTTP response and extract content as list of strings.
Args:
response: Response object from requests
Returns:
List[str]: Response content split into lines
"""
response.encoding = 'utf-8'
logger.info(f"Response status: {response.status_code}")
if not response.ok:
error_msg = f"Error {response.status_code}: {response.text.strip()}"
logger.error(error_msg)
return [error_msg]
# Try to parse as JSON
try:
json_data = response.json()
# For text-based responses in JSON, extract and return as lines
if isinstance(json_data, dict) and any(isinstance(v, str) and '\n' in v for v in json_data.values()):
# Find the first string value that contains newlines and return it split
for value in json_data.values():
if isinstance(value, str) and '\n' in value:
return value.splitlines()
# Otherwise return the JSON as a single-item list
return [str(json_data)]
except ValueError:
# Not JSON, return text
return response.text.splitlines()
def _execute_request(self, url: str, method: str, params: Dict[str, Any], data: Optional[Dict[str, Any]]) -> List[str]:
"""
Execute HTTP request with given parameters and return response content.
Args:
url: Full URL for the request
method: HTTP method to use
params: Query parameters for the request
data: Body data for POST requests
Returns:
List[str]: Response content split into lines
Raises:
Exception: If request fails or receives invalid response
"""
try:
if method.upper() == "GET":
response = requests.get(url, params=params, timeout=self.timeout)
elif method.upper() == "POST":
response = requests.post(url, json=data, params=params, timeout=self.timeout)
else:
return [f"Unsupported HTTP method: {method}"]
return self._process_response(response)
except Exception as e:
return self._handle_request_error(e)
def request(self, base_url: str, endpoint: str, method: str = "GET",
params: Optional[Dict[str, Any]] = None,
data: Optional[Dict[str, Any]] = None) -> List[str]:
"""
Perform an HTTP request with error handling.
Args:
base_url: Base URL of the API
endpoint: API endpoint to call
method: HTTP method (GET, POST, etc.)
params: Query parameters for requests
data: Body data for POST requests
Returns:
List[str]: Response content split into lines
Raises:
Exception: If request fails or receives invalid response
"""
params = params or {}
url = f"{base_url}/{endpoint}"
logger.info(f"Making {method} request to: {url}")
return self._execute_request(url, method, params, data)
def get(self, base_url: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> List[str]:
"""
Perform a GET request using instance method.
Args:
base_url: Base URL of the API
endpoint: API endpoint to call
params: Query parameters for the request
Returns:
List[str]: Response content split into lines
"""
return self.request(base_url, endpoint, method="GET", params=params)
@staticmethod
def http_get(base_url: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> List[str]:
"""
Perform a GET request using a new client instance.
Args:
base_url: Base URL of the API
endpoint: API endpoint to call
params: Query parameters for the request
Returns:
List[str]: Response content split into lines
"""
client = HttpClient()
return client.get(base_url, endpoint, params=params)
@staticmethod
def http_post(base_url: str, endpoint: str, data: Optional[Dict[str, Any]] = None,
params: Optional[Dict[str, Any]] = None) -> List[str]:
"""
Perform a POST request using a new client instance.
Args:
base_url: Base URL of the API
endpoint: API endpoint to call
data: Body data for POST request
params: Query parameters for the request
Returns:
List[str]: Response content split into lines
"""
client = HttpClient()
return client.request(base_url, endpoint, method="POST", params=params, data=data)