Git init
[profile/ivi/libsoup2.4.git] / docs / reference / server-howto.xml
1 <?xml version="1.0"?>
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">
5 <refmeta>
6 <refentrytitle>Soup Server Basics</refentrytitle>
7 <manvolnum>3</manvolnum>
8 <refmiscinfo>LIBSOUP Library</refmiscinfo>
9 </refmeta>
10
11 <refnamediv>
12 <refname>Soup Server Basics</refname><refpurpose>Server-side tutorial</refpurpose>
13 </refnamediv>
14
15 <refsect2>
16 <title>Creating a SoupSession</title>
17
18 <para>
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>.
22 </para>
23
24 <para>
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:
29 </para>
30
31 <variablelist>
32     <varlistentry>
33         <term><link linkend="SOUP-SERVER-PORT--CAPS"><literal>SOUP_SERVER_PORT</literal></link></term>
34         <listitem><para>
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>.
39         </para></listitem>
40     </varlistentry>
41     <varlistentry>
42         <term><link linkend="SOUP-SERVER-INTERFACE--CAPS"><literal>SOUP_SERVER_INTERFACE</literal></link></term>
43         <listitem><para>
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.
48         </para></listitem>
49     </varlistentry>
50     <varlistentry>
51         <term><link linkend="SOUP-SERVER-SSL-CERT-FILE--CAPS"><literal>SOUP_SERVER_SSL_CERT_FILE</literal></link></term>
52         <listitem><para>
53             Points to a file containing an SSL certificate to use. If
54             this is set, then the server will speak HTTPS; otherwise
55             it will speak HTTP.
56         </para></listitem>
57     </varlistentry>
58     <varlistentry>
59         <term><link linkend="SOUP-SERVER-SSL-KEY-FILE--CAPS"><literal>SOUP_SERVER_SSL_KEY_FILE</literal></link></term>
60         <listitem><para>
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.)
64         </para></listitem>
65     </varlistentry>
66     <varlistentry>
67         <term><link linkend="SOUP-SERVER-ASYNC-CONTEXT--CAPS"><literal>SOUP_SERVER_ASYNC_CONTEXT</literal></link></term>
68         <listitem><para>
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.
73         </para></listitem>
74     </varlistentry>
75     <varlistentry>
76         <term><link linkend="SOUP-SERVER-RAW-PATHS--CAPS"><literal>SOUP_SERVER_RAW_PATHS</literal></link></term>
77         <listitem><para>
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.
83         </para></listitem>
84     </varlistentry>
85 </variablelist>
86
87 </refsect2>
88
89 <refsect2>
90 <title>Adding Handlers</title>
91
92 <para>
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
96 behavior, call <link
97 linkend="soup-server-add-handler"><function>soup_server_add_handler</function></link>
98 to set a callback to handle certain URI paths.
99 </para>
100
101 <informalexample><programlisting>
102         soup_server_add_handler (server, "/foo", server_callback,
103                                  data, destroy_notify);
104 </programlisting></informalexample>
105
106 <para>
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
113 the form
114 "<literal>GET&#xA0;/foo/bar/baz.html?a=1&amp;b=2&#xA0;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.
120 </para>
121
122 </refsect2>
123
124 <refsect2>
125 <title>Responding to Requests</title>
126
127 <para>
128 A handler callback looks something like this:
129 </para>
130
131 <informalexample><programlisting>
132 static void
133 server_callback (SoupServer        *server,
134                  SoupMessage       *msg, 
135                  const char        *path,
136                  GHashTable        *query,
137                  SoupClientContext *client,
138                  gpointer           user_data)
139 {
140         ...
141 }
142 </programlisting></informalexample>
143
144 <para>
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).
155 </para>
156
157 <para>
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.)
171 </para>
172
173 <para>
174 To set the response status, call <link
175 linkend="soup-message-set-status"><function>soup_message_set_status</function></link>
176 or <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.
181 </para>
182
183 <refsect3>
184 <title>Responding with <literal>Content-Length</literal>
185 Encoding</title>
186
187 <para>
188 This is the simpler way to set a response body, if you have all of the
189 data available at once.
190 </para>
191
192 <informalexample><programlisting>
193 static void
194 server_callback (SoupServer        *server,
195                  SoupMessage       *msg, 
196                  const char        *path,
197                  GHashTable        *query,
198                  SoupClientContext *client,
199                  gpointer           user_data)
200 {
201         MyServerData *server_data = user_data;
202         const char *mime_type;
203         GByteArray *body;
204
205         if (msg->method != SOUP_METHOD_GET) {
206                 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
207                 return;
208         }
209
210         /* This is somewhat silly. Presumably your server will do
211          * something more interesting.
212          */
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);
217                 return;
218         }
219
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);
223 }
224 </programlisting></informalexample>
225
226 </refsect3>
227
228 <refsect3>
229 <title>Responding with <literal>chunked</literal> Encoding</title>
230
231 <para>
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>&#160;<literal>(msg->response_headers,&#160;<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>
240 (or <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
246 also call <link
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.)
252 </para>
253
254 <para>
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.)
263 </para>
264
265 <para>
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.
269 </para>
270
271 </refsect3>
272 </refsect2>
273
274
275 <refsect2>
276 <title>Handling Authentication</title>
277
278 <para>
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>
282 or <link
283 linkend="SoupAuthDomainDigest"><type>SoupAuthDomainDigest</type></link>,
284 and pass it to <link
285 linkend="soup-server-add-auth-domain"><function>soup_server_add_auth_domain</function></link>:
286 </para>
287
288 <informalexample><programlisting>
289         SoupAuthDomain *domain;
290
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",
297                 NULL);
298         soup_server_add_auth_domain (server, domain);
299         g_object_unref (domain);
300 </programlisting></informalexample>
301
302 <para>
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>:
306 </para>
307
308 <informalexample><programlisting>
309 static gboolean
310 auth_callback (SoupAuthDomain *domain, SoupMessage *msg,
311                const char *username, const char *password,
312                gpointer user_data)
313 {
314         MyServerData *server_data = user_data;
315         MyUserData *user;
316
317         user = my_server_data_lookup_user (server_data, username);
318         if (!user)
319                 return FALSE;
320
321         /* FIXME: Don't do this. Keeping a cleartext password database
322          * is bad.
323          */
324         return strcmp (password, user->password) == 0;
325 }
326 </programlisting></informalexample>
327
328 <para>
329 The <link
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.)
338 </para>
339
340 <para>
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>
347 for more details.
348 </para>
349
350 <para>
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
357 domains.
358 </para>
359
360 <para>
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 
364 <link
365 linkend="SoupAuthDomainFilter"><type>SoupAuthDomainFilter</type></link>.
366 </para>
367
368 </refsect2>
369
370 </refentry>