Creating GoAhead Handlers

GoAhead responds to client requests by routing the request to a request handler. The request handler is responsible for generating the response content or redirecting to another more suitable handler.

GoAhead provides a suite of handlers for standard content types and web frameworks. But you can also create your own custom handler to process Http requests and perform any processing you desire. Once created handlers are configured via routes in the route table. See Request Routing for more details about Routing.

Request Processing

When a request is received from the client, GoAhead parses the HTTP request headers and then determines the best GoAhead route for the request. A route contains the full details for how to process a request including the required handler and required authentication. GoAhead matches each route in the route table in-order and selects the first matching route. The route specifies the desired handler for requests matching that route.

Matching a Handler

The last step of selecting a route is calling the candidate handler's optional match() callback. If the match callback returns true, the handler will be selected. If it returns false, the handler and route will be skipped and the route selection process continues.

Running a Handler

Once the route has been selected, GoAhead invokes the handler service callback to process the request and generate a response. At this point, request body data will be received and buffered. The handler may choose to not handler the request by returning a zero status code. In that case, the router continues matching routes to find a more suitable route and handler combination.

Generating Responses

An HTTP response consists of a status code, a set of HTTP headers and optionally a response body. If a status is not set, the successful status of 200 will be used. If not custom headers are defined, then a minimal standard set will be generated.

Setting Status and Headers

The response status may be set via: websSetStatus. The response headers may be set via: websWriteHeaders. For example:

websSetStatus(wp, 200);
websWriteHeaders(wp, contentLength, 0);
websWriteHeader(wp, "X-MyCustomHeader", "1234");
websWriteEndHeaders(wp);
websWriteBlock(wp, buf, len);
websDone(wp);

The websWriteBlock function will buffer written data that will be written to the client in the background.

Generating an Error Response

If the request has an error, the status and a response message may be set in one step via: websError. When websError is called to indicate a request error, the supplied response text is used instead of any partially generated response body and the the connection field conn->error is set. Once set, pipeline processing is abbreviated and handler callbacks will not be called anymore. Consequently, if you need to continue handler processing, but want to set a non-zero status return code, do not use websError. Rather, use websSetStatus.

websError(conn, 404, "Can't find %s", path);

Aborting Requests

The status argument to websError can also accept flags to control how the socket connection is managed. If WEBS_CLOSE is supplied, the connection will be closed when the request is completed. Normally the connection is kept-open for subsequent requests on the same socket.

websError(conn, 404 | WEBS_CLOSE, "Protocol error");

Redirecting

Sometimes a handler will want to generate a response that will redirect the client to a new URI. Use the websRedirect call to redirect the client. For example:

websRedirect(wp, WEBS_CODE_MOVED_PERMANENTLY, uri);

Generating Response Body

The simplest way to generate a response is to use websWrite. The websWrite routine will automatically flush data as required. This routine may block while data drains to the client if the data cannot be buffered. See the main.bit configuration limit: LimitBuffer for how to control the internal buffer size. When all the data has been written, call: websDone. This finalizes the request.

websWrite(p, "Hello World\n");
websDone(wp);

Defining a Handler

To define an GoAhead handler, you need to call websDefineHandler. For example:

static bool matchFoo(Webs *wp)
{
    /* Handle request */
    return 1;
}
static bool serviceFoo(Webs *wp)
{
    /* Do work here */
    return 1;
}
static void closeFoo() {
    /* Cleanup when goahead is exiting */
}
...
websDefineHandler("foo", matchFoo, serviceFoo, closeFoo, 0);

© Embedthis Software. All rights reserved.