1.4.12 becomes 1.5.0 11

Posted by jan Wed, 26 Jul 2006 22:41:00 GMT

moo poked me today and was so right: “With all the changes going into SVN we shouldn’t call the next release 1.4.12, but 1.5.0”. Lifting the restriction on ‘try to stay compatible to the 1.4.x plugin-API I started right away on ripping the internals apart and put them together sliglty different.

If you are developing a plugin for 1.4.x right now, be asured that it won’t work without changes in 1.5.0. Let me explain what is changing.

The major change for the plugin developers are 3 or 4 things:

  1. the fdevent-handling interface is simpler now and hides the nasty details. You only provide a iosocket
  2. chunkqueues everywhere and no direct call to write() or read() on a socket. This is all done through the network_* interface. You don’t have to care about platform dependent functions.
  3. there is a lemon-based HTTP-Response parser (see mod_proxy_core)
  4. TRACE ( ) and ERROR ( ) instead of log_error_write(...)

All this is in SVN already. Some other changes are coming up right now and are mostly around the central state-engine and how a request is steps through the server. Currently we have these steps:

  1. accept connection
  2. read request header + request content
  3. call backend and send all the data
  4. read backend response and prepare response header
  5. send response to the client
  6. on keep-alive go to 2, otherwise close the connection

What I currently implement is slightly different:

  1. accept connection
  2. read the request header
  3. set up the request-handling filter-chain
  4. forward request content to the backend
  5. read the backend response header
  6. set up the the response-handling filter-chain
  7. forward the response content to the client
  8. on keep-alive go to 2 otherwise close the connection

This follows a simple idea: ‘After parsing the HTTP-headers you have all the information on how you want to continue to handle the request.’ All plugins will get called and can hook into the filter-chain.

  • mod_uploadprogress will hook into the request-filter-chain to track to progress of connections
  • mod_deflate will replace content in the response-filter-chain
  • mod_demux will split a proxy-response into multiple client responses
  • mod_http_chunking will provide generic HTTP/1.1 chunking
It will be left to backend when they want to make the connection to the backend:
  • when they have the request header
  • when they have a part of the request-content (POST body)
  • when they have the full request-content as now

What else will change ?

  • the hand-written HTTP-request parser will get kicked out in favour of a lemon based one. We already have one for the HTTP-responses and can use most of its code.

lighttpd unleashed - part two 2

Posted by jan Wed, 24 Aug 2005 09:24:00 GMT

The big thing of lighttpd 1.4.0 were the nested conditionals, but how can they be used ? And what are includes ?

A example for nested confitionals went already into the announcement:

$HTTP["host"] == "www.example.org" {
  $HTTP["url"] =~ "^/dav($|/)" {
    webdav.activate = "enable" 
  }
  $HTTP["remoteip"] != "10.0.0.0/16" {
    auth.require = ( "" => ( "method" => "basic",
                             "realm" => "webdav",
                             "require" => "valid-user" ) )
  }
}

But what are includes for ? For a start we want to go the mass-hosting way and want to create a generic pattern for virtual hosts without using mod_simple_vhost or similar modules.

We have a simple webserver structure:

  • all servers are under /var/www/servers/
  • the part is the hostname of the server
  • and logs and public files are at logs/ and pages/

resulting in /var/www/servers/www.example.org/pages/.

In lighttpd 1.3.x you had to copy the conditionals for all host including all the options. There was no way to do some interpretation of the config file.

In lighttpd 1.4.0 this has changed and we can use expressions and includes:

server.document-root = "/tmp" 
server.port = 1025

server.modules = ( "mod_access" )

access.deny = ( "~", ".inc" )

$HTTP["host"] == "www.example.org" {
  var.hostname = "www.example.org" 
  include "baseconfig.conf" 
}

$HTTP["host"] == "www2.example.org" {
  var.hostname = "www2.example.org" 
  include "baseconfig.conf" 
}

and a baseconfig.conf

server.document-root = "/var/www/servers/" + hostname + "/pages/" 
access.logfile = "/var/www/servers/" + hostname + "/logs/accesslog" 

With var.hostname you can set a user-variable in the configuration which can be used everywhere in the config to pass data around. We use it here to substiture the parts of the baseconfig for each host and set the document-root and the location of the accesslog for each host.

But how does the config look like that is used by lighttpd ? The option -p will tell us:

$ /lighttpd -p -f ./lighttpd-includes.conf
config {
    server.document-root = "/tmp" 
    server.port          = 1025
    server.modules       = ("mod_indexfile", "mod_access", "mod_dirlisting", "mod_staticfile")
    access.deny          = ("~", ".inc")

    $HTTP["host"] == "www.example.org" {
        # block 1
        var.hostname         = "www.example.org" 
        server.document-root = "/var/www/servers/www.example.org/pages/" 
        access.logfile       = "/var/www/servers/www.example.org/logs/accesslog" 

    } # end of $HTTP["host"] == "www.example.org" 

    $HTTP["host"] == "www2.example.org" {
        # block 2
        var.hostname         = "www2.example.org" 
        server.document-root = "/var/www/servers/www2.example.org/pages/" 
        access.logfile       = "/var/www/servers/www2.example.org/logs/accesslog" 

    } # end of $HTTP["host"] == "www2.example.org" 
}

Nice, isn’t it ? :)