1 /*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2013 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21 /**
22 * @file test_process_arguments.c
23 * @brief Testcase for HTTP URI arguments
24 * @author Christian Grothoff
25 */
26
27 #include "MHD_config.h"
28 #include "platform.h"
29 #include <curl/curl.h>
30 #include <microhttpd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34
35 #ifndef WINDOWS
36 #include <unistd.h>
37 #endif
38
39 static int oneone;
40
41 struct CBC
42 {
43 char *buf;
44 size_t pos;
45 size_t size;
46 };
47
48
49 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)50 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
51 {
52 struct CBC *cbc = ctx;
53
54 if (cbc->pos + size * nmemb > cbc->size)
55 return 0; /* overflow */
56 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
57 cbc->pos += size * nmemb;
58 return size * nmemb;
59 }
60
61
62 static int
ahc_echo(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)63 ahc_echo (void *cls,
64 struct MHD_Connection *connection,
65 const char *url,
66 const char *method,
67 const char *version,
68 const char *upload_data, size_t *upload_data_size,
69 void **unused)
70 {
71 static int ptr;
72 const char *me = cls;
73 struct MHD_Response *response;
74 int ret;
75 const char *hdr;
76
77 if (0 != strcmp (me, method))
78 return MHD_NO; /* unexpected method */
79 if (&ptr != *unused)
80 {
81 *unused = &ptr;
82 return MHD_YES;
83 }
84 *unused = NULL;
85 hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k");
86 if ((hdr == NULL) || (0 != strcmp (hdr, "v x")))
87 abort ();
88 hdr = MHD_lookup_connection_value (connection,
89 MHD_GET_ARGUMENT_KIND, "hash");
90 if ((hdr == NULL) || (0 != strcmp (hdr, "#foo")))
91 abort ();
92 hdr = MHD_lookup_connection_value (connection,
93 MHD_GET_ARGUMENT_KIND, "space");
94 if ((hdr == NULL) || (0 != strcmp (hdr, "\240bar")))
95 abort ();
96 if (3 != MHD_get_connection_values (connection,
97 MHD_GET_ARGUMENT_KIND,
98 NULL, NULL))
99 abort ();
100 response = MHD_create_response_from_buffer (strlen (url),
101 (void *) url,
102 MHD_RESPMEM_MUST_COPY);
103 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
104 MHD_destroy_response (response);
105 if (ret == MHD_NO)
106 abort ();
107 return ret;
108 }
109
110
111 static int
testExternalGet()112 testExternalGet ()
113 {
114 struct MHD_Daemon *d;
115 CURL *c;
116 char buf[2048];
117 struct CBC cbc;
118 CURLM *multi;
119 CURLMcode mret;
120 fd_set rs;
121 fd_set ws;
122 fd_set es;
123 MHD_socket max;
124 int running;
125 struct CURLMsg *msg;
126 time_t start;
127 struct timeval tv;
128
129 multi = NULL;
130 cbc.buf = buf;
131 cbc.size = 2048;
132 cbc.pos = 0;
133 d = MHD_start_daemon (MHD_USE_DEBUG,
134 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
135 if (d == NULL)
136 return 256;
137 c = curl_easy_init ();
138 curl_easy_setopt (c, CURLOPT_URL,
139 "http://127.0.0.1:21080/hello+world?k=v+x&hash=%23foo&space=%A0bar");
140 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
141 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
142 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
143 if (oneone)
144 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
145 else
146 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
147 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
148 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
149 /* NOTE: use of CONNECTTIMEOUT without also
150 setting NOSIGNAL results in really weird
151 crashes on my system! */
152 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
153
154
155 multi = curl_multi_init ();
156 if (multi == NULL)
157 {
158 curl_easy_cleanup (c);
159 MHD_stop_daemon (d);
160 return 512;
161 }
162 mret = curl_multi_add_handle (multi, c);
163 if (mret != CURLM_OK)
164 {
165 curl_multi_cleanup (multi);
166 curl_easy_cleanup (c);
167 MHD_stop_daemon (d);
168 return 1024;
169 }
170 start = time (NULL);
171 while ((time (NULL) - start < 5) && (multi != NULL))
172 {
173 max = 0;
174 FD_ZERO (&rs);
175 FD_ZERO (&ws);
176 FD_ZERO (&es);
177 curl_multi_perform (multi, &running);
178 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
179 if (mret != CURLM_OK)
180 {
181 curl_multi_remove_handle (multi, c);
182 curl_multi_cleanup (multi);
183 curl_easy_cleanup (c);
184 MHD_stop_daemon (d);
185 return 2048;
186 }
187 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
188 {
189 curl_multi_remove_handle (multi, c);
190 curl_multi_cleanup (multi);
191 curl_easy_cleanup (c);
192 MHD_stop_daemon (d);
193 return 4096;
194 }
195 tv.tv_sec = 0;
196 tv.tv_usec = 1000;
197 select (max + 1, &rs, &ws, &es, &tv);
198 curl_multi_perform (multi, &running);
199 if (running == 0)
200 {
201 msg = curl_multi_info_read (multi, &running);
202 if (msg == NULL)
203 break;
204 if (msg->msg == CURLMSG_DONE)
205 {
206 if (msg->data.result != CURLE_OK)
207 printf ("%s failed at %s:%d: `%s'\n",
208 "curl_multi_perform",
209 __FILE__,
210 __LINE__, curl_easy_strerror (msg->data.result));
211 curl_multi_remove_handle (multi, c);
212 curl_multi_cleanup (multi);
213 curl_easy_cleanup (c);
214 c = NULL;
215 multi = NULL;
216 }
217 }
218 MHD_run (d);
219 }
220 if (multi != NULL)
221 {
222 curl_multi_remove_handle (multi, c);
223 curl_easy_cleanup (c);
224 curl_multi_cleanup (multi);
225 }
226 MHD_stop_daemon (d);
227 if (cbc.pos != strlen ("/hello+world"))
228 return 8192;
229 if (0 != strncmp ("/hello+world", cbc.buf, strlen ("/hello+world")))
230 return 16384;
231 return 0;
232 }
233
234
235 int
main(int argc,char * const * argv)236 main (int argc, char *const *argv)
237 {
238 unsigned int errorCount = 0;
239
240 oneone = (NULL != strrchr (argv[0], (int) '/')) ?
241 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
242 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
243 return 2;
244 errorCount += testExternalGet ();
245 if (errorCount != 0)
246 fprintf (stderr, "Error (code: %u)\n", errorCount);
247 curl_global_cleanup ();
248 return errorCount != 0; /* 0 == pass */
249 }
250