Skip to content

Commit aaa87a8

Browse files
Much more flexible support for static files in the server
1 parent 3b32dbd commit aaa87a8

File tree

5 files changed

+95
-45
lines changed

5 files changed

+95
-45
lines changed

docs/server.rst

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,85 @@ ASGI application::
4949
# wrap with ASGI application
5050
app = socketio.ASGIApp(sio)
5151

52-
The WSGI and ASGI application wrappers support serving static files, which is
53-
a convenient way to deliver JavaScript based Socket.IO clients to the web
54-
browser::
52+
These two wrappers can also act as middlewares, forwarding any traffic that is
53+
not intended to the Socket.IO server to another application. This allows
54+
Socket.IO servers to integrate easily into existing WSGI or ASGI applications::
5555

56-
app = socketio.ASGIApp(sio, static_files={
57-
'/': {'content_type': 'text/html', 'filename': 'latency.html'},
58-
'/static/style.css': {'content_type': 'text/css',
59-
'filename': 'static/style.css'},
60-
})
56+
from wsgi import app # a Flask, Django, etc. application
57+
app = socketio.WSGIApp(sio, app)
6158

62-
The dictionary provided with the ``static_files`` argument has static file
63-
endpoints as keys. For each of these endpoints, a dictionary with the file's
64-
content type and local filename is given.
59+
Serving Static Files
60+
--------------------
6561

66-
These wrappers can also act as middlewares, forwarding any traffic that is not
67-
intended to Socket.IO server to another application. This allows Socket.IO
68-
servers to integrate easily into existing WSGI or ASGI applications::
62+
This package offers the option to configure the serving of static files. This
63+
is particularly useful to deliver HTML, CSS and JavaScript files to clients
64+
when this package is used without a companion web framework.
6965

70-
from wsgi import app # a Flask, Django, etc. application
66+
Static files are configured with a Python dictionary in which each key/value
67+
pair is a static file mapping rule. In its simplest form, this dictionary has
68+
one or more static file URLs as keys, and the corresponding files in the server
69+
as values::
7170

72-
app = socketio.WSGIApp(sio, app)
71+
static_files = {
72+
'/': 'latency.html',
73+
'/static/socket.io.js': 'static/socket.io.js',
74+
'/static/style.css': 'static/style.css',
75+
}
76+
77+
With this example configuration, when the server receives a request for ``/``
78+
(the root URL) it will return the contents of the file ``latency.html`` in the
79+
current directory, and will assign a content type based on the file extension,
80+
in this case ``text/html``.
81+
82+
Files with the ``.html``, ``.css``, ``.js``, ``.json``, ``.jpg``, ``.png``,
83+
``.gif`` and ``.txt`` file extensions are automatically recognized and
84+
assigned the correct content type. For files with other file extensions or
85+
with no file extension, the ``application/octet-stream`` content type is used
86+
as a default.
87+
88+
If desired, an explicit content type for a static file can be given as follows::
89+
90+
static_files = {
91+
'/': {'filename': 'latency.html', 'content_type': 'text/plain'},
92+
}
93+
94+
Finally, it is also possible to configure an entire directory in a single rule,
95+
so that all the files in it are served as static files::
96+
97+
static_files = {
98+
'/static': './public',
99+
'/': './public/index.html',
100+
}
101+
102+
In this example any files with URLs starting with ``/static`` will be served
103+
directly from the ``public`` folder in the current directory, so for example,
104+
the URL ``/static/index.html`` will return local file ``./public/index.html``
105+
and the URL ``/static/css/styles.css`` will return local file
106+
``./public/css/styles.css``. The second rule creates a default mapping for the
107+
``index.html`` file when the root URL is requested.
108+
109+
The static file configuration dictionary is given as the ``static_files``
110+
argument to the ``socketio.WSGIApp`` or ``socketio.ASGIApp`` classes::
111+
112+
# for standard WSGI applications
113+
sio = socketio.Server()
114+
app = socketio.WSGIApp(sio, static_files=static_files)
115+
116+
# for asyncio-based ASGI applications
117+
sio = socketio.AsyncServer()
118+
app = socketio.ASGIApp(sio, static_files=static_files)
119+
120+
The routing precedence in these two classes is as follows:
121+
122+
- First, the path is checked against the Socket.IO endpoint.
123+
- Next, the path is checked against the static file configuration, if present.
124+
- If the path did not match the Socket.IO endpoint or any static file, control
125+
is passed to the secondary application if configured, else a 404 error is
126+
returned.
127+
128+
Note: static file serving is intended for development use only, and as such
129+
it lacks important features such as caching. Do not use in a production
130+
environment.
73131

74132
Defining Event Handlers
75133
-----------------------
@@ -490,7 +548,7 @@ explicitly, the ``async_mode`` option can be given in the constructor::
490548
sio = socketio.AsyncServer(async_mode='tornado')
491549

492550
A server configured for tornado must include a request handler for
493-
Engine.IO::
551+
Socket.IO::
494552

