test_process_arguments.c revision 748945ec6f1c67b7efc934ab0808e1d32f2fb98d
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
39static int oneone;
40
41struct CBC
42{
43  char *buf;
44  size_t pos;
45  size_t size;
46};
47
48
49static size_t
50copyBuffer (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
62static int
63ahc_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
111static int
112testExternalGet ()
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, &copyBuffer);
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
235int
236main (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