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