Soup Server Basics

## Soup Server Basics Soup Server Basics — Server-side tutorial |

### Creating a SoupSession

As with the client API, there is a single object that will encapsulate most of your interactions with libsoup. In this case, SoupServer.

### Warning

Note that SoupServer isn't as polished as SoupSession, and thus not as stable, and the APIs will likely change in incompatible (but not difficult-to-port-to) ways in the future to make things nicer. We apologize in advance for the inconvenience.

You create the server with `soup_server_new`, and as with the SoupSession constructor, you can specify various additional options:

`SOUP_SERVER_PORT` | The TCP port to listen on. If `0` (or left unspecified), some unused port will be selected for you. (You can find out what port by calling `soup_server_get_port`.
`SOUP_SERVER_INTERFACE` | A SoupAddress, specifying the IP address of the network interface to run the server on. If `NULL` (or left unspecified), the server will listen on all interfaces.
`SOUP_SERVER_SSL_CERT_FILE` | Points to a file containing an SSL certificate to use. If this is set, then the server will speak HTTPS; otherwise it will speak HTTP.
`SOUP_SERVER_SSL_KEY_FILE` | Points to a file containing the private key for the `SOUP_SERVER_SSL_CERT_FILE`. (It may point to the same file.)
`SOUP_SERVER_ASYNC_CONTEXT` | A GMainContext which the server will use for asynchronous operations. This can be set if you want to use a SoupServer in a thread other than the main thread.

### Adding Handlers

By default, SoupServer returns "404 Not Found" in response to all requests (except ones that it can't parse, which get "400 Bad Request"). To override this behavior, call `soup_server_add_handler` to set a callback to handle certain URI paths.

    soup_server_add_handler (server, "/foo", NULL, server_callback,
    			 unregister_callback, data);

The `"/foo"` indicates the base path for this handler. When a request comes in, if there is a handler registered for exactly the path in the request's `Request-URI`, then that handler will be called. Otherwise libsoup will strip path components one by one until it finds a matching handler. So for example, a request of the form "`GET /foo/bar/baz.html?a=1&b=2 HTTP/1.1`" would look for handlers for "`/foo/bar/baz.html`", "`/foo/bar`", and "`/foo`". If a handler has been registered with a `NULL` base path, then it is used as the default handler for any request that doesn't match any other handler.

### Responding to Requests

A handler callback looks something like this:

    static void
    server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
    {
    	...
    }

`msg` is the request that has been received. `data` is the same data that was passed to `soup_server_add_handler`. The context argument contains some additional information related to the request.

By default, libsoup assumes that you have completely finished processing the message when you return from the callback, and that it can therefore begin sending the response. If you are not ready to send a response immediately (eg, you have to contact another server, or wait for data from a database), you must call `soup_message_io_pause` on the message before returning from the callback. This will delay sending a response until you call `soup_message_io_unpause`. (You must also connect to the finished signal on the message in this case, so that you can break off processing if the client unexpectedly disconnects before you start sending the data.)

To set the response status, call `soup_message_set_status` or `soup_message_set_status_full`. If the response requires a body, the callback must call `soup_server_message_set_encoding` to indicate whether it will provide the response all at once with `Content-Length` encoding, or in pieces with `chunked` encoding.

#### Responding with `Content-Length` Encoding

This is the simpler way to set a response body, if you have all of the data available at once.

    static void
    server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
    {
    	MyServerData *server_data = data;
    	SoupUri *uri = soup_message_get_uri (msg);
    	const char *mime_type;
    	GByteArray *body;

    	if (context->method_id != SOUP_METHOD_ID_GET) {
    		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
    		return;
    	}

    	body = g_hash_table_lookup (server_data->bodies, uri->path);
    	mime_type = g_hash_table_lookup (server_data->mime_types, uri->path);
    	if (!body || !mime_type) {
    		soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
    		return;
    	}

    	soup_message_set_status (msg, SOUP_STATUS_OK);
    	soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg),
    					  SOUP_TRANSFER_CONTENT_LENGTH);
    	soup_message_set_response (msg, mime_type, SOUP_BUFFER_USER_OWNED,
    				   body->data, body->len);
    }

#### Responding with `chunked` Encoding

If you want to supply the response body in chunks as it becomes available, use `chunked` encoding instead. In this case, call `soup_message_add_chunk` with each chunk of the response body as it becomes available, and call `soup_message_add_final_chunk` when the response is complete. After each of these calls, you must also call `soup_message_io_unpause` to cause the chunk to be sent. (You do not normally need to call `soup_message_io_pause`, because I/O is automatically paused when doing a `chunked` transfer if no chunks are available.)

When using chunked encoding, you must also connect to the finished signal on the message, so that you will be notified if the client disconnects between two chunks; SoupServer will unref the message if that happens, so you must stop adding new chunks to the response at that point.

The `simple-proxy` example in the `tests/` directory gives an example of using `chunked` encoding.

### Handling Authentication

To have SoupServer handle HTTP authentication for you, pass a SoupAuthContext to `soup_server_add_handler`:

    SoupServerAuthContext auth_ctx;

    auth_ctx.types            = SOUP_AUTH_TYPE_BASIC;
    auth_ctx.callback         = auth_callback;
    auth_ctx.user_data        = data;
    auth_ctx.basic_info.realm = "My Realm";

    soup_server_add_handler (server, "/bar", &auth_ctx, server_callback,
    			 unregister_callback, data);

Then, every request that matches that handler will be passed to the `auth_callback` first before being passed to the `server_callback`:

    static gboolean
    auth_callback (SoupServerAuthContext *auth_ctx, SoupServerAuth *auth,
    	       SoupMessage *msg, gpointer user_data)
    {
    	MyServerData *server_data = user_data;
    	const char *username, *password;

    	if (!auth)
    		return FALSE;

    	username = soup_server_auth_get_user (auth);
    	password = g_hash_table_lookup (server_data->passwords, username);
    	if (!password)
    		return FALSE;

    	return soup_server_auth_check_passwd (auth, password);
    }

The `auth` parameter indicates the authentication information passed by the client. If no `WWW-Authenticate` header was present, this will be `NULL`, so we return `FALSE` from the callback to indicate that the server should return a `401 Unauthorized` response. If it is non-`NULL`, we extract the username from it, and compare it against our stored password. Assuming it matches, we return `TRUE`, and the server callback is then invoked normally.