libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 7f0a04de96ac133f16458830dcab6ad0a1223db3
parent 5454d9f3b520e597dc783d974596c9591cf4631d
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  4 Feb 2015 19:37:19 +0000

fix issue with chunked encoding used for http1.0 connections of Keep-Alive header was set

Diffstat:
MChangeLog | 5+++++
Msrc/examples/Makefile.am | 70++++++++++++++++++++++++++++++++++++++--------------------------------
Asrc/examples/chunked_example.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/microhttpd.h | 2+-
Msrc/microhttpd/connection.c | 11+++++++----
Msrc/testcurl/test_get.c | 20++++++++++----------
6 files changed, 155 insertions(+), 47 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,8 @@ +Wed Feb 4 20:34:22 CET 2015 + Fix issue where for HTTP/1.0-clients that set + Connection: Keep-Alive header a response of + indefinite size was generated with chunked encoding. -CG + Sun Jan 18 20:09:06 CET 2015 Fix potential infinite loop on shutdown in multi-threaded mode under certain conditions. -CG diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am @@ -16,7 +16,7 @@ if ENABLE_SPDY spdyex = \ spdy_event_loop \ spdy_fileserver \ - spdy_response_with_callback + spdy_response_with_callback if HAVE_SPDYLAY spdyex += mhd2spdy @@ -28,6 +28,7 @@ endif noinst_PROGRAMS = \ benchmark \ benchmark_https \ + chunked_example \ minimal_example \ dual_stack_example \ minimal_example_comet \ @@ -40,7 +41,7 @@ noinst_PROGRAMS = \ if ENABLE_HTTPS -noinst_PROGRAMS += https_fileserver_example +noinst_PROGRAMS += https_fileserver_example endif if HAVE_POSTPROCESSOR noinst_PROGRAMS += \ @@ -53,12 +54,12 @@ endif if ENABLE_DAUTH noinst_PROGRAMS += \ - digest_auth_example + digest_auth_example endif if ENABLE_BAUTH noinst_PROGRAMS += \ - authorization_example + authorization_example endif if HAVE_W32 @@ -66,9 +67,14 @@ AM_CFLAGS += -DWINDOWS endif minimal_example_SOURCES = \ - minimal_example.c + minimal_example.c minimal_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la + +chunked_example_SOURCES = \ + chunked_example.c +chunked_example_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la demo_SOURCES = \ demo.c @@ -90,68 +96,68 @@ mhd2spdy_LDADD = \ -lssl -lcrypto -lspdylay benchmark_SOURCES = \ - benchmark.c + benchmark.c benchmark_CPPFLAGS = \ $(AM_CPPFLAGS) $(CPU_COUNT_DEF) benchmark_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la benchmark_https_SOURCES = \ - benchmark_https.c + benchmark_https.c benchmark_https_CPPFLAGS = \ $(AM_CPPFLAGS) $(CPU_COUNT_DEF) benchmark_https_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la dual_stack_example_SOURCES = \ - dual_stack_example.c + dual_stack_example.c dual_stack_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la post_example_SOURCES = \ - post_example.c + post_example.c post_example_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la minimal_example_comet_SOURCES = \ - minimal_example_comet.c + minimal_example_comet.c minimal_example_comet_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la authorization_example_SOURCES = \ - authorization_example.c + authorization_example.c authorization_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la digest_auth_example_SOURCES = \ - digest_auth_example.c + digest_auth_example.c digest_auth_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la refuse_post_example_SOURCES = \ - refuse_post_example.c + refuse_post_example.c refuse_post_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la querystring_example_SOURCES = \ - querystring_example.c + querystring_example.c querystring_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la fileserver_example_SOURCES = \ - fileserver_example.c + fileserver_example.c fileserver_example_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la fileserver_example_dirs_SOURCES = \ - fileserver_example_dirs.c + fileserver_example_dirs.c fileserver_example_dirs_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la fileserver_example_external_select_SOURCES = \ - fileserver_example_external_select.c + fileserver_example_external_select.c fileserver_example_external_select_LDADD = \ - $(top_builddir)/src/microhttpd/libmicrohttpd.la + $(top_builddir)/src/microhttpd/libmicrohttpd.la https_fileserver_example_SOURCES = \ https_fileserver_example.c @@ -162,19 +168,19 @@ https_fileserver_example_LDADD = \ spdy_event_loop_SOURCES = \ - spdy_event_loop.c + spdy_event_loop.c spdy_event_loop_LDADD = \ $(top_builddir)/src/microspdy/libmicrospdy.la \ -lz spdy_fileserver_SOURCES = \ - spdy_fileserver.c + spdy_fileserver.c spdy_fileserver_LDADD = \ $(top_builddir)/src/microspdy/libmicrospdy.la \ -lz spdy_response_with_callback_SOURCES = \ - spdy_response_with_callback.c + spdy_response_with_callback.c spdy_response_with_callback_LDADD = \ $(top_builddir)/src/microspdy/libmicrospdy.la \ -lz diff --git a/src/examples/chunked_example.c b/src/examples/chunked_example.c @@ -0,0 +1,94 @@ +/* + This file is part of libmicrohttpd + (C) 2015 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file chunked_example.c + * @brief example for generating chunked encoding with libmicrohttpd + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> + + +static ssize_t +callback (void *cls, + uint64_t pos, + char *buf, + size_t max) +{ + return MHD_CONTENT_READER_END_OF_STREAM; +} + + + +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 **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (method, "GET")) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, + 1024, + &callback, + NULL, + NULL); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 2) + { + printf ("%s PORT\n", argv[0]); + return 1; + } + d = MHD_start_daemon (// MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | MHD_USE_POLL, + MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | MHD_USE_POLL, + // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, + MHD_OPTION_END); + if (d == NULL) + return 1; + (void) getc (stdin); + MHD_stop_daemon (d); + return 0; +} diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -130,7 +130,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00093901 +#define MHD_VERSION 0x00093902 /** * MHD-internal return code for "YES". diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -741,7 +741,9 @@ build_header_response (struct MHD_Connection *connection) close the connection */ /* 'close' header doesn't exist yet, see if we need to add one; if the client asked for a close, no need to start chunk'ing */ - if (MHD_YES == keepalive_possible (connection)) + if ( (MHD_YES == keepalive_possible (connection)) && + (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, + connection->version) ) ) { have_encoding = MHD_get_response_header (connection->response, MHD_HTTP_HEADER_TRANSFER_ENCODING); @@ -762,7 +764,8 @@ build_header_response (struct MHD_Connection *connection) } else { - /* Keep alive not possible => set close header if not present */ + /* Keep alive or chunking not possible + => set close header if not present */ if (NULL == response_has_close) must_add_close = MHD_YES; } @@ -782,8 +785,8 @@ build_header_response (struct MHD_Connection *connection) if ( (MHD_SIZE_UNKNOWN != connection->response->total_size) && (NULL == have_content_length) && ( (NULL == connection->method) || - (!MHD_str_equal_caseless_ (connection->method, - MHD_HTTP_METHOD_CONNECT)) ) ) + (! MHD_str_equal_caseless_ (connection->method, + MHD_HTTP_METHOD_CONNECT)) ) ) { /* Here we add a content-length if one is missing; however, diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c @@ -19,7 +19,7 @@ */ /** - * @file daemontest_get.c + * @file test_get.c * @brief Testcase for libmicrohttpd GET operations * TODO: test parsing of query * @author Christian Grothoff @@ -271,7 +271,7 @@ testExternalGet () fd_set ws; fd_set es; MHD_socket max; - int running; + int running; struct CURLMsg *msg; time_t start; struct timeval tv; @@ -461,41 +461,41 @@ testStopRace (int poll_flag) struct sockaddr_in sin; MHD_socket fd; struct MHD_Daemon *d; - + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag, 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_CONNECTION_TIMEOUT, 5, MHD_OPTION_END); if (d == NULL) return 16; - + fd = socket (PF_INET, SOCK_STREAM, 0); if (fd == MHD_INVALID_SOCKET) { fprintf(stderr, "socket error\n"); return 256; } - + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(1081); sin.sin_addr.s_addr = htonl(0x7f000001); - + if (connect (fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0) { fprintf(stderr, "connect error\n"); MHD_socket_close_ (fd); return 512; } - + /* printf("Waiting\n"); */ /* Let the thread get going. */ usleep(500000); - + /* printf("Stopping daemon\n"); */ MHD_stop_daemon (d); - + MHD_socket_close_ (fd); - + /* printf("good\n"); */ return 0; }