1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Red Hat, Inc.
4  */
5 
6 #include "test-utils.h"
7 
8 #define RESPONSE_CHUNK_SIZE 1024
9 
10 SoupBuffer *full_response;
11 char *full_response_md5;
12 
13 static void
write_next_chunk(SoupMessage * msg,gpointer user_data)14 write_next_chunk (SoupMessage *msg, gpointer user_data)
15 {
16 	gsize *offset = user_data;
17 	gsize chunk_length;
18 
19 	chunk_length = MIN (RESPONSE_CHUNK_SIZE, full_response->length - *offset);
20 	if (chunk_length > 0) {
21 		debug_printf (2, "  writing chunk\n");
22 		soup_message_body_append (msg->response_body,
23 					  SOUP_MEMORY_STATIC,
24 					  full_response->data + *offset,
25 					  chunk_length);
26 		*offset += chunk_length;
27 	} else {
28 		debug_printf (2, "  done\n");
29 		/* This is only actually needed in the chunked and eof
30 		 * cases, but it's harmless in the content-length
31 		 * case.
32 		 */
33 		soup_message_body_complete (msg->response_body);
34 	}
35 }
36 
37 static void
free_offset(SoupMessage * msg,gpointer offset)38 free_offset (SoupMessage *msg, gpointer offset)
39 {
40 	g_free (offset);
41 }
42 
43 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)44 server_callback (SoupServer *server, SoupMessage *msg,
45 		 const char *path, GHashTable *query,
46 		 SoupClientContext *context, gpointer data)
47 {
48 	gsize *offset;
49 
50 	if (!strcmp (path, "/chunked")) {
51 		soup_message_headers_set_encoding (msg->response_headers,
52 						   SOUP_ENCODING_CHUNKED);
53 	} else if (!strcmp (path, "/content-length")) {
54 		soup_message_headers_set_encoding (msg->response_headers,
55 						   SOUP_ENCODING_CONTENT_LENGTH);
56 		soup_message_headers_set_content_length (msg->response_headers,
57 							 full_response->length);
58 	} else if (!strcmp (path, "/eof")) {
59 		soup_message_headers_set_encoding (msg->response_headers,
60 						   SOUP_ENCODING_EOF);
61 	} else {
62 		soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
63 		return;
64 	}
65 	soup_message_set_status (msg, SOUP_STATUS_OK);
66 
67 	offset = g_new0 (gsize, 1);
68 	g_signal_connect (msg, "wrote_headers",
69 			  G_CALLBACK (write_next_chunk), offset);
70 	g_signal_connect (msg, "wrote_chunk",
71 			  G_CALLBACK (write_next_chunk), offset);
72 	g_signal_connect (msg, "finished",
73 			  G_CALLBACK (free_offset), offset);
74 }
75 
76 static void
do_request(SoupSession * session,SoupURI * base_uri,char * path)77 do_request (SoupSession *session, SoupURI *base_uri, char *path)
78 {
79 	SoupURI *uri;
80 	SoupMessage *msg;
81 	char *md5;
82 
83 	uri = soup_uri_new_with_base (base_uri, path);
84 	msg = soup_message_new_from_uri ("GET", uri);
85 	soup_uri_free (uri);
86 
87 	soup_session_send_message (session, msg);
88 
89 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
90 	g_assert_cmpint (msg->response_body->length, ==, full_response->length);
91 
92 	md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
93 					   (guchar *)msg->response_body->data,
94 					   msg->response_body->length);
95 	g_assert_cmpstr (md5, ==, full_response_md5);
96 	g_free (md5);
97 
98 	g_object_unref (msg);
99 }
100 
101 static void
do_chunked_test(gconstpointer data)102 do_chunked_test (gconstpointer data)
103 {
104 	SoupURI *base_uri = (SoupURI *)data;
105 	SoupSession *session;
106 
107 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
108 	do_request (session, base_uri, "chunked");
109 	soup_test_session_abort_unref (session);
110 }
111 
112 static void
do_content_length_test(gconstpointer data)113 do_content_length_test (gconstpointer data)
114 {
115 	SoupURI *base_uri = (SoupURI *)data;
116 	SoupSession *session;
117 
118 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
119 	do_request (session, base_uri, "content-length");
120 	soup_test_session_abort_unref (session);
121 }
122 
123 static void
do_eof_test(gconstpointer data)124 do_eof_test (gconstpointer data)
125 {
126 	SoupURI *base_uri = (SoupURI *)data;
127 	SoupSession *session;
128 
129 	g_test_bug ("572153");
130 
131 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
132 	do_request (session, base_uri, "eof");
133 	soup_test_session_abort_unref (session);
134 }
135 
136 int
main(int argc,char ** argv)137 main (int argc, char **argv)
138 {
139 	GMainLoop *loop;
140 	SoupServer *server;
141 	SoupURI *base_uri;
142 	int ret;
143 
144 	test_init (argc, argv, NULL);
145 
146 	full_response = soup_test_get_index ();
147 	full_response_md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
148 							 (guchar *)full_response->data,
149 							 full_response->length);
150 
151 	server = soup_test_server_new (SOUP_TEST_SERVER_DEFAULT);
152 	soup_server_add_handler (server, NULL,
153 				 server_callback, NULL, NULL);
154 
155 	loop = g_main_loop_new (NULL, TRUE);
156 
157 	base_uri = soup_test_server_get_uri (server, "http", NULL);
158 
159 	g_test_add_data_func ("/streaming/chunked", base_uri, do_chunked_test);
160 	g_test_add_data_func ("/streaming/content-length", base_uri, do_content_length_test);
161 	g_test_add_data_func ("/streaming/eof", base_uri, do_eof_test);
162 
163 	ret = g_test_run ();
164 
165 	soup_uri_free (base_uri);
166 	g_main_loop_unref (loop);
167 
168 	g_free (full_response_md5);
169 	soup_test_server_quit_unref (server);
170 	test_cleanup ();
171 
172 	return ret;
173 }
174