pyproxytools 0.4.1__tar.gz → 0.5.1__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.
Files changed (67) hide show
  1. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/LICENSE +1 -1
  2. pyproxytools-0.5.1/MANIFEST.in +2 -0
  3. {pyproxytools-0.4.1/pyproxytools.egg-info → pyproxytools-0.5.1}/PKG-INFO +36 -23
  4. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/README.md +25 -14
  5. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproject.toml +25 -3
  6. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/__init__.py +1 -1
  7. pyproxytools-0.5.1/pyproxy/handlers/client.py +114 -0
  8. pyproxytools-0.5.1/pyproxy/handlers/http.py +257 -0
  9. pyproxytools-0.5.1/pyproxy/handlers/https.py +408 -0
  10. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/modules/filter.py +6 -17
  11. pyproxytools-0.5.1/pyproxy/monitoring/__init__.py +57 -0
  12. pyproxytools-0.5.1/pyproxy/monitoring/auth.py +31 -0
  13. pyproxytools-0.5.1/pyproxy/monitoring/messages.pot +235 -0
  14. pyproxytools-0.5.1/pyproxy/monitoring/monitor.py +196 -0
  15. pyproxytools-0.5.1/pyproxy/monitoring/routes.py +253 -0
  16. pyproxytools-0.5.1/pyproxy/monitoring/translations/en/LC_MESSAGES/messages.mo +0 -0
  17. pyproxytools-0.5.1/pyproxy/monitoring/translations/en/LC_MESSAGES/messages.po +248 -0
  18. pyproxytools-0.5.1/pyproxy/monitoring/translations/fr/LC_MESSAGES/messages.mo +0 -0
  19. pyproxytools-0.5.1/pyproxy/monitoring/translations/fr/LC_MESSAGES/messages.po +248 -0
  20. pyproxytools-0.5.1/pyproxy/pyproxy.py +145 -0
  21. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/server.py +84 -70
  22. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/utils/args.py +10 -30
  23. pyproxytools-0.5.1/pyproxy/utils/config.py +102 -0
  24. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/utils/crypto.py +1 -3
  25. pyproxytools-0.5.1/pyproxy/utils/http_req.py +24 -0
  26. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/utils/logger.py +22 -3
  27. {pyproxytools-0.4.1 → pyproxytools-0.5.1/pyproxytools.egg-info}/PKG-INFO +36 -23
  28. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxytools.egg-info/SOURCES.txt +9 -6
  29. pyproxytools-0.5.1/pyproxytools.egg-info/requires.txt +8 -0
  30. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxytools.egg-info/top_level.txt +0 -1
  31. pyproxytools-0.5.1/requirements.txt +8 -0
  32. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/setup.py +3 -1
  33. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/modules/test_filter.py +2 -6
  34. pyproxytools-0.5.1/tests/utils/test_http_req.py +39 -0
  35. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/utils/test_logger.py +15 -6
  36. pyproxytools-0.4.1/benchmark/benchmark.py +0 -165
  37. pyproxytools-0.4.1/benchmark/utils/html.py +0 -179
  38. pyproxytools-0.4.1/benchmark/utils/req.py +0 -43
  39. pyproxytools-0.4.1/pyproxy/handlers/client.py +0 -126
  40. pyproxytools-0.4.1/pyproxy/handlers/http.py +0 -197
  41. pyproxytools-0.4.1/pyproxy/handlers/https.py +0 -308
  42. pyproxytools-0.4.1/pyproxy/monitoring/web.py +0 -279
  43. pyproxytools-0.4.1/pyproxy/pyproxy.py +0 -120
  44. pyproxytools-0.4.1/pyproxy/utils/config.py +0 -124
  45. pyproxytools-0.4.1/pyproxy/utils/http_req.py +0 -53
  46. pyproxytools-0.4.1/pyproxy/utils/version.py +0 -0
  47. pyproxytools-0.4.1/pyproxytools.egg-info/requires.txt +0 -7
  48. pyproxytools-0.4.1/requirements.txt +0 -7
  49. pyproxytools-0.4.1/tests/modules/__init__.py +0 -0
  50. pyproxytools-0.4.1/tests/utils/__init__.py +0 -0
  51. pyproxytools-0.4.1/tests/utils/test_http_req.py +0 -69
  52. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/__main__.py +0 -0
  53. {pyproxytools-0.4.1/benchmark/utils → pyproxytools-0.5.1/pyproxy/handlers}/__init__.py +0 -0
  54. {pyproxytools-0.4.1/pyproxy/handlers → pyproxytools-0.5.1/pyproxy/modules}/__init__.py +0 -0
  55. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/modules/cancel_inspect.py +0 -0
  56. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/modules/custom_header.py +0 -0
  57. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxy/modules/shortcuts.py +0 -0
  58. {pyproxytools-0.4.1/pyproxy/modules → pyproxytools-0.5.1/pyproxy/utils}/__init__.py +0 -0
  59. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxytools.egg-info/dependency_links.txt +0 -0
  60. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/pyproxytools.egg-info/entry_points.txt +0 -0
  61. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/setup.cfg +0 -0
  62. {pyproxytools-0.4.1/pyproxy/monitoring → pyproxytools-0.5.1/tests/modules}/__init__.py +0 -0
  63. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/modules/test_cancel_inspect.py +0 -0
  64. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/modules/test_custom_header.py +0 -0
  65. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/modules/test_shortcuts.py +0 -0
  66. {pyproxytools-0.4.1/pyproxy → pyproxytools-0.5.1/tests}/utils/__init__.py +0 -0
  67. {pyproxytools-0.4.1 → pyproxytools-0.5.1}/tests/utils/test_crypto.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 6C656C65
