pyproxytools 0.4.1__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyproxytools-0.4.1/pyproxytools.egg-info → pyproxytools-0.4.3}/PKG-INFO +7 -1
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/README.md +6 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/__init__.py +1 -1
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/handlers/client.py +30 -43
- pyproxytools-0.4.3/pyproxy/handlers/http.py +267 -0
- pyproxytools-0.4.3/pyproxy/handlers/https.py +402 -0
- pyproxytools-0.4.3/pyproxy/pyproxy.py +159 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/server.py +80 -48
- pyproxytools-0.4.3/pyproxy/utils/config.py +102 -0
- pyproxytools-0.4.3/pyproxy/utils/http_req.py +24 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/utils/logger.py +24 -3
- {pyproxytools-0.4.1 → pyproxytools-0.4.3/pyproxytools.egg-info}/PKG-INFO +7 -1
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxytools.egg-info/SOURCES.txt +0 -1
- pyproxytools-0.4.3/tests/utils/test_http_req.py +39 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/utils/test_logger.py +15 -6
- pyproxytools-0.4.1/pyproxy/handlers/http.py +0 -197
- pyproxytools-0.4.1/pyproxy/handlers/https.py +0 -308
- pyproxytools-0.4.1/pyproxy/pyproxy.py +0 -120
- pyproxytools-0.4.1/pyproxy/utils/config.py +0 -124
- pyproxytools-0.4.1/pyproxy/utils/http_req.py +0 -53
- pyproxytools-0.4.1/pyproxy/utils/version.py +0 -0
- pyproxytools-0.4.1/tests/utils/test_http_req.py +0 -69
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/LICENSE +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/benchmark/benchmark.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/benchmark/utils/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/benchmark/utils/html.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/benchmark/utils/req.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproject.toml +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/__main__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/handlers/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/modules/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/modules/cancel_inspect.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/modules/custom_header.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/modules/filter.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/modules/shortcuts.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/monitoring/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/monitoring/web.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/utils/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/utils/args.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxy/utils/crypto.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxytools.egg-info/dependency_links.txt +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxytools.egg-info/entry_points.txt +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxytools.egg-info/requires.txt +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/pyproxytools.egg-info/top_level.txt +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/requirements.txt +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/setup.cfg +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/setup.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/modules/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/modules/test_cancel_inspect.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/modules/test_custom_header.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/modules/test_filter.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/modules/test_shortcuts.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/utils/__init__.py +0 -0
- {pyproxytools-0.4.1 → pyproxytools-0.4.3}/tests/utils/test_crypto.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyproxytools
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Lightweight and fast python web proxy
|
|
5
5
|
Author: 6C656C65
|
|
6
6
|
License-Expression: MIT
|
|
@@ -93,6 +93,12 @@ docker run -d ghcr.io/6c656c65/pyproxy:latest
|
|
|
93
93
|
```
|
|
94
94
|
You can use slim images by adding `-slim` to the end of the tags
|
|
95
95
|
|
|
96
|
+
### Install with Compose
|
|
97
|
+
```bash
|
|
98
|
+
wget https://raw.githubusercontent.com/6C656C65/pyproxy/main/docker-compose.yml
|
|
99
|
+
docker-compose up -d
|
|
100
|
+
```
|
|
101
|
+
|
|
96
102
|
## 🚀 **Usage**
|
|
97
103
|
|
|
98
104
|
### Start the proxy
|
|
@@ -60,6 +60,12 @@ docker run -d ghcr.io/6c656c65/pyproxy:latest
|
|
|
60
60
|
```
|
|
61
61
|
You can use slim images by adding `-slim` to the end of the tags
|
|
62
62
|
|
|
63
|
+
### Install with Compose
|
|
64
|
+
```bash
|
|
65
|
+
wget https://raw.githubusercontent.com/6C656C65/pyproxy/main/docker-compose.yml
|
|
66
|
+
docker-compose up -d
|
|
67
|
+
```
|
|
68
|
+
|
|
63
69
|
## 🚀 **Usage**
|
|
64
70
|
|
|
65
71
|
### Start the proxy
|
|
@@ -39,9 +39,7 @@ class ProxyHandlers:
|
|
|
39
39
|
shortcuts,
|
|
40
40
|
custom_header,
|
|
41
41
|
active_connections,
|
|
42
|
-
|
|
43
|
-
proxy_host,
|
|
44
|
-
proxy_port,
|
|
42
|
+
proxy_config,
|
|
45
43
|
):
|
|
46
44
|
self.html_403 = html_403
|
|
47
45
|
self.logger_config = logger_config
|
|
@@ -58,11 +56,32 @@ class ProxyHandlers:
|
|
|
58
56
|
self.console_logger = console_logger
|
|
59
57
|
self.config_shortcuts = shortcuts
|
|
60
58
|
self.config_custom_header = custom_header
|
|
61
|
-
self.
|
|
62
|
-
self.proxy_host = proxy_host
|
|
63
|
-
self.proxy_port = proxy_port
|
|
59
|
+
self.proxy_config = proxy_config
|
|
64
60
|
self.active_connections = active_connections
|
|
65
61
|
|
|
62
|
+
def _create_handler(self, handler_class, **extra_kwargs):
|
|
63
|
+
"""
|
|
64
|
+
Factory to create handler instance with shared common parameters.
|
|
65
|
+
"""
|
|
66
|
+
params = dict(
|
|
67
|
+
html_403=self.html_403,
|
|
68
|
+
logger_config=self.logger_config,
|
|
69
|
+
filter_config=self.filter_config,
|
|
70
|
+
filter_queue=self.filter_queue,
|
|
71
|
+
filter_result_queue=self.filter_result_queue,
|
|
72
|
+
shortcuts_queue=self.shortcuts_queue,
|
|
73
|
+
shortcuts_result_queue=self.shortcuts_result_queue,
|
|
74
|
+
custom_header_queue=self.custom_header_queue,
|
|
75
|
+
custom_header_result_queue=self.custom_header_result_queue,
|
|
76
|
+
console_logger=self.console_logger,
|
|
77
|
+
shortcuts=self.config_shortcuts,
|
|
78
|
+
custom_header=self.config_custom_header,
|
|
79
|
+
proxy_config=self.proxy_config,
|
|
80
|
+
active_connections=self.active_connections,
|
|
81
|
+
)
|
|
82
|
+
params.update(extra_kwargs)
|
|
83
|
+
return handler_class(**params)
|
|
84
|
+
|
|
66
85
|
def handle_client(self, client_socket):
|
|
67
86
|
"""
|
|
68
87
|
Handles an incoming client connection by processing the request and forwarding
|
|
@@ -82,45 +101,13 @@ class ProxyHandlers:
|
|
|
82
101
|
first_line = request.decode(errors="ignore").split("\n")[0]
|
|
83
102
|
|
|
84
103
|
if first_line.startswith("CONNECT"):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
logger_config=self.logger_config,
|
|
88
|
-
filter_config=self.filter_config,
|
|
104
|
+
https_handler = self._create_handler(
|
|
105
|
+
HttpsHandler,
|
|
89
106
|
ssl_config=self.ssl_config,
|
|
90
|
-
filter_queue=self.filter_queue,
|
|
91
|
-
filter_result_queue=self.filter_result_queue,
|
|
92
|
-
shortcuts_queue=self.shortcuts_queue,
|
|
93
|
-
shortcuts_result_queue=self.shortcuts_result_queue,
|
|
94
107
|
cancel_inspect_queue=self.cancel_inspect_queue,
|
|
95
108
|
cancel_inspect_result_queue=self.cancel_inspect_result_queue,
|
|
96
|
-
custom_header_queue=self.custom_header_queue,
|
|
97
|
-
custom_header_result_queue=self.custom_header_result_queue,
|
|
98
|
-
console_logger=self.console_logger,
|
|
99
|
-
shortcuts=self.config_shortcuts,
|
|
100
|
-
custom_header=self.config_custom_header,
|
|
101
|
-
proxy_enable=self.proxy_enable,
|
|
102
|
-
proxy_host=self.proxy_host,
|
|
103
|
-
proxy_port=self.proxy_port,
|
|
104
|
-
active_connections=self.active_connections,
|
|
105
109
|
)
|
|
106
|
-
|
|
110
|
+
https_handler.handle_https_connection(client_socket, first_line)
|
|
107
111
|
else:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
logger_config=self.logger_config,
|
|
111
|
-
filter_config=self.filter_config,
|
|
112
|
-
filter_queue=self.filter_queue,
|
|
113
|
-
filter_result_queue=self.filter_result_queue,
|
|
114
|
-
shortcuts_queue=self.shortcuts_queue,
|
|
115
|
-
shortcuts_result_queue=self.shortcuts_result_queue,
|
|
116
|
-
custom_header_queue=self.custom_header_queue,
|
|
117
|
-
custom_header_result_queue=self.custom_header_result_queue,
|
|
118
|
-
console_logger=self.console_logger,
|
|
119
|
-
shortcuts=self.config_shortcuts,
|
|
120
|
-
custom_header=self.config_custom_header,
|
|
121
|
-
proxy_enable=self.proxy_enable,
|
|
122
|
-
proxy_host=self.proxy_host,
|
|
123
|
-
proxy_port=self.proxy_port,
|
|
124
|
-
active_connections=self.active_connections,
|
|
125
|
-
)
|
|
126
|
-
client_http_handler.handle_http_request(client_socket, request)
|
|
112
|
+
http_handler = self._create_handler(HttpHandler)
|
|
113
|
+
http_handler.handle_http_request(client_socket, request)
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyproxy.handlers.http.py
|
|
3
|
+
|
|
4
|
+
This module defines the HttpHandler class used by the proxy server to process
|
|
5
|
+
HTTP client connections. It handles request forwarding, blocking, and custom headers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import socket
|
|
9
|
+
import os
|
|
10
|
+
import threading
|
|
11
|
+
from urllib.parse import urlparse
|
|
12
|
+
|
|
13
|
+
from pyproxy.utils.http_req import extract_headers
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HttpHandler:
|
|
17
|
+
"""
|
|
18
|
+
HttpHandler manages client HTTP connections for a proxy server,
|
|
19
|
+
handling request forwarding, filtering, blocking, and custom header modification
|
|
20
|
+
based on configuration settings.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
html_403,
|
|
26
|
+
logger_config,
|
|
27
|
+
filter_config,
|
|
28
|
+
filter_queue,
|
|
29
|
+
filter_result_queue,
|
|
30
|
+
shortcuts_queue,
|
|
31
|
+
shortcuts_result_queue,
|
|
32
|
+
custom_header_queue,
|
|
33
|
+
custom_header_result_queue,
|
|
34
|
+
console_logger,
|
|
35
|
+
shortcuts,
|
|
36
|
+
custom_header,
|
|
37
|
+
active_connections,
|
|
38
|
+
proxy_config,
|
|
39
|
+
):
|
|
40
|
+
self.html_403 = html_403
|
|
41
|
+
self.logger_config = logger_config
|
|
42
|
+
self.filter_config = filter_config
|
|
43
|
+
self.filter_queue = filter_queue
|
|
44
|
+
self.filter_result_queue = filter_result_queue
|
|
45
|
+
self.shortcuts_queue = shortcuts_queue
|
|
46
|
+
self.shortcuts_result_queue = shortcuts_result_queue
|
|
47
|
+
self.custom_header_queue = custom_header_queue
|
|
48
|
+
self.custom_header_result_queue = custom_header_result_queue
|
|
49
|
+
self.console_logger = console_logger
|
|
50
|
+
self.config_shortcuts = shortcuts
|
|
51
|
+
self.config_custom_header = custom_header
|
|
52
|
+
self.proxy_config = proxy_config
|
|
53
|
+
self.active_connections = active_connections
|
|
54
|
+
|
|
55
|
+
def _get_modified_headers(self, url, request_text):
|
|
56
|
+
"""
|
|
57
|
+
Extract headers from a request
|
|
58
|
+
"""
|
|
59
|
+
headers = extract_headers(request_text)
|
|
60
|
+
self.custom_header_queue.put(url)
|
|
61
|
+
try:
|
|
62
|
+
new_headers = self.custom_header_result_queue.get(timeout=5)
|
|
63
|
+
headers.update(new_headers)
|
|
64
|
+
except Exception:
|
|
65
|
+
self.console_logger.warning(
|
|
66
|
+
"Timeout while getting custom headers for %s", url
|
|
67
|
+
)
|
|
68
|
+
return headers
|
|
69
|
+
|
|
70
|
+
def _rebuild_http_request(self, request_line, headers, body=""):
|
|
71
|
+
"""
|
|
72
|
+
Reconstructs an HTTP request with the new headers.
|
|
73
|
+
"""
|
|
74
|
+
header_lines = [f"{key}: {value}" for key, value in headers.items()]
|
|
75
|
+
reconstructed_headers = "\r\n".join(header_lines)
|
|
76
|
+
return f"{request_line}\r\n{reconstructed_headers}\r\n\r\n{body}".encode()
|
|
77
|
+
|
|
78
|
+
def _apply_shortcut(self, url: str) -> str | None:
|
|
79
|
+
"""
|
|
80
|
+
Checks if a shortcut is defined for the given domain.
|
|
81
|
+
"""
|
|
82
|
+
if self.config_shortcuts and os.path.isfile(self.config_shortcuts):
|
|
83
|
+
parsed_url = urlparse(url)
|
|
84
|
+
domain = parsed_url.hostname
|
|
85
|
+
self.shortcuts_queue.put(domain)
|
|
86
|
+
try:
|
|
87
|
+
return self.shortcuts_result_queue.get(timeout=5)
|
|
88
|
+
except Exception:
|
|
89
|
+
self.console_logger.warning(
|
|
90
|
+
"Timeout while getting shortcut for %s", url
|
|
91
|
+
)
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
def _is_blocked(self, url: str) -> bool:
|
|
95
|
+
"""
|
|
96
|
+
Checks if a URL is blocked by the configuration filter.
|
|
97
|
+
"""
|
|
98
|
+
if not self.filter_config.no_filter:
|
|
99
|
+
self.filter_queue.put(url)
|
|
100
|
+
try:
|
|
101
|
+
result = self.filter_result_queue.get(timeout=5)
|
|
102
|
+
return result[1] == "Blocked"
|
|
103
|
+
except Exception:
|
|
104
|
+
self.console_logger.warning("Timeout while filtering %s", url)
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
def _send_403(self, client_socket, url, first_line):
|
|
108
|
+
"""
|
|
109
|
+
Sends an HTTP 403 Forbidden response to the client.
|
|
110
|
+
"""
|
|
111
|
+
if not self.logger_config.no_logging_block:
|
|
112
|
+
method, domain_port, protocol = first_line.split(" ")
|
|
113
|
+
domain, port = domain_port.split(":")
|
|
114
|
+
self.logger_config.block_logger.info(
|
|
115
|
+
"",
|
|
116
|
+
extra={
|
|
117
|
+
"ip_src": client_socket.getpeername()[0],
|
|
118
|
+
"url": url,
|
|
119
|
+
"method": method,
|
|
120
|
+
"domain": domain,
|
|
121
|
+
"port": port,
|
|
122
|
+
"protocol": protocol,
|
|
123
|
+
},
|
|
124
|
+
)
|
|
125
|
+
with open(self.html_403, "r", encoding="utf-8") as f:
|
|
126
|
+
custom_403_page = f.read()
|
|
127
|
+
response = (
|
|
128
|
+
f"HTTP/1.1 403 Forbidden\r\n"
|
|
129
|
+
f"Content-Length: {len(custom_403_page)}\r\n"
|
|
130
|
+
f"\r\n"
|
|
131
|
+
f"{custom_403_page}"
|
|
132
|
+
)
|
|
133
|
+
client_socket.sendall(response.encode())
|
|
134
|
+
client_socket.close()
|
|
135
|
+
self.active_connections.pop(threading.get_ident(), None)
|
|
136
|
+
|
|
137
|
+
def handle_http_request(self, client_socket, request):
|
|
138
|
+
"""
|
|
139
|
+
Processes an HTTP request, checks for URL filtering, applies shortcuts,
|
|
140
|
+
and forwards the request to the target server if not blocked.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
client_socket (socket): The socket object for the client connection.
|
|
144
|
+
request (bytes): The raw HTTP request sent by the client.
|
|
145
|
+
"""
|
|
146
|
+
first_line = request.decode(errors="ignore").split("\n")[0]
|
|
147
|
+
url = first_line.split(" ")[1]
|
|
148
|
+
|
|
149
|
+
if self.config_shortcuts and os.path.isfile(self.config_shortcuts):
|
|
150
|
+
shortcut_url = self._apply_shortcut(url)
|
|
151
|
+
if shortcut_url:
|
|
152
|
+
response = (
|
|
153
|
+
f"HTTP/1.1 302 Found\r\n"
|
|
154
|
+
f"Location: {shortcut_url}\r\n"
|
|
155
|
+
f"Content-Length: 0\r\n"
|
|
156
|
+
"\r\n"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
client_socket.sendall(response.encode())
|
|
160
|
+
client_socket.close()
|
|
161
|
+
self.active_connections.pop(threading.get_ident(), None)
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
if self._is_blocked(url):
|
|
165
|
+
self._send_403(client_socket, url, first_line)
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
if self.config_custom_header and os.path.isfile(self.config_custom_header):
|
|
169
|
+
request_text = request.decode(errors="ignore")
|
|
170
|
+
request_lines = request_text.split("\r\n")
|
|
171
|
+
headers = self._get_modified_headers(url, request_text)
|
|
172
|
+
request_line = request_lines[0]
|
|
173
|
+
body = (
|
|
174
|
+
request_text.split("\r\n\r\n", 1)[1]
|
|
175
|
+
if "\r\n\r\n" in request_text
|
|
176
|
+
else ""
|
|
177
|
+
)
|
|
178
|
+
modified_request = self._rebuild_http_request(request_line, headers, body)
|
|
179
|
+
|
|
180
|
+
self.forward_request_to_server(
|
|
181
|
+
client_socket, modified_request, url, first_line
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
else:
|
|
185
|
+
self.forward_request_to_server(client_socket, request, url, first_line)
|
|
186
|
+
|
|
187
|
+
def forward_request_to_server(self, client_socket, request, url, first_line):
|
|
188
|
+
"""
|
|
189
|
+
Forwards the HTTP request to the target server and sends the response back to the client.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
client_socket (socket): The socket object for the client connection.
|
|
193
|
+
request (bytes): The raw HTTP request sent by the client.
|
|
194
|
+
url (str): The target URL from the HTTP request.
|
|
195
|
+
first_line (str): The first line of the HTTP request (e.g., "GET / HTTP/1.1").
|
|
196
|
+
"""
|
|
197
|
+
if self.proxy_config.enable:
|
|
198
|
+
server_host, server_port = self.proxy_config.host, self.proxy_config.port
|
|
199
|
+
else:
|
|
200
|
+
parsed_url = urlparse(url)
|
|
201
|
+
server_host = parsed_url.hostname
|
|
202
|
+
server_port = parsed_url.port or (
|
|
203
|
+
443 if parsed_url.scheme == "https" else 80
|
|
204
|
+
)
|
|
205
|
+
thread_id = threading.get_ident()
|
|
206
|
+
|
|
207
|
+
if thread_id in self.active_connections:
|
|
208
|
+
self.active_connections[thread_id] = {
|
|
209
|
+
"target_ip": server_host,
|
|
210
|
+
"target_port": server_port,
|
|
211
|
+
"bytes_sent": 0,
|
|
212
|
+
"bytes_received": 0,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
217
|
+
server_socket.connect((server_host, server_port))
|
|
218
|
+
server_socket.sendall(request)
|
|
219
|
+
server_socket.settimeout(5)
|
|
220
|
+
self.active_connections[thread_id]["bytes_sent"] += len(request)
|
|
221
|
+
|
|
222
|
+
while True:
|
|
223
|
+
try:
|
|
224
|
+
response = server_socket.recv(4096)
|
|
225
|
+
if response:
|
|
226
|
+
client_socket.send(response)
|
|
227
|
+
self.active_connections[thread_id]["bytes_received"] += len(
|
|
228
|
+
response
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
break
|
|
232
|
+
except socket.timeout:
|
|
233
|
+
break
|
|
234
|
+
except (socket.timeout, socket.gaierror, ConnectionRefusedError, OSError) as e:
|
|
235
|
+
self.console_logger.error(
|
|
236
|
+
"Error connecting to the server %s : %s", server_host, e
|
|
237
|
+
)
|
|
238
|
+
response = (
|
|
239
|
+
f"HTTP/1.1 502 Bad Gateway\r\n"
|
|
240
|
+
f"Content-Length: {len('Bad Gateway')} \r\n"
|
|
241
|
+
"\r\n"
|
|
242
|
+
f"Bad Gateway"
|
|
243
|
+
)
|
|
244
|
+
client_socket.sendall(response.encode())
|
|
245
|
+
client_socket.close()
|
|
246
|
+
self.active_connections.pop(thread_id, None)
|
|
247
|
+
finally:
|
|
248
|
+
if not self.logger_config.no_logging_access:
|
|
249
|
+
method, url, protocol = first_line.split(" ")
|
|
250
|
+
|
|
251
|
+
conn_data = self.active_connections.get(thread_id, {})
|
|
252
|
+
self.logger_config.access_logger.info(
|
|
253
|
+
"",
|
|
254
|
+
extra={
|
|
255
|
+
"ip_src": client_socket.getpeername()[0],
|
|
256
|
+
"url": f"http://{server_host}",
|
|
257
|
+
"method": method,
|
|
258
|
+
"domain": parsed_url.hostname,
|
|
259
|
+
"port": parsed_url.port,
|
|
260
|
+
"protocol": protocol,
|
|
261
|
+
"bytes_sent": conn_data.get("bytes_sent", 0),
|
|
262
|
+
"bytes_received": conn_data.get("bytes_received", 0),
|
|
263
|
+
},
|
|
264
|
+
)
|
|
265
|
+
client_socket.close()
|
|
266
|
+
server_socket.close()
|
|
267
|
+
self.active_connections.pop(thread_id, None)
|