Skip to content

Commit

Permalink
fixes #1
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Nov 23, 2020
1 parent e92c532 commit 4770a23
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 51 deletions.
6 changes: 3 additions & 3 deletions 00_core.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,12 @@
"outputs": [],
"source": [
"p = Path('fcgi.sock')\n",
"if p.exists(): p.unlink()\n",
"\n",
"@threaded\n",
"def _f():\n",
" with UnixStreamServer(str(p), TestHandler) as srv: srv.handle_request()\n",
"\n",
"if p.exists(): p.unlink()\n",
"t = _f()\n",
"_f()\n",
"time.sleep(0.2) # wait for server to start"
]
},
Expand Down Expand Up @@ -622,6 +621,7 @@
"text": [
"Converted 00_core.ipynb.\n",
"Converted 01_decorator.ipynb.\n",
"Converted 02_http.ipynb.\n",
"Converted index.ipynb.\n"
]
}
Expand Down
12 changes: 2 additions & 10 deletions 01_decorator.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,7 @@
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<html>foo=bar&greeting=你好 ; a=1</html>\r\n",
"\n"
]
}
],
"outputs": [],
"source": [
"time.sleep(0.5)\n",
"proc = subprocess.Popen('./http2fcgi -fcgi tcp://localhost:8003'.split())\n",
Expand Down Expand Up @@ -198,6 +189,7 @@
"text": [
"Converted 00_core.ipynb.\n",
"Converted 01_decorator.ipynb.\n",
"Converted 02_http.ipynb.\n",
"Converted index.ipynb.\n"
]
}
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ docs: $(SRC)
touch docs

test:
nbdev_test_nbs
nbdev_test_nbs --n_workers 0

release: pypi conda_release
nbdev_bump_version
Expand All @@ -34,4 +34,4 @@ dist: clean
python setup.py sdist bdist_wheel

clean:
rm -rf dist
rm -rf dist
51 changes: 45 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# fastcgi
> A fastcgi handler for Python's `socketserver` classes
> FastCGI and HTTP handlers for Python's `socketserver` classes

[FastCGI](http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html) is a way for front-end servers to talk to back-end workers in a (somewhat) efficient and (somewhat) simple way. Although it's been around since 1996, it is not very widely appreciated, except in the PHP community, where it is very commonly used.
Expand All @@ -13,21 +13,42 @@ There's no new frameworks or concepts to learn. Just call `send` to send anythin
example.com
reverse_proxy localhost:1234 { transport fastcgi }

This library also provides an HTTP handler that can be used in an identical way, except remove `{ transport fastcgi }` from the above `Caddyfile` example. Python's standard library already includes an HTTP handler (in `http.server`), however the documentation warns that that module should not be used in production code. The HTTP handler provided here is trimmed down to a minimal implementation (just 40 lines of code) so that it can easily be studied and extended. It uses the same basic API as Python's other `socketserver` classes (and the same as `FcgiHandler` here) so there's fewer new concepts to understand.

## Install

`pip install fastcgi` or `conda install -c fastai fastcgi`

## How to use

Probably the only thing you need to use is `FcgiHandler`, which is used in much the same way as Python's [BaseRequestHandler](https://docs.python.org/3/library/socketserver.html#request-handler-objects). Here's an example:
See the full docs pages for each class for details. Quick overviews of each approach are shown below.

### fastcgi decorator

Using the `fastcgi` decorator you can use CGI scripts with minimal changes. Just add the decorator above a function used for CGI, and it converts that script automatically into a FastCGI server, e.g if you save this as `server.py`:

```python
@fastcgi()
def hello():
query = os.environ["QUERY_STRING"]
content = sys.stdin.read()
sys.stdout.write(f"Content-type: text/html\r\n\r\n<html>{content} ; ")
sys.stdout.write(f"{query}</html>\r\n")
```

...then if you run `python server.py` it will make a unix socket available as `fcgi.sock` in the current directory.

### FcgiHandler

`FcgiHandler` is used in much the same way as Python's [BaseRequestHandler](https://docs.python.org/3/library/socketserver.html#request-handler-objects). Here's an example:

```python
class TestHandler(FcgiHandler):
def handle(self):
print('query:', self.params['QUERY_STRING'])
print('content type:', self.params['HTTP_CONTENT_TYPE'])
print('stdin:', self.content)
self.stdout.write(b"Content-type: text/html\r\n\r\n<html>foobar</html>\r\n")
print('query:', self.environ['QUERY_STRING'])
print('content type:', self.environ['HTTP_CONTENT_TYPE'])
print('stdin:', self['stdin'].read())
self['stdout'].write(b"Content-type: text/html\r\n\r\n<html>foobar</html>\r\n")
```

You can run this using any of Python's `socketserver` classes, e.g to listen on localhost port 1234:
Expand All @@ -42,3 +63,21 @@ See the API docs for `FcgiHandler` for an end-to-end example.
You can also create a forking or threading server by using Python's [mixins or predefined classes](https://docs.python.org/3/library/socketserver.html#socketserver.ThreadingMixIn).

In your `handle` method, you can use the `stdin`, `stdout`, and `stderr` attributes, which each contain a `BytesIO` stream.

### MinimalHTTPHandler

`fastcgi` also comes with the `MinimalHTTPHandler` class, which provides very similar functionality to `FcgiHandler`, but using the `HTTP` protocol instead of the `FastCGI` protocol. Here's an example:

```python
class _TestHandler(MinimalHTTPHandler):
def handle(self):
print(f'Command/path/version: {self.command} {self.path} {self.request_version}')
print(self.headers)
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header('Content-Length', '2')
self.end_headers()
self.wfile.write(b'ok')
```

You can run it with a `socketserver` server in the same way shown above for `FcgiHandler`.
3 changes: 3 additions & 0 deletions docs/_data/sidebars/home_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ entries:
- output: web,pdf
title: fastcgi.decorator
url: decorator.html
- external_url: http.html
output: web,pdf
title: fastcgi.http
output: web
title: fastcgi
output: web
Expand Down
5 changes: 2 additions & 3 deletions docs/core.html
Original file line number Diff line number Diff line change
Expand Up @@ -540,13 +540,12 @@ <h2 id="FcgiHandler" class="doc_header"><code>class</code> <code>FcgiHandler</co
<div class="inner_cell">
<div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;fcgi.sock&#39;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span> <span class="n">p</span><span class="o">.</span><span class="n">unlink</span><span class="p">()</span>

<span class="nd">@threaded</span>
<span class="k">def</span> <span class="nf">_f</span><span class="p">():</span>
<span class="k">with</span> <span class="n">UnixStreamServer</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">p</span><span class="p">),</span> <span class="n">TestHandler</span><span class="p">)</span> <span class="k">as</span> <span class="n">srv</span><span class="p">:</span> <span class="n">srv</span><span class="o">.</span><span class="n">handle_request</span><span class="p">()</span>

<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span> <span class="n">p</span><span class="o">.</span><span class="n">unlink</span><span class="p">()</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">_f</span><span class="p">()</span>
<span class="n">_f</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span> <span class="c1"># wait for server to start</span>
</pre></div>

Expand Down
Loading

0 comments on commit 4770a23

Please sign in to comment.