3
+ Copyright (c) 2025 pyproxytools
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,2 @@
1
+ include pyproxy/monitoring/messages.pot
2
+ recursive-include pyproxy/monitoring/translations *
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyproxytools
3
- Version: 0.4.1
3
+ Version: 0.5.1
4
4
  Summary: Lightweight and fast python web proxy
5
- Author: 6C656C65
5
+ Author: pyproxytools
6
6
  License-Expression: MIT
7
- Project-URL: Documentation, https://github.com/6C656C65/pyproxy/wiki
8
- Project-URL: Issue tracker, https://github.com/6C656C65/pyproxy/issues
7
+ Project-URL: Documentation, https://pyproxytools.github.io/pyproxy-docs/
8
+ Project-URL: Issue tracker, https://github.com/pyproxytools/pyproxy/issues
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Natural Language :: English
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
18
19
  Classifier: Topic :: Internet
19
20
  Classifier: Topic :: Software Development :: Libraries
20
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -22,12 +23,13 @@ Classifier: Topic :: Utilities
22
23
  Classifier: Typing :: Typed
23
24
  Description-Content-Type: text/markdown
24
25
  License-File: LICENSE
25
- Requires-Dist: rich-argparse>=1.7.0
26
- Requires-Dist: pyOpenSSL>=25.0.0
27
- Requires-Dist: requests>=2.31.0
28
- Requires-Dist: Flask>=3.1.0
26
+ Requires-Dist: rich-argparse>=1.7.1
27
+ Requires-Dist: pyOpenSSL>=25.3.0
28
+ Requires-Dist: requests>=2.32.5
29
+ Requires-Dist: Flask>=3.1.2
29
30
  Requires-Dist: Flask-HTTPAuth>=4.8.0
30
- Requires-Dist: psutil>=5.9.8
31
+ Requires-Dist: Flask-Babel>=4.0.0
32
+ Requires-Dist: psutil>=7.1.0
31
33
  Requires-Dist: colorlog>=6.9.0
32
34
  Dynamic: license-file
33
35
 
@@ -39,14 +41,14 @@ Dynamic: license-file
39
41
  **pyproxy** is a lightweight, fast, and customizable Python-based web proxy server designed to handle both HTTP and HTTPS traffic efficiently. It can be used for various purposes, including web scraping, traffic monitoring, and content filtering.
40
42
 
41
43
  <p align="center">
42
- <img src="https://img.shields.io/github/license/6C656C65/pyproxy?style=for-the-badge">
43
- <img src="https://img.shields.io/github/issues/6C656C65/pyproxy?style=for-the-badge">
44
- <img src="https://img.shields.io/github/issues-closed/6C656C65/pyproxy?style=for-the-badge">
44
+ <img src="https://img.shields.io/github/license/pyproxytools/pyproxy?style=for-the-badge">
45
+ <img src="https://img.shields.io/github/issues/pyproxytools/pyproxy?style=for-the-badge">
46
+ <img src="https://img.shields.io/github/issues-closed/pyproxytools/pyproxy?style=for-the-badge">
45
47
  <br>
