aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-07-29 19:23:35 +0200
committerChristian Grothoff <christian@grothoff.org>2019-07-29 19:30:27 +0200
commit40bf201dc53465be1d2805039ef5963a21e44c08 (patch)
treec3cb5639c71dc8d30739c3770d8c7646259a0bc5
parent1aaff72582b6093f0dcf8c187d125e5fca2d2e8b (diff)
downloadlibmicrohttpd-40bf201dc53465be1d2805039ef5963a21e44c08.tar.gz
libmicrohttpd-40bf201dc53465be1d2805039ef5963a21e44c08.zip
indentation fixes, adding test_upgrade_large.c test for issue reported by Viet
-rw-r--r--src/microhttpd/.gitignore2
-rw-r--r--src/microhttpd/Makefile.am34
-rw-r--r--src/microhttpd/daemon.c167
-rw-r--r--src/microhttpd/response.c88
-rw-r--r--src/microhttpd/test_upgrade_large.c1353
5 files changed, 1513 insertions, 131 deletions
diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore
index ec2e027d..611f88ec 100644
--- a/src/microhttpd/.gitignore
+++ b/src/microhttpd/.gitignore
@@ -57,3 +57,5 @@ test_shutdown_poll
57test_shutdown_select 57test_shutdown_select
58test_md5 58test_md5
59test_sha256 59test_sha256
60test_upgrade_large
61test_upgrade_large_tls
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 3fb65fe1..8bc60879 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -165,17 +165,17 @@ check_PROGRAMS = \
165if HAVE_POSIX_THREADS 165if HAVE_POSIX_THREADS
166if ENABLE_UPGRADE 166if ENABLE_UPGRADE
167if USE_POSIX_THREADS 167if USE_POSIX_THREADS
168 check_PROGRAMS += test_upgrade 168 check_PROGRAMS += test_upgrade test_upgrade_large
169endif 169endif
170if USE_W32_THREADS 170if USE_W32_THREADS
171 check_PROGRAMS += test_upgrade 171 check_PROGRAMS += test_upgrade test_upgrade_large
172endif 172endif
173if ENABLE_HTTPS 173if ENABLE_HTTPS
174if USE_POSIX_THREADS 174if USE_POSIX_THREADS
175check_PROGRAMS += test_upgrade_tls 175check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls
176endif 176endif
177if USE_W32_THREADS 177if USE_W32_THREADS
178check_PROGRAMS += test_upgrade_tls 178check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls
179endif 179endif
180endif 180endif
181endif 181endif
@@ -230,6 +230,19 @@ test_upgrade_LDADD = \
230 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ 230 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
231 $(PTHREAD_LIBS) 231 $(PTHREAD_LIBS)
232 232
233test_upgrade_large_SOURCES = \
234 test_upgrade_large.c test_helpers.h mhd_sockets.h
235test_upgrade_large_CPPFLAGS = \
236 $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
237test_upgrade_large_CFLAGS = \
238 $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
239test_upgrade_large_LDFLAGS = \
240 $(MHD_TLS_LIB_LDFLAGS)
241test_upgrade_large_LDADD = \
242 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
243 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
244 $(PTHREAD_LIBS)
245
233test_upgrade_tls_SOURCES = \ 246test_upgrade_tls_SOURCES = \
234 test_upgrade.c test_helpers.h mhd_sockets.h 247 test_upgrade.c test_helpers.h mhd_sockets.h
235test_upgrade_tls_CPPFLAGS = \ 248test_upgrade_tls_CPPFLAGS = \
@@ -243,6 +256,19 @@ test_upgrade_tls_LDADD = \
243 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ 256 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
244 $(PTHREAD_LIBS) 257 $(PTHREAD_LIBS)
245 258
259test_upgrade_large_tls_SOURCES = \
260 test_upgrade_large.c test_helpers.h mhd_sockets.h
261test_upgrade_large_tls_CPPFLAGS = \
262 $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
263test_upgrade_large_tls_CFLAGS = \
264 $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
265test_upgrade_large_tls_LDFLAGS = \
266 $(MHD_TLS_LIB_LDFLAGS)
267test_upgrade_large_tls_LDADD = \
268 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
269 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
270 $(PTHREAD_LIBS)
271
246test_postprocessor_SOURCES = \ 272test_postprocessor_SOURCES = \
247 test_postprocessor.c 273 test_postprocessor.c
248test_postprocessor_CPPFLAGS = \ 274test_postprocessor_CPPFLAGS = \
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index b312c305..3fc992de 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -4178,28 +4178,29 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4178 struct MHD_UpgradeResponseHandle * prev; 4178 struct MHD_UpgradeResponseHandle * prev;
4179 4179
4180 num_events = MAX_EVENTS; 4180 num_events = MAX_EVENTS;
4181 while (MAX_EVENTS == num_events) 4181 while (0 != num_events)
4182 { 4182 {
4183 unsigned int i; 4183 unsigned int i;
4184 /* update event masks */ 4184 /* update event masks */
4185 num_events = epoll_wait (daemon->epoll_upgrade_fd, 4185 num_events = epoll_wait (daemon->epoll_upgrade_fd,
4186 events, 4186 events,
4187 MAX_EVENTS, 4187 MAX_EVENTS,
4188 0); 4188 0);
4189 if (-1 == num_events) 4189 if (-1 == num_events)
4190 { 4190 {
4191 const int err = MHD_socket_get_error_ (); 4191 const int err = MHD_socket_get_error_ ();
4192
4192 if (MHD_SCKT_ERR_IS_EINTR_ (err)) 4193 if (MHD_SCKT_ERR_IS_EINTR_ (err))
4193 return MHD_YES; 4194 return MHD_YES;
4194#ifdef HAVE_MESSAGES 4195#ifdef HAVE_MESSAGES
4195 MHD_DLOG (daemon, 4196 MHD_DLOG (daemon,
4196 _("Call to epoll_wait failed: %s\n"), 4197 _("Call to epoll_wait failed: %s\n"),
4197 MHD_socket_strerr_ (err)); 4198 MHD_socket_strerr_ (err));
4198#endif 4199#endif
4199 return MHD_NO; 4200 return MHD_NO;
4200 } 4201 }
4201 for (i = 0; i < (unsigned int) num_events; i++) 4202 for (i = 0; i < (unsigned int) num_events; i++)
4202 { 4203 {
4203 struct UpgradeEpollHandle * const ueh = events[i].data.ptr; 4204 struct UpgradeEpollHandle * const ueh = events[i].data.ptr;
4204 struct MHD_UpgradeResponseHandle * const urh = ueh->urh; 4205 struct MHD_UpgradeResponseHandle * const urh = ueh->urh;
4205 bool new_err_state = false; 4206 bool new_err_state = false;
@@ -4217,24 +4218,24 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4217 4218
4218 if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) && 4219 if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) &&
4219 (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) ) 4220 (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) )
4220 { 4221 {
4221 /* Process new error state only one time 4222 /* Process new error state only one time
4222 * and avoid continuously marking this connection 4223 * and avoid continuously marking this connection
4223 * as 'ready'. */ 4224 * as 'ready'. */
4224 ueh->celi |= MHD_EPOLL_STATE_ERROR; 4225 ueh->celi |= MHD_EPOLL_STATE_ERROR;
4225 new_err_state = true; 4226 new_err_state = true;
4226 } 4227 }
4227 4228
4228 if (! urh->in_eready_list) 4229 if (! urh->in_eready_list)
4229 { 4230 {
4230 if (new_err_state || 4231 if (new_err_state ||
4231 is_urh_ready(urh)) 4232 is_urh_ready(urh))
4232 { 4233 {
4233 EDLL_insert (daemon->eready_urh_head, 4234 EDLL_insert (daemon->eready_urh_head,
4234 daemon->eready_urh_tail, 4235 daemon->eready_urh_tail,
4235 urh); 4236 urh);
4236 urh->in_eready_list = true; 4237 urh->in_eready_list = true;
4237 } 4238 }
4238 } 4239 }
4239 } 4240 }
4240 } 4241 }
@@ -4246,8 +4247,8 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4246 if (! is_urh_ready(pos)) 4247 if (! is_urh_ready(pos))
4247 { 4248 {
4248 EDLL_remove (daemon->eready_urh_head, 4249 EDLL_remove (daemon->eready_urh_head,
4249 daemon->eready_urh_tail, 4250 daemon->eready_urh_tail,
4250 pos); 4251 pos);
4251 pos->in_eready_list = false; 4252 pos->in_eready_list = false;
4252 } 4253 }
4253 /* Finished forwarding? */ 4254 /* Finished forwarding? */
@@ -4287,7 +4288,7 @@ static const char * const epoll_itc_marker = "itc_marker";
4287 */ 4288 */
4288static int 4289static int
4289MHD_epoll (struct MHD_Daemon *daemon, 4290MHD_epoll (struct MHD_Daemon *daemon,
4290 int may_block) 4291 int may_block)
4291{ 4292{
4292#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4293#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4293 static const char * const upgrade_marker = "upgrade_ptr"; 4294 static const char * const upgrade_marker = "upgrade_ptr";
@@ -4302,7 +4303,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
4302 unsigned int i; 4303 unsigned int i;
4303 MHD_socket ls; 4304 MHD_socket ls;
4304#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4305#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4305 int run_upgraded = MHD_NO; 4306 bool run_upgraded = false;
4306#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4307#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4307 4308
4308 if (-1 == daemon->epoll_fd) 4309 if (-1 == daemon->epoll_fd)
@@ -4318,31 +4319,31 @@ MHD_epoll (struct MHD_Daemon *daemon,
4318 event.events = EPOLLIN; 4319 event.events = EPOLLIN;
4319 event.data.ptr = daemon; 4320 event.data.ptr = daemon;
4320 if (0 != epoll_ctl (daemon->epoll_fd, 4321 if (0 != epoll_ctl (daemon->epoll_fd,
4321 EPOLL_CTL_ADD, 4322 EPOLL_CTL_ADD,
4322 ls, 4323 ls,
4323 &event)) 4324 &event))
4324 { 4325 {
4325#ifdef HAVE_MESSAGES 4326#ifdef HAVE_MESSAGES
4326 MHD_DLOG (daemon, 4327 MHD_DLOG (daemon,
4327 _("Call to epoll_ctl failed: %s\n"), 4328 _("Call to epoll_ctl failed: %s\n"),
4328 MHD_socket_last_strerr_ ()); 4329 MHD_socket_last_strerr_ ());
4329#endif 4330#endif
4330 return MHD_NO; 4331 return MHD_NO;
4331 } 4332 }
4332 daemon->listen_socket_in_epoll = true; 4333 daemon->listen_socket_in_epoll = true;
4333 } 4334 }
4334 if ( (daemon->was_quiesced) && 4335 if ( (daemon->was_quiesced) &&
4335 (daemon->listen_socket_in_epoll) ) 4336 (daemon->listen_socket_in_epoll) )
4336 { 4337 {
4337 if ( (0 != epoll_ctl (daemon->epoll_fd, 4338 if ( (0 != epoll_ctl (daemon->epoll_fd,
4338 EPOLL_CTL_DEL, 4339 EPOLL_CTL_DEL,
4339 ls, 4340 ls,
4340 NULL)) && 4341 NULL)) &&
4341 (ENOENT != errno) ) /* ENOENT can happen due to race with 4342 (ENOENT != errno) ) /* ENOENT can happen due to race with
4342 #MHD_quiesce_daemon() */ 4343 #MHD_quiesce_daemon() */
4343 MHD_PANIC ("Failed to remove listen FD from epoll set\n"); 4344 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
4344 daemon->listen_socket_in_epoll = false; 4345 daemon->listen_socket_in_epoll = false;
4345 } 4346 }
4346 4347
4347#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4348#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4348 if ( (! daemon->upgrade_fd_in_epoll) && 4349 if ( (! daemon->upgrade_fd_in_epoll) &&
@@ -4351,17 +4352,17 @@ MHD_epoll (struct MHD_Daemon *daemon,
4351 event.events = EPOLLIN | EPOLLOUT; 4352 event.events = EPOLLIN | EPOLLOUT;
4352 event.data.ptr = (void *) upgrade_marker; 4353 event.data.ptr = (void *) upgrade_marker;
4353 if (0 != epoll_ctl (daemon->epoll_fd, 4354 if (0 != epoll_ctl (daemon->epoll_fd,
4354 EPOLL_CTL_ADD, 4355 EPOLL_CTL_ADD,
4355 daemon->epoll_upgrade_fd, 4356 daemon->epoll_upgrade_fd,
4356 &event)) 4357 &event))
4357 { 4358 {
4358#ifdef HAVE_MESSAGES 4359#ifdef HAVE_MESSAGES
4359 MHD_DLOG (daemon, 4360 MHD_DLOG (daemon,
4360 _("Call to epoll_ctl failed: %s\n"), 4361 _("Call to epoll_ctl failed: %s\n"),
4361 MHD_socket_last_strerr_ ()); 4362 MHD_socket_last_strerr_ ());
4362#endif 4363#endif
4363 return MHD_NO; 4364 return MHD_NO;
4364 } 4365 }
4365 daemon->upgrade_fd_in_epoll = true; 4366 daemon->upgrade_fd_in_epoll = true;
4366 } 4367 }
4367#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4368#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
@@ -4373,10 +4374,10 @@ MHD_epoll (struct MHD_Daemon *daemon,
4373 /* we're at the connection limit, disable listen socket 4374 /* we're at the connection limit, disable listen socket
4374 for event loop for now */ 4375 for event loop for now */
4375 if (0 != epoll_ctl (daemon->epoll_fd, 4376 if (0 != epoll_ctl (daemon->epoll_fd,
4376 EPOLL_CTL_DEL, 4377 EPOLL_CTL_DEL,
4377 ls, 4378 ls,
4378 NULL)) 4379 NULL))
4379 MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); 4380 MHD_PANIC (_("Failed to remove listen FD from epoll set\n"));
4380 daemon->listen_socket_in_epoll = false; 4381 daemon->listen_socket_in_epoll = false;
4381 } 4382 }
4382 4383
@@ -4388,14 +4389,14 @@ MHD_epoll (struct MHD_Daemon *daemon,
4388 { 4389 {
4389 if (MHD_YES == MHD_get_timeout (daemon, 4390 if (MHD_YES == MHD_get_timeout (daemon,
4390 &timeout_ll)) 4391 &timeout_ll))
4391 { 4392 {
4392 if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) 4393 if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
4393 timeout_ms = INT_MAX; 4394 timeout_ms = INT_MAX;
4394 else 4395 else
4395 timeout_ms = (int) timeout_ll; 4396 timeout_ms = (int) timeout_ll;
4396 } 4397 }
4397 else 4398 else
4398 timeout_ms = -1; 4399 timeout_ms = -1;
4399 } 4400 }
4400 else 4401 else
4401 timeout_ms = 0; 4402 timeout_ms = 0;
@@ -4414,33 +4415,33 @@ MHD_epoll (struct MHD_Daemon *daemon,
4414 { 4415 {
4415 /* update event masks */ 4416 /* update event masks */
4416 num_events = epoll_wait (daemon->epoll_fd, 4417 num_events = epoll_wait (daemon->epoll_fd,
4417 events, 4418 events,
4418 MAX_EVENTS, 4419 MAX_EVENTS,
4419 timeout_ms); 4420 timeout_ms);
4420 if (-1 == num_events) 4421 if (-1 == num_events)
4421 { 4422 {
4422 const int err = MHD_socket_get_error_ (); 4423 const int err = MHD_socket_get_error_ ();
4423 if (MHD_SCKT_ERR_IS_EINTR_ (err)) 4424 if (MHD_SCKT_ERR_IS_EINTR_ (err))
4424 return MHD_YES; 4425 return MHD_YES;
4425#ifdef HAVE_MESSAGES 4426#ifdef HAVE_MESSAGES
4426 MHD_DLOG (daemon, 4427 MHD_DLOG (daemon,
4427 _("Call to epoll_wait failed: %s\n"), 4428 _("Call to epoll_wait failed: %s\n"),
4428 MHD_socket_strerr_ (err)); 4429 MHD_socket_strerr_ (err));
4429#endif 4430#endif
4430 return MHD_NO; 4431 return MHD_NO;
4431 } 4432 }
4432 for (i=0;i<(unsigned int) num_events;i++) 4433 for (i=0;i<(unsigned int) num_events;i++)
4433 { 4434 {
4434 /* First, check for the values of `ptr` that would indicate 4435 /* First, check for the values of `ptr` that would indicate
4435 that this event is not about a normal connection. */ 4436 that this event is not about a normal connection. */
4436 if (NULL == events[i].data.ptr) 4437 if (NULL == events[i].data.ptr)
4437 continue; /* shutdown signal! */ 4438 continue; /* shutdown signal! */
4438#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4439#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4439 if (upgrade_marker == events[i].data.ptr) 4440 if (upgrade_marker == events[i].data.ptr)
4440 { 4441 {
4441 /* activity on an upgraded connection, we process 4442 /* activity on an upgraded connection, we process
4442 those in a separate epoll() */ 4443 those in a separate epoll() */
4443 run_upgraded = MHD_YES; 4444 run_upgraded = true;
4444 continue; 4445 continue;
4445 } 4446 }
4446#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4447#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
@@ -4451,8 +4452,8 @@ MHD_epoll (struct MHD_Daemon *daemon,
4451 MHD_itc_clear_ (daemon->itc); 4452 MHD_itc_clear_ (daemon->itc);
4452 continue; 4453 continue;
4453 } 4454 }
4454 if (daemon == events[i].data.ptr) 4455 if (daemon == events[i].data.ptr)
4455 { 4456 {
4456 /* Check for error conditions on listen socket. */ 4457 /* Check for error conditions on listen socket. */
4457 /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */ 4458 /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */
4458 if (0 == (events[i].events & (EPOLLERR | EPOLLHUP))) 4459 if (0 == (events[i].events & (EPOLLERR | EPOLLHUP)))
@@ -4467,9 +4468,9 @@ MHD_epoll (struct MHD_Daemon *daemon,
4467 (daemon->connections < daemon->connection_limit) && 4468 (daemon->connections < daemon->connection_limit) &&
4468 (! daemon->at_limit) ) 4469 (! daemon->at_limit) )
4469 series_length++; 4470 series_length++;
4470 } 4471 }
4471 continue; 4472 continue;
4472 } 4473 }
4473 /* this is an event relating to a 'normal' connection, 4474 /* this is an event relating to a 'normal' connection,
4474 remember the event and if appropriate mark the 4475 remember the event and if appropriate mark the
4475 connection as 'eready'. */ 4476 connection as 'eready'. */
@@ -4518,7 +4519,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
4518 } 4519 }
4519 4520
4520#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4521#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4521 if (MHD_YES == run_upgraded) 4522 if (run_upgraded)
4522 run_epoll_for_upgrade (daemon); 4523 run_epoll_for_upgrade (daemon);
4523#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4524#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4524 4525
@@ -4606,22 +4607,22 @@ MHD_run (struct MHD_Daemon *daemon)
4606 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) ) 4607 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
4607 return MHD_NO; 4608 return MHD_NO;
4608 if (0 != (daemon->options & MHD_USE_POLL)) 4609 if (0 != (daemon->options & MHD_USE_POLL))
4609 { 4610 {
4610 MHD_poll (daemon, MHD_NO); 4611 MHD_poll (daemon, MHD_NO);
4611 MHD_cleanup_connections (daemon); 4612 MHD_cleanup_connections (daemon);
4612 } 4613 }
4613#ifdef EPOLL_SUPPORT 4614#ifdef EPOLL_SUPPORT
4614 else if (0 != (daemon->options & MHD_USE_EPOLL)) 4615 else if (0 != (daemon->options & MHD_USE_EPOLL))
4615 { 4616 {
4616 MHD_epoll (daemon, MHD_NO); 4617 MHD_epoll (daemon, MHD_NO);
4617 MHD_cleanup_connections (daemon); 4618 MHD_cleanup_connections (daemon);
4618 } 4619 }
4619#endif 4620#endif
4620 else 4621 else
4621 { 4622 {
4622 MHD_select (daemon, MHD_NO); 4623 MHD_select (daemon, MHD_NO);
4623 /* MHD_select does MHD_cleanup_connections already */ 4624 /* MHD_select does MHD_cleanup_connections already */
4624 } 4625 }
4625 return MHD_YES; 4626 return MHD_YES;
4626} 4627}
4627 4628
@@ -6494,10 +6495,10 @@ thread_failed:
6494 if (daemon->upgrade_fd_in_epoll) 6495 if (daemon->upgrade_fd_in_epoll)
6495 { 6496 {
6496 if (0 != epoll_ctl (daemon->epoll_fd, 6497 if (0 != epoll_ctl (daemon->epoll_fd,
6497 EPOLL_CTL_DEL, 6498 EPOLL_CTL_DEL,
6498 daemon->epoll_upgrade_fd, 6499 daemon->epoll_upgrade_fd,
6499 NULL)) 6500 NULL))
6500 MHD_PANIC (_("Failed to remove FD from epoll set\n")); 6501 MHD_PANIC (_("Failed to remove FD from epoll set\n"));
6501 daemon->upgrade_fd_in_epoll = false; 6502 daemon->upgrade_fd_in_epoll = false;
6502 } 6503 }
6503#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 6504#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 035e3054..3e9fb053 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -80,9 +80,9 @@
80 */ 80 */
81static int 81static int
82add_response_entry (struct MHD_Response *response, 82add_response_entry (struct MHD_Response *response,
83 enum MHD_ValueKind kind, 83 enum MHD_ValueKind kind,
84 const char *header, 84 const char *header,
85 const char *content) 85 const char *content)
86{ 86{
87 struct MHD_HTTP_Header *hdr; 87 struct MHD_HTTP_Header *hdr;
88 88
@@ -195,7 +195,7 @@ MHD_add_response_footer (struct MHD_Response *response,
195int 195int
196MHD_del_response_header (struct MHD_Response *response, 196MHD_del_response_header (struct MHD_Response *response,
197 const char *header, 197 const char *header,
198 const char *content) 198 const char *content)
199{ 199{
200 struct MHD_HTTP_Header *pos; 200 struct MHD_HTTP_Header *pos;
201 struct MHD_HTTP_Header *prev; 201 struct MHD_HTTP_Header *prev;
@@ -280,7 +280,7 @@ MHD_get_response_headers (struct MHD_Response *response,
280 */ 280 */
281const char * 281const char *
282MHD_get_response_header (struct MHD_Response *response, 282MHD_get_response_header (struct MHD_Response *response,
283 const char *key) 283 const char *key)
284{ 284{
285 struct MHD_HTTP_Header *pos; 285 struct MHD_HTTP_Header *pos;
286 size_t key_size; 286 size_t key_size;
@@ -558,8 +558,8 @@ free_callback (void *cls)
558 */ 558 */
559struct MHD_Response * 559struct MHD_Response *
560MHD_create_response_from_fd_at_offset (size_t size, 560MHD_create_response_from_fd_at_offset (size_t size,
561 int fd, 561 int fd,
562 off_t offset) 562 off_t offset)
563{ 563{
564 return MHD_create_response_from_fd_at_offset64 (size, 564 return MHD_create_response_from_fd_at_offset64 (size,
565 fd, 565 fd,
@@ -627,7 +627,7 @@ MHD_create_response_from_fd_at_offset64 (uint64_t size,
627 */ 627 */
628struct MHD_Response * 628struct MHD_Response *
629MHD_create_response_from_fd (size_t size, 629MHD_create_response_from_fd (size_t size,
630 int fd) 630 int fd)
631{ 631{
632 return MHD_create_response_from_fd_at_offset64 (size, 632 return MHD_create_response_from_fd_at_offset64 (size,
633 fd, 633 fd,
@@ -732,8 +732,8 @@ MHD_create_response_from_data (size_t size,
732 */ 732 */
733struct MHD_Response * 733struct MHD_Response *
734MHD_create_response_from_buffer (size_t size, 734MHD_create_response_from_buffer (size_t size,
735 void *buffer, 735 void *buffer,
736 enum MHD_ResponseMemoryMode mode) 736 enum MHD_ResponseMemoryMode mode)
737{ 737{
738 return MHD_create_response_from_data (size, 738 return MHD_create_response_from_data (size,
739 buffer, 739 buffer,
@@ -754,15 +754,15 @@ MHD_create_response_from_buffer (size_t size,
754 */ 754 */
755_MHD_EXTERN struct MHD_Response * 755_MHD_EXTERN struct MHD_Response *
756MHD_create_response_from_buffer_with_free_callback (size_t size, 756MHD_create_response_from_buffer_with_free_callback (size_t size,
757 void *buffer, 757 void *buffer,
758 MHD_ContentReaderFreeCallback crfc) 758 MHD_ContentReaderFreeCallback crfc)
759{ 759{
760 struct MHD_Response *r; 760 struct MHD_Response *r;
761 761
762 r = MHD_create_response_from_data (size, 762 r = MHD_create_response_from_data (size,
763 buffer, 763 buffer,
764 MHD_YES, 764 MHD_YES,
765 MHD_NO); 765 MHD_NO);
766 if (NULL == r) 766 if (NULL == r)
767 return r; 767 return r;
768 r->crfc = crfc; 768 r->crfc = crfc;
@@ -997,17 +997,17 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
997 EPOLL_CTL_ADD, 997 EPOLL_CTL_ADD,
998 connection->socket_fd, 998 connection->socket_fd,
999 &event)) 999 &event))
1000 { 1000 {
1001#ifdef HAVE_MESSAGES 1001#ifdef HAVE_MESSAGES
1002 MHD_DLOG (daemon, 1002 MHD_DLOG (daemon,
1003 _("Call to epoll_ctl failed: %s\n"), 1003 _("Call to epoll_ctl failed: %s\n"),
1004 MHD_socket_last_strerr_ ()); 1004 MHD_socket_last_strerr_ ());
1005#endif 1005#endif
1006 MHD_socket_close_chk_ (sv[0]); 1006 MHD_socket_close_chk_ (sv[0]);
1007 MHD_socket_close_chk_ (sv[1]); 1007 MHD_socket_close_chk_ (sv[1]);
1008 free (urh); 1008 free (urh);
1009 return MHD_NO; 1009 return MHD_NO;
1010 } 1010 }
1011 1011
1012 /* Second, add our end of the UNIX socketpair() */ 1012 /* Second, add our end of the UNIX socketpair() */
1013 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; 1013 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
@@ -1016,28 +1016,28 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
1016 EPOLL_CTL_ADD, 1016 EPOLL_CTL_ADD,
1017 urh->mhd.socket, 1017 urh->mhd.socket,
1018 &event)) 1018 &event))
1019 { 1019 {
1020 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; 1020 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
1021 event.data.ptr = &urh->app; 1021 event.data.ptr = &urh->app;
1022 if (0 != epoll_ctl (daemon->epoll_upgrade_fd, 1022 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
1023 EPOLL_CTL_DEL, 1023 EPOLL_CTL_DEL,
1024 connection->socket_fd, 1024 connection->socket_fd,
1025 &event)) 1025 &event))
1026 MHD_PANIC (_("Error cleaning up while handling epoll error")); 1026 MHD_PANIC (_("Error cleaning up while handling epoll error"));
1027#ifdef HAVE_MESSAGES 1027#ifdef HAVE_MESSAGES
1028 MHD_DLOG (daemon, 1028 MHD_DLOG (daemon,
1029 _("Call to epoll_ctl failed: %s\n"), 1029 _("Call to epoll_ctl failed: %s\n"),
1030 MHD_socket_last_strerr_ ()); 1030 MHD_socket_last_strerr_ ());
1031#endif 1031#endif
1032 MHD_socket_close_chk_ (sv[0]); 1032 MHD_socket_close_chk_ (sv[0]);
1033 MHD_socket_close_chk_ (sv[1]); 1033 MHD_socket_close_chk_ (sv[1]);
1034 free (urh); 1034 free (urh);
1035 return MHD_NO; 1035 return MHD_NO;
1036 } 1036 }
1037 EDLL_insert (daemon->eready_urh_head, 1037 EDLL_insert (daemon->eready_urh_head,
1038 daemon->eready_urh_tail, 1038 daemon->eready_urh_tail,
1039 urh); 1039 urh);
1040 urh->in_eready_list = true; 1040 urh->in_eready_list = true;
1041 } 1041 }
1042#endif /* EPOLL_SUPPORT */ 1042#endif /* EPOLL_SUPPORT */
1043 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) 1043 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) )
diff --git a/src/microhttpd/test_upgrade_large.c b/src/microhttpd/test_upgrade_large.c
new file mode 100644
index 00000000..fdf2edf7
--- /dev/null
+++ b/src/microhttpd/test_upgrade_large.c
@@ -0,0 +1,1353 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016, 2019 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_upgrade_large.c
23 * @brief Testcase for libmicrohttpd upgrading a connection,
24 * modified to test the "large" corner case reported
25 * by Viet on the mailinglist in 6'2019
26 * @author Christian Grothoff
27 * @author Karlson2k (Evgeny Grin)
28 */
29
30#include "mhd_options.h"
31#include <stdlib.h>
32#include <string.h>
33#include <stdio.h>
34#include <pthread.h>
35#include <stdlib.h>
36#include <stddef.h>
37#ifndef WINDOWS
38#include <unistd.h>
39#endif
40#ifdef HAVE_STDBOOL_H
41#include <stdbool.h>
42#endif /* HAVE_STDBOOL_H */
43
44#include "mhd_sockets.h"
45#ifdef HAVE_NETINET_IP_H
46#include <netinet/ip.h>
47#endif /* HAVE_NETINET_IP_H */
48
49#include "platform.h"
50#include "microhttpd.h"
51
52#include "test_helpers.h"
53
54#define LARGE_STRING "HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello"
55
56#define LARGE_REPLY_STRING "WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorld"
57
58#ifdef HTTPS_SUPPORT
59#include <gnutls/gnutls.h>
60#include "../testcurl/https/tls_test_keys.h"
61
62#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
63#include <sys/types.h>
64#include <sys/wait.h>
65#endif /* HAVE_FORK && HAVE_WAITPID */
66#endif /* HTTPS_SUPPORT */
67
68static int verbose = 0;
69
70enum tls_tool
71{
72 TLS_CLI_NO_TOOL = 0,
73 TLS_CLI_GNUTLS,
74 TLS_CLI_OPENSSL,
75 TLS_LIB_GNUTLS
76};
77
78enum tls_tool use_tls_tool;
79
80#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
81/**
82 * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to
83 * talk to our port over a socket in @a sp without having to worry
84 * about TLS.
85 *
86 * @param location where the socket is returned
87 * @return -1 on error, otherwise PID of TLS child process
88 */
89static pid_t
90gnutlscli_connect (int *sock,
91 uint16_t port)
92{
93 pid_t chld;
94 int sp[2];
95 char destination[30];
96
97 if (0 != socketpair (AF_UNIX,
98 SOCK_STREAM,
99 0,
100 sp))
101 return -1;
102 chld = fork ();
103 if (0 != chld)
104 {
105 *sock = sp[1];
106 MHD_socket_close_chk_ (sp[0]);
107 return chld;
108 }
109 MHD_socket_close_chk_ (sp[1]);
110 (void) close (0);
111 (void) close (1);
112 if (-1 == dup2 (sp[0], 0))
113 abort ();
114 if (-1 == dup2 (sp[0], 1))
115 abort ();
116 MHD_socket_close_chk_ (sp[0]);
117 if (TLS_CLI_GNUTLS == use_tls_tool)
118 {
119 snprintf (destination,
120 sizeof(destination),
121 "%u",
122 (unsigned int) port);
123 execlp ("gnutls-cli",
124 "gnutls-cli",
125 "--insecure",
126 "-p",
127 destination,
128 "127.0.0.1",
129 (char *) NULL);
130 }
131 else if (TLS_CLI_OPENSSL == use_tls_tool)
132 {
133 snprintf (destination,
134 sizeof(destination),
135 "127.0.0.1:%u",
136 (unsigned int) port);
137 execlp ("openssl",
138 "openssl",
139 "s_client",
140 "-connect",
141 destination,
142 "-verify",
143 "1",
144 (char *) NULL);
145 }
146 _exit (1);
147}
148#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
149
150
151/**
152 * Wrapper structure for plain&TLS sockets
153 */
154struct wr_socket
155{
156 /**
157 * Real network socket
158 */
159 MHD_socket fd;
160
161 /**
162 * Type of this socket
163 */
164 enum wr_type
165 {
166 wr_invalid = 0,
167 wr_plain = 1,
168 wr_tls = 2
169 } t;
170#ifdef HTTPS_SUPPORT
171 /**
172 * TLS credentials
173 */
174 gnutls_certificate_credentials_t tls_crd;
175
176 /**
177 * TLS session.
178 */
179 gnutls_session_t tls_s;
180
181 /**
182 * TLS handshake already succeed?
183 */
184 bool tls_connected;
185#endif
186};
187
188
189/**
190 * Get underlying real socket.
191 * @return FD of real socket
192 */
193#define wr_fd(s) ((s)->fd)
194
195
196/**
197 * Create wr_socket with plain TCP underlying socket
198 * @return created socket on success, NULL otherwise
199 */
200static struct wr_socket *
201wr_create_plain_sckt(void)
202{
203 struct wr_socket *s = malloc(sizeof(struct wr_socket));
204 if (NULL == s)
205 return NULL;
206 s->t = wr_plain;
207 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
208 if (MHD_INVALID_SOCKET != s->fd)
209 return s;
210 free(s);
211 return NULL;
212}
213
214
215/**
216 * Create wr_socket with TLS TCP underlying socket
217 * @return created socket on success, NULL otherwise
218 */
219static struct wr_socket *
220wr_create_tls_sckt(void)
221{
222#ifdef HTTPS_SUPPORT
223 struct wr_socket *s = malloc(sizeof(struct wr_socket));
224 if (NULL == s)
225 return NULL;
226 s->t = wr_tls;
227 s->tls_connected = 0;
228 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
229 if (MHD_INVALID_SOCKET != s->fd)
230 {
231 if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT))
232 {
233 if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s))
234 {
235 if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (&(s->tls_crd)))
236 {
237 if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, GNUTLS_CRD_CERTIFICATE, s->tls_crd))
238 {
239#if GNUTLS_VERSION_NUMBER+0 >= 0x030109
240 gnutls_transport_set_int (s->tls_s, (int)(s->fd));
241#else /* GnuTLS before 3.1.9 */
242 gnutls_transport_set_ptr (s->tls_s, (gnutls_transport_ptr_t)(intptr_t)(s->fd));
243#endif /* GnuTLS before 3.1.9 */
244 return s;
245 }
246 gnutls_certificate_free_credentials (s->tls_crd);
247 }
248 }
249 gnutls_deinit (s->tls_s);
250 }
251 (void)MHD_socket_close_ (s->fd);
252 }
253 free(s);
254#endif /* HTTPS_SUPPORT */
255 return NULL;
256}
257
258
259/**
260 * Create wr_socket with plain TCP underlying socket
261 * from already created TCP socket.
262 * @param plain_sk real TCP socket
263 * @return created socket on success, NULL otherwise
264 */
265static struct wr_socket *
266wr_create_from_plain_sckt(MHD_socket plain_sk)
267{
268 struct wr_socket *s = malloc(sizeof(struct wr_socket));
269
270 if (NULL == s)
271 return NULL;
272 s->t = wr_plain;
273 s->fd = plain_sk;
274 return s;
275}
276
277
278/**
279 * Connect socket to specified address.
280 * @param s socket to use
281 * @param addr address to connect
282 * @param length of sturcture pointed by @a addr
283 * @return zero on success, -1 otherwise.
284 */
285static int
286wr_connect(struct wr_socket *s,
287 const struct sockaddr *addr,
288 int length)
289{
290 if (0 != connect (s->fd, addr, length))
291 return -1;
292 if (wr_plain == s->t)
293 return 0;
294#ifdef HTTPS_SUPPORT
295 if (wr_tls == s->t)
296 {
297 /* Do not try handshake here as
298 * it require processing on MHD side and
299 * when testing with "external" polling,
300 * test will call MHD processing only
301 * after return from wr_connect(). */
302 s->tls_connected = 0;
303 return 0;
304 }
305#endif /* HTTPS_SUPPORT */
306 return -1;
307}
308
309#ifdef HTTPS_SUPPORT
310/* Only to be called from wr_send() and wr_recv() ! */
311static bool
312wr_handshake(struct wr_socket *s)
313{
314 int res = gnutls_handshake (s->tls_s);
315 if (GNUTLS_E_SUCCESS == res)
316 s->tls_connected = true;
317 else if (GNUTLS_E_AGAIN == res)
318 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
319 else
320 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
321 return s->tls_connected;
322}
323#endif /* HTTPS_SUPPORT */
324
325
326/**
327 * Send data to remote by socket.
328 * @param s the socket to use
329 * @param buf the buffer with data to send
330 * @param len the length of data in @a buf
331 * @return number of bytes were sent if succeed,
332 * -1 if failed. Use #MHD_socket_get_error_()
333 * to get socket error.
334 */
335static ssize_t
336wr_send (struct wr_socket *s,
337 const void *buf,
338 size_t len)
339{
340 if (wr_plain == s->t)
341 return MHD_send_(s->fd, buf, len);
342#ifdef HTTPS_SUPPORT
343 if (wr_tls == s->t)
344 {
345 ssize_t ret;
346 if (!s->tls_connected && !wr_handshake (s))
347 return -1;
348
349 ret = gnutls_record_send (s->tls_s, buf, len);
350 if (ret > 0)
351 return ret;
352 if (GNUTLS_E_AGAIN == ret)
353 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
354 else
355 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
356 }
357#endif /* HTTPS_SUPPORT */
358 return -1;
359}
360
361
362/**
363 * Receive data from remote by socket.
364 * @param s the socket to use
365 * @param buf the buffer to store received data
366 * @param len the length of @a buf
367 * @return number of bytes were received if succeed,
368 * -1 if failed. Use #MHD_socket_get_error_()
369 * to get socket error.
370 */
371static ssize_t
372wr_recv (struct wr_socket *s,
373 void *buf,
374 size_t len)
375{
376 if (wr_plain == s->t)
377 return MHD_recv_ (s->fd, buf, len);
378#ifdef HTTPS_SUPPORT
379 if (wr_tls == s->t)
380 {
381 ssize_t ret;
382 if (!s->tls_connected && !wr_handshake (s))
383 return -1;
384
385 ret = gnutls_record_recv (s->tls_s, buf, len);
386 if (ret > 0)
387 return ret;
388 if (GNUTLS_E_AGAIN == ret)
389 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
390 else
391 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
392 }
393#endif /* HTTPS_SUPPORT */
394 return -1;
395}
396
397
398/**
399 * Close socket and release allocated resourced
400 * @param s the socket to close
401 * @return zero on succeed, -1 otherwise
402 */
403static int
404wr_close (struct wr_socket *s)
405{
406 int ret = (MHD_socket_close_(s->fd)) ? 0 : -1;
407#ifdef HTTPS_SUPPORT
408 if (wr_tls == s->t)
409 {
410 gnutls_deinit (s->tls_s);
411 gnutls_certificate_free_credentials (s->tls_crd);
412 }
413#endif /* HTTPS_SUPPORT */
414 free (s);
415 return ret;
416}
417
418
419/**
420 * Thread we use to run the interaction with the upgraded socket.
421 */
422static pthread_t pt;
423
424/**
425 * Will be set to the upgraded socket.
426 */
427static struct wr_socket *usock;
428
429/**
430 * Thread we use to run the interaction with the upgraded socket.
431 */
432static pthread_t pt_client;
433
434/**
435 * Flag set to 1 once the test is finished.
436 */
437static volatile bool done;
438
439
440/**
441 * Callback used by MHD to notify the application about completed
442 * requests. Frees memory.
443 *
444 * @param cls client-defined closure
445 * @param connection connection handle
446 * @param con_cls value as set by the last call to
447 * the #MHD_AccessHandlerCallback
448 * @param toe reason for request termination
449 */
450static void
451notify_completed_cb (void *cls,
452 struct MHD_Connection *connection,
453 void **con_cls,
454 enum MHD_RequestTerminationCode toe)
455{
456 pthread_t* ppth = *con_cls;
457
458 (void) cls;
459 (void) connection; /* Unused. Silent compiler warning. */
460 if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) &&
461 (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) &&
462 (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) )
463 abort ();
464 if (! pthread_equal (**((pthread_t**)con_cls),
465 pthread_self ()))
466 abort ();
467 if (NULL != ppth)
468 free (*con_cls);
469 *con_cls = NULL;
470}
471
472
473/**
474 * Logging callback.
475 *
476 * @param cls logging closure (NULL)
477 * @param uri access URI
478 * @param connection connection handle
479 * @return #TEST_PTR
480 */
481static void *
482log_cb (void *cls,
483 const char *uri,
484 struct MHD_Connection *connection)
485{
486 pthread_t *ppth;
487
488 (void) cls;
489 (void) connection; /* Unused. Silent compiler warning. */
490 if (0 != strcmp (uri,
491 "/"))
492 abort ();
493 ppth = malloc (sizeof (pthread_t));
494 if (NULL == ppth)
495 abort();
496 *ppth = pthread_self ();
497 return (void *) ppth;
498}
499
500
501/**
502 * Function to check that MHD properly notifies about starting
503 * and stopping.
504 *
505 * @param cls client-defined closure
506 * @param connection connection handle
507 * @param socket_context socket-specific pointer where the
508 * client can associate some state specific
509 * to the TCP connection; note that this is
510 * different from the "con_cls" which is per
511 * HTTP request. The client can initialize
512 * during #MHD_CONNECTION_NOTIFY_STARTED and
513 * cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
514 * and access in the meantime using
515 * #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
516 * @param toe reason for connection notification
517 * @see #MHD_OPTION_NOTIFY_CONNECTION
518 * @ingroup request
519 */
520static void
521notify_connection_cb (void *cls,
522 struct MHD_Connection *connection,
523 void **socket_context,
524 enum MHD_ConnectionNotificationCode toe)
525{
526 static int started;
527
528 (void) cls;
529 (void) connection; /* Unused. Silent compiler warning. */
530 switch (toe)
531 {
532 case MHD_CONNECTION_NOTIFY_STARTED:
533 if (MHD_NO != started)
534 abort ();
535 started = MHD_YES;
536 *socket_context = &started;
537 break;
538 case MHD_CONNECTION_NOTIFY_CLOSED:
539 if (MHD_YES != started)
540 abort ();
541 if (&started != *socket_context)
542 abort ();
543 *socket_context = NULL;
544 started = MHD_NO;
545 break;
546 }
547}
548
549
550/**
551 * Change socket to blocking.
552 *
553 * @param fd the socket to manipulate
554 * @return non-zero if succeeded, zero otherwise
555 */
556static void
557make_blocking (MHD_socket fd)
558{
559#if defined(MHD_POSIX_SOCKETS)
560 int flags;
561
562 flags = fcntl (fd, F_GETFL);
563 if (-1 == flags)
564 return;
565 if ((flags & ~O_NONBLOCK) != flags)
566 if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
567 abort ();
568#elif defined(MHD_WINSOCK_SOCKETS)
569 unsigned long flags = 1;
570
571 ioctlsocket (fd, FIONBIO, &flags);
572#endif /* MHD_WINSOCK_SOCKETS */
573
574}
575
576
577static void
578send_all (struct wr_socket *sock,
579 const char *text)
580{
581 size_t len = strlen (text);
582 ssize_t ret;
583 size_t off;
584
585 make_blocking (wr_fd (sock));
586 for (off = 0; off < len; off += ret)
587 {
588 ret = wr_send (sock,
589 &text[off],
590 len - off);
591 if (0 > ret)
592 {
593 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
594 {
595 ret = 0;
596 continue;
597 }
598 abort ();
599 }
600 }
601}
602
603
604/**
605 * Read character-by-character until we
606 * get '\r\n\r\n'.
607 */
608static void
609recv_hdr (struct wr_socket *sock)
610{
611 unsigned int i;
612 char next;
613 char c;
614 ssize_t ret;
615
616 make_blocking (wr_fd (sock));
617 next = '\r';
618 i = 0;
619 while (i < 4)
620 {
621 ret = wr_recv (sock,
622 &c,
623 1);
624 if (0 > ret)
625 {
626 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
627 continue;
628 abort ();
629 }
630 if (0 == ret)
631 continue;
632 if (c == next)
633 {
634 i++;
635 if (next == '\r')
636 next = '\n';
637 else
638 next = '\r';
639 continue;
640 }
641 if (c == '\r')
642 {
643 i = 1;
644 next = '\n';
645 continue;
646 }
647 i = 0;
648 next = '\r';
649 }
650}
651
652
653static void
654recv_all (struct wr_socket *sock,
655 const char *text)
656{
657 size_t len = strlen (text);
658 char buf[len];
659 ssize_t ret;
660 size_t off;
661
662 make_blocking (wr_fd (sock));
663 for (off = 0; off < len; off += ret)
664 {
665 ret = wr_recv (sock,
666 &buf[off],
667 len - off);
668 if (0 > ret)
669 {
670 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
671 {
672 ret = 0;
673 continue;
674 }
675 abort ();
676 }
677 }
678 if (0 != strncmp (text, buf, len))
679 abort();
680}
681
682
683/**
684 * Main function for the thread that runs the interaction with
685 * the upgraded socket.
686 *
687 * @param cls the handle for the upgrade
688 */
689static void *
690run_usock (void *cls)
691{
692 struct MHD_UpgradeResponseHandle *urh = cls;
693
694 send_all (usock,
695 LARGE_STRING);
696 recv_all (usock,
697 LARGE_REPLY_STRING);
698 send_all (usock,
699 "Finished");
700 MHD_upgrade_action (urh,
701 MHD_UPGRADE_ACTION_CLOSE);
702 free (usock);
703 usock = NULL;
704 return NULL;
705}
706
707
708/**
709 * Main function for the thread that runs the client-side of the
710 * interaction with the upgraded socket.
711 *
712 * @param cls the client socket
713 */
714static void *
715run_usock_client (void *cls)
716{
717 struct wr_socket *sock = cls;
718
719 send_all (sock,
720 "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
721 recv_hdr (sock);
722 recv_all (sock,
723 LARGE_STRING);
724 send_all (sock,
725 LARGE_REPLY_STRING);
726 recv_all (sock,
727 "Finished");
728 wr_close (sock);
729 done = true;
730 return NULL;
731}
732
733
734/**
735 * Function called after a protocol "upgrade" response was sent
736 * successfully and the socket should now be controlled by some
737 * protocol other than HTTP.
738 *
739 * Any data already received on the socket will be made available in
740 * @e extra_in. This can happen if the application sent extra data
741 * before MHD send the upgrade response. The application should
742 * treat data from @a extra_in as if it had read it from the socket.
743 *
744 * Note that the application must not close() @a sock directly,
745 * but instead use #MHD_upgrade_action() for special operations
746 * on @a sock.
747 *
748 * Except when in 'thread-per-connection' mode, implementations
749 * of this function should never block (as it will still be called
750 * from within the main event loop).
751 *
752 * @param cls closure, whatever was given to #MHD_create_response_for_upgrade().
753 * @param connection original HTTP connection handle,
754 * giving the function a last chance
755 * to inspect the original HTTP request
756 * @param con_cls last value left in `con_cls` of the `MHD_AccessHandlerCallback`
757 * @param extra_in if we happened to have read bytes after the
758 * HTTP header already (because the client sent
759 * more than the HTTP header of the request before
760 * we sent the upgrade response),
761 * these are the extra bytes already read from @a sock
762 * by MHD. The application should treat these as if
763 * it had read them from @a sock.
764 * @param extra_in_size number of bytes in @a extra_in
765 * @param sock socket to use for bi-directional communication
766 * with the client. For HTTPS, this may not be a socket
767 * that is directly connected to the client and thus certain
768 * operations (TCP-specific setsockopt(), getsockopt(), etc.)
769 * may not work as expected (as the socket could be from a
770 * socketpair() or a TCP-loopback). The application is expected
771 * to perform read()/recv() and write()/send() calls on the socket.
772 * The application may also call shutdown(), but must not call
773 * close() directly.
774 * @param urh argument for #MHD_upgrade_action()s on this @a connection.
775 * Applications must eventually use this callback to (indirectly)
776 * perform the close() action on the @a sock.
777 */
778static void
779upgrade_cb (void *cls,
780 struct MHD_Connection *connection,
781 void *con_cls,
782 const char *extra_in,
783 size_t extra_in_size,
784 MHD_socket sock,
785 struct MHD_UpgradeResponseHandle *urh)
786{
787 (void) cls;
788 (void) connection;
789 (void) con_cls;
790 (void) extra_in; /* Unused. Silent compiler warning. */
791
792 usock = wr_create_from_plain_sckt (sock);
793 if (0 != extra_in_size)
794 abort ();
795 if (0 != pthread_create (&pt,
796 NULL,
797 &run_usock,
798 urh))
799 abort ();
800}
801
802
803/**
804 * A client has requested the given url using the given method
805 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
806 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
807 * must call MHD callbacks to provide content to give back to the
808 * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
809 * #MHD_HTTP_NOT_FOUND, etc.).
810 *
811 * @param cls argument given together with the function
812 * pointer when the handler was registered with MHD
813 * @param url the requested url
814 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
815 * #MHD_HTTP_METHOD_PUT, etc.)
816 * @param version the HTTP version string (i.e.
817 * #MHD_HTTP_VERSION_1_1)
818 * @param upload_data the data being uploaded (excluding HEADERS,
819 * for a POST that fits into memory and that is encoded
820 * with a supported encoding, the POST data will NOT be
821 * given in upload_data and is instead available as
822 * part of #MHD_get_connection_values; very large POST
823 * data *will* be made available incrementally in
824 * @a upload_data)
825 * @param upload_data_size set initially to the size of the
826 * @a upload_data provided; the method must update this
827 * value to the number of bytes NOT processed;
828 * @param con_cls pointer that the callback can set to some
829 * address and that will be preserved by MHD for future
830 * calls for this request; since the access handler may
831 * be called many times (i.e., for a PUT/POST operation
832 * with plenty of upload data) this allows the application
833 * to easily associate some request-specific state.
834 * If necessary, this state can be cleaned up in the
835 * global #MHD_RequestCompletedCallback (which
836 * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
837 * Initially, `*con_cls` will be NULL.
838 * @return #MHD_YES if the connection was handled successfully,
839 * #MHD_NO if the socket must be closed due to a serios
840 * error while handling the request
841 */
842static int
843ahc_upgrade (void *cls,
844 struct MHD_Connection *connection,
845 const char *url,
846 const char *method,
847 const char *version,
848 const char *upload_data,
849 size_t *upload_data_size,
850 void **con_cls)
851{
852 struct MHD_Response *resp;
853 int ret;
854 (void) cls;
855 (void) url;
856 (void) method; /* Unused. Silent compiler warning. */
857 (void) version;
858 (void) upload_data;
859 (void) upload_data_size; /* Unused. Silent compiler warning. */
860
861 if (NULL == *con_cls)
862 abort ();
863 if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
864 abort ();
865 resp = MHD_create_response_for_upgrade (&upgrade_cb,
866 NULL);
867 MHD_add_response_header (resp,
868 MHD_HTTP_HEADER_UPGRADE,
869 "Hello World Protocol");
870 ret = MHD_queue_response (connection,
871 MHD_HTTP_SWITCHING_PROTOCOLS,
872 resp);
873 MHD_destroy_response (resp);
874 return ret;
875}
876
877
878/**
879 * Run the MHD external event loop using select.
880 *
881 * @param daemon daemon to run it for
882 */
883static void
884run_mhd_select_loop (struct MHD_Daemon *daemon)
885{
886 fd_set rs;
887 fd_set ws;
888 fd_set es;
889 MHD_socket max_fd;
890 MHD_UNSIGNED_LONG_LONG to;
891 struct timeval tv;
892
893 while (! done)
894 {
895 FD_ZERO (&rs);
896 FD_ZERO (&ws);
897 FD_ZERO (&es);
898 max_fd = -1;
899 to = 1000;
900
901 if (MHD_YES !=
902 MHD_get_fdset (daemon,
903 &rs,
904 &ws,
905 &es,
906 &max_fd))
907 abort ();
908 (void) MHD_get_timeout (daemon,
909 &to);
910 if (1000 < to)
911 to = 1000;
912 tv.tv_sec = to / 1000;
913 tv.tv_usec = 1000 * (to % 1000);
914 if (0 > MHD_SYS_select_ (max_fd + 1,
915 &rs,
916 &ws,
917 &es,
918 &tv))
919 abort ();
920 MHD_run_from_select (daemon,
921 &rs,
922 &ws,
923 &es);
924 }
925}
926
927#ifdef HAVE_POLL
928
929/**
930 * Run the MHD external event loop using select.
931 *
932 * @param daemon daemon to run it for
933 */
934static void
935run_mhd_poll_loop (struct MHD_Daemon *daemon)
936{
937 (void)daemon; /* Unused. Silent compiler warning. */
938 abort (); /* currently not implementable with existing MHD API */
939}
940#endif /* HAVE_POLL */
941
942
943#ifdef EPOLL_SUPPORT
944/**
945 * Run the MHD external event loop using select.
946 *
947 * @param daemon daemon to run it for
948 */
949static void
950run_mhd_epoll_loop (struct MHD_Daemon *daemon)
951{
952 const union MHD_DaemonInfo *di;
953 MHD_socket ep;
954 fd_set rs;
955 MHD_UNSIGNED_LONG_LONG to;
956 struct timeval tv;
957 int ret;
958
959 di = MHD_get_daemon_info (daemon,
960 MHD_DAEMON_INFO_EPOLL_FD);
961 ep = di->listen_fd;
962 while (! done)
963 {
964 FD_ZERO (&rs);
965 to = 1000;
966
967 FD_SET (ep, &rs);
968 (void) MHD_get_timeout (daemon,
969 &to);
970 if (1000 < to)
971 to = 1000;
972 tv.tv_sec = to / 1000;
973 tv.tv_usec = 1000 * (to % 1000);
974 ret = select (ep + 1,
975 &rs,
976 NULL,
977 NULL,
978 &tv);
979 if ( (-1 == ret) &&
980 (EAGAIN != errno) &&
981 (EINTR != errno) )
982 abort ();
983 MHD_run (daemon);
984 }
985}
986#endif /* EPOLL_SUPPORT */
987
988/**
989 * Run the MHD external event loop using select.
990 *
991 * @param daemon daemon to run it for
992 */
993static void
994run_mhd_loop (struct MHD_Daemon *daemon,
995 int flags)
996{
997 if (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL)))
998 run_mhd_select_loop (daemon);
999#ifdef HAVE_POLL
1000 else if (0 != (flags & MHD_USE_POLL))
1001 run_mhd_poll_loop (daemon);
1002#endif /* HAVE_POLL */
1003#if EPOLL_SUPPORT
1004 else if (0 != (flags & MHD_USE_EPOLL))
1005 run_mhd_epoll_loop (daemon);
1006#endif
1007 else
1008 abort ();
1009}
1010
1011
1012static bool test_tls;
1013
1014/**
1015 * Test upgrading a connection.
1016 *
1017 * @param flags which event loop style should be tested
1018 * @param pool size of the thread pool, 0 to disable
1019 */
1020static int
1021test_upgrade (int flags,
1022 unsigned int pool)
1023{
1024 struct MHD_Daemon *d = NULL;
1025 struct wr_socket *sock;
1026 struct sockaddr_in sa;
1027 const union MHD_DaemonInfo *real_flags;
1028 const union MHD_DaemonInfo *dinfo;
1029#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1030 pid_t pid = -1;
1031#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
1032
1033 done = false;
1034
1035 if (! test_tls)
1036 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE,
1037 MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
1038 0 : 1090,
1039 NULL, NULL,
1040 &ahc_upgrade, NULL,
1041 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512,
1042 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
1043 MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
1044 MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
1045 MHD_OPTION_THREAD_POOL_SIZE, pool,
1046 MHD_OPTION_END);
1047#ifdef HTTPS_SUPPORT
1048 else
1049 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE | MHD_USE_TLS,
1050 MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
1051 0 : 1090,
1052 NULL, NULL,
1053 &ahc_upgrade, NULL,
1054 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512,
1055 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
1056 MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
1057 MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
1058 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
1059 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
1060 MHD_OPTION_THREAD_POOL_SIZE, pool,
1061 MHD_OPTION_END);
1062#endif /* HTTPS_SUPPORT */
1063 if (NULL == d)
1064 return 2;
1065 real_flags = MHD_get_daemon_info (d,
1066 MHD_DAEMON_INFO_FLAGS);
1067 if (NULL == real_flags)
1068 abort ();
1069 dinfo = MHD_get_daemon_info (d,
1070 MHD_DAEMON_INFO_BIND_PORT);
1071 if ( (NULL == dinfo) ||
1072 (0 == dinfo->port) )
1073 abort ();
1074 if (!test_tls || TLS_LIB_GNUTLS == use_tls_tool)
1075 {
1076 sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt ();
1077 if (NULL == sock)
1078 abort ();
1079 sa.sin_family = AF_INET;
1080 sa.sin_port = htons (dinfo->port);
1081 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1082 if (0 != wr_connect (sock,
1083 (struct sockaddr *) &sa,
1084 sizeof (sa)))
1085 abort ();
1086 }
1087 else
1088 {
1089#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1090 MHD_socket tls_fork_sock;
1091 uint16_t port;
1092
1093 /* make address sanitizer happy */
1094 memcpy (&port,
1095 dinfo /* ->port */,
1096 sizeof (port));
1097 if (-1 == (pid = gnutlscli_connect (&tls_fork_sock,
1098 port)))
1099 {
1100 MHD_stop_daemon (d);
1101 return 4;
1102 }
1103
1104 sock = wr_create_from_plain_sckt (tls_fork_sock);
1105 if (NULL == sock)
1106 abort ();
1107#else /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
1108 abort ();
1109#endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
1110 }
1111
1112 if (0 != pthread_create (&pt_client,
1113 NULL,
1114 &run_usock_client,
1115 sock))
1116 abort ();
1117 if (0 == (flags & MHD_USE_INTERNAL_POLLING_THREAD) )
1118 {
1119 enum MHD_FLAG flags;
1120
1121 /* make address sanitizer happy */
1122 memcpy (&flags,
1123 real_flags /* ->flags */,
1124 sizeof (flags));
1125 run_mhd_loop (d, flags);
1126 }
1127 pthread_join (pt_client,
1128 NULL);
1129 pthread_join (pt,
1130 NULL);
1131#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1132 if (test_tls && TLS_LIB_GNUTLS != use_tls_tool)
1133 waitpid (pid, NULL, 0);
1134#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
1135 MHD_stop_daemon (d);
1136 return 0;
1137}
1138
1139
1140int
1141main (int argc,
1142 char *const *argv)
1143{
1144 int error_count = 0;
1145 int res;
1146
1147 use_tls_tool = TLS_CLI_NO_TOOL;
1148 test_tls = has_in_name(argv[0], "_tls");
1149
1150 verbose = 1;
1151 if (has_param(argc, argv, "-q") ||
1152 has_param(argc, argv, "--quiet"))
1153 verbose = 0;
1154
1155 if (test_tls)
1156 {
1157#ifdef HTTPS_SUPPORT
1158 if (has_param(argc, argv, "--use-gnutls-cli"))
1159 use_tls_tool = TLS_CLI_GNUTLS;
1160 else if (has_param(argc, argv, "--use-openssl"))
1161 use_tls_tool = TLS_CLI_OPENSSL;
1162 else if (has_param(argc, argv, "--use-gnutls-lib"))
1163 use_tls_tool = TLS_LIB_GNUTLS;
1164#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
1165 else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null"))
1166 use_tls_tool = TLS_CLI_GNUTLS;
1167 else if (0 == system ("openssl version 1> /dev/null 2> /dev/null"))
1168 use_tls_tool = TLS_CLI_OPENSSL;
1169#endif /* HAVE_FORK && HAVE_WAITPID */
1170 else
1171 use_tls_tool = TLS_LIB_GNUTLS; /* Should be available as MHD use it. */
1172 if (verbose)
1173 {
1174 switch (use_tls_tool)
1175 {
1176 case TLS_CLI_GNUTLS:
1177 printf ("GnuTLS-CLI will be used for testing.\n");
1178 break;
1179 case TLS_CLI_OPENSSL:
1180 printf ("Command line version of OpenSSL will be used for testing.\n");
1181 break;
1182 case TLS_LIB_GNUTLS:
1183 printf ("GnuTLS library will be used for testing.\n");
1184 break;
1185 default:
1186 abort ();
1187 }
1188 }
1189 if ( (TLS_LIB_GNUTLS == use_tls_tool) &&
1190 (GNUTLS_E_SUCCESS != gnutls_global_init()) )
1191 abort ();
1192
1193#else /* ! HTTPS_SUPPORT */
1194 fprintf (stderr, "HTTPS support was disabled by configure.\n");
1195 return 77;
1196#endif /* ! HTTPS_SUPPORT */
1197 }
1198
1199 /* run tests */
1200 if (verbose)
1201 printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n",
1202 test_tls ? "TLS" : "plain");
1203 /* try external select */
1204 res = test_upgrade (0,
1205 0);
1206 error_count += res;
1207 if (res)
1208 fprintf (stderr,
1209 "FAILED: Upgrade with external select, return code %d.\n",
1210 res);
1211 else if (verbose)
1212 printf ("PASSED: Upgrade with external select.\n");
1213
1214 /* Try external auto */
1215 res = test_upgrade (MHD_USE_AUTO,
1216 0);
1217 error_count += res;
1218 if (res)
1219 fprintf (stderr,
1220 "FAILED: Upgrade with external 'auto', return code %d.\n",
1221 res);
1222 else if (verbose)
1223 printf ("PASSED: Upgrade with external 'auto'.\n");
1224
1225#ifdef EPOLL_SUPPORT
1226 res = test_upgrade (MHD_USE_EPOLL,
1227 0);
1228 error_count += res;
1229 if (res)
1230 fprintf (stderr,
1231 "FAILED: Upgrade with external select with EPOLL, return code %d.\n",
1232 res);
1233 else if (verbose)
1234 printf ("PASSED: Upgrade with external select with EPOLL.\n");
1235#endif
1236
1237 /* Test thread-per-connection */
1238 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
1239 0);
1240 error_count += res;
1241 if (res)
1242 fprintf (stderr,
1243 "FAILED: Upgrade with thread per connection, return code %d.\n",
1244 res);
1245 else if (verbose)
1246 printf ("PASSED: Upgrade with thread per connection.\n");
1247
1248 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
1249 0);
1250 error_count += res;
1251 if (res)
1252 fprintf (stderr,
1253 "FAILED: Upgrade with thread per connection and 'auto', return code %d.\n",
1254 res);
1255 else if (verbose)
1256 printf ("PASSED: Upgrade with thread per connection and 'auto'.\n");
1257#ifdef HAVE_POLL
1258 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
1259 0);
1260 error_count += res;
1261 if (res)
1262 fprintf (stderr,
1263 "FAILED: Upgrade with thread per connection and poll, return code %d.\n",
1264 res);
1265 else if (verbose)
1266 printf ("PASSED: Upgrade with thread per connection and poll.\n");
1267#endif /* HAVE_POLL */
1268
1269 /* Test different event loops, with and without thread pool */
1270 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
1271 0);
1272 error_count += res;
1273 if (res)
1274 fprintf (stderr,
1275 "FAILED: Upgrade with internal select, return code %d.\n",
1276 res);
1277 else if (verbose)
1278 printf ("PASSED: Upgrade with internal select.\n");
1279 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
1280 2);
1281 error_count += res;
1282 if (res)
1283 fprintf (stderr,
1284 "FAILED: Upgrade with internal select with thread pool, return code %d.\n",
1285 res);
1286 else if (verbose)
1287 printf ("PASSED: Upgrade with internal select with thread pool.\n");
1288 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
1289 0);
1290 error_count += res;
1291 if (res)
1292 fprintf (stderr,
1293 "FAILED: Upgrade with internal 'auto' return code %d.\n",
1294 res);
1295 else if (verbose)
1296 printf ("PASSED: Upgrade with internal 'auto'.\n");
1297 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
1298 2);
1299 error_count += res;
1300 if (res)
1301 fprintf (stderr,
1302 "FAILED: Upgrade with internal 'auto' with thread pool, return code %d.\n",
1303 res);
1304 else if (verbose)
1305 printf ("PASSED: Upgrade with internal 'auto' with thread pool.\n");
1306#ifdef HAVE_POLL
1307 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
1308 0);
1309 error_count += res;
1310 if (res)
1311 fprintf (stderr,
1312 "FAILED: Upgrade with internal poll, return code %d.\n",
1313 res);
1314 else if (verbose)
1315 printf ("PASSED: Upgrade with internal poll.\n");
1316 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
1317 2);
1318 if (res)
1319 fprintf (stderr,
1320 "FAILED: Upgrade with internal poll with thread pool, return code %d.\n",
1321 res);
1322 else if (verbose)
1323 printf ("PASSED: Upgrade with internal poll with thread pool.\n");
1324#endif
1325#ifdef EPOLL_SUPPORT
1326 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
1327 0);
1328 if (res)
1329 fprintf (stderr,
1330 "FAILED: Upgrade with internal epoll, return code %d.\n",
1331 res);
1332 else if (verbose)
1333 printf ("PASSED: Upgrade with internal epoll.\n");
1334 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
1335 2);
1336 if (res)
1337 fprintf (stderr,
1338 "FAILED: Upgrade with internal epoll, return code %d.\n",
1339 res);
1340 else if (verbose)
1341 printf ("PASSED: Upgrade with internal epoll.\n");
1342#endif
1343 /* report result */
1344 if (0 != error_count)
1345 fprintf (stderr,
1346 "Error (code: %u)\n",
1347 error_count);
1348#ifdef HTTPS_SUPPORT
1349 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool))
1350 gnutls_global_deinit();
1351#endif /* HTTPS_SUPPORT */
1352 return error_count != 0; /* 0 == pass */
1353}