Skip to content

Commit

Permalink
docs: add Usage and README document
Browse files Browse the repository at this point in the history
- add `Usage` document
- improve `README.md`
- adjust the source code docs in `src/`.
  • Loading branch information
WSH032 committed Nov 25, 2023
1 parent 250af30 commit 0155d89
Show file tree
Hide file tree
Showing 10 changed files with 466 additions and 135 deletions.
122 changes: 121 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,121 @@
Documentation is coming, please use [API Reference](https://WSH032.github.io/fastapi-proxy-lib/) first. :smile:
# FastAPI Proxy Lib

<p align="center">
<em>HTTP/WebSocket proxy for starlette/FastAPI</em>
</p>

| | |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| CI/CD | [![CI: lint-test]][CI: lint-test#link] [![CI: docs]][CI: docs#link] |
| Code | [![codecov]][codecov#link] [![Code style: black]][Code style: black#link] [![Ruff]][Ruff#link] [![Checked with pyright]][Checked with pyright#link] |
| Package | [![Python-Version]][Python-Version#link] |
| Meta | [![Hatch project]][Hatch project#link] [![GitHub License]][GitHub License#link] |

---

Documentation: <https://wsh032.github.io/fastapi-proxy-lib/>

Source Code: <https://github.com/WSH032/fastapi-proxy-lib/>

---

## Features

- [X] **Out of the box !** [Helper functions](#quick-start) to get FastAPI `app`/`router` for proxy conveniently.
- [x] **Only `Starlette` is required** for it to work ([`FastAPI` is optional](#installation)).
- [x] Support both **HTTP** and **WebSocket** proxy.
- [x] Supports all HTTP methods (`GET`, `POST`, etc.)
- [x] Support both **reverse** proxy and **forward** proxy.
- [x] **Transparently** and **losslessly** handle all proxy requests,
- [x] Asynchronous streaming transfer, support **file proxy**.

### other features

- [x] Strict linting and strict-mode Pyright type checking.
- [x] **100%** [Type Completeness](https://microsoft.github.io/pyright/#/typed-libraries?id=type-completeness), [Code coverage of **over 95%**][codecov#link].
- [x] Forced keep-alive connections, minimizing proxy latency.
- [x] Handle errors as gracefully as possible.

### `FastAPI Proxy Lib` stands on the shoulders of giants

- [httpx](https://github.com/encode/httpx) for HTTP proxy
- [httpx-ws](https://github.com/frankie567/httpx-ws) for WebSocket proxy

So, it perfectly supports all features of [httpx.AsyncClient](https://www.python-httpx.org/advanced/#client-instances), you can even use your custom `AsyncClient`, [`Transport`](https://www.python-httpx.org/advanced/#custom-transports).

## Installation

> !!! note
>
> We follow semantic versioning.<br>
> This is a young project, and before 1.0.0, there may be changes in the API (though we try to avoid that).<br>
> We recommend pinning to any minor versions, such as 0.1.x.
Pypi will come soon, please install from github temporarily:

```shell
pip install fastapi-proxy-lib[standard]@git+https://github.com/WSH032/fastapi-proxy-lib.git
```

Perhaps you've noticed that we're installing `fastapi-proxy-lib[standard]` instead of `fastapi-proxy-lib`. The difference is:

- The former will install `FastAPI` at the same time.
- The latter installs only the basic dependencies for `fastapi-proxy-lib`.

If you **only need to use this library with Starlette**, you only need to install the latter.

## Quick start

With the helper functions, get the FastAPI proxy server app is very convenient and out of the box:

```python
from fastapi_proxy_lib.fastapi.app import reverse_http_app

app = reverse_http_app(base_url="http://www.example.com/foo/")
```

That's all! Now, you can launch the proxy server with `uvicorn`:

```shell
uvicorn main:app --host 127.0.0.1 --port 8000
```

Then, visit `http://127.0.0.1:8000/bar?baz=1`, you will get the response from `http://www.example.com/foo/bar?baz=1`.

For support with `FastAPI router` or only using `Starlette`, please **visit to our [documentation 📚](https://wsh032.github.io/fastapi-proxy-lib/) for more details**.

## development

- If you find any issues, please don't hesitate to [open an issue](https://github.com/WSH032/fastapi-proxy-lib/issues).
- If you need assistance, feel free to [start a discussion](https://github.com/WSH032/fastapi-proxy-lib/discussions).
- [Welcome PR](https://github.com/WSH032/fastapi-proxy-lib/pulls)

English is not the native language of the author (me), so if you find any areas for improvement in the documentation, your feedback is welcome.

If you think this project helpful, consider giving it a star ![GitHub Repo stars](https://img.shields.io/github/stars/wsh032/fastapi-proxy-lib?style=social)
, which makes me happy. :smile:

## License

This project is licensed under the terms of the *Apache License 2.0*.

<!-- link -->

[CI: lint-test]: https://github.com/WSH032/fastapi-proxy-lib/actions/workflows/lint-test.yml/badge.svg?branch=main
[CI: lint-test#link]: https://github.com/WSH032/fastapi-proxy-lib/actions/workflows/lint-test.yml
[CI: docs]: https://github.com/WSH032/fastapi-proxy-lib/actions/workflows/docs.yml/badge.svg?branch=main
[CI: docs#link]: https://github.com/WSH032/fastapi-proxy-lib/actions/workflows/docs.yml
[Python-Version]: https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2FWSH032%2Ffastapi-proxy%2Fmain%2Fpyproject.toml&logo=python&logoColor=gold&label=Python
[Python-Version#link]: https://github.com/WSH032/fastapi-proxy-lib/blob/main/pyproject.toml
[Code style: black]: https://img.shields.io/badge/code%20style-black-000000.svg
[Code style: black#link]: https://github.com/psf/black
[GitHub License]: https://img.shields.io/github/license/WSH032/fastapi-proxy-lib?color=9400d3
[GitHub License#link]: https://github.com/WSH032/fastapi-proxy-lib/blob/main/LICENSE
[Ruff]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
[Ruff#link]: https://github.com/astral-sh/ruff
[Checked with pyright]: https://microsoft.github.io/pyright/img/pyright_badge.svg
[Checked with pyright#link]: https://microsoft.github.io/pyright
[Hatch project]: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg
[Hatch project#link]: https://github.com/pypa/hatch
[codecov]: https://codecov.io/gh/WSH032/fastapi-proxy-lib/graph/badge.svg?token=62QQU06E8X
[codecov#link]: https://codecov.io/gh/WSH032/fastapi-proxy-lib
18 changes: 18 additions & 0 deletions docs/Usage/Advanced-and-Starlette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Advanced and Starlette

For the following scenarios, you might prefer [fastapi_proxy_lib.core][]:

- When you need to use proxies with **only** `Starlette` dependencies (without `FastAPI`).
- When you need more fine-grained control over parameters and lifespan event.
- When you need to further process the input and output before and after the proxy (similar to middleware).

We will demonstrate with `FastAPI`,
but you can completely switch to the `Starlette` approach,
which is officially supported by this project.

**^^[Please visit the `ReverseHttpProxy#examples` to view the demo with annotations :material-file-document: ][fastapi_proxy_lib.core.http.ReverseHttpProxy--examples]^^**.

Also (without annotations):

- [`ForwardHttpProxy#examples`][fastapi_proxy_lib.core.http.ForwardHttpProxy--examples]
- [`ReverseWebSocketProxy#examples`][fastapi_proxy_lib.core.websocket.ReverseWebSocketProxy--examples]
48 changes: 48 additions & 0 deletions docs/Usage/FastAPI-Helper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# FastAPI Helper

!!!note
FastAPI Helper Module need `FastAPI` installed.

There are two helper modules to get FastAPI `app`/`router` for proxy conveniently.

- [fastapi_proxy_lib.fastapi.app][]: High-level
- [fastapi_proxy_lib.fastapi.router][]: Low-level

## app

use `fastapi_proxy_lib.fastapi.app` is very convenient and out of the box, there are three helper functions:

- [forward_http_app][fastapi_proxy_lib.fastapi.app.forward_http_app]
- [reverse_http_app][fastapi_proxy_lib.fastapi.app.reverse_http_app]
- [reverse_ws_app][fastapi_proxy_lib.fastapi.app.reverse_ws_app]

Example:

```python
from fastapi_proxy_lib.fastapi.app import reverse_http_app
from httpx import AsyncClient

client = AsyncClient() # (1)!
base_url = "http://www.example.com/" # (2)!

app = reverse_http_app(client=client, base_url=base_url)
```

1. You can pass `httpx.AsyncClient` instance:
- if you want to customize the arguments, e.g. `httpx.AsyncClient(proxies={})`
- if you want to reuse the connection pool of `httpx.AsyncClient`
---
Or you can pass `None`(The default value), then `fastapi-proxy-lib` will create a new `httpx.AsyncClient` instance for you.
2. !!! note
The `base_url` must end with `/`!

For other app helpers, please refer to their API references.

## router

For the following scenarios, you might prefer [fastapi_proxy_lib.fastapi.router][]:

- When you need to adjust the `app`/`router` parameters.
- When you need to [mount the proxy on a route of larger app](https://fastapi.tiangolo.com/tutorial/bigger-applications/).

**^^[Please refer to the documentation of `RouterHelper` for more information :material-file-document: ][fastapi_proxy_lib.fastapi.router.RouterHelper--examples]^^**.
53 changes: 53 additions & 0 deletions docs/Usage/Security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Security

## proxy requests filter in forward proxy

Forward proxy allows access to any URL on input, which can be **scary** 😫 if not restricted.

For example, through `http://www.my-proxy-server.com/http://127.0.0.1:8000`,
an attacker can access the server's local network.

So, there is a `proxy_filter` argument in [`ForwardHttpProxy`][fastapi_proxy_lib.core.http.ForwardHttpProxy.__init__] to filter requests.

If you do not explicitly specify it, `ForwardHttpProxy` will issue a warning and specify a [default_proxy_filter][fastapi_proxy_lib.core.tool.default_proxy_filter].

- If you want to accept all proxy requests (**never do this on a public server**), you can do it like this:

```python
proxy_filter = lambda _: None
```

- If you want to implement your own proxy filter, please refer to the [fastapi_proxy_lib.core.tool.ProxyFilterProto][].

## `http` vs `https`

!!! danger
**Never use a server with the HTTPS protocol to proxy a target server (`base_url`) with the HTTP protocol !**

e.g. `https://www.my-proxy-server.com/http://www.example.com/`

There is a security issue:

Browsers may send sensitive HTTPS information to your HTTPS proxy server,
then because of transparency feature, `fastapi-proxy-lib` will forward
these information to the target server using the HTTP protocol without modification,
which may cause privacy leaks.

!!! failure
If you reverse it. Use an HTTP server to proxy an HTTPS target server.

There is a high probability that the request will fail.

## The same-origin policy of `ForwardHttpProxy`

The `ForwardHttpProxy` server uses the same source to proxy different target servers. e.g:

> http://www.my-proxy-server.com/http://www.example.com/<br>
> http://www.my-proxy-server.com/http://www.google.com/
>
> both source are `http://www.my-proxy-server.com/`

For this situation, the browser's same-origin protection policy will fail,
and cookies from `http://www.example.com/` will be sent to` http://www.google.com/`.

You should inform the user of this situation and let them decide whether to continue.
27 changes: 27 additions & 0 deletions docs/Usage/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Introduction

We provide two types of proxies:

- reverse proxy:
- [ReverseHttpProxy][fastapi_proxy_lib.core.http.ReverseHttpProxy]
- [ReverseWebSocketProxy][fastapi_proxy_lib.core.websocket.ReverseWebSocketProxy]
- forward proxy:
- [ForwardHttpProxy][fastapi_proxy_lib.core.http.ForwardHttpProxy]

## What is a reverse proxy?

A reverse proxy is similar to a gateway.

All reverse proxies have a `base_url` parameter, which transparently forwards all requests sent to the proxy server to the target server specified by `base_url`.

For example, if you set `base_url` to `http://www.example.com/foo/`, and the proxy server launches at `http://127.0.0.1:8000`.

Then all requests sent to the proxy server will be forwarded to `http://www.example.com/foo/`, including `path-params`, `query-params`, `headers`, `cookies`, etc.

Visit `http//127.0.0.1:8000/bar?baz=1`, will get the response from `http://www.example.com/foo/bar?baz=1`.

## What is a forward proxy?

A forward proxy is very similar to a reverse proxy, except that the forward proxy server uses the full `path` of the requests it receives as the `base_url`.

For example, visit `http//127.0.0.1:8000/http://www.example.com/foo/bar?baz=1`, will get the response from `http://www.example.com/foo/bar?baz=1`.
9 changes: 8 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ theme:
- content.action.view
- content.tabs.link
- content.tooltips
# - navigation.top
- navigation.top
# - navigation.expand
# - navigation.tracking
# https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#system-preference
Expand Down Expand Up @@ -124,6 +124,8 @@ extra:

watch:
- src/fastapi_proxy_lib
- README.md
- CONTRIBUTING.md

validation:
omitted_files: warn
Expand All @@ -134,4 +136,9 @@ validation:
# It's used in scripts/gen_ref_pages.py
nav:
- Home: index.md
- Usage:
- Usage/index.md
- Usage/FastAPI-Helper.md
- Usage/Advanced-and-Starlette.md
- Usage/Security.md
- API Reference: reference/
Loading

0 comments on commit 0155d89

Please sign in to comment.