• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007, 2008 Red Hat, Inc.
4  */
5 
6 #include "test-utils.h"
7 
8 static struct {
9 	const char *title, *name;
10 	const char *result;
11 } tests[] = {
12 	/* Both fields must be filled in */
13 	{ NULL, "Name", "" },
14 	{ "Mr.", NULL, "" },
15 
16 	/* Filled-in but empty is OK */
17 	{ "", "", "Hello,  " },
18 	{ "", "Name", "Hello,  Name" },
19 	{ "Mr.", "", "Hello, MR. " },
20 
21 	/* Simple */
22 	{ "Mr.", "Name", "Hello, MR. Name" },
23 
24 	/* Encoding of spaces */
25 	{ "Mr.", "Full Name", "Hello, MR. Full Name" },
26 	{ "Mr. and Mrs.", "Full Name", "Hello, MR. AND MRS. Full Name" },
27 
28 	/* Encoding of "+" */
29 	{ "Mr.+Mrs.", "Full Name", "Hello, MR.+MRS. Full Name" },
30 
31 	/* Encoding of non-ASCII. */
32 	{ "Se\xC3\xB1or", "Nombre", "Hello, SE\xC3\xB1OR Nombre" },
33 
34 	/* Encoding of '%' */
35 	{ "Mr.", "Foo %2f Bar", "Hello, MR. Foo %2f Bar" },
36 };
37 
38 static void
do_hello_test(int n,gboolean extra,const char * uri)39 do_hello_test (int n, gboolean extra, const char *uri)
40 {
41 	GPtrArray *args;
42 	char *title_arg = NULL, *name_arg = NULL;
43 	char *str_stdout = NULL;
44 	GError *error = NULL;
45 
46 	debug_printf (1, "%2d. '%s' '%s'%s: ", n * 2 + (extra ? 2 : 1),
47 		      tests[n].title ? tests[n].title : "(null)",
48 		      tests[n].name  ? tests[n].name  : "(null)",
49 		      extra ? " + extra" : "");
50 
51 	args = g_ptr_array_new ();
52 	g_ptr_array_add (args, "curl");
53 	g_ptr_array_add (args, "--noproxy");
54 	g_ptr_array_add (args, "*");
55 	g_ptr_array_add (args, "-G");
56 	if (tests[n].title) {
57 		title_arg = soup_form_encode ("title", tests[n].title, NULL);
58 		g_ptr_array_add (args, "-d");
59 		g_ptr_array_add (args, title_arg);
60 	}
61 	if (tests[n].name) {
62 		name_arg = soup_form_encode ("n@me", tests[n].name, NULL);
63 		g_ptr_array_add (args, "-d");
64 		g_ptr_array_add (args, name_arg);
65 	}
66 	if (extra) {
67 		g_ptr_array_add (args, "-d");
68 		g_ptr_array_add (args, "extra=something");
69 	}
70 	g_ptr_array_add (args, (char *)uri);
71 	g_ptr_array_add (args, NULL);
72 
73 	if (g_spawn_sync (NULL, (char **)args->pdata, NULL,
74 			  G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
75 			  NULL, NULL,
76 			  &str_stdout, NULL, NULL, &error)) {
77 		g_assert_cmpstr (str_stdout, ==, tests[n].result);
78 		g_free (str_stdout);
79 	} else {
80 		g_assert_no_error (error);
81 		g_error_free (error);
82 	}
83 	g_ptr_array_free (args, TRUE);
84 	g_free (title_arg);
85 	g_free (name_arg);
86 }
87 
88 static void
do_hello_tests(gconstpointer uri)89 do_hello_tests (gconstpointer uri)
90 {
91 	int n;
92 
93 	if (!have_curl()) {
94 		g_test_skip ("curl is not available");
95 		return;
96 	}
97 
98 	for (n = 0; n < G_N_ELEMENTS (tests); n++) {
99 		do_hello_test (n, FALSE, uri);
100 		do_hello_test (n, TRUE, uri);
101 	}
102 }
103 
104 #define MD5_TEST_FILE (g_test_get_filename (G_TEST_DIST, "index.txt", NULL))
105 #define MD5_TEST_FILE_BASENAME "index.txt"
106 #define MD5_TEST_FILE_MIME_TYPE "text/plain"
107 
108 static char *
get_md5_data(char ** contents,gsize * length)109 get_md5_data (char **contents, gsize *length)
110 {
111 	char *my_contents, *md5;
112 	gsize my_length;
113 	GError *error = NULL;
114 
115 	if (!g_file_get_contents (MD5_TEST_FILE, &my_contents, &my_length, &error)) {
116 		g_assert_no_error (error);
117 		g_error_free (error);
118 		return NULL;
119 	}
120 
121 	md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, my_contents, my_length);
122 
123 	if (contents)
124 		*contents = my_contents;
125 	else
126 		g_free (my_contents);
127 	if (length)
128 		*length = my_length;
129 
130 	return md5;
131 }
132 
133 static void
do_md5_test_curl(gconstpointer data)134 do_md5_test_curl (gconstpointer data)
135 {
136 	const char *uri = data;
137 	char *md5;
138 	GPtrArray *args;
139 	char *file_arg, *str_stdout;
140 	GError *error = NULL;
141 
142 	if (!have_curl()) {
143 		g_test_skip ("curl is not available");
144 		return;
145 	}
146 
147 	md5 = get_md5_data (NULL, NULL);
148 	if (!md5)
149 		return;
150 
151 	args = g_ptr_array_new ();
152 	g_ptr_array_add (args, "curl");
153 	g_ptr_array_add (args, "--noproxy");
154 	g_ptr_array_add (args, "*");
155 	g_ptr_array_add (args, "-L");
156 	g_ptr_array_add (args, "-F");
157 	file_arg = g_strdup_printf ("file=@%s", MD5_TEST_FILE);
158 	g_ptr_array_add (args, file_arg);
159 	g_ptr_array_add (args, "-F");
160 	g_ptr_array_add (args, "fmt=txt");
161 	g_ptr_array_add (args, (char *)uri);
162 	g_ptr_array_add (args, NULL);
163 
164 	if (g_spawn_sync (NULL, (char **)args->pdata, NULL,
165 			  G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
166 			  NULL, NULL,
167 			  &str_stdout, NULL, NULL, NULL)) {
168 		g_assert_cmpstr (str_stdout, ==, md5);
169 		g_free (str_stdout);
170 	} else {
171 		g_assert_no_error (error);
172 		g_error_free (error);
173 	}
174 	g_ptr_array_free (args, TRUE);
175 	g_free (file_arg);
176 
177 	g_free (md5);
178 }
179 
180 static void
do_md5_test_libsoup(gconstpointer data)181 do_md5_test_libsoup (gconstpointer data)
182 {
183 	const char *uri = data;
184 	char *contents, *md5;
185 	gsize length;
186 	SoupMultipart *multipart;
187 	SoupBuffer *buffer;
188 	SoupMessage *msg;
189 	SoupSession *session;
190 
191 	g_test_bug ("601640");
192 
193 	md5 = get_md5_data (&contents, &length);
194 	if (!md5)
195 		return;
196 
197 	multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART);
198 	buffer = soup_buffer_new (SOUP_MEMORY_COPY, contents, length);
199 	soup_multipart_append_form_file (multipart, "file",
200 					 MD5_TEST_FILE_BASENAME,
201 					 MD5_TEST_FILE_MIME_TYPE,
202 					 buffer);
203 	soup_buffer_free (buffer);
204 	soup_multipart_append_form_string (multipart, "fmt", "text");
205 
206 	msg = soup_form_request_new_from_multipart (uri, multipart);
207 	soup_multipart_free (multipart);
208 
209 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
210 	soup_session_send_message (session, msg);
211 
212 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
213 	g_assert_cmpstr (msg->response_body->data, ==, md5);
214 
215 	g_object_unref (msg);
216 	soup_test_session_abort_unref (session);
217 
218 	g_free (contents);
219 	g_free (md5);
220 }
221 
222 static void
do_form_decode_test(void)223 do_form_decode_test (void)
224 {
225 	GHashTable *table;
226 	const gchar *value;
227 	gchar *tmp;
228 
229 	if (!have_curl()) {
230 		g_test_skip ("curl is not available");
231 		return;
232 	}
233 
234 	/*  Test that the code handles multiple values with the same key.  */
235 	table = soup_form_decode ("foo=first&foo=second&foo=third");
236 
237 	/*  Allocate some memory. We do this to test for a bug in
238 	 *  soup_form_decode() that resulted in values from the hash
239 	 *  table pointing to memory that is already released.
240 	 */
241 	tmp = g_strdup ("other");
242 
243 	value = g_hash_table_lookup (table, "foo");
244 	g_assert_cmpstr (value, ==, "third");
245 
246 	g_free (tmp);
247 	g_hash_table_destroy (table);
248 }
249 
250 static void
hello_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)251 hello_callback (SoupServer *server, SoupMessage *msg,
252 		const char *path, GHashTable *query,
253 		SoupClientContext *context, gpointer data)
254 {
255 	char *title, *name, *fmt;
256 	const char *content_type;
257 	GString *buf;
258 
259 	if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_HEAD) {
260 		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
261 		return;
262 	}
263 
264 	if (query) {
265 		title = g_hash_table_lookup (query, "title");
266 		name = g_hash_table_lookup (query, "n@me");
267 		fmt = g_hash_table_lookup (query, "fmt");
268 	} else
269 		title = name = fmt = NULL;
270 
271 	buf = g_string_new (NULL);
272 	if (!query || (fmt && !strcmp (fmt, "html"))) {
273 		content_type = "text/html";
274 		g_string_append (buf, "<html><head><title>forms-test: hello</title></head><body>\r\n");
275 		if (title && name) {
276 			/* mumble mumble html-escape... */
277 			g_string_append_printf (buf, "<p>Hello, <b><em>%s</em> %s</b></p>\r\n",
278 						title, name);
279 		}
280 		g_string_append (buf, "<form action='/hello' method='get'>"
281 				 "<p>Title: <input name='title'></p>"
282 				 "<p>Name: <input name='n@me'></p>"
283 				 "<p><input type=hidden name='fmt' value='html'></p>"
284 				 "<p><input type=submit></p>"
285 				 "</form>\r\n");
286 		g_string_append (buf, "</body></html>\r\n");
287 	} else {
288 		content_type = "text/plain";
289 		if (title && name) {
290 			char *uptitle = g_ascii_strup (title, -1);
291 			g_string_append_printf (buf, "Hello, %s %s",
292 						uptitle, name);
293 			g_free (uptitle);
294 		}
295 	}
296 
297 	soup_message_set_response (msg, content_type,
298 				   SOUP_MEMORY_TAKE,
299 				   buf->str, buf->len);
300 	g_string_free (buf, FALSE);
301 	soup_message_set_status (msg, SOUP_STATUS_OK);
302 }
303 
304 static void
md5_get_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)305 md5_get_callback (SoupServer *server, SoupMessage *msg,
306 		  const char *path, GHashTable *query,
307 		  SoupClientContext *context, gpointer data)
308 {
309 	const char *file = NULL, *md5sum = NULL, *fmt;
310 	const char *content_type;
311 	GString *buf;
312 
313 	if (query) {
314 		file = g_hash_table_lookup (query, "file");
315 		md5sum = g_hash_table_lookup (query, "md5sum");
316 		fmt = g_hash_table_lookup (query, "fmt");
317 	} else
318 		fmt = "html";
319 
320 	buf = g_string_new (NULL);
321 	if (!strcmp (fmt, "html")) {
322 		content_type = "text/html";
323 		g_string_append (buf, "<html><head><title>forms-test: md5</title></head><body>\r\n");
324 		if (file && md5sum) {
325 			/* mumble mumble html-escape... */
326 			g_string_append_printf (buf, "<p>File: %s<br>MD5: <b>%s</b></p>\r\n",
327 						file, md5sum);
328 		}
329 		g_string_append (buf, "<form action='/md5' method='post' enctype='multipart/form-data'>"
330 				 "<p>File: <input type='file' name='file'></p>"
331 				 "<p><input type=hidden name='fmt' value='html'></p>"
332 				 "<p><input type=submit></p>"
333 				 "</form>\r\n");
334 		g_string_append (buf, "</body></html>\r\n");
335 	} else {
336 		content_type = "text/plain";
337 		if (md5sum)
338 			g_string_append_printf (buf, "%s", md5sum);
339 	}
340 
341 	soup_message_set_response (msg, content_type,
342 				   SOUP_MEMORY_TAKE,
343 				   buf->str, buf->len);
344 	g_string_free (buf, FALSE);
345 	soup_message_set_status (msg, SOUP_STATUS_OK);
346 }
347 
348 static void
md5_post_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)349 md5_post_callback (SoupServer *server, SoupMessage *msg,
350 		   const char *path, GHashTable *query,
351 		   SoupClientContext *context, gpointer data)
352 {
353 	const char *content_type;
354 	GHashTable *params;
355 	const char *fmt;
356 	char *filename, *md5sum, *redirect_uri;
357 	SoupBuffer *file;
358 	SoupURI *uri;
359 
360 	content_type = soup_message_headers_get_content_type (msg->request_headers, NULL);
361 	if (!content_type || strcmp (content_type, "multipart/form-data") != 0) {
362 		soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
363 		return;
364 	}
365 
366 	params = soup_form_decode_multipart (msg, "file",
367 					     &filename, NULL, &file);
368 	if (!params) {
369 		soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
370 		return;
371 	}
372 	fmt = g_hash_table_lookup (params, "fmt");
373 
374 	md5sum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
375 					      (gpointer)file->data,
376 					      file->length);
377 	soup_buffer_free (file);
378 
379 	uri = soup_uri_copy (soup_message_get_uri (msg));
380 	soup_uri_set_query_from_fields (uri,
381 					"file", filename ? filename : "",
382 					"md5sum", md5sum,
383 					"fmt", fmt ? fmt : "html",
384 					NULL);
385 	redirect_uri = soup_uri_to_string (uri, FALSE);
386 
387 	soup_message_set_redirect (msg, SOUP_STATUS_SEE_OTHER, redirect_uri);
388 
389 	g_free (redirect_uri);
390 	soup_uri_free (uri);
391 	g_free (md5sum);
392 	g_free (filename);
393 	g_hash_table_destroy (params);
394 }
395 
396 static void
md5_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)397 md5_callback (SoupServer *server, SoupMessage *msg,
398 	      const char *path, GHashTable *query,
399 	      SoupClientContext *context, gpointer data)
400 {
401 	if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD)
402 		md5_get_callback (server, msg, path, query, context, data);
403 	else if (msg->method == SOUP_METHOD_POST)
404 		md5_post_callback (server, msg, path, query, context, data);
405 	else
406 		soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
407 }
408 
409 static gboolean run_tests = TRUE;
410 
411 static GOptionEntry no_test_entry[] = {
412         { "no-tests", 'n', G_OPTION_FLAG_REVERSE,
413           G_OPTION_ARG_NONE, &run_tests,
414           "Don't run tests, just run the test server", NULL },
415         { NULL }
416 };
417 
418 int
main(int argc,char ** argv)419 main (int argc, char **argv)
420 {
421 	GMainLoop *loop;
422 	SoupServer *server;
423 	SoupURI *base_uri, *uri;
424 	int ret = 0;
425 
426 	test_init (argc, argv, no_test_entry);
427 
428 	server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
429 	soup_server_add_handler (server, "/hello",
430 				 hello_callback, NULL, NULL);
431 	soup_server_add_handler (server, "/md5",
432 				 md5_callback, NULL, NULL);
433 	base_uri = soup_test_server_get_uri (server, "http", NULL);
434 
435 	loop = g_main_loop_new (NULL, TRUE);
436 
437 	if (run_tests) {
438 		uri = soup_uri_new_with_base (base_uri, "/hello");
439 		g_test_add_data_func_full ("/forms/hello", soup_uri_to_string (uri, FALSE), do_hello_tests, g_free);
440 		soup_uri_free (uri);
441 
442 		uri = soup_uri_new_with_base (base_uri, "/md5");
443 		g_test_add_data_func_full ("/forms/md5/curl", soup_uri_to_string (uri, FALSE), do_md5_test_curl, g_free);
444 		g_test_add_data_func_full ("/forms/md5/libsoup", soup_uri_to_string (uri, FALSE), do_md5_test_libsoup, g_free);
445 		soup_uri_free (uri);
446 
447 		g_test_add_func ("/forms/decode", do_form_decode_test);
448 
449 		ret = g_test_run ();
450 	} else {
451 		g_print ("Listening on port %d\n", base_uri->port);
452 		g_main_loop_run (loop);
453 	}
454 
455 	g_main_loop_unref (loop);
456 
457 	soup_test_server_quit_unref (server);
458 	soup_uri_free (base_uri);
459 
460 	if (run_tests)
461 		test_cleanup ();
462 	return ret;
463 }
464