2 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
3 "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
4 <refentry id="libsoup-server-howto">
6 <refentrytitle>Soup Server Basics</refentrytitle>
7 <manvolnum>3</manvolnum>
8 <refmiscinfo>LIBSOUP Library</refmiscinfo>
12 <refname>Soup Server Basics</refname><refpurpose>Server-side tutorial</refpurpose>
16 <title>Creating a SoupSession</title>
19 As with the client API, there is a single object that will encapsulate
20 most of your interactions with libsoup. In this case, <link
21 linkend="SoupServer"><type>SoupServer</type></link>.
25 You create the server with <link
26 linkend="soup-server-new"><function>soup_server_new</function></link>,
27 and as with the <type>SoupSession</type> constructor, you can specify
28 various additional options:
33 <term><link linkend="SOUP-SERVER-PORT--CAPS"><literal>SOUP_SERVER_PORT</literal></link></term>
35 The TCP port to listen on. If <literal>0</literal> (or
36 left unspecified), some unused port will be selected for
37 you. (You can find out what port by calling <link
38 linkend="soup-server-get-port"><function>soup_server_get_port</function></link>.
42 <term><link linkend="SOUP-SERVER-INTERFACE--CAPS"><literal>SOUP_SERVER_INTERFACE</literal></link></term>
44 A <link linkend="SoupAddress"><type>SoupAddress</type></link>,
45 specifying the IP address of the network interface to run
46 the server on. If <literal>NULL</literal> (or left
47 unspecified), the server will listen on all interfaces.
51 <term><link linkend="SOUP-SERVER-SSL-CERT-FILE--CAPS"><literal>SOUP_SERVER_SSL_CERT_FILE</literal></link></term>
53 Points to a file containing an SSL certificate to use. If
54 this is set, then the server will speak HTTPS; otherwise
59 <term><link linkend="SOUP-SERVER-SSL-KEY-FILE--CAPS"><literal>SOUP_SERVER_SSL_KEY_FILE</literal></link></term>
61 Points to a file containing the private key for the
62 <literal>SOUP_SERVER_SSL_CERT_FILE</literal>. (It may
63 point to the same file.)
67 <term><link linkend="SOUP-SERVER-ASYNC-CONTEXT--CAPS"><literal>SOUP_SERVER_ASYNC_CONTEXT</literal></link></term>
69 A <link linkend="GMainContext"><type>GMainContext</type></link> which
70 the server will use for asynchronous operations. This can
71 be set if you want to use a SoupServer in a thread
72 other than the main thread.
76 <term><link linkend="SOUP-SERVER-RAW-PATHS--CAPS"><literal>SOUP_SERVER_RAW_PATHS</literal></link></term>
78 Set this to <literal>TRUE</literal> if you don't want
79 <application>libsoup</application> to decode %-encoding
80 in the Request-URI. (Eg, because you need to treat
81 <literal>"/foo/bar"</literal> and
82 <literal>"/foo%2Fbar"</literal> as different paths.
90 <title>Adding Handlers</title>
93 By default, <link linkend="SoupServer"><type>SoupServer</type></link>
94 returns "404 Not Found" in response to all requests (except ones that
95 it can't parse, which get "400 Bad Request"). To override this
97 linkend="soup-server-add-handler"><function>soup_server_add_handler</function></link>
98 to set a callback to handle certain URI paths.
101 <informalexample><programlisting>
102 soup_server_add_handler (server, "/foo", server_callback,
103 data, destroy_notify);
104 </programlisting></informalexample>
107 The <literal>"/foo"</literal> indicates the base path for this
108 handler. When a request comes in, if there is a handler registered for
109 exactly the path in the request's <literal>Request-URI</literal>, then
110 that handler will be called. Otherwise
111 <application>libsoup</application> will strip path components one by
112 one until it finds a matching handler. So for example, a request of
114 "<literal>GET /foo/bar/baz.html?a=1&b=2 HTTP/1.1</literal>"
115 would look for handlers for "<literal>/foo/bar/baz.html</literal>",
116 "<literal>/foo/bar</literal>", and "<literal>/foo</literal>". If a
117 handler has been registered with a <literal>NULL</literal> base path,
118 then it is used as the default handler for any request that doesn't
119 match any other handler.
125 <title>Responding to Requests</title>
128 A handler callback looks something like this:
131 <informalexample><programlisting>
133 server_callback (SoupServer *server,
137 SoupClientContext *client,
142 </programlisting></informalexample>
145 <literal>msg</literal> is the request that has been received and
146 <literal>user_data</literal> is the data that was passed to <link
147 linkend="soup-server-add-handler"><function>soup_server_add_handler</function></link>.
148 <literal>path</literal> is the path (from <literal>msg</literal>'s
149 URI), and <literal>query</literal> contains the result of parsing the
150 URI query field. (It is <literal>NULL</literal> if there was no
151 query.) <literal>client</literal> is a <link
152 linkend="SoupClientContext"><type>SoupClientContext</type></link>,
153 which contains additional information about the client (including its
154 IP address, and whether or not it used HTTP authentication).
158 By default, <application>libsoup</application> assumes that you have
159 completely finished processing the message when you return from the
160 callback, and that it can therefore begin sending the response. If you
161 are not ready to send a response immediately (eg, you have to contact
162 another server, or wait for data from a database), you must call <link
163 linkend="soup-server-pause-message"><function>soup_server_pause_message</function></link>
164 on the message before returning from the callback. This will delay
165 sending a response until you call <link
166 linkend="soup-server-unpause-message"><function>soup_server_unpause_message</function></link>.
167 (You must also connect to the <link
168 linkend="SoupMessage-finished">finished</link> signal on the message
169 in this case, so that you can break off processing if the client
170 unexpectedly disconnects before you start sending the data.)
174 To set the response status, call <link
175 linkend="soup-message-set-status"><function>soup_message_set_status</function></link>
177 linkend="soup-message-set-status-full"><function>soup_message_set_status_full</function></link>.
178 If the response requires a body, you must decide whether to use
179 <literal>Content-Length</literal> encoding (the default), or
180 <literal>chunked</literal> encoding.
184 <title>Responding with <literal>Content-Length</literal>
188 This is the simpler way to set a response body, if you have all of the
189 data available at once.
192 <informalexample><programlisting>
194 server_callback (SoupServer *server,
198 SoupClientContext *client,
201 MyServerData *server_data = user_data;
202 const char *mime_type;
205 if (msg->method != SOUP_METHOD_GET) {
206 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
210 /* This is somewhat silly. Presumably your server will do
211 * something more interesting.
213 body = g_hash_table_lookup (server_data->bodies, path);
214 mime_type = g_hash_table_lookup (server_data->mime_types, path);
215 if (!body || !mime_type) {
216 soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
220 soup_message_set_status (msg, SOUP_STATUS_OK);
221 soup_message_set_response (msg, mime_type, SOUP_MEMORY_COPY,
222 body->data, body->len);
224 </programlisting></informalexample>
229 <title>Responding with <literal>chunked</literal> Encoding</title>
232 If you want to supply the response body in chunks as it becomes
233 available, use <literal>chunked</literal> encoding instead. In this
234 case, first call <link
235 linkend="soup-message-headers-set-encoding"><function>soup_message_headers_set_encoding</function></link> <literal>(msg->response_headers, <link
236 linkend="SoupEncoding">SOUP_ENCODING_CHUNKED</link>)</literal>
237 to tell <application>libsoup</application> that you'll be using
238 chunked encoding. Then call <link
239 linkend="soup-message-body-append"><function>soup_message_body_append</function></link>
241 linkend="soup-message-body-append-buffer"><function>soup_message_body_append_buffer</function></link>)
242 on <literal>msg->response_body</literal> with each chunk of the
243 response body as it becomes available, and call <link
244 linkend="soup-message-body-complete"><function>soup_message_body_complete</function></link>
245 when the response is complete. After each of these calls, you must
247 linkend="soup-server-unpause-message"><function>soup_server_unpause_message</function></link>
248 to cause the chunk to be sent. (You do not normally need to call <link
249 linkend="soup-server-pause-message"><function>soup_server_pause_message</function></link>,
250 because I/O is automatically paused when doing a
251 <literal>chunked</literal> transfer if no chunks are available.)
255 When using chunked encoding, you must also connect to the <link
256 linkend="SoupMessage-finished">finished</link> signal on the message,
257 so that you will be notified if the client disconnects between two
258 chunks; <type>SoupServer</type> will unref the message if that
259 happens, so you must stop adding new chunks to the response at that
260 point. (An alternate possibility is to write each new chunk only when
261 the <link linkend="SoupMessage-wrote-chunk">wrote_chunk</link> signal
262 is emitted indicating that the previous one was written successfully.)
266 The <emphasis role="bold"><literal>simple-proxy</literal></emphasis>
267 example in the <literal>tests/</literal> directory gives an example of
268 using <literal>chunked</literal> encoding.
276 <title>Handling Authentication</title>
279 To have <link linkend="SoupServer"><type>SoupServer</type></link>
280 handle HTTP authentication for you, create a <link
281 linkend="SoupAuthDomainBasic"><type>SoupAuthDomainBasic</type></link>
283 linkend="SoupAuthDomainDigest"><type>SoupAuthDomainDigest</type></link>,
285 linkend="soup-server-add-auth-domain"><function>soup_server_add_auth_domain</function></link>:
288 <informalexample><programlisting>
289 SoupAuthDomain *domain;
291 domain = soup_auth_domain_basic_new (
292 SOUP_AUTH_DOMAIN_REALM, "My Realm",
293 SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, auth_callback,
294 SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA, auth_data,
295 SOUP_AUTH_DOMAIN_ADD_PATH, "/foo",
296 SOUP_AUTH_DOMAIN_ADD_PATH, "/bar/private",
298 soup_server_add_auth_domain (server, domain);
299 g_object_unref (domain);
300 </programlisting></informalexample>
303 Then, every request under one of the auth domain's paths will be
304 passed to the <literal>auth_callback</literal> first before being
305 passed to the <literal>server_callback</literal>:
308 <informalexample><programlisting>
310 auth_callback (SoupAuthDomain *domain, SoupMessage *msg,
311 const char *username, const char *password,
314 MyServerData *server_data = user_data;
317 user = my_server_data_lookup_user (server_data, username);
321 /* FIXME: Don't do this. Keeping a cleartext password database
324 return strcmp (password, user->password) == 0;
326 </programlisting></informalexample>
330 linkend="SoupAuthDomainBasicAuthCallback"><type>SoupAuthDomainBasicAuthCallback</type></link>
331 is given the username and password from the
332 <literal>Authorization</literal> header and must determine, in some
333 server-specific manner, whether or not to accept them. (In this
334 example we compare the password against a cleartext password database,
335 but it would be better to store the password somehow encoded, as in
336 the UNIX password database. Alternatively, you may need to delegate
337 the password check to PAM or some other service.)
341 If you are using Digest authentication, note that <link
342 linkend="SoupAuthDomainDigestAuthCallback"><type>SoupAuthDomainDigestAuthCallback</type></link>
343 works completely differently (since the server doesn't receive the
344 cleartext password from the client in that case, so there's no way to
345 compare it directly). See the documentation for <link
346 linkend="SoupAuthDomainDigest"><type>SoupAuthDomainDigest</type></link>
351 You can have multiple <type>SoupAuthDomain</type>s attached to a
352 <literal>SoupServer</literal>, either in separate parts of the path
353 hierarchy, or overlapping. (Eg, you might want to accept either Basic
354 or Digest authentication for a given path.) When more than one auth
355 domain covers a given path, the request will be accepted if the user
356 authenticates successfully against <emphasis>any</emphasis> of the
361 If you want to require authentication for some requests under a
362 certain path, but not all of them (eg, you want to authenticate
363 <literal>PUT</literal>s, but not <literal>GET</literal>s), use a
365 linkend="SoupAuthDomainFilter"><type>SoupAuthDomainFilter</type></link>.