More/fixed documentation on the octoprint.server.util module
This commit is contained in:
parent
7263fb74a9
commit
ad054338b5
4 changed files with 214 additions and 109 deletions
|
|
@ -10,6 +10,7 @@ Internal Modules
|
|||
filemanager.rst
|
||||
plugin.rst
|
||||
printer.rst
|
||||
server.rst
|
||||
settings.rst
|
||||
slicing.rst
|
||||
util.rst
|
||||
|
|
|
|||
42
docs/modules/server.rst
Normal file
42
docs/modules/server.rst
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
.. _sec-modules-server:
|
||||
|
||||
octoprint.server
|
||||
----------------
|
||||
|
||||
.. automodule:: octoprint.server
|
||||
:members:
|
||||
|
||||
.. _sec-modules-server-util:
|
||||
|
||||
octoprint.server.util
|
||||
---------------------
|
||||
|
||||
.. automodule:: octoprint.server.util
|
||||
:members:
|
||||
|
||||
.. _sec-modules-server-util-flask:
|
||||
|
||||
octoprint.server.util.flask
|
||||
---------------------------
|
||||
|
||||
.. automodule:: octoprint.server.util.flask
|
||||
:members:
|
||||
|
||||
.. _sec-modules-server-util-sockjs:
|
||||
|
||||
octoprint.server.util.sockjs
|
||||
----------------------------
|
||||
|
||||
.. automodule:: octoprint.server.util.sockjs
|
||||
:members:
|
||||
|
||||
.. _sec-modules-server-util-tornado:
|
||||
|
||||
octoprint.server.util.tornado
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: octoprint.server.util.tornado
|
||||
:members:
|
||||
|
||||
|
||||
|
||||
|
|
@ -20,10 +20,11 @@ from . import watchdog
|
|||
|
||||
def apiKeyRequestHandler():
|
||||
"""
|
||||
All requests in this blueprint need to be made supplying an API key. This may be the UI_API_KEY, in which case
|
||||
the underlying request processing will directly take place, or it may be the global or a user specific case. In any
|
||||
case it has to be present and must be valid, so anything other than the above three types will result in denying
|
||||
the request.
|
||||
``before_request`` handler for blueprints for which all requests need to be made supplying an API key.
|
||||
|
||||
This may be the UI_API_KEY, in which case the underlying request processing will directly take place, or it may be
|
||||
the global, an app specific or a user specific one. In any case it has to be present and must be valid, so anything
|
||||
other than the above types will result in the application denying the request.
|
||||
"""
|
||||
|
||||
import octoprint.server
|
||||
|
|
@ -62,6 +63,11 @@ def apiKeyRequestHandler():
|
|||
|
||||
|
||||
def corsResponseHandler(resp):
|
||||
"""
|
||||
``after_request`` handler for blueprints for which CORS is supported.
|
||||
|
||||
Sets ``Access-Control-Allow-Origin`` headers for ``Origin`` request header on response.
|
||||
"""
|
||||
|
||||
# Allow crossdomain
|
||||
allowCrossOrigin = settings().getBoolean(["api", "allowCrossOrigin"])
|
||||
|
|
@ -72,7 +78,9 @@ def corsResponseHandler(resp):
|
|||
|
||||
|
||||
def optionsAllowOrigin(request):
|
||||
""" Always reply 200 on OPTIONS request """
|
||||
"""
|
||||
Shortcut for request handling for CORS OPTIONS requests to set CORS headers.
|
||||
"""
|
||||
|
||||
resp = _flask.current_app.make_default_options_response()
|
||||
|
||||
|
|
@ -131,18 +139,24 @@ class ReverseProxied(object):
|
|||
different than what is used locally.
|
||||
|
||||
In nginx:
|
||||
location /myprefix {
|
||||
proxy_pass http://192.168.0.1:5001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Scheme $scheme;
|
||||
proxy_set_header X-Script-Name /myprefix;
|
||||
}
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
location /myprefix {
|
||||
proxy_pass http://192.168.0.1:5001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Scheme $scheme;
|
||||
proxy_set_header X-Script-Name /myprefix;
|
||||
}
|
||||
|
||||
Alternatively define prefix and scheme via config.yaml:
|
||||
server:
|
||||
baseUrl: /myprefix
|
||||
scheme: http
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
server:
|
||||
baseUrl: /myprefix
|
||||
scheme: http
|
||||
|
||||
:param app: the WSGI application
|
||||
:param header_script_name: the HTTP header in the wsgi environment from which to determine the prefix
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import octoprint.util
|
|||
|
||||
def fix_ioloop_scheduling():
|
||||
"""
|
||||
This monkey patches tornado's :meth:`tornado.ioloop.PeriodicCallback._schedule_next` method so it no longer
|
||||
This monkey patches tornado's :meth:``tornado.ioloop.PeriodicCallback._schedule_next`` method so it no longer
|
||||
blocks for long times on slow machines (RPi) when the system time happens to change by a large amount (e.g. due to
|
||||
the first ever contact to an NTP server).
|
||||
|
||||
|
|
@ -65,63 +65,67 @@ def fix_ioloop_scheduling():
|
|||
@tornado.web.stream_request_body
|
||||
class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
||||
"""
|
||||
A `RequestHandler` similar to `tornado.web.FallbackHandler` which fetches any files contained in the request bodies
|
||||
of content type `multipart`, stores them in temporary files and supplies the `fallback` with the file's `name`,
|
||||
`content_type`, `path` and `size` instead via a rewritten body.
|
||||
A ``RequestHandler`` similar to ``tornado.web.FallbackHandler`` which fetches any files contained in the request bodies
|
||||
of content type ``multipart``, stores them in temporary files and supplies the ``fallback`` with the file's ``name``,
|
||||
``content_type``, ``path`` and ``size`` instead via a rewritten body.
|
||||
|
||||
Basically similar to what the nginx upload module does.
|
||||
|
||||
Basic request body example:
|
||||
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file"; filename="test.gcode"
|
||||
Content-Type: application/octet-stream
|
||||
.. code-block:: none
|
||||
|
||||
...
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="apikey"
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file"; filename="test.gcode"
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
my_funny_apikey
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="select"
|
||||
...
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="apikey"
|
||||
|
||||
true
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C--
|
||||
my_funny_apikey
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="select"
|
||||
|
||||
true
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C--
|
||||
|
||||
That would get turned into:
|
||||
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="apikey"
|
||||
.. code-block:: none
|
||||
|
||||
my_funny_apikey
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="select"
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="apikey"
|
||||
|
||||
true
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.path"
|
||||
my_funny_apikey
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="select"
|
||||
|
||||
/tmp/tmpzupkro
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.name"
|
||||
true
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.path"
|
||||
|
||||
test.gcode
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.content_type"
|
||||
/tmp/tmpzupkro
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.name"
|
||||
|
||||
application/octet-stream
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.size"
|
||||
test.gcode
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.content_type"
|
||||
|
||||
349182
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C--
|
||||
application/octet-stream
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C
|
||||
Content-Disposition: form-data; name="file.size"
|
||||
|
||||
349182
|
||||
------WebKitFormBoundarypYiSUx63abAmhT5C--
|
||||
|
||||
The underlying application can then access the contained files via their respective paths and just move them
|
||||
where necessary.
|
||||
"""
|
||||
|
||||
# the request methods that may contain a request body
|
||||
BODY_METHODS = ("POST", "PATCH", "PUT")
|
||||
""" The request methods that may contain a request body. """
|
||||
|
||||
def initialize(self, fallback, file_prefix="tmp", file_suffix="", path=None, suffixes=None):
|
||||
if not suffixes:
|
||||
|
|
@ -162,8 +166,8 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
def prepare(self):
|
||||
"""
|
||||
Prepares the processing of the request. If it's a request that may contain a request body (as defined in
|
||||
`UploadStorageFallbackHandler.BODY_METHODS) prepares the multipart parsing if content type fits. If it's a
|
||||
body-less request, just calls the `fallback` with an empty body and finishes the request.
|
||||
:attr:`UploadStorageFallbackHandler.BODY_METHODS`) prepares the multipart parsing if content type fits. If it's a
|
||||
body-less request, just calls the ``fallback`` with an empty body and finishes the request.
|
||||
"""
|
||||
if self.request.method in UploadStorageFallbackHandler.BODY_METHODS:
|
||||
self._bytes_left = self.request.headers.get("Content-Length", 0)
|
||||
|
|
@ -194,7 +198,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
def data_received(self, chunk):
|
||||
"""
|
||||
Called by Tornado on receiving a chunk of the request body. If request is a multipart request, takes care of
|
||||
processing the multipart data structure via `self._process_multipart_data`. If not, just adds the chunk to
|
||||
processing the multipart data structure via :func:`_process_multipart_data`. If not, just adds the chunk to
|
||||
internal in-memory buffer.
|
||||
|
||||
:param chunk: chunk of data received from Tornado
|
||||
|
|
@ -207,7 +211,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
self._buffer = data
|
||||
|
||||
def is_multipart(self):
|
||||
"""Checks whether this request is a `multipart` request"""
|
||||
"""Checks whether this request is a ``multipart`` request"""
|
||||
return self._content_type is not None and self._content_type.startswith("multipart")
|
||||
|
||||
def _process_multipart_data(self, data):
|
||||
|
|
@ -251,7 +255,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
|
||||
def _on_part_header(self, header):
|
||||
"""
|
||||
Called for a new multipart header, takes care of parsing the header and calling `self._on_part` with the
|
||||
Called for a new multipart header, takes care of parsing the header and calling :func:`_on_part` with the
|
||||
relevant data, setting the current part in the process.
|
||||
|
||||
:param header: header to parse
|
||||
|
|
@ -283,23 +287,24 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
|
||||
def _on_part_start(self, name, content_type, filename=None):
|
||||
"""
|
||||
Called for new parts in the multipart stream. If `filename` is given creates new `file` part (which leads
|
||||
to storage of the data as temporary file on disk), if not creates a new `data` part (which stores
|
||||
Called for new parts in the multipart stream. If ``filename`` is given creates new ``file`` part (which leads
|
||||
to storage of the data as temporary file on disk), if not creates a new ``data`` part (which stores
|
||||
incoming data in memory).
|
||||
|
||||
Structure of `file` parts:
|
||||
Structure of ``file`` parts:
|
||||
|
||||
* `name`: name of the part
|
||||
* `filename`: filename associated with the part
|
||||
* `path`: path to the temporary file storing the file's data
|
||||
* `content_type`: content type of the part
|
||||
* `file`: file handle for the temporary file (mode "wb", not deleted on close!)
|
||||
* ``name``: name of the part
|
||||
* ``filename``: filename associated with the part
|
||||
* ``path``: path to the temporary file storing the file's data
|
||||
* ``content_type``: content type of the part
|
||||
* ``file``: file handle for the temporary file (mode "wb", not deleted on close, will be deleted however after
|
||||
handling of the request has finished in :func:`_handle_method`)
|
||||
|
||||
Structure of `data` parts:
|
||||
Structure of ``data`` parts:
|
||||
|
||||
* `name`: name of the part
|
||||
* `content_type`: content type of the part
|
||||
* `data`: bytes of the part (initialized to "")
|
||||
* ``name``: name of the part
|
||||
* ``content_type``: content type of the part
|
||||
* ``data``: bytes of the part (initialized to an empty string)
|
||||
|
||||
:param name: name of the part
|
||||
:param content_type: content type of the part
|
||||
|
|
@ -321,7 +326,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
|
||||
def _on_part_data(self, part, data):
|
||||
"""
|
||||
Called when new bytes are received for the given `part`, takes care of writing them to their storage.
|
||||
Called when new bytes are received for the given ``part``, takes care of writing them to their storage.
|
||||
|
||||
:param part: part for which data was received
|
||||
:param data: data chunk which was received
|
||||
|
|
@ -334,7 +339,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
def _on_part_finish(self, part):
|
||||
"""
|
||||
Called when a part gets closed, takes care of storing the finished part in the internal parts storage and for
|
||||
`file` parts closing the temporary file and storing the part in the internal files storage.
|
||||
``file`` parts closing the temporary file and storing the part in the internal files storage.
|
||||
|
||||
:param part: part which was closed
|
||||
"""
|
||||
|
|
@ -348,8 +353,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
def _on_request_body_finish(self):
|
||||
"""
|
||||
Called when the request body has been read completely. Takes care of creating the replacement body out of the
|
||||
logged parts, turning `file` parts into new
|
||||
:return:
|
||||
logged parts, turning ``file`` parts into new ``data`` parts.
|
||||
"""
|
||||
|
||||
self._new_body = b""
|
||||
|
|
@ -375,8 +379,8 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
|
||||
def _handle_method(self, *args, **kwargs):
|
||||
"""
|
||||
Handler for any request method, takes care of defining the new request body if necessary and forwarding
|
||||
the current request and changed body to the `fallback`.
|
||||
Takes care of defining the new request body if necessary and forwarding
|
||||
the current request and changed body to the ``fallback``.
|
||||
"""
|
||||
|
||||
# determine which body to supply
|
||||
|
|
@ -417,20 +421,22 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
|
|||
|
||||
class WsgiInputContainer(object):
|
||||
"""
|
||||
A WSGI container for use with Tornado that allows supplying the request body to be used for `wsgi.input` in the
|
||||
A WSGI container for use with Tornado that allows supplying the request body to be used for ``wsgi.input`` in the
|
||||
generated WSGI environment upon call.
|
||||
|
||||
A `RequestHandler` can thus provide the WSGI application with a stream for the request body, or a modified body.
|
||||
A ``RequestHandler`` can thus provide the WSGI application with a stream for the request body, or a modified body.
|
||||
|
||||
Example usage:
|
||||
|
||||
wsgi_app = octoprint.server.util.WsgiInputContainer(octoprint_app)
|
||||
application = tornado.web.Application([
|
||||
(r".*", UploadStorageFallbackHandler, dict(fallback=wsgi_app),
|
||||
])
|
||||
.. code-block:: python
|
||||
|
||||
The implementation logic is basically the same as `tornado.wsgi.WSGIContainer` but the `__call__` and `environ`
|
||||
methods have been adjusted to for an optionally supplied `body` argument which is then used for `wsgi.input`.
|
||||
wsgi_app = octoprint.server.util.WsgiInputContainer(octoprint_app)
|
||||
application = tornado.web.Application([
|
||||
(r".*", UploadStorageFallbackHandler, dict(fallback=wsgi_app),
|
||||
])
|
||||
|
||||
The implementation logic is basically the same as ``tornado.wsgi.WSGIContainer`` but the ``__call__`` and ``environ``
|
||||
methods have been adjusted to allow for an optionally supplied ``body`` argument which is then used for ``wsgi.input``.
|
||||
"""
|
||||
|
||||
def __init__(self, wsgi_application):
|
||||
|
|
@ -438,10 +444,10 @@ class WsgiInputContainer(object):
|
|||
|
||||
def __call__(self, request, body=None):
|
||||
"""
|
||||
Wraps the call against the WSGI app, deriving the WSGI environment from the supplied Tornado `HTTPServerRequest`.
|
||||
Wraps the call against the WSGI app, deriving the WSGI environment from the supplied Tornado ``HTTPServerRequest``.
|
||||
|
||||
:param request: the `tornado.httpserver.HTTPServerRequest` to derive the WSGI environment from
|
||||
:param body: an optional body to use as `wsgi.input` instead of `request.body`, can be a string or a stream
|
||||
:param request: the ``tornado.httpserver.HTTPServerRequest`` to derive the WSGI environment from
|
||||
:param body: an optional body to use as ``wsgi.input`` instead of ``request.body``, can be a string or a stream
|
||||
"""
|
||||
|
||||
data = {}
|
||||
|
|
@ -486,13 +492,13 @@ class WsgiInputContainer(object):
|
|||
@staticmethod
|
||||
def environ(request, body=None):
|
||||
"""
|
||||
Converts a `tornado.httputil.HTTPServerRequest` to a WSGI environment.
|
||||
Converts a ``tornado.httputil.HTTPServerRequest`` to a WSGI environment.
|
||||
|
||||
An optional `body` to be used for populating `wsgi.input` can be supplied (either a string or a stream). If not
|
||||
supplied, `request.body` will be wrapped into a `io.BytesIO` stream and used instead.
|
||||
An optional ``body`` to be used for populating ``wsgi.input`` can be supplied (either a string or a stream). If not
|
||||
supplied, ``request.body`` will be wrapped into a ``io.BytesIO`` stream and used instead.
|
||||
|
||||
:param request: the `tornado.httpserver.HTTPServerRequest` to derive the WSGI environment from
|
||||
:param body: an optional body to use as `wsgi.input` instead of `request.body`, can be a string or a stream
|
||||
:param request: the ``tornado.httpserver.HTTPServerRequest`` to derive the WSGI environment from
|
||||
:param body: an optional body to use as ``wsgi.input`` instead of ``request.body``, can be a string or a stream
|
||||
"""
|
||||
from tornado.wsgi import to_wsgi_str
|
||||
import sys
|
||||
|
|
@ -560,19 +566,19 @@ class WsgiInputContainer(object):
|
|||
|
||||
class CustomHTTPServer(tornado.httpserver.HTTPServer):
|
||||
"""
|
||||
Custom implementation of `tornado.httpserver.HTTPServer` that allows defining max body sizes depending on path and
|
||||
Custom implementation of ``tornado.httpserver.HTTPServer`` that allows defining max body sizes depending on path and
|
||||
method.
|
||||
|
||||
The implementation is mostly taken from `tornado.httpserver.HTTPServer`, the only difference is the creation
|
||||
of a `CustomHTTP1ConnectionParameters` instance instead of `tornado.http1connection.HTTP1ConnectionParameters`
|
||||
which is supplied with the two new constructor arguments `max_body_sizes` and `max_default_body_size` and the
|
||||
creation of a `CustomHTTP1ServerConnection` instead of a `tornado.http1connection.HTTP1ServerConnection` upon
|
||||
The implementation is mostly taken from ``tornado.httpserver.HTTPServer``, the only difference is the creation
|
||||
of a ``CustomHTTP1ConnectionParameters`` instance instead of ``tornado.http1connection.HTTP1ConnectionParameters``
|
||||
which is supplied with the two new constructor arguments ``max_body_sizes`` and ``max_default_body_size`` and the
|
||||
creation of a ``CustomHTTP1ServerConnection`` instead of a ``tornado.http1connection.HTTP1ServerConnection`` upon
|
||||
connection by a client.
|
||||
|
||||
`max_body_sizes` is expected to be an iterable containing tuples of the form (method, path regex, maximum body size),
|
||||
``max_body_sizes`` is expected to be an iterable containing tuples of the form (method, path regex, maximum body size),
|
||||
with method and path regex having to match in order for maximum body size to take affect.
|
||||
|
||||
`default_max_body_size` is the default maximum body size to apply if no specific one from `max_body_sizes` matches.
|
||||
``default_max_body_size`` is the default maximum body size to apply if no specific one from ``max_body_sizes`` matches.
|
||||
"""
|
||||
|
||||
def __init__(self, request_callback, no_keep_alive=False, io_loop=None,
|
||||
|
|
@ -610,9 +616,9 @@ class CustomHTTPServer(tornado.httpserver.HTTPServer):
|
|||
|
||||
class CustomHTTP1ServerConnection(tornado.http1connection.HTTP1ServerConnection):
|
||||
"""
|
||||
A custom implementation of `tornado.http1connection.HTTP1ServerConnection` which utilizes a `CustomHTTP1Connection`
|
||||
instead of a `tornado.http1connection.HTTP1Connection` in `_server_request_loop`. The implementation logic is
|
||||
otherwise the same as `tornado.http1connection.HTTP1ServerConnection`.
|
||||
A custom implementation of ``tornado.http1connection.HTTP1ServerConnection`` which utilizes a ``CustomHTTP1Connection``
|
||||
instead of a ``tornado.http1connection.HTTP1Connection`` in ``_server_request_loop``. The implementation logic is
|
||||
otherwise the same as ``tornado.http1connection.HTTP1ServerConnection``.
|
||||
"""
|
||||
|
||||
@tornado.gen.coroutine
|
||||
|
|
@ -644,8 +650,8 @@ class CustomHTTP1ServerConnection(tornado.http1connection.HTTP1ServerConnection)
|
|||
|
||||
class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
|
||||
"""
|
||||
A custom implementation of `tornado.http1connection.HTTP1Connection` which upon checking the `Content-Length` of
|
||||
the request against the configured maximum utilizes `max_body_sizes` and `default_max_body_size` as a fallback.
|
||||
A custom implementation of ``tornado.http1connection.HTTP1Connection`` which upon checking the ``Content-Length`` of
|
||||
the request against the configured maximum utilizes ``max_body_sizes`` and ``default_max_body_size`` as a fallback.
|
||||
"""
|
||||
|
||||
def __init__(self, stream, is_client, params=None, context=None):
|
||||
|
|
@ -657,12 +663,12 @@ class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
|
|||
|
||||
def _read_body(self, code, headers, delegate):
|
||||
"""
|
||||
Basically the same as `tornado.http1connection.HTTP1Connection._read_body`, but determines the maximum
|
||||
content length individually for the request (utilizing `._get_max_content_length`).
|
||||
Basically the same as ``tornado.http1connection.HTTP1Connection._read_body``, but determines the maximum
|
||||
content length individually for the request (utilizing ``._get_max_content_length``).
|
||||
|
||||
If the individual max content length is 0 or smaller no content length is checked. If the content length of the
|
||||
current request exceeds the individual max content length, the request processing is aborted and an
|
||||
`HTTPInputError` is raised.
|
||||
``HTTPInputError`` is raised.
|
||||
"""
|
||||
content_length = headers.get("Content-Length")
|
||||
if "Content-Length" in headers:
|
||||
|
|
@ -706,8 +712,8 @@ class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
|
|||
def _get_max_content_length(self, method, path):
|
||||
"""
|
||||
Gets the max content length for the given method and path. Checks whether method and path match against any
|
||||
of the specific maximum content lengths supplied in `max_body_sizes` and returns that as the maximum content
|
||||
length if available, otherwise returns `default_max_body_size`.
|
||||
of the specific maximum content lengths supplied in ``max_body_sizes`` and returns that as the maximum content
|
||||
length if available, otherwise returns ``default_max_body_size``.
|
||||
|
||||
:param method: method of the request to match against
|
||||
:param path: path od the request to match against
|
||||
|
|
@ -723,10 +729,10 @@ class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
|
|||
|
||||
class CustomHTTP1ConnectionParameters(tornado.http1connection.HTTP1ConnectionParameters):
|
||||
"""
|
||||
An implementation of `tornado.http1connection.HTTP1ConnectionParameters` that adds to new parameters
|
||||
`max_body_sizes` and `default_max_body_size`.
|
||||
An implementation of ``tornado.http1connection.HTTP1ConnectionParameters`` that adds two new parameters
|
||||
``max_body_sizes`` and ``default_max_body_size``.
|
||||
|
||||
For a description of these please see the documentation of `CustomHTTPServer` above.
|
||||
For a description of these please see the documentation of ``CustomHTTPServer`` above.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -738,6 +744,23 @@ class CustomHTTP1ConnectionParameters(tornado.http1connection.HTTP1ConnectionPar
|
|||
|
||||
|
||||
class LargeResponseHandler(tornado.web.StaticFileHandler):
|
||||
"""
|
||||
Customized `tornado.web.StaticFileHandler <http://tornado.readthedocs.org/en/branch4.0/web.html#tornado.web.StaticFileHandler>`_
|
||||
that allows delivery of the requested resource as attachment and access validation through an optional callback.
|
||||
|
||||
Arguments:
|
||||
path (str): The system path from which to serve files (this will be forwarded to the ``initialize`` method of
|
||||
:class:``~tornado.web.StaticFileHandler``)
|
||||
default_filename (str): The default filename to serve if none is explicitely specified and the request references
|
||||
a subdirectory of the served path (this will be forwarded to the ``initialize`` method of
|
||||
:class:``~tornado.web.StaticFileHandler`` as the ``default_filename`` keyword parameter). Defaults to ``None``.
|
||||
as_attachment (bool): Whether to serve requested files with ``Content-Disposition: attachment`` header (``True``)
|
||||
or not. Defaults to ``False``.
|
||||
access_validation (function): Callback to call in the ``get`` method to validate access to the resource. Will
|
||||
be called with ``self.request`` as parameter which contains the full tornado request object. Should raise
|
||||
a ``tornado.web.HTTPError`` if access is not allowed in which case the request will not be further processed.
|
||||
Defaults to ``None`` and hence no access validation being performed.
|
||||
"""
|
||||
|
||||
def initialize(self, path, default_filename=None, as_attachment=False, access_validation=None):
|
||||
tornado.web.StaticFileHandler.initialize(self, os.path.abspath(path), default_filename)
|
||||
|
|
@ -764,6 +787,31 @@ class LargeResponseHandler(tornado.web.StaticFileHandler):
|
|||
|
||||
|
||||
class UrlForwardHandler(tornado.web.RequestHandler):
|
||||
"""
|
||||
`tornado.web.RequestHandler <http://tornado.readthedocs.org/en/branch4.0/web.html#request-handlers>`_ that proxies
|
||||
requests to a preconfigured url and returns the response. Allows delivery of the requested content as attachment
|
||||
and access validation through an optional callback.
|
||||
|
||||
This will use `tornado.httpclient.AsyncHTTPClient <http://tornado.readthedocs.org/en/branch4.0/httpclient.html#tornado.httpclient.AsyncHTTPClient>`_
|
||||
for making the request to the configured endpoint and return the body of the client response with the status code
|
||||
from the client response and the following headers:
|
||||
|
||||
* ``Date``, ``Cache-Control``, ``Server``, ``Content-Type`` and ``Location`` will be copied over.
|
||||
* If ``as_attachment`` is set to True, ``Content-Disposition`` will be set to ``attachment``. If ``basename`` is
|
||||
set including the attachement's ``filename`` attribute will be set to the base name followed by the extension
|
||||
guessed based on the MIME type from the ``Content-Type`` header of the response. If no extension can be guessed
|
||||
no ``filename`` attribute will be set.
|
||||
|
||||
Arguments:
|
||||
url (str): URL to forward any requests to. A 404 response will be returned if this is not set. Defaults to ``None``.
|
||||
as_attachment (bool): Whether to serve files with ``Content-Disposition: attachment`` header (``True``)
|
||||
or not. Defaults to ``False``.
|
||||
basename (str): base name of file names to return as part of the attachment header, see above. Defaults to ``None``.
|
||||
access_validation (function): Callback to call in the ``get`` method to validate access to the resource. Will
|
||||
be called with ``self.request`` as parameter which contains the full tornado request object. Should raise
|
||||
a ``tornado.web.HTTPError`` if access is not allowed in which case the request will not be further processed.
|
||||
Defaults to ``None`` and hence no access validation being performed.
|
||||
"""
|
||||
|
||||
def initialize(self, url=None, as_attachment=False, basename=None, access_validation=None):
|
||||
tornado.web.RequestHandler.initialize(self)
|
||||
|
|
|
|||
Loading…
Reference in a new issue