lighttpd 1.4.x
https://www.lighttpd.net/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.1 KiB
170 lines
4.1 KiB
============================ |
|
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()``
|
|
|