Skip to content

Commit 2a9db3a

Browse files
authored
Update outdated sections of the codebase (#670)
* Remove autopep8, is redundant now after recent CI changes * Add pyenv .python-version to .gitignore * Update year * Add lib-pytest target so that pytest can run in isolation * Add git-push hook which will also run the lint. By default now git-pre-commit hook will only run pytest. * Update outdated sections of README * Update requirement to match setup.cfg install_requires * Deprecate proxy.start and TestCase.PROXY_PORT Proxy port during test is now available as self.PROXY.pool.flags.port. Also now TestCase utilize ephemeral port strategy instead of calling get_available_port utility method. * Rename to git-pre-push * Ideally public repo dont require CODECOV_TOKEN but codecov integration is broken since introduction of codecov-action@v2 (instead of codecov binary invocation) * Issue is possibly with codecov@v2 action, fallback to codecov. See https://github.com/abhinavsingh/proxy.py/runs/4110423084\?check_suite_focus\=true and codecov/uploader#223 * Revert back to v2
1 parent 62969b8 commit 2a9db3a

File tree

12 files changed

+125
-107
lines changed

12 files changed

+125
-107
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
.mypy_cache
1010
.hypothesis
1111
.tox
12+
.python-version
1213

1314
coverage.xml
1415
proxy.py.iml

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2013-2020 by Abhinav Singh and contributors.
1+
Copyright (c) 2013-2022 by Abhinav Singh and contributors.
22
All rights reserved.
33

44
Redistribution and use in source and binary forms, with or without modification,

Makefile

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,14 @@ CA_KEY_FILE_PATH := ca-key.pem
1515
CA_CERT_FILE_PATH := ca-cert.pem
1616
CA_SIGNING_KEY_FILE_PATH := ca-signing-key.pem
1717

18-
.PHONY: all https-certificates ca-certificates autopep8 devtools
19-
.PHONY: lib-version lib-clean lib-test lib-package lib-coverage lib-lint
18+
.PHONY: all https-certificates sign-https-certificates ca-certificates
19+
.PHONY: lib-version lib-clean lib-test lib-package lib-coverage lib-lint lib-pytest
2020
.PHONY: lib-release-test lib-release lib-profile
2121
.PHONY: container container-run container-release
22-
.PHONY: dashboard dashboard-clean
22+
.PHONY: devtools dashboard dashboard-clean
2323

2424
all: lib-test
2525

26-
devtools:
27-
pushd dashboard && npm run devtools && popd
28-
29-
autopep8:
30-
autopep8 --recursive --in-place --aggressive examples
31-
autopep8 --recursive --in-place --aggressive proxy
32-
autopep8 --recursive --in-place --aggressive tests
33-
3426
https-certificates:
3527
# Generate server key
3628
python -m proxy.common.pki gen_private_key \
@@ -91,9 +83,11 @@ lib-clean:
9183
lib-lint:
9284
python -m tox -e lint
9385

94-
lib-test: lib-clean lib-version lib-lint
86+
lib-pytest:
9587
python -m tox -e python -- -v
9688

89+
lib-test: lib-clean lib-version lib-lint lib-pytest
90+
9791
lib-package: lib-clean lib-version
9892
python -m tox -e cleanup-dists,build-dists,metadata-validation
9993

@@ -110,6 +104,9 @@ lib-coverage:
110104
lib-profile:
111105
sudo py-spy record -o profile.svg -t -F -s -- python -m proxy
112106

107+
devtools:
108+
pushd dashboard && npm run devtools && popd
109+
113110
dashboard:
114111
pushd dashboard && npm run build && popd
115112

README.md

Lines changed: 94 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,19 @@
6969
- [Embed proxy.py](#embed-proxypy)
7070
- [Blocking Mode](#blocking-mode)
7171
- [Non-blocking Mode](#non-blocking-mode)
72+
- [Ephemeral Port](#ephemeral-port)
7273
- [Loading Plugins](#loading-plugins)
7374
- [Unit testing with proxy.py](#unit-testing-with-proxypy)
7475
- [proxy.TestCase](#proxytestcase)
7576
- [Override Startup Flags](#override-startup-flags)
7677
- [With unittest.TestCase](#with-unittesttestcase)
7778
- [Plugin Developer and Contributor Guide](#plugin-developer-and-contributor-guide)
79+
- [High level architecture](#high-level-architecture)
7880
- [Everything is a plugin](#everything-is-a-plugin)
79-
- [Internal Architecture](#internal-architecture)
8081
- [Internal Documentation](#internal-documentation)
8182
- [Development Guide](#development-guide)
8283
- [Setup Local Environment](#setup-local-environment)
83-
- [Setup pre-commit hook](#setup-pre-commit-hook)
84+
- [Setup Git Hooks](#setup-git-hooks)
8485
- [Sending a Pull Request](#sending-a-pull-request)
8586
- [Utilities](#utilities)
8687
- [TCP](#tcp-sockets)
@@ -307,8 +308,7 @@ To start `proxy.py` from source code follow these instructions:
307308
- Install deps
308309

309310
```bash
310-
❯ pip install -r requirements.txt
311-
❯ pip install -r requirements-testing.txt
311+
❯ pip install -rrequirements.txt -rrequirements-testing.txt -rrequirements-tunnel.txt
312312
```
313313

314314
- Run tests
@@ -1149,24 +1149,40 @@ by using `start` method: Example:
11491149
import proxy
11501150
11511151
if __name__ == '__main__':
1152-
with proxy.start([]):
1152+
with proxy.Proxy([]) as p:
11531153
# ... your logic here ...
11541154
```
11551155
11561156
Note that:
11571157
1158-
1. `start` is similar to `main`, except `start` won't block.
1159-
1. `start` is a context manager.
1158+
1. `Proxy` is similar to `main`, except `Proxy` does not block.
1159+
1. Internally `Proxy` is a context manager.
11601160
It will start `proxy.py` when called and will shut it down
1161-
once scope ends.
1162-
1. Just like `main`, startup flags with `start` method
1161+
once the scope ends.
1162+
1. Just like `main`, startup flags with `Proxy`
11631163
can be customized by either passing flags as list of
1164-
input arguments e.g. `start(['--port', '8899'])` or
1165-
by using passing flags as kwargs e.g. `start(port=8899)`.
1164+
input arguments e.g. `Proxy(['--port', '8899'])` or
1165+
by using passing flags as kwargs e.g. `Proxy(port=8899)`.
1166+
1167+
## Ephemeral Port
1168+
1169+
Use `--port=0` to bind `proxy.py` on a random port allocated by the kernel.
1170+
1171+
In embedded mode, you can access this port. Example:
1172+
1173+
```python
1174+
import proxy
1175+
1176+
if __name__ == '__main__':
1177+
with proxy.Proxy([]) as p:
1178+
print(p.pool.flags.port)
1179+
```
1180+
1181+
`pool.flags.port` will give you access to the random port allocated by the kernel.
11661182
11671183
## Loading Plugins
11681184
1169-
You can, of course, list plugins to load in the input arguments list of `proxy.main`, `proxy.start` or the `Proxy` constructor. Use the `--plugins` flag as when starting from command line:
1185+
You can, of course, list plugins to load in the input arguments list of `proxy.main` or `Proxy` constructor. Use the `--plugins` flag when starting from command line:
11701186
11711187
```python
11721188
import proxy
@@ -1177,7 +1193,7 @@ if __name__ == '__main__':
11771193
])
11781194
```
11791195
1180-
However, for simplicity you can pass the list of plugins to load as a keyword argument to `proxy.main`, `proxy.start` or the `Proxy` constructor:
1196+
For simplicity you can pass the list of plugins to load as a keyword argument to `proxy.main` or the `Proxy` constructor:
11811197
11821198
```python
11831199
import proxy
@@ -1193,20 +1209,19 @@ if __name__ == '__main__':
11931209
Note that it supports:
11941210
11951211
1. The fully-qualified name of a class as `bytes`
1196-
2. Any `type` instance for a Proxy.py plugin class. This is especially useful for custom plugins defined locally.
1212+
2. Any `type` instance of a plugin class. This is especially useful for plugins defined at runtime
11971213
11981214
# Unit testing with proxy.py
11991215
12001216
## proxy.TestCase
12011217
1202-
To setup and teardown `proxy.py` for your Python unittest classes,
1218+
To setup and teardown `proxy.py` for your Python `unittest` classes,
12031219
simply use `proxy.TestCase` instead of `unittest.TestCase`.
12041220
Example:
12051221
12061222
```python
12071223
import proxy
12081224
1209-
12101225
class TestProxyPyEmbedded(proxy.TestCase):
12111226
12121227
def test_my_application_with_proxy(self) -> None:
@@ -1217,7 +1232,7 @@ Note that:
12171232
12181233
1. `proxy.TestCase` overrides `unittest.TestCase.run()` method to setup and teardown `proxy.py`.
12191234
2. `proxy.py` server will listen on a random available port on the system.
1220-
This random port is available as `self.PROXY_PORT` within your test cases.
1235+
This random port is available as `self.PROXY.pool.flags.port` within your test cases.
12211236
3. Only a single worker is started by default (`--num-workers 1`) for faster setup and teardown.
12221237
4. Most importantly, `proxy.TestCase` also ensures `proxy.py` server
12231238
is up and running before proceeding with execution of tests. By default,
@@ -1272,52 +1287,63 @@ or simply setup / teardown `proxy.py` within
12721287
12731288
# Plugin Developer and Contributor Guide
12741289
1275-
## Everything is a plugin
1276-
1277-
As you might have guessed by now, in `proxy.py` everything is a plugin.
1290+
## High level architecture
12781291
1279-
- We enabled proxy server plugins using `--plugins` flag.
1280-
All the [plugin examples](#plugin-examples) were implementing
1281-
`HttpProxyBasePlugin`. See documentation of
1282-
[HttpProxyBasePlugin](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L894-L938)
1283-
for available lifecycle hooks. Use `HttpProxyBasePlugin` to modify
1284-
behavior of http(s) proxy protocol between client and upstream server.
1285-
Example, [FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
1286-
1287-
- We also enabled inbuilt web server using `--enable-web-server`.
1288-
Inbuilt web server implements `HttpProtocolHandlerPlugin` plugin.
1289-
See documentation of [HttpProtocolHandlerPlugin](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L793-L850)
1290-
for available lifecycle hooks. Use `HttpProtocolHandlerPlugin` to add
1291-
new features for http(s) clients. Example,
1292-
[HttpWebServerPlugin](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L1185-L1260).
1293-
1294-
- There also is a `--disable-http-proxy` flag. It disables inbuilt proxy server.
1295-
Use this flag with `--enable-web-server` flag to run `proxy.py` as a programmable
1296-
http(s) server. [HttpProxyPlugin](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L941-L1182)
1297-
also implements `HttpProtocolHandlerPlugin`.
1292+
```bash
1293+
+-------------+
1294+
| Proxy([]) |
1295+
+------+------+
1296+
|
1297+
|
1298+
+-----------v--------------+
1299+
| AcceptorPool(...) |
1300+
+------------+-------------+
1301+
|
1302+
|
1303+
+-----------------+ | +-----------------+
1304+
| Acceptor(..) <-------------+-----------> Acceptor(..) |
1305+
+-----------------+ +-----------------+
1306+
```
1307+
1308+
`proxy.py` is made with performance in mind. By default, `proxy.py`
1309+
will try to utilize all available CPU cores to it for accepting new
1310+
client connections. This is achieved by starting `AcceptorPool` which
1311+
listens on configured server port. Then, `AcceptorPool` starts `Acceptor`
1312+
processes (`--num-workers`) to accept incoming client connections.
1313+
1314+
Each `Acceptor` process delegates the accepted client connection
1315+
to a `Work` class. Currently, `HttpProtocolHandler` is the default
1316+
work klass hardcoded into the code.
1317+
1318+
`HttpProtocolHandler` simply assumes that incoming clients will follow
1319+
HTTP specification. Specific HTTP proxy and HTTP server implementations
1320+
are written as plugins of `HttpProtocolHandler`.
1321+
1322+
See documentation of `HttpProtocolHandlerPlugin` for available lifecycle hooks.
1323+
Use `HttpProtocolHandlerPlugin` to add new features for http(s) clients. Example,
1324+
See `HttpWebServerPlugin`.
12981325
1299-
## Internal Architecture
1326+
## Everything is a plugin
13001327
1301-
- [HttpProtocolHandler](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L1263-L1440)
1302-
thread is started with the accepted [TcpClientConnection](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L230-L237).
1303-
`HttpProtocolHandler` is responsible for parsing incoming client request and invoking
1304-
`HttpProtocolHandlerPlugin` lifecycle hooks.
1328+
Within `proxy.py` everything is a plugin.
13051329
1306-
- `HttpProxyPlugin` which implements `HttpProtocolHandlerPlugin` also has its own plugin
1307-
mechanism. Its responsibility is to establish connection between client and
1308-
upstream [TcpServerConnection](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L204-L227)
1309-
and invoke `HttpProxyBasePlugin` lifecycle hooks.
1330+
- We enabled `proxy server` plugins using `--plugins` flag.
1331+
Proxy server `HttpProxyPlugin` is a plugin of `HttpProtocolHandler`.
1332+
Further, Proxy server allows plugin through `HttpProxyBasePlugin` specification.
13101333
1311-
- `HttpProtocolHandler` threads are started by [Acceptor](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L424-L472)
1312-
processes.
1334+
- All the proxy server [plugin examples](#plugin-examples) were implementing
1335+
`HttpProxyBasePlugin`. See documentation of `HttpProxyBasePlugin` for available
1336+
lifecycle hooks. Use `HttpProxyBasePlugin` to modify behavior of http(s) proxy protocol
1337+
between client and upstream server. Example,
1338+
[FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
13131339
1314-
- `--num-workers` `Acceptor` processes are started by
1315-
[AcceptorPool](https://github.com/abhinavsingh/proxy.py/blob/b03629fa0df1595eb4995427bc601063be7fdca9/proxy.py#L368-L421)
1316-
on start-up.
1340+
- We also enabled inbuilt `web server` using `--enable-web-server`.
1341+
Web server `HttpWebServerPlugin` is a plugin of `HttpProtocolHandler`
1342+
and implements `HttpProtocolHandlerPlugin` specification.
13171343
1318-
- `AcceptorPool` listens on server socket and pass the handler to `Acceptor` processes.
1319-
Workers are responsible for accepting new client connections and starting
1320-
`HttpProtocolHandler` thread.
1344+
- There also is a `--disable-http-proxy` flag. It disables inbuilt proxy server.
1345+
Use this flag with `--enable-web-server` flag to run `proxy.py` as a programmable
1346+
http(s) server.
13211347
13221348
## Development Guide
13231349
@@ -1327,13 +1353,23 @@ Contributors must start `proxy.py` from source to verify and develop new feature
13271353
13281354
See [Run proxy.py from command line using repo source](#from-command-line-using-repo-source) for details.
13291355
1330-
### Setup pre-commit hook
1356+
[![WARNING](https://img.shields.io/static/v1?label=MacOS&message=warning&color=red)]
1357+
(https://github.com/abhinavsingh/proxy.py/issues/642#issuecomment-960819271) On `macOS`
1358+
you must install `Python` using `pyenv`, as `Python` installed via `homebrew` tends
1359+
to be problematic. See linked thread for more details.
1360+
1361+
### Setup Git Hooks
13311362
1332-
Pre-commit hook ensures lint checking and tests execution.
1363+
Pre-commit hook ensures tests are passing.
13331364
13341365
1. `cd /path/to/proxy.py`
13351366
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`
13361367
1368+
Pre-push hook ensures lint and tests are passing.
1369+
1370+
1. `cd /path/to/proxy.py`
1371+
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`
1372+
13371373
### Sending a Pull Request
13381374
13391375
Every pull request is tested using GitHub actions.

git-pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/bash
22

3-
make
3+
make lib-pytest

git-pre-push

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
make

proxy/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
:copyright: (c) 2013-present by Abhinav Singh and contributors.
99
:license: BSD, see LICENSE for more details.
1010
"""
11-
from .proxy import entry_point
12-
from .proxy import main, start
13-
from .proxy import Proxy
11+
from .proxy import entry_point, main, Proxy
1412
from .testing.test_case import TestCase
1513

1614
__all__ = [
@@ -19,7 +17,7 @@
1917
'entry_point',
2018
# Embed proxy.py. See
2119
# https://github.com/abhinavsingh/proxy.py#embed-proxypy
22-
'main', 'start',
20+
'main',
2321
# Unit testing with proxy.py. See
2422
# https://github.com/abhinavsingh/proxy.py#unit-testing-with-proxypy
2523
'TestCase',

proxy/proxy.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import argparse
1313
import base64
1414
import collections
15-
import contextlib
1615
import ipaddress
1716
import multiprocessing
1817
import os
@@ -24,7 +23,7 @@
2423
import inspect
2524

2625
from types import TracebackType
27-
from typing import Dict, List, Optional, Generator, Any, Tuple, Type, Union, cast
26+
from typing import Dict, List, Optional, Any, Tuple, Type, Union, cast
2827

2928
from proxy.core.acceptor.work import Work
3029

@@ -497,21 +496,6 @@ def set_open_file_limit(soft_limit: int) -> None:
497496
)
498497

499498

500-
@contextlib.contextmanager
501-
def start(
502-
input_args: Optional[List[str]] = None,
503-
**opts: Any,
504-
) -> Generator[Proxy, None, None]:
505-
"""Deprecated. Kept for backward compatibility.
506-
507-
New users must directly use proxy.Proxy context manager class."""
508-
try:
509-
with Proxy(input_args, **opts) as p:
510-
yield p
511-
except KeyboardInterrupt:
512-
pass
513-
514-
515499
def main(
516500
input_args: Optional[List[str]] = None,
517501
**opts: Any,

0 commit comments

Comments
 (0)