1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007, 2008 Red Hat, Inc.
20 #include <libsoup/soup.h>
22 #include "test-utils.h"
25 const char *title, *name;
28 /* Both fields must be filled in */
32 /* Filled-in but empty is OK */
33 { "", "", "Hello, " },
34 { "", "Name", "Hello, Name" },
35 { "Mr.", "", "Hello, MR. " },
38 { "Mr.", "Name", "Hello, MR. Name" },
40 /* Encoding of spaces */
41 { "Mr.", "Full Name", "Hello, MR. Full Name" },
42 { "Mr. and Mrs.", "Full Name", "Hello, MR. AND MRS. Full Name" },
45 { "Mr.+Mrs.", "Full Name", "Hello, MR.+MRS. Full Name" },
47 /* Encoding of non-ASCII. */
48 { "Se\xC3\xB1or", "Nombre", "Hello, SE\xC3\xB1OR Nombre" },
51 { "Mr.", "Foo %2f Bar", "Hello, MR. Foo %2f Bar" },
55 do_hello_test (int n, gboolean extra, const char *uri)
58 char *title_arg = NULL, *name_arg = NULL;
59 char *str_stdout = NULL;
61 debug_printf (1, "%2d. '%s' '%s'%s: ", n * 2 + (extra ? 2 : 1),
62 tests[n].title ? tests[n].title : "(null)",
63 tests[n].name ? tests[n].name : "(null)",
64 extra ? " + extra" : "");
66 args = g_ptr_array_new ();
67 g_ptr_array_add (args, "curl");
68 g_ptr_array_add (args, "-G");
70 title_arg = soup_form_encode ("title", tests[n].title, NULL);
71 g_ptr_array_add (args, "-d");
72 g_ptr_array_add (args, title_arg);
75 name_arg = soup_form_encode ("n@me", tests[n].name, NULL);
76 g_ptr_array_add (args, "-d");
77 g_ptr_array_add (args, name_arg);
80 g_ptr_array_add (args, "-d");
81 g_ptr_array_add (args, "extra=something");
83 g_ptr_array_add (args, (char *)uri);
84 g_ptr_array_add (args, NULL);
86 if (g_spawn_sync (NULL, (char **)args->pdata, NULL,
87 G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
89 &str_stdout, NULL, NULL, NULL)) {
90 if (str_stdout && !strcmp (str_stdout, tests[n].result))
91 debug_printf (1, "OK!\n");
93 debug_printf (1, "WRONG!\n");
94 debug_printf (1, " expected '%s', got '%s'\n",
96 str_stdout ? str_stdout : "(error)");
101 debug_printf (1, "ERROR!\n");
104 g_ptr_array_free (args, TRUE);
110 do_hello_tests (const char *uri)
114 debug_printf (1, "Hello tests (GET, application/x-www-form-urlencoded)\n");
115 for (n = 0; n < G_N_ELEMENTS (tests); n++) {
116 do_hello_test (n, FALSE, uri);
117 do_hello_test (n, TRUE, uri);
122 do_md5_test_curl (const char *uri, const char *file, const char *md5)
125 char *file_arg, *str_stdout;
127 debug_printf (1, " via curl: ");
129 args = g_ptr_array_new ();
130 g_ptr_array_add (args, "curl");
131 g_ptr_array_add (args, "-L");
132 g_ptr_array_add (args, "-F");
133 file_arg = g_strdup_printf ("file=@%s", file);
134 g_ptr_array_add (args, file_arg);
135 g_ptr_array_add (args, "-F");
136 g_ptr_array_add (args, "fmt=txt");
137 g_ptr_array_add (args, (char *)uri);
138 g_ptr_array_add (args, NULL);
140 if (g_spawn_sync (NULL, (char **)args->pdata, NULL,
141 G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
143 &str_stdout, NULL, NULL, NULL)) {
144 if (str_stdout && !strcmp (str_stdout, md5))
145 debug_printf (1, "OK!\n");
147 debug_printf (1, "WRONG!\n");
148 debug_printf (1, " expected '%s', got '%s'\n",
149 md5, str_stdout ? str_stdout : "(error)");
154 debug_printf (1, "ERROR!\n");
157 g_ptr_array_free (args, TRUE);
161 #define MD5_TEST_FILE SRCDIR "/resources/home.gif"
162 #define MD5_TEST_FILE_BASENAME "home.gif"
163 #define MD5_TEST_FILE_MIME_TYPE "image/gif"
166 do_md5_test_libsoup (const char *uri, const char *contents,
167 gsize length, const char *md5)
169 SoupMultipart *multipart;
172 SoupSession *session;
174 debug_printf (1, " via libsoup: ");
176 multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART);
177 buffer = soup_buffer_new (SOUP_MEMORY_COPY, contents, length);
178 soup_multipart_append_form_file (multipart, "file",
179 MD5_TEST_FILE_BASENAME,
180 MD5_TEST_FILE_MIME_TYPE,
182 soup_buffer_free (buffer);
183 soup_multipart_append_form_string (multipart, "fmt", "text");
185 msg = soup_form_request_new_from_multipart (uri, multipart);
186 soup_multipart_free (multipart);
188 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
189 soup_session_send_message (session, msg);
191 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
192 debug_printf (1, "ERROR: Unexpected status %d %s\n",
193 msg->status_code, msg->reason_phrase);
195 } else if (strcmp (msg->response_body->data, md5) != 0) {
196 debug_printf (1, "ERROR: Incorrect response: expected '%s' got '%s'\n",
197 md5, msg->response_body->data);
200 debug_printf (1, "OK!\n");
202 g_object_unref (msg);
203 soup_test_session_abort_unref (session);
207 do_md5_tests (const char *uri)
209 char *contents, *md5;
211 GError *error = NULL;
213 debug_printf (1, "\nMD5 tests (POST, multipart/form-data)\n");
215 if (!g_file_get_contents (MD5_TEST_FILE, &contents, &length, &error)) {
216 debug_printf (1, " ERROR: Could not read " MD5_TEST_FILE ": %s\n", error->message);
217 g_error_free (error);
222 md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, contents, length);
224 do_md5_test_curl (uri, MD5_TEST_FILE, md5);
225 do_md5_test_libsoup (uri, contents, length, md5);
233 do_form_decode_test (void)
239 debug_printf (1, "\nDecode tests\n");
241 /* Test that the code handles multiple values with the same key. */
242 table = soup_form_decode ("foo=first&foo=second&foo=third");
244 /* Allocate some memory. We do this to test for a bug in
245 * soup_form_decode() that resulted in values from the hash
246 * table pointing to memory that is already released.
248 tmp = g_strdup ("other");
250 value = g_hash_table_lookup (table, "foo");
251 if (g_strcmp0 (value, "third") != 0) {
252 debug_printf (1, " ERROR: expected '%s', got '%s'\n",
253 "third", value ? value : "(null)");
258 g_hash_table_destroy (table);
262 hello_callback (SoupServer *server, SoupMessage *msg,
263 const char *path, GHashTable *query,
264 SoupClientContext *context, gpointer data)
266 char *title, *name, *fmt;
267 const char *content_type;
270 if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_HEAD) {
271 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
276 title = g_hash_table_lookup (query, "title");
277 name = g_hash_table_lookup (query, "n@me");
278 fmt = g_hash_table_lookup (query, "fmt");
280 title = name = fmt = NULL;
282 buf = g_string_new (NULL);
283 if (!query || (fmt && !strcmp (fmt, "html"))) {
284 content_type = "text/html";
285 g_string_append (buf, "<html><head><title>forms-test: hello</title></head><body>\r\n");
287 /* mumble mumble html-escape... */
288 g_string_append_printf (buf, "<p>Hello, <b><em>%s</em> %s</b></p>\r\n",
291 g_string_append (buf, "<form action='/hello' method='get'>"
292 "<p>Title: <input name='title'></p>"
293 "<p>Name: <input name='n@me'></p>"
294 "<p><input type=hidden name='fmt' value='html'></p>"
295 "<p><input type=submit></p>"
297 g_string_append (buf, "</body></html>\r\n");
299 content_type = "text/plain";
301 char *uptitle = g_ascii_strup (title, -1);
302 g_string_append_printf (buf, "Hello, %s %s",
308 soup_message_set_response (msg, content_type,
311 g_string_free (buf, FALSE);
312 soup_message_set_status (msg, SOUP_STATUS_OK);
316 md5_get_callback (SoupServer *server, SoupMessage *msg,
317 const char *path, GHashTable *query,
318 SoupClientContext *context, gpointer data)
320 const char *file = NULL, *md5sum = NULL, *fmt;
321 const char *content_type;
325 file = g_hash_table_lookup (query, "file");
326 md5sum = g_hash_table_lookup (query, "md5sum");
327 fmt = g_hash_table_lookup (query, "fmt");
331 buf = g_string_new (NULL);
332 if (!strcmp (fmt, "html")) {
333 content_type = "text/html";
334 g_string_append (buf, "<html><head><title>forms-test: md5</title></head><body>\r\n");
335 if (file && md5sum) {
336 /* mumble mumble html-escape... */
337 g_string_append_printf (buf, "<p>File: %s<br>MD5: <b>%s</b></p>\r\n",
340 g_string_append (buf, "<form action='/md5' method='post' enctype='multipart/form-data'>"
341 "<p>File: <input type='file' name='file'></p>"
342 "<p><input type=hidden name='fmt' value='html'></p>"
343 "<p><input type=submit></p>"
345 g_string_append (buf, "</body></html>\r\n");
347 content_type = "text/plain";
349 g_string_append_printf (buf, "%s", md5sum);
352 soup_message_set_response (msg, content_type,
355 g_string_free (buf, FALSE);
356 soup_message_set_status (msg, SOUP_STATUS_OK);
360 md5_post_callback (SoupServer *server, SoupMessage *msg,
361 const char *path, GHashTable *query,
362 SoupClientContext *context, gpointer data)
364 const char *content_type;
367 char *filename, *md5sum, *redirect_uri;
371 content_type = soup_message_headers_get_content_type (msg->request_headers, NULL);
372 if (!content_type || strcmp (content_type, "multipart/form-data") != 0) {
373 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
377 params = soup_form_decode_multipart (msg, "file",
378 &filename, NULL, &file);
380 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
383 fmt = g_hash_table_lookup (params, "fmt");
385 md5sum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
386 (gpointer)file->data,
388 soup_buffer_free (file);
390 uri = soup_uri_copy (soup_message_get_uri (msg));
391 soup_uri_set_query_from_fields (uri,
392 "file", filename ? filename : "",
394 "fmt", fmt ? fmt : "html",
396 redirect_uri = soup_uri_to_string (uri, FALSE);
398 soup_message_set_status (msg, SOUP_STATUS_SEE_OTHER);
399 soup_message_headers_replace (msg->response_headers, "Location",
402 g_free (redirect_uri);
406 g_hash_table_destroy (params);
410 md5_callback (SoupServer *server, SoupMessage *msg,
411 const char *path, GHashTable *query,
412 SoupClientContext *context, gpointer data)
414 if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD)
415 md5_get_callback (server, msg, path, query, context, data);
416 else if (msg->method == SOUP_METHOD_POST)
417 md5_post_callback (server, msg, path, query, context, data);
419 soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
422 static gboolean run_tests = TRUE;
424 static GOptionEntry no_test_entry[] = {
425 { "no-tests", 'n', G_OPTION_FLAG_REVERSE,
426 G_OPTION_ARG_NONE, &run_tests,
427 "Don't run tests, just run the test server", NULL },
432 main (int argc, char **argv)
439 test_init (argc, argv, no_test_entry);
441 server = soup_test_server_new (TRUE);
442 soup_server_add_handler (server, "/hello",
443 hello_callback, NULL, NULL);
444 soup_server_add_handler (server, "/md5",
445 md5_callback, NULL, NULL);
446 port = soup_server_get_port (server);
448 loop = g_main_loop_new (NULL, TRUE);
451 uri_str = g_strdup_printf ("http://127.0.0.1:%u/hello", port);
452 do_hello_tests (uri_str);
455 uri_str = g_strdup_printf ("http://127.0.0.1:%u/md5", port);
456 do_md5_tests (uri_str);
459 do_form_decode_test ();
461 printf ("Listening on port %d\n", port);
462 g_main_loop_run (loop);
465 g_main_loop_unref (loop);
467 soup_test_server_quit_unref (server);