1/*
2     This file is part of libmicrohttpd
3     Copyright (C) 2007, 2008 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 2, 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_long_header.c
23 * @brief  Testcase for libmicrohttpd handling of very long headers
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#include "socat.c"
40
41/**
42 * We will set the memory available per connection to
43 * half of this value, so the actual value does not have
44 * to be big at all...
45 */
46#define VERY_LONG (1024*10)
47
48static int oneone;
49
50static int
51apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
52{
53  return MHD_YES;
54}
55
56struct CBC
57{
58  char *buf;
59  size_t pos;
60  size_t size;
61};
62
63static size_t
64copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
65{
66  return size * nmemb;
67}
68
69static int
70ahc_echo (void *cls,
71          struct MHD_Connection *connection,
72          const char *url,
73          const char *method,
74          const char *version,
75          const char *upload_data, size_t *upload_data_size,
76          void **unused)
77{
78  const char *me = cls;
79  struct MHD_Response *response;
80  int ret;
81
82  if (0 != strcmp (me, method))
83    return MHD_NO;              /* unexpected method */
84  response = MHD_create_response_from_buffer (strlen (url),
85					      (void *) url,
86					      MHD_RESPMEM_MUST_COPY);
87  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
88  MHD_destroy_response (response);
89  return ret;
90}
91
92
93static int
94testLongUrlGet ()
95{
96  struct MHD_Daemon *d;
97  CURL *c;
98  char buf[2048];
99  struct CBC cbc;
100  char *url;
101  int i;
102
103  cbc.buf = buf;
104  cbc.size = 2048;
105  cbc.pos = 0;
106  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
107                        11080,
108                        &apc_all,
109                        NULL,
110                        &ahc_echo,
111                        "GET",
112                        MHD_OPTION_CONNECTION_MEMORY_LIMIT,
113                        (size_t) (VERY_LONG / 2), MHD_OPTION_END);
114
115  if (d == NULL)
116    return 1;
117  zzuf_socat_start ();
118  for (i = 0; i < LOOP_COUNT; i++)
119    {
120      fprintf (stderr, ".");
121
122      c = curl_easy_init ();
123      url = malloc (VERY_LONG);
124      memset (url, 'a', VERY_LONG);
125      url[VERY_LONG - 1] = '\0';
126      memcpy (url, "http://localhost:11081/",
127              strlen ("http://localhost:11081/"));
128      curl_easy_setopt (c, CURLOPT_URL, url);
129      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
130      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
131      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
132      curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
133      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
134      if (oneone)
135        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
136      else
137        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
138      // NOTE: use of CONNECTTIMEOUT without also
139      //   setting NOSIGNAL results in really weird
140      //   crashes on my system!
141      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
142      curl_easy_perform (c);
143      curl_easy_cleanup (c);
144    }
145  fprintf (stderr, "\n");
146  zzuf_socat_stop ();
147
148  MHD_stop_daemon (d);
149  free (url);
150  return 0;
151}
152
153
154static int
155testLongHeaderGet ()
156{
157  struct MHD_Daemon *d;
158  CURL *c;
159  char buf[2048];
160  struct CBC cbc;
161  char *url;
162  struct curl_slist *header = NULL;
163  int i;
164
165  cbc.buf = buf;
166  cbc.size = 2048;
167  cbc.pos = 0;
168  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
169                        11080,
170                        &apc_all,
171                        NULL,
172                        &ahc_echo,
173                        "GET",
174                        MHD_OPTION_CONNECTION_MEMORY_LIMIT,
175                        (size_t) (VERY_LONG / 2), MHD_OPTION_END);
176  if (d == NULL)
177    return 16;
178  zzuf_socat_start ();
179  for (i = 0; i < LOOP_COUNT; i++)
180    {
181      fprintf (stderr, ".");
182      c = curl_easy_init ();
183      url = malloc (VERY_LONG);
184      memset (url, 'a', VERY_LONG);
185      url[VERY_LONG - 1] = '\0';
186      url[VERY_LONG / 2] = ':';
187      url[VERY_LONG / 2 + 1] = ' ';
188      header = curl_slist_append (header, url);
189
190      curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
191      curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
192      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
193      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
194      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
195      curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
196      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
197      if (oneone)
198        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
199      else
200        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
201      // NOTE: use of CONNECTTIMEOUT without also
202      //   setting NOSIGNAL results in really weird
203      //   crashes on my system!
204      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
205      curl_easy_perform (c);
206      curl_slist_free_all (header);
207      header = NULL;
208      curl_easy_cleanup (c);
209    }
210  fprintf (stderr, "\n");
211  zzuf_socat_stop ();
212
213  MHD_stop_daemon (d);
214  free (url);
215  return 0;
216}
217
218
219int
220main (int argc, char *const *argv)
221{
222  unsigned int errorCount = 0;
223
224  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
225    (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
226  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
227    return 2;
228  errorCount += testLongUrlGet ();
229  errorCount += testLongHeaderGet ();
230  if (errorCount != 0)
231    fprintf (stderr, "Error (code: %u)\n", errorCount);
232  curl_global_cleanup ();
233  return errorCount != 0;       /* 0 == pass */
234}
235