diff options
author | Lawouach <sh@defuze.org> | 2014-05-13 21:33:43 +0200 |
---|---|---|
committer | Lawouach <sh@defuze.org> | 2014-05-13 21:33:43 +0200 |
commit | cb8cac6f060e893c285baea740f6c3c5130b31c6 (patch) | |
tree | 2b98e4515231a2e816996661bb2c0e7977f3a2e5 | |
parent | b95be8f2f7d071bbe45bb4d0e10f1abcce39daa1 (diff) | |
download | cherrypy-cb8cac6f060e893c285baea740f6c3c5130b31c6.tar.gz |
not losing the streaming section from our old doc
-rw-r--r-- | sphinx/source/_static/images/cpreturn.gif | bin | 0 -> 6088 bytes | |||
-rw-r--r-- | sphinx/source/_static/images/cpyield.gif | bin | 0 -> 9112 bytes | |||
-rw-r--r-- | sphinx/source/advanced.rst | 84 |
3 files changed, 84 insertions, 0 deletions
diff --git a/sphinx/source/_static/images/cpreturn.gif b/sphinx/source/_static/images/cpreturn.gif Binary files differnew file mode 100644 index 00000000..074ea3cd --- /dev/null +++ b/sphinx/source/_static/images/cpreturn.gif diff --git a/sphinx/source/_static/images/cpyield.gif b/sphinx/source/_static/images/cpyield.gif Binary files differnew file mode 100644 index 00000000..e07c50aa --- /dev/null +++ b/sphinx/source/_static/images/cpyield.gif diff --git a/sphinx/source/advanced.rst b/sphinx/source/advanced.rst index bf1e7f8c..c502cd82 100644 --- a/sphinx/source/advanced.rst +++ b/sphinx/source/advanced.rst @@ -208,6 +208,90 @@ This would handle the following URL: Notice finally how the whole stack of segments is passed to each page handler so that you have the full context. +Streaming the response body +########################### + +CherryPy handles HTTP requests, packing and unpacking the low-level details, +then passing control to your application's :term:`page handler`, which produce +the body of the response. CherryPy allows you to return body content in a +variety of types: a string, a list of strings, a file. CherryPy also allows you +to *yield* content, rather than *return* content. When you use "yield", you also +have the option of streaming the output. + +**In general, it is safer and easier to not stream output.** Therefore, +streaming output is off by default. Streaming output and also using sessions +requires a good understanding of :py:mod:`how session locks work +<cherrypy.lib.sessions>`. + +The "normal" CherryPy response process +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When you provide content from your page handler, CherryPy manages the +conversation between the HTTP server and your code like this: + +.. image:: _static/images/cpreturn.gif + +Notice that the HTTP server gathers all output first and then writes everything +to the client at once: status, headers, and body. This works well for static or +simple pages, since the entire response can be changed at any time, either in +your application code, or by the CherryPy framework. + +How "streaming output" works with CherryPy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When you set the config entry "response.stream" to True (and use "yield"), +CherryPy manages the conversation between the HTTP server and your code like this: + +.. image:: _static/images/cpyield.gif + +When you stream, your application doesn't immediately pass raw body content +back to CherryPy or to the HTTP server. Instead, it passes back a generator. +At that point, CherryPy finalizes the status and headers, **before** the +generator has been consumed, or has produced any output. This is necessary to +allow the HTTP server to send the headers and pieces of the body as they become +available. + +Once CherryPy has set the status and headers, it sends them to the HTTP server, +which then writes them out to the client. From that point on, the CherryPy +ramework mostly steps out of the way, and the HTTP server essentially requests +content directly from your application code (your page handler method). + +Therefore, when streaming, if an error occurs within your page handler, +CherryPy will not catch it--the HTTP server will catch it. Because the headers +(and potentially some of the body) have already been written to the client, +the server *cannot* know a safe means of handling the error, and will therefore +simply close the connection (the current, builtin servers actually write out a +short error message in the body, but this may be changed, and is not guaranteed +behavior for all HTTP servers you might use with CherryPy). + +In addition, you cannot manually modify the status or headers within your page +handler if that handler method is a streaming generator, because the method will +not be iterated over until after the headers have been written to the client. +**This includes raising exceptions like HTTPError, NotFound, InternalRedirect +and HTTPRedirect.** To use a streaming generator while modifying headers, you +would have to return a generator that is separate from (or embedded in) your +page handler. For example: + +.. code-block:: python + + class Root: + @cherrypy.expose + def thing(self): + cherrypy.response.headers['Content-Type'] = 'text/plain' + if not authorized(): + raise cherrypy.NotFound() + def content(): + yield "Hello, " + yield "world" + return content() + thing._cp_config = {'response.stream': True} + +Streaming generators are sexy, but they play havoc with HTTP. CherryPy allows +you to stream output for specific situations: pages which take many minutes to +produce, or pages which need a portion of their content immediately output to +the client. Because of the issues outlined above, **it is usually better to +flatten (buffer) content rather than stream content**. Do otherwise only when +the benefits of streaming outweigh the risks. Response timeouts ################# |