46
- <img src="https://img.shields.io/github/forks/6C656C65/pyproxy?style=for-the-badge">
47
- <img src="https://img.shields.io/github/stars/6C656C65/pyproxy?style=for-the-badge">
48
- <img src="https://img.shields.io/github/commit-activity/w/6C656C65/pyproxy?style=for-the-badge">
49
- <img src="https://img.shields.io/github/contributors/6C656C65/pyproxy?style=for-the-badge">
48
+ <img src="https://img.shields.io/github/forks/pyproxytools/pyproxy?style=for-the-badge">
49
+ <img src="https://img.shields.io/github/stars/pyproxytools/pyproxy?style=for-the-badge">
50
+ <img src="https://img.shields.io/github/commit-activity/w/pyproxytools/pyproxy?style=for-the-badge">
51
+ <img src="https://img.shields.io/github/contributors/pyproxytools/pyproxy?style=for-the-badge">
50
52
  <br>
51
53
  <img src="https://img.shields.io/pypi/v/pyproxytools?style=for-the-badge">
52
54
  <img src="https://img.shields.io/pypi/pyversions/pyproxytools?style=for-the-badge">
@@ -81,18 +83,24 @@ pip install pyproxytools
81
83
 
82
84
  ### Install from source
83
85
  ```bash
84
- git clone https://github.com/6C656C65/pyproxy.git
86
+ git clone https://github.com/pyproxytools/pyproxy.git
85
87
  cd pyproxy
86
88
  pip install -r requirements.txt
87
89
  ```
88
90
 
89
91
  ### Install with Docker
90
92
  ```bash
91
- docker pull ghcr.io/6c656c65/pyproxy:latest
92
- docker run -d ghcr.io/6c656c65/pyproxy:latest
93
+ docker pull ghcr.io/pyproxytools/pyproxy:latest
94
+ docker run -d ghcr.io/pyproxytools/pyproxy:latest
93
95
  ```
94
96
  You can use slim images by adding `-slim` to the end of the tags
95
97
 
98
+ ### Install with Compose
99
+ ```bash
100
+ wget https://raw.githubusercontent.com/pyproxytools/pyproxy/main/docker-compose.yml
101
+ docker-compose up -d
102
+ ```
103
+
96
104
  ## 🚀 **Usage**
97
105
 
98
106
  ### Start the proxy
@@ -103,7 +111,7 @@ The proxy will be available at: `0.0.0.0:8080`.
103
111
  The access log will be available at `./logs/access.log`.
104
112
 
105
113
  ## 📚 **Documentation**
