The server consists of one or more threads running in parallel to any application threads and which serve web pages to clients. Apart from defining content, the application does not need to do anything to start the HTTP server.
The HTTP server is, by default, started by a static constructor. This
simply creates an initial thread and sets it running. Since this is
called before the scheduler is started, nothing will happen until the
application calls cyg_scheduler_start()
. The
server thread can also be started explicitly by the application, see
the CYGNUM_HTTPD_SERVER_AUTO_START option for
details.
When the thread gets to run it first optionally delays for some period of time. This is to allow the application to perform any initialization free of any interference from the HTTP server. When the thread does finally run it creates a socket, binds it to the HTTP server port, and puts it into listen mode. It will then create any additional HTTPD server threads that have been configured before becoming a server thread itself.
Each HTTPD server thread simply waits for a connection to be made to the server port. When the connection is made it reads the HTTP request and extracts the filename being accessed. If the request also contains form data, this is also preserved. The filename is then looked up in a table.
Each table entry contains a filename pattern string, a pointer to a handler function, and a user defined argument for the function. Table entries are defined using the same link-time table building mechanism used to generate device tables. This is all handled by the CYG_HTTPD_TABLE_ENTRY() macro which has the following format:
#include <cyg/httpd/httpd.h> CYG_HTTPD_TABLE_ENTRY( __name, __pattern, __handler, __arg ) |
The __name
argument is a variable name for the
table entry since C does not allow us to define anonymous data
structures. This name should be chosen so that it is unique and does
not pollute the name space. The __pattern
argument is the match pattern. The __handler
argument is a pointer to the handler function and
__arg
the user defined value.
The link-time table building means that several different pieces of code can define server table entries, and so long as the patterns do not clash they can be totally oblivious of each other. However, note also that this mechanism does not guarantee the order in which entries appear, this depends on the order of object files in the link, which could vary from one build to the next. So any tricky pattern matching that relies on this may not always work.
A request filename matches an entry in the table if either it exactly matches the pattern string, or if the pattern ends in an asterisk, and it matches everything up to that point. So for example the pattern "/monitor/threads.html" will only match that exact filename, but the pattern "/monitor/thread-*" will match "/monitor/thread-0040.html", "/monitor/thread-0100.html" and any other filename starting with "/monitor/thread-".
When a pattern is matched, the hander function is called. It has the following prototype:
cyg_bool cyg_httpd_handler(FILE *client, char *filename, char *formdata, void *arg); |
The client
argument is the TCP connection to
the client: anything output through this stream will be returned to
the browser. The filename
argument is the
filename from the HTTP request and the formdata
argument is any form response data, or NULL if none was sent. The
arg
argument is the user defined value from the
table entry.
The handler is entirely responsible for generating the response to the client, both HTTP header and content. If the handler decides that it does not want to generate a response it can return false, in which case the table scan is resumed for another match. If no match is found, or no handler returns true, then a default response page is generated indicating that the requested page cannot be found.
Finally, the server thread closes the connection to the client and loops back to accept a new connection.