495553
app = tornado.web.Application(
496554
[
@@ -572,10 +630,10 @@ explicitly, the ``async_mode`` option can be given in the constructor::
572630

573631
sio = socketio.Server(async_mode='eventlet')
574632

575-
A server configured for eventlet is deployed as a regular WSGI application,
576-
using the provided ``socketio.Middleware``::
633+
A server configured for eventlet is deployed as a regular WSGI application
634+
using the provided ``socketio.WSGIApp``::
577635

578-
app = socketio.Middleware(sio)
636+
app = socketio.WSGIApp(sio)
579637
import eventlet
580638
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
581639

@@ -614,10 +672,10 @@ option can be given in the constructor::
614672

615673
sio = socketio.Server(async_mode='gevent')
616674

617-
A server configured for gevent is deployed as a regular WSGI application,
618-
using the provided ``socketio.Middleware``::
675+
A server configured for gevent is deployed as a regular WSGI application
676+
using the provided ``socketio.WSGIApp``::
619677

620-
app = socketio.Middleware(sio)
678+
app = socketio.WSGIApp(sio)
621679
from gevent import pywsgi
622680
pywsgi.WSGIServer(('', 8000), app).serve_forever()
623681

@@ -626,7 +684,7 @@ follows::
626684

627685
from gevent import pywsgi
628686
from geventwebsocket.handler import WebSocketHandler
629-
app = socketio.Middleware(sio)
687+
app = socketio.WSGIApp(sio)
630688
pywsgi.WSGIServer(('', 8000), app,
631689
handler_class=WebSocketHandler).serve_forever()
632690

@@ -699,7 +757,7 @@ development web server based on Werkzeug::
699757

700758
sio = socketio.Server(async_mode='threading')
701759
app = Flask(__name__)
702-
app.wsgi_app = socketio.Middleware(sio, app.wsgi_app)
760+
app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app)
703761

704762
# ... Socket.IO and Flask handler functions ...
705763

examples/server/asgi/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
sio = socketio.AsyncServer(async_mode='asgi')
99
app = socketio.ASGIApp(sio, static_files={
10-
'/': {'content_type': 'text/html', 'filename': 'app.html'},
10+
'/': 'app.html',
1111
})
1212
background_task_started = False
1313

examples/server/asgi/latency.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55

66
sio = socketio.AsyncServer(async_mode='asgi')
77
app = socketio.ASGIApp(sio, static_files={
8-
'/': {'content_type': 'text/html', 'filename': 'latency.html'},
9-
'/static/style.css': {'content_type': 'text/css',
10-
'filename': 'static/style.css'},
8+
'/': 'latency.html',
9+
'/static': 'static',
1110
})
1211

1312

socketio/asgi.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ class ASGIApp(engineio.ASGIApp): # pragma: no cover
1010
1111
:param socketio_server: The Socket.IO server. Must be an instance of the
1212
``socketio.AsyncServer`` class.
13-
:param static_files: A dictionary where the keys are URLs that should be
14-
served as static files. For each URL, the value is
15-
a dictionary with ``content_type`` and ``filename``
16-
keys. This option is intended to be used for serving
17-
client files during development.
13+
:param static_files: A dictionary with static file mapping rules. See the
14+
documentation for details on this argument.
1815
:param other_asgi_app: A separate ASGI app that receives all other traffic.
1916
:param socketio_path: The endpoint where the Socket.IO application should
2017
be installed. The default value is appropriate for
@@ -25,13 +22,12 @@ class ASGIApp(engineio.ASGIApp): # pragma: no cover
2522
import socketio
2623
import uvicorn
2724
28-
eio = socketio.AsyncServer()
29-
app = engineio.ASGIApp(eio, static_files={
30-
'/': {'content_type': 'text/html', 'filename': 'index.html'},
31-
'/index.html': {'content_type': 'text/html',
32-
'filename': 'index.html'},
25+
sio = socketio.AsyncServer()
26+
app = engineio.ASGIApp(sio, static_files={
27+
'/': 'index.html',
28+
'/static': './public',
3329
})
34-
uvicorn.run(app, '127.0.0.1', 5000)
30+
uvicorn.run(app, host='127.0.0.1', port=5000)
3531
"""
3632
def __init__(self, socketio_server, other_asgi_app=None,
3733
static_files=None, socketio_path='socket.io'):

socketio/middleware.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ class WSGIApp(engineio.WSGIApp):
1111
:param socketio_app: The Socket.IO server. Must be an instance of the
1212
``socketio.Server`` class.
1313
:param wsgi_app: The WSGI app that receives all other traffic.
14-
:param static_files: A dictionary where the keys are URLs that should be
15-
served as static files. For each URL, the value is
16-
a dictionary with ``content_type`` and ``filename``
17-
keys. This option is intended to be used for serving
18-
client files during development.
14+
:param static_files: A dictionary with static file mapping rules. See the
15+
documentation for details on this argument.
1916
:param socketio_path: The endpoint where the Socket.IO application should
2017
be installed. The default value is appropriate for
2118
most cases.

0 commit comments

Comments
 (0)