106
- If you encounter any problems, or if you want to use the program in a particular way, I advise you to read the [documentation](https://github.com/6C656C65/pyproxy/wiki).
114
+ If you encounter any problems, or if you want to use the program in a particular way, I advise you to read the [documentation](https://pyproxytools.github.io/pyproxy-docs/).
107
115
 
108
116
  ## 🔧 **To do**
109
117
 
@@ -112,7 +120,7 @@ If you encounter any problems, or if you want to use the program in a particular
112
120
 
113
121
  ## 🏎️ **Benchmark**
114
122
 
115
- If you're interested in benchmarking the performance of the proxy or comparing request times with and without a proxy, please refer to the [Benchmark README](benchmark/README.md) for detailed instructions on how to run the benchmarking tests and generate reports.
123
+ If you're interested in benchmarking the performance of the proxy or comparing request times with and without a proxy, please refer to the [Benchmark repository](https://github.com/pyproxytools/pyproxy-benchmark) for detailed instructions on how to run the benchmarking tests and generate reports.
116
124
 
117
125
  ## 📄 **License**
118
126
 
@@ -124,12 +132,17 @@ Contributions are welcome and appreciated! If you'd like to improve this project
124
132
 
125
133
  ## 📦 Deployment with Ansible
126
134
 
127
- If you want to deploy **pyproxy** automatically to remote servers (via source or Docker), an official [Ansible role](https://github.com/6C656C65/pyproxy_ansible) is available:
135
+ If you want to deploy **pyproxy** automatically to remote servers (via source or Docker), an official [Ansible role](https://github.com/pyproxytools/pyproxy-ansible) is available:
128
136
 
129
137
  * 🔧 Install from source or run as a Docker container
130
138
  * 📁 Supports customization of ports, versions, and paths
131
139
  * 🚀 Easily integrable into your infrastructure or CI/CD pipelines
132
140
 
133
- 👉 Check out the [ansible-role-pyproxy](https://github.com/6C656C65/pyproxy_ansible) repository for more details and usage instructions.
141
+ 👉 Check out the [pyproxy-ansible](https://github.com/pyproxytools/pyproxy-ansible) repository for more details and usage instructions.
142
+
143
+ ## 🧩 **Python SDK for Administration and Monitoring**
144
+
145
+ A dedicated Python SDK is available to interact programmatically with the **pyproxy** administration and monitoring interface: [**pyproxy-sdk-py**](https://github.com/pyproxytools/pyproxy-sdk-py).
146
+ This SDK provides a simple and consistent API to manage your proxy configuration remotely — allowing you to add or delete domains, manage URLs, create and remove clients, and perform other administrative tasks. It is designed to integrate easily into automation scripts, dashboards, or backend systems that need to control and monitor pyproxy instances.
134
147
 
135
148
  ---
@@ -6,14 +6,14 @@
6
6
  **pyproxy** is a lightweight, fast, and customizable Python-based web proxy server designed to handle both HTTP and HTTPS traffic efficiently. It can be used for various purposes, including web scraping, traffic monitoring, and content filtering.
7
7
 
8
8
  <p align="center">
9
- <img src="https://img.shields.io/github/license/6C656C65/pyproxy?style=for-the-badge">
10
- <img src="https://img.shields.io/github/issues/6C656C65/pyproxy?style=for-the-badge">
11
- <img src="https://img.shields.io/github/issues-closed/6C656C65/pyproxy?style=for-the-badge">
9
+ <img src="https://img.shields.io/github/license/pyproxytools/pyproxy?style=for-the-badge">
10
+ <img src="https://img.shields.io/github/issues/pyproxytools/pyproxy?style=for-the-badge">
11
+ <img src="https://img.shields.io/github/issues-closed/pyproxytools/pyproxy?style=for-the-badge">
12
12
  <br>
13
- <img src="https://img.shields.io/github/forks/6C656C65/pyproxy?style=for-the-badge">
14
- <img src="https://img.shields.io/github/stars/6C656C65/pyproxy?style=for-the-badge">
15
- <img src="https://img.shields.io/github/commit-activity/w/6C656C65/pyproxy?style=for-the-badge">
16
- <img src="https://img.shields.io/github/contributors/6C656C65/pyproxy?style=for-the-badge">
13
+ <img src="https://img.shields.io/github/forks/pyproxytools/pyproxy?style=for-the-badge">
14
+ <img src="https://img.shields.io/github/stars/pyproxytools/pyproxy?style=for-the-badge">
15
+ <img src="https://img.shields.io/github/commit-activity/w/pyproxytools/pyproxy?style=for-the-badge">
16
+ <img src="https://img.shields.io/github/contributors/pyproxytools/pyproxy?style=for-the-badge">
17
17
  <br>
18
18
  <img src="https://img.shields.io/pypi/v/pyproxytools?style=for-the-badge">
19
19
  <img src="https://img.shields.io/pypi/pyversions/pyproxytools?style=for-the-badge">
@@ -48,18 +48,24 @@ pip install pyproxytools
48
48
 
49
49
  ### Install from source
50
50
  ```bash
51
- git clone https://github.com/6C656C65/pyproxy.git
51
+ git clone https://github.com/pyproxytools/pyproxy.git
52
52
  cd pyproxy
53
53
  pip install -r requirements.txt
54
54
  ```
55
55
 
56
56
  ### Install with Docker
57
57
  ```bash
58
- docker pull ghcr.io/6c656c65/pyproxy:latest
59
- docker run -d ghcr.io/6c656c65/pyproxy:latest
58
+ docker pull ghcr.io/pyproxytools/pyproxy:latest
59
+ docker run -d ghcr.io/pyproxytools/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/pyproxytools/pyproxy/main/docker-compose.yml
66
+ docker-compose up -d
67
+ ```
68
+
63
69
  ## 🚀 **Usage**
64
70
 
65
71
  ### Start the proxy
@@ -70,7 +76,7 @@ The proxy will be available at: `0.0.0.0:8080`.
70
76
  The access log will be available at `./logs/access.log`.
71
77
 
72
78
  ## 📚 **Documentation**
73
- If you encounter any problems, or if you want to use the program in a particular way, I advise you to read the [documentation](https://github.com/6C656C65/pyproxy/wiki).
79
+ If you encounter any problems, or if you want to use the program in a particular way, I advise you to read the [documentation](https://pyproxytools.github.io/pyproxy-docs/).
74
80
 
75
81
  ## 🔧 **To do**
76
82
 
@@ -79,7 +85,7 @@ If you encounter any problems, or if you want to use the program in a particular
79
85
 
80
86
  ## 🏎️ **Benchmark**
81
87
 
82
- If you're interested in benchmarking the performance of the proxy or comparing request times with and without a proxy, please refer to the [Benchmark README](benchmark/README.md) for detailed instructions on how to run the benchmarking tests and generate reports.
88
+ If you're interested in benchmarking the performance of the proxy or comparing request times with and without a proxy, please refer to the [Benchmark repository](https://github.com/pyproxytools/pyproxy-benchmark) for detailed instructions on how to run the benchmarking tests and generate reports.
83
89
 
84
90
  ## 📄 **License**
85
91
 
@@ -91,12 +97,17 @@ Contributions are welcome and appreciated! If you'd like to improve this project
91
97
 
92
98
  ## 📦 Deployment with Ansible
93
99
 
94
- If you want to deploy **pyproxy** automatically to remote servers (via source or Docker), an official [Ansible role](https://github.com/6C656C65/pyproxy_ansible) is available:
100
+ If you want to deploy **pyproxy** automatically to remote servers (via source or Docker), an official [Ansible role](https://github.com/pyproxytools/pyproxy-ansible) is available:
95
101
 
96
102
  * 🔧 Install from source or run as a Docker container
97
103
  * 📁 Supports customization of ports, versions, and paths
98
104
  * 🚀 Easily integrable into your infrastructure or CI/CD pipelines
99
105
 
100
- 👉 Check out the [ansible-role-pyproxy](https://github.com/6C656C65/pyproxy_ansible) repository for more details and usage instructions.
106
+ 👉 Check out the [pyproxy-ansible](https://github.com/pyproxytools/pyproxy-ansible) repository for more details and usage instructions.
107
+
108
+ ## 🧩 **Python SDK for Administration and Monitoring**
109
+
110
+ A dedicated Python SDK is available to interact programmatically with the **pyproxy** administration and monitoring interface: [**pyproxy-sdk-py**](https://github.com/pyproxytools/pyproxy-sdk-py).
111
+ This SDK provides a simple and consistent API to manage your proxy configuration remotely — allowing you to add or delete domains, manage URLs, create and remove clients, and perform other administrative tasks. It is designed to integrate easily into automation scripts, dashboards, or backend systems that need to control and monitor pyproxy instances.
101
112
 
102
113
  ---
@@ -6,7 +6,7 @@ license = "MIT"
6
6
  license-files = [
7
7
  "LICENSE",
8
8
  ]
9
- authors = [{name = "6C656C65"}]
9
+ authors = [{name = "pyproxytools"}]
10
10
  classifiers = [
11
11
  "Development Status :: 5 - Production/Stable",
12
12
  "Intended Audience :: Developers",
@@ -17,6 +17,7 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3.10",
18
18
  "Programming Language :: Python :: 3.11",
19
19
  "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
20
21
  "Topic :: Internet",
21
22
  "Topic :: Software Development :: Libraries",
22
23
  "Topic :: Software Development :: Libraries :: Python Modules",
@@ -26,8 +27,8 @@ classifiers = [
26
27
  dynamic = ["version", "dependencies"]
27
28
 
28
29
  [project.urls]
29
- Documentation = "https://github.com/6C656C65/pyproxy/wiki"
30
- "Issue tracker" = "https://github.com/6C656C65/pyproxy/issues"
30
+ Documentation = "https://pyproxytools.github.io/pyproxy-docs/"
31
+ "Issue tracker" = "https://github.com/pyproxytools/pyproxy/issues"
31
32
 
32
33
  [tool.setuptools.packages]
33
34
  find = {}
@@ -35,6 +36,27 @@ find = {}
35
36
  [tool.setuptools.dynamic]
36
37
  dependencies = { file = "requirements.txt" }
37
38
 
39
+ [tool.ruff]
40
+ line-length = 100
41
+ src = ["pyproxy", "tests"]
42
+ exclude = [
43
+ ".git",
44
+ "__pycache__",
45
+ "build",
46
+ "dist",
47
+ "venv",
48
+ "setup.py",
49
+ ]
50
+
51
+ [tool.ruff.lint]
52
+ select = ["E", "F", "W", "S"]
53
+
54
+ [tool.ruff.format]
55
+ quote-style = "double"
56
+ indent-style = "space"
57
+ line-ending = "auto"
58
+ skip-magic-trailing-comma = false
59
+
38
60
  [project.scripts]
39
61
  pyproxy = "pyproxy.pyproxy:main"
40
62
 
@@ -5,7 +5,7 @@ that holds the current version number of the application.
5
5
 
6
6
  import os
7
7
 
8
- __version__ = "0.4.1"
8
+ __version__ = "0.5.1"
9
9
 
10
10
  if os.path.isdir("pyproxy/monitoring"):
11
11
  __slim__ = False
@@ -0,0 +1,114 @@
1
+ """
2
+ pyproxy.handlers.client.py
3
+
4
+ This module defines the ProxyHandlers class used by the proxy server to process
5
+ HTTP and HTTPS client connections. It handles request forwarding, blocking, shortcut
6
+ redirection, custom headers, and optional SSL inspection.
7
+ """
8
+
9
+ import threading
10
+
11
+ from pyproxy.handlers.http import HttpHandler
12
+ from pyproxy.handlers.https import HttpsHandler
13
+
14
+
15
+ class ProxyHandlers:
16
+ """
17
+ ProxyHandlers manages client connections for a proxy server, handling both HTTP
18
+ and HTTPS requests. It processes request forwarding, blocking, SSL inspection,
19
+ and custom headers based on configuration settings. This class is responsible
20
+ for dispatching the correct handler for HTTP or HTTPS requests and managing
21
+ connection-related operations.
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ html_403,
27
+ logger_config,
28
+ filter_config,
29
+ ssl_config,
30
+ filter_queue,
31
+ filter_result_queue,
32
+ shortcuts_queue,
33
+ shortcuts_result_queue,
34
+ cancel_inspect_queue,
35
+ cancel_inspect_result_queue,
36
+ custom_header_queue,
37
+ custom_header_result_queue,
38
+ console_logger,
39
+ shortcuts,
40
+ custom_header,
41
+ active_connections,
42
+ proxy_config,
43
+ ):
44
+ self.html_403 = html_403
45
+ self.logger_config = logger_config
46
+ self.filter_config = filter_config
47
+ self.ssl_config = ssl_config
48
+ self.filter_queue = filter_queue
49
+ self.filter_result_queue = filter_result_queue
50
+ self.shortcuts_queue = shortcuts_queue
51
+ self.shortcuts_result_queue = shortcuts_result_queue
52
+ self.cancel_inspect_queue = cancel_inspect_queue
53
+ self.cancel_inspect_result_queue = cancel_inspect_result_queue
54
+ self.custom_header_queue = custom_header_queue
55
+ self.custom_header_result_queue = custom_header_result_queue
56
+ self.console_logger = console_logger
57
+ self.config_shortcuts = shortcuts
58
+ self.config_custom_header = custom_header
59
+ self.proxy_config = proxy_config
60
+ self.active_connections = active_connections
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
+
85
+ def handle_client(self, client_socket):
86
+ """
87
+ Handles an incoming client connection by processing the request and forwarding
88
+ it to the appropriate handler based on whether the request is HTTP or HTTPS.
89
+
90
+ Args:
91
+ client_socket (socket): The socket object for the client connection.
92
+ """
93
+ try:
94
+ client_socket.settimeout(10)
95
+ request = client_socket.recv(4096)
96
+
97
+ if not request:
98
+ return
99
+
100
+ first_line = request.decode(errors="ignore").split("\n")[0]
101
+ if first_line.startswith("CONNECT"):
102
+ https_handler = self._create_handler(
103
+ HttpsHandler,
104
+ ssl_config=self.ssl_config,
105
+ cancel_inspect_queue=self.cancel_inspect_queue,
106
+ cancel_inspect_result_queue=self.cancel_inspect_result_queue,
107
+ )
108
+ https_handler.handle_https_connection(client_socket, first_line)
109
+ else:
110
+ http_handler = self._create_handler(HttpHandler)
111
+ http_handler.handle_http_request(client_socket, request)
112
+ finally:
113
+ client_socket.close()
114
+ self.active_connections.pop(threading.get_ident(), None)
@@ -0,0 +1,257 @@
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("Timeout while getting custom headers for %s", url)
66
+ return headers
67
+
68
+ def _rebuild_http_request(self, request_line, headers, body=""):
69
+ """
70
+ Reconstructs an HTTP request with the new headers.
71
+ """
72
+ header_lines = [f"{key}: {value}" for key, value in headers.items()]
73
+ reconstructed_headers = "\r\n".join(header_lines)
74
+ return f"{request_line}\r\n{reconstructed_headers}\r\n\r\n{body}".encode()
75
+
76
+ def _apply_shortcut(self, url: str) -> str | None:
77
+ """
78
+ Checks if a shortcut is defined for the given domain.
79
+ """
80
+ if self.config_shortcuts and os.path.isfile(self.config_shortcuts):
81
+ parsed_url = urlparse(url)
82
+ domain = parsed_url.hostname
83
+ self.shortcuts_queue.put(domain)
84
+ try:
85
+ return self.shortcuts_result_queue.get(timeout=5)
86
+ except Exception:
87
+ self.console_logger.warning("Timeout while getting shortcut for %s", url)
88
+ return None
89
+
90
+ def _is_blocked(self, url: str) -> bool:
91
+ """
92
+ Checks if a URL is blocked by the configuration filter.
93
+ """
94
+ if not self.filter_config.no_filter:
95
+ self.filter_queue.put(url)
96
+ try:
97
+ result = self.filter_result_queue.get(timeout=5)
98
+ return result[1] == "Blocked"
99
+ except Exception:
100
+ self.console_logger.warning("Timeout while filtering %s", url)
101
+ return False
102
+
103
+ def _send_403(self, client_socket, url, first_line):
104
+ """
105
+ Sends an HTTP 403 Forbidden response to the client.
106
+ """
107
+ if not self.logger_config.no_logging_block:
108
+ method, domain_port, protocol = first_line.split(" ")
109
+ domain, port = domain_port.split(":")
110
+ self.logger_config.block_logger.info(
111
+ "",
112
+ extra={
113
+ "ip_src": client_socket.getpeername()[0],
114
+ "url": url,
115
+ "method": method,
116
+ "domain": domain,
117
+ "port": port,
118
+ "protocol": protocol,
119
+ },
120
+ )
121
+ with open(self.html_403, "r", encoding="utf-8") as f:
122
+ custom_403_page = f.read()
123
+ response = (
124
+ f"HTTP/1.1 403 Forbidden\r\n"
125
+ f"Content-Length: {len(custom_403_page)}\r\n"
126
+ f"\r\n"
127
+ f"{custom_403_page}"
128
+ )
129
+ client_socket.sendall(response.encode())
130
+ client_socket.close()
131
+ self.active_connections.pop(threading.get_ident(), None)
132
+
133
+ def handle_http_request(self, client_socket, request):
134
+ """
135
+ Processes an HTTP request, checks for URL filtering, applies shortcuts,
136
+ and forwards the request to the target server if not blocked.
137
+
138
+ Args:
139
+ client_socket (socket): The socket object for the client connection.
140
+ request (bytes): The raw HTTP request sent by the client.
141
+ """
142
+ first_line = request.decode(errors="ignore").split("\n")[0]
143
+ url = first_line.split(" ")[1]
144
+
145
+ if self.config_shortcuts and os.path.isfile(self.config_shortcuts):
146
+ shortcut_url = self._apply_shortcut(url)
147
+ if shortcut_url:
148
+ response = (
149
+ f"HTTP/1.1 302 Found\r\nLocation: {shortcut_url}\r\nContent-Length: 0\r\n\r\n"
150
+ )
151
+
152
+ client_socket.sendall(response.encode())
153
+ client_socket.close()
154
+ self.active_connections.pop(threading.get_ident(), None)
155
+ return
156
+
157
+ if self._is_blocked(url):
158
+ self._send_403(client_socket, url, first_line)
159
+ return
160
+
161
+ if self.config_custom_header and os.path.isfile(self.config_custom_header):
162
+ request_text = request.decode(errors="ignore")
163
+ request_lines = request_text.split("\r\n")
164
+ headers = self._get_modified_headers(url, request_text)
165
+ request_line = request_lines[0]
166
+ body = request_text.split("\r\n\r\n", 1)[1] if "\r\n\r\n" in request_text else ""
167
+ modified_request = self._rebuild_http_request(request_line, headers, body)
168
+
169
+ self.forward_request_to_server(client_socket, modified_request, url, first_line)
170
+
171
+ else:
172
+ self.forward_request_to_server(client_socket, request, url, first_line)
173
+
174
+ def forward_request_to_server(self, client_socket, request, url, first_line):
175
+ """
176
+ Forwards the HTTP request to the target server and sends the response back to the client.
177
+
178
+ Args:
179
+ client_socket (socket): The socket object for the client connection.
180
+ request (bytes): The raw HTTP request sent by the client.
181
+ url (str): The target URL from the HTTP request.
182
+ first_line (str): The first line of the HTTP request (e.g., "GET / HTTP/1.1").
183
+ """
184
+ if self.proxy_config.enable:
185
+ server_host, server_port = self.proxy_config.host, self.proxy_config.port
186
+ else:
187
+ parsed_url = urlparse(url)
188
+ server_host = parsed_url.hostname
189
+ server_port = parsed_url.port or (443 if parsed_url.scheme == "https" else 80)
190
+
191
+ try:
192
+ ip_address = socket.gethostbyname(server_host)
193
+ except socket.gaierror:
194
+ ip_address = server_host
195
+
196
+ thread_id = threading.get_ident()
197
+
198
+ if thread_id in self.active_connections:
199
+ self.active_connections[thread_id].update(
200
+ {
201
+ "target_ip": ip_address,
202
+ "target_domain": server_host,
203
+ "target_port": server_port,
204
+ "bytes_sent": 0,
205
+ "bytes_received": 0,
206
+ }
207
+ )
208
+
209
+ try:
210
+ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
211
+ server_socket.connect((server_host, server_port))
212
+ server_socket.sendall(request)
213
+ server_socket.settimeout(5)
214
+ self.active_connections[thread_id]["bytes_sent"] += len(request)
215
+
216
+ while True:
217
+ try:
218
+ response = server_socket.recv(4096)
219
+ if response:
220
+ client_socket.send(response)
221
+ self.active_connections[thread_id]["bytes_received"] += len(response)
222
+ else:
223
+ break
224
+ except socket.timeout:
225
+ break
226
+ except (socket.timeout, socket.gaierror, ConnectionRefusedError, OSError) as e:
227
+ self.console_logger.error("Error connecting to the server %s : %s", server_host, e)
228
+ response = (
229
+ f"HTTP/1.1 502 Bad Gateway\r\n"
230
+ f"Content-Length: {len('Bad Gateway')} \r\n"
231
+ "\r\n"
232
+ f"Bad Gateway"
233
+ )
234
+ client_socket.sendall(response.encode())
235
+ client_socket.close()
236
+ self.active_connections.pop(thread_id, None)
237
+ finally:
238
+ if not self.logger_config.no_logging_access:
239
+ method, url, protocol = first_line.split(" ")
240
+
241
+ conn_data = self.active_connections.get(thread_id, {})
242
+ self.logger_config.access_logger.info(
243
+ "",
244
+ extra={
245
+ "ip_src": client_socket.getpeername()[0],
246
+ "url": f"http://{server_host}",
247
+ "method": method,
248
+ "domain": parsed_url.hostname,
249
+ "port": parsed_url.port,
250
+ "protocol": protocol,
251
+ "bytes_sent": conn_data.get("bytes_sent", 0),
252
+ "bytes_received": conn_data.get("bytes_received", 0),
253
+ },
254
+ )
255
+ client_socket.close()
256
+ server_socket.close()
257
+ self.active_connections.pop(thread_id, None)