171 lines
4.1 KiB
Plaintext
171 lines
4.1 KiB
Plaintext
============================
|
|
The State Engine of lighttpd
|
|
============================
|
|
|
|
------------
|
|
Module: core
|
|
------------
|
|
|
|
:Author: Jan Kneschke
|
|
:Date: $Date: 2004/08/01 07:01:29 $
|
|
:Revision: $Revision: 1.1 $
|
|
|
|
:abstract:
|
|
This is a short summary of the state-engine which is driving the lighttpd
|
|
webserver. It describes the basic concepts and the way the different parts
|
|
of the server are connected.
|
|
|
|
.. meta::
|
|
:keywords: lighttpd, state-engine
|
|
|
|
.. contents:: Table of Contents
|
|
|
|
Description
|
|
===========
|
|
|
|
States
|
|
------
|
|
|
|
The state-engine is currently made of 11 states which are walk-through on
|
|
the way each connection. Some of them are specific for a special operation
|
|
and some may never be hit at all.
|
|
|
|
:connect:
|
|
waiting for a connection
|
|
:reqstart:
|
|
init the read-idle timer
|
|
:read:
|
|
read http-request-header from network
|
|
:reqend:
|
|
parse request
|
|
:readpost:
|
|
read http-request-content from network
|
|
:handlereq:
|
|
handle the request internally (might result in sub-requests)
|
|
:respstart:
|
|
prepare response header
|
|
:write:
|
|
write response-header + content to network
|
|
:respend:
|
|
cleanup environment, log request
|
|
:error:
|
|
reset connection (incl. close())
|
|
:close:
|
|
close connection (handle lingering close)
|
|
|
|
.. image:: state.png
|
|
|
|
A simple GET request (green path)
|
|
---------------------------------
|
|
|
|
The connection is idling in the 'connect' state waiting for a connection.
|
|
As soon as the connection is set up we init the read-timer in 'reqstart'
|
|
and start to read data from the network. As soon as we get the
|
|
HTTP-request terminator (CRLFCRLF) we forward the header to the parser.
|
|
|
|
The parsed request is handled by 'handlereq' and as soon as a decision out
|
|
the request is made it is sent to 'respstart' to prepare the
|
|
HTTP-response header. In the 'write' state the prepare content is sent out
|
|
to the network. When everything is sent 'respend' is entered to log the
|
|
request and cleanup the environment. After the close() call the connection
|
|
is set back to the 'connect' state again.
|
|
|
|
Keep-Alive (blue path)
|
|
----------------------
|
|
|
|
The Keep-Alive handling is implemented by going from the 'respend'
|
|
directly to 'reqstart' without the close() and the accept() calls.
|
|
|
|
POST requests (grey path)
|
|
-------------------------
|
|
|
|
As requests might contain a request-body the state 'readpost' entered as
|
|
soon as the header is parsed and we know how much data we expect.
|
|
|
|
Pipelining
|
|
----------
|
|
|
|
HTTP/1.1 supportes pipelining (sending multiple requests without waiting
|
|
for the response of the first request). This is handled transparently by
|
|
the 'read' state.
|
|
|
|
Unexpected errors (red path)
|
|
----------------------------
|
|
|
|
For really hard errors we use the 'error' state which resets the
|
|
connection and can be call from every state. It is only use if there is no
|
|
other way to handle the issue (e.g. client-side close of the connection).
|
|
If possible we should use http-status 500 ('internal server error') and
|
|
log the issue in the errorlog.
|
|
|
|
If we have to take care of some data which is coming in after we ran into
|
|
the error condition the 'close' state is used the init a half-close and
|
|
read all the delay packet from the network.
|
|
|
|
Sub-Requests (lightblue)
|
|
------------------------
|
|
|
|
The FastCGI, CGI, ... intergration is done by introducing a loop in
|
|
'handlereq' to handle all aspect which are neccesary to find out what has
|
|
to be sent back to the client.
|
|
|
|
Functions
|
|
=========
|
|
|
|
Important functions used by the state-engine
|
|
|
|
:state-engine:
|
|
|
|
- ``connection_state_machine()``
|
|
|
|
:connect:
|
|
|
|
- (nothing)
|
|
|
|
:reqstart:
|
|
|
|
- (nothing)
|
|
|
|
:read:
|
|
|
|
- ``connection_handle_read_state()``
|
|
- ``connection_handle_read()``
|
|
|
|
:reqend:
|
|
|
|
- ``http_request_parse()``
|
|
|
|
:readpost:
|
|
|
|
- ``connection_handle_read_state()``
|
|
- ``connection_handle_read()``
|
|
|
|
:handlereq:
|
|
|
|
- ``http_response_prepare()``
|
|
|
|
:respstart:
|
|
|
|
- ``connection_handle_write_prepare()``
|
|
|
|
:write:
|
|
|
|
- ``connection_handle_write()``
|
|
|
|
:respend:
|
|
|
|
- ``plugins_call_handle_request_done()``
|
|
- ``plugins_call_handle_connection_close()``
|
|
- ``connection_close()`` (if not keep-alive)
|
|
- ``connection_reset()``
|
|
|
|
:error:
|
|
|
|
- ``plugins_call_handle_request_done()``
|
|
- ``plugins_call_handle_connection_close()``
|
|
- ``connection_reset()``
|
|
|
|
:close:
|
|
|
|
- ``connection_close()``
|