aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-05-05 18:07:33 +0000
committerChristian Grothoff <christian@grothoff.org>2013-05-05 18:07:33 +0000
commit9eb27c8dbe1939344ccced9c498895f0e92e8197 (patch)
treea97d1b7caf1e5dc79c22b08d58be70bc8c205cba /src/microhttpd
parent1725bcf3c546fccbf22d7794bf7290fcc28c385d (diff)
downloadlibmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.tar.gz
libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.zip
-changing directory name
Diffstat (limited to 'src/microhttpd')
-rw-r--r--src/microhttpd/EXPORT.sym37
-rw-r--r--src/microhttpd/Makefile.am92
-rw-r--r--src/microhttpd/base64.c62
-rw-r--r--src/microhttpd/base64.h17
-rw-r--r--src/microhttpd/basicauth.c136
-rw-r--r--src/microhttpd/connection.c2578
-rw-r--r--src/microhttpd/connection.h128
-rw-r--r--src/microhttpd/connection_https.c175
-rw-r--r--src/microhttpd/connection_https.h35
-rw-r--r--src/microhttpd/daemon.c2947
-rw-r--r--src/microhttpd/digestauth.c807
-rw-r--r--src/microhttpd/internal.c171
-rw-r--r--src/microhttpd/internal.h1093
-rw-r--r--src/microhttpd/md5.c267
-rw-r--r--src/microhttpd/md5.h51
-rw-r--r--src/microhttpd/memorypool.c261
-rw-r--r--src/microhttpd/memorypool.h114
-rw-r--r--src/microhttpd/postprocessor.c1158
-rw-r--r--src/microhttpd/reason_phrase.c159
-rw-r--r--src/microhttpd/reason_phrase.h37
-rw-r--r--src/microhttpd/response.c459
-rw-r--r--src/microhttpd/response.h37
-rw-r--r--src/microhttpd/test_daemon.c168
-rw-r--r--src/microhttpd/test_postprocessor.c271
-rw-r--r--src/microhttpd/test_postprocessor_amp.c47
-rw-r--r--src/microhttpd/test_postprocessor_large.c105
-rw-r--r--src/microhttpd/tsearch.c123
-rw-r--r--src/microhttpd/tsearch.h39
28 files changed, 11574 insertions, 0 deletions
diff --git a/src/microhttpd/EXPORT.sym b/src/microhttpd/EXPORT.sym
new file mode 100644
index 00000000..dc32b6d3
--- /dev/null
+++ b/src/microhttpd/EXPORT.sym
@@ -0,0 +1,37 @@
1MHD_start_daemon
2MHD_start_daemon_va
3MHD_stop_daemon
4MHD_get_fdset
5MHD_get_timeout
6MHD_run
7MHD_run_from_select
8MHD_get_connection_values
9MHD_set_connection_value
10MHD_lookup_connection_value
11MHD_queue_response
12MHD_create_response_from_callback
13MHD_create_response_from_data
14MHD_create_response_from_fd
15MHD_create_response_from_fd_at_offset
16MHD_create_response_from_buffer
17MHD_destroy_response
18MHD_add_response_header
19MHD_add_response_footer
20MHD_del_response_header
21MHD_get_response_headers
22MHD_get_response_header
23MHD_create_post_processor
24MHD_post_process
25MHD_quiesce_daemon
26MHD_destroy_post_processor
27MHD_get_daemon_info
28MHD_get_connection_info
29MHD_set_panic_func
30MHD_get_version
31MHD_digest_auth_get_username
32MHD_digest_auth_check
33MHD_queue_auth_fail_response
34MHD_basic_auth_get_username_password
35MHD_queue_basic_auth_fail_response
36MHD_add_connection
37MHD_set_connection_option
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
new file mode 100644
index 00000000..bb9dead6
--- /dev/null
+++ b/src/microhttpd/Makefile.am
@@ -0,0 +1,92 @@
1if USE_PRIVATE_PLIBC_H
2 PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc
3endif
4
5AM_CPPFLAGS = \
6 $(PLIBC_INCLUDE) \
7 -I$(top_srcdir)/src/include \
8 -I$(top_srcdir)/src/daemon \
9 @LIBGCRYPT_CFLAGS@
10
11EXTRA_DIST = EXPORT.sym
12
13lib_LTLIBRARIES = \
14 libmicrohttpd.la
15
16
17libmicrohttpd_la_SOURCES = \
18 connection.c connection.h \
19 reason_phrase.c reason_phrase.h \
20 daemon.c \
21 internal.c internal.h \
22 memorypool.c memorypool.h \
23 response.c response.h
24libmicrohttpd_la_LDFLAGS = \
25 $(MHD_LIB_LDFLAGS) \
26 -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@
27
28if USE_COVERAGE
29 AM_CFLAGS = --coverage
30endif
31
32if !HAVE_TSEARCH
33libmicrohttpd_la_SOURCES += \
34 tsearch.c tsearch.h
35endif
36
37if HAVE_POSTPROCESSOR
38libmicrohttpd_la_SOURCES += \
39 postprocessor.c
40endif
41
42if ENABLE_DAUTH
43libmicrohttpd_la_SOURCES += \
44 digestauth.c \
45 md5.c md5.h
46endif
47
48if ENABLE_BAUTH
49libmicrohttpd_la_SOURCES += \
50 basicauth.c \
51 base64.c base64.h
52endif
53
54if ENABLE_HTTPS
55libmicrohttpd_la_SOURCES += \
56 connection_https.c connection_https.h
57libmicrohttpd_la_LIBADD = -lgnutls @LIBGCRYPT_LIBS@
58endif
59
60
61
62check_PROGRAMS = \
63 test_daemon
64
65if HAVE_POSTPROCESSOR
66check_PROGRAMS += \
67 test_postprocessor \
68 test_postprocessor_large \
69 test_postprocessor_amp
70endif
71
72TESTS = $(check_PROGRAMS)
73
74test_daemon_SOURCES = \
75 test_daemon.c
76test_daemon_LDADD = \
77 $(top_builddir)/src/daemon/libmicrohttpd.la
78
79test_postprocessor_SOURCES = \
80 test_postprocessor.c
81test_postprocessor_LDADD = \
82 $(top_builddir)/src/daemon/libmicrohttpd.la
83
84test_postprocessor_amp_SOURCES = \
85 test_postprocessor_amp.c
86test_postprocessor_amp_LDADD = \
87 $(top_builddir)/src/daemon/libmicrohttpd.la
88
89test_postprocessor_large_SOURCES = \
90 test_postprocessor_large.c
91test_postprocessor_large_LDADD = \
92 $(top_builddir)/src/daemon/libmicrohttpd.la
diff --git a/src/microhttpd/base64.c b/src/microhttpd/base64.c
new file mode 100644
index 00000000..d14317b3
--- /dev/null
+++ b/src/microhttpd/base64.c
@@ -0,0 +1,62 @@
1/*
2 * This code implements the BASE64 algorithm.
3 * This code is in the public domain; do with it what you wish.
4 *
5 * @file base64.c
6 * @brief This code implements the BASE64 algorithm
7 * @author Matthieu Speder
8 */
9#include "base64.h"
10
11static const char base64_chars[] =
12 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13
14static const char base64_digits[] =
15 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
18 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
19 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26,
20 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
21 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
27
28
29char *
30BASE64Decode(const char* src)
31{
32 size_t in_len = strlen (src);
33 char* dest;
34 char* result;
35
36 if (in_len % 4)
37 {
38 /* Wrong base64 string length */
39 return NULL;
40 }
41 result = dest = malloc(in_len / 4 * 3 + 1);
42 if (result == NULL)
43 return NULL; /* out of memory */
44 while (*src) {
45 char a = base64_digits[(unsigned char)*(src++)];
46 char b = base64_digits[(unsigned char)*(src++)];
47 char c = base64_digits[(unsigned char)*(src++)];
48 char d = base64_digits[(unsigned char)*(src++)];
49 *(dest++) = (a << 2) | ((b & 0x30) >> 4);
50 if (c == (char)-1)
51 break;
52 *(dest++) = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
53 if (d == (char)-1)
54 break;
55 *(dest++) = ((c & 0x03) << 6) | d;
56 }
57 *dest = 0;
58 return result;
59}
60
61
62/* end of base64.c */
diff --git a/src/microhttpd/base64.h b/src/microhttpd/base64.h
new file mode 100644
index 00000000..831adf97
--- /dev/null
+++ b/src/microhttpd/base64.h
@@ -0,0 +1,17 @@
1/*
2 * This code implements the BASE64 algorithm.
3 * This code is in the public domain; do with it what you wish.
4 *
5 * @file base64.c
6 * @brief This code implements the BASE64 algorithm
7 * @author Matthieu Speder
8 */
9#ifndef BASE64_H
10#define BASE64_H
11
12#include "platform.h"
13
14char *
15BASE64Decode(const char* src);
16
17#endif /* !BASE64_H */
diff --git a/src/microhttpd/basicauth.c b/src/microhttpd/basicauth.c
new file mode 100644
index 00000000..e8a69e7d
--- /dev/null
+++ b/src/microhttpd/basicauth.c
@@ -0,0 +1,136 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19/**
20 * @file basicauth.c
21 * @brief Implements HTTP basic authentication methods
22 * @author Amr Ali
23 * @author Matthieu Speder
24 */
25#include "platform.h"
26#include <limits.h>
27#include "internal.h"
28#include "base64.h"
29
30/**
31 * Beginning string for any valid Basic authentication header.
32 */
33#define _BASIC_BASE "Basic "
34
35
36/**
37 * Get the username and password from the basic authorization header sent by the client
38 *
39 * @param connection The MHD connection structure
40 * @param password a pointer for the password
41 * @return NULL if no username could be found, a pointer
42 * to the username if found
43 */
44char *
45MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
46 char** password)
47{
48 const char *header;
49 char *decode;
50 const char *separator;
51 char *user;
52
53 if ( (NULL == (header = MHD_lookup_connection_value (connection,
54 MHD_HEADER_KIND,
55 MHD_HTTP_HEADER_AUTHORIZATION))) ||
56 (0 != strncmp (header, _BASIC_BASE, strlen(_BASIC_BASE))) )
57 return NULL;
58 header += strlen (_BASIC_BASE);
59 if (NULL == (decode = BASE64Decode (header)))
60 {
61#if HAVE_MESSAGES
62 MHD_DLOG (connection->daemon,
63 "Error decoding basic authentication\n");
64#endif
65 return NULL;
66 }
67 /* Find user:password pattern */
68 if (NULL == (separator = strchr (decode, ':')))
69 {
70#if HAVE_MESSAGES
71 MHD_DLOG(connection->daemon,
72 "Basic authentication doesn't contain ':' separator\n");
73#endif
74 free (decode);
75 return NULL;
76 }
77 if (NULL == (user = strdup (decode)))
78 {
79 free (decode);
80 return NULL;
81 }
82 user[separator - decode] = '\0'; /* cut off at ':' */
83 if (NULL != password)
84 {
85 *password = strdup (separator + 1);
86 if (NULL == *password)
87 {
88#if HAVE_MESSAGES
89 MHD_DLOG(connection->daemon,
90 "Failed to allocate memory for password\n");
91#endif
92 free (decode);
93 free (user);
94 return NULL;
95 }
96 }
97 free (decode);
98 return user;
99}
100
101
102/**
103 * Queues a response to request basic authentication from the client.
104 * The given response object is expected to include the payload for
105 * the response; the "WWW-Authenticate" header will be added and the
106 * response queued with the 'UNAUTHORIZED' status code.
107 *
108 * @param connection The MHD connection structure
109 * @param realm the realm presented to the client
110 * @param response response object to modify and queue
111 * @return MHD_YES on success, MHD_NO otherwise
112 */
113int
114MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection,
115 const char *realm,
116 struct MHD_Response *response)
117{
118 int ret;
119 size_t hlen = strlen(realm) + strlen("Basic realm=\"\"") + 1;
120 char header[hlen];
121
122 snprintf (header,
123 sizeof (header),
124 "Basic realm=\"%s\"",
125 realm);
126 ret = MHD_add_response_header (response,
127 MHD_HTTP_HEADER_WWW_AUTHENTICATE,
128 header);
129 if (MHD_YES == ret)
130 ret = MHD_queue_response (connection,
131 MHD_HTTP_UNAUTHORIZED,
132 response);
133 return ret;
134}
135
136/* end of basicauth.c */
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
new file mode 100644
index 00000000..728da12d
--- /dev/null
+++ b/src/microhttpd/connection.c
@@ -0,0 +1,2578 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file connection.c
23 * @brief Methods for managing connections
24 * @author Daniel Pittman
25 * @author Christian Grothoff
26 */
27
28#include "internal.h"
29#include <limits.h>
30#include "connection.h"
31#include "memorypool.h"
32#include "response.h"
33#include "reason_phrase.h"
34
35#if HAVE_NETINET_TCP_H
36/* for TCP_CORK */
37#include <netinet/tcp.h>
38#endif
39
40/**
41 * Minimum size by which MHD tries to increment read/write buffers.
42 * We usually begin with half the available pool space for the
43 * IO-buffer, but if absolutely needed we additively grow by the
44 * number of bytes given here (up to -- theoretically -- the full pool
45 * space).
46 */
47#define MHD_BUF_INC_SIZE 1024
48
49/**
50 * Message to transmit when http 1.1 request is received
51 */
52#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
53
54/**
55 * Response text used when the request (http header) is too big to
56 * be processed.
57 *
58 * Intentionally empty here to keep our memory footprint
59 * minimal.
60 */
61#if HAVE_MESSAGES
62#define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
63#else
64#define REQUEST_TOO_BIG ""
65#endif
66
67/**
68 * Response text used when the request (http header) does not
69 * contain a "Host:" header and still claims to be HTTP 1.1.
70 *
71 * Intentionally empty here to keep our memory footprint
72 * minimal.
73 */
74#if HAVE_MESSAGES
75#define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>"
76#else
77#define REQUEST_LACKS_HOST ""
78#endif
79
80/**
81 * Response text used when the request (http header) is
82 * malformed.
83 *
84 * Intentionally empty here to keep our memory footprint
85 * minimal.
86 */
87#if HAVE_MESSAGES
88#define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
89#else
90#define REQUEST_MALFORMED ""
91#endif
92
93/**
94 * Response text used when there is an internal server error.
95 *
96 * Intentionally empty here to keep our memory footprint
97 * minimal.
98 */
99#if HAVE_MESSAGES
100#define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
101#else
102#define INTERNAL_ERROR ""
103#endif
104
105/**
106 * Add extra debug messages with reasons for closing connections
107 * (non-error reasons).
108 */
109#define DEBUG_CLOSE MHD_NO
110
111/**
112 * Should all data send be printed to stderr?
113 */
114#define DEBUG_SEND_DATA MHD_NO
115
116
117/**
118 * Get all of the headers from the request.
119 *
120 * @param connection connection to get values from
121 * @param kind types of values to iterate over
122 * @param iterator callback to call on each header;
123 * maybe NULL (then just count headers)
124 * @param iterator_cls extra argument to iterator
125 * @return number of entries iterated over
126 */
127int
128MHD_get_connection_values (struct MHD_Connection *connection,
129 enum MHD_ValueKind kind,
130 MHD_KeyValueIterator iterator, void *iterator_cls)
131{
132 int ret;
133 struct MHD_HTTP_Header *pos;
134
135 if (NULL == connection)
136 return -1;
137 ret = 0;
138 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
139 if (0 != (pos->kind & kind))
140 {
141 ret++;
142 if ((NULL != iterator) &&
143 (MHD_YES != iterator (iterator_cls,
144 kind, pos->header, pos->value)))
145 return ret;
146 }
147 return ret;
148}
149
150
151/**
152 * This function can be used to append an entry to
153 * the list of HTTP headers of a connection (so that the
154 * MHD_get_connection_values function will return
155 * them -- and the MHD PostProcessor will also
156 * see them). This maybe required in certain
157 * situations (see Mantis #1399) where (broken)
158 * HTTP implementations fail to supply values needed
159 * by the post processor (or other parts of the
160 * application).
161 * <p>
162 * This function MUST only be called from within
163 * the MHD_AccessHandlerCallback (otherwise, access
164 * maybe improperly synchronized). Furthermore,
165 * the client must guarantee that the key and
166 * value arguments are 0-terminated strings that
167 * are NOT freed until the connection is closed.
168 * (The easiest way to do this is by passing only
169 * arguments to permanently allocated strings.).
170 *
171 * @param connection the connection for which a
172 * value should be set
173 * @param kind kind of the value
174 * @param key key for the value
175 * @param value the value itself
176 * @return MHD_NO if the operation could not be
177 * performed due to insufficient memory;
178 * MHD_YES on success
179 */
180int
181MHD_set_connection_value (struct MHD_Connection *connection,
182 enum MHD_ValueKind kind,
183 const char *key, const char *value)
184{
185 struct MHD_HTTP_Header *pos;
186
187 pos = MHD_pool_allocate (connection->pool,
188 sizeof (struct MHD_HTTP_Header), MHD_NO);
189 if (NULL == pos)
190 return MHD_NO;
191 pos->header = (char *) key;
192 pos->value = (char *) value;
193 pos->kind = kind;
194 pos->next = NULL;
195 /* append 'pos' to the linked list of headers */
196 if (NULL == connection->headers_received_tail)
197 {
198 connection->headers_received = pos;
199 connection->headers_received_tail = pos;
200 }
201 else
202 {
203 connection->headers_received_tail->next = pos;
204 connection->headers_received_tail = pos;
205 }
206 return MHD_YES;
207}
208
209
210/**
211 * Get a particular header value. If multiple
212 * values match the kind, return any one of them.
213 *
214 * @param connection connection to get values from
215 * @param kind what kind of value are we looking for
216 * @param key the header to look for, NULL to lookup 'trailing' value without a key
217 * @return NULL if no such item was found
218 */
219const char *
220MHD_lookup_connection_value (struct MHD_Connection *connection,
221 enum MHD_ValueKind kind, const char *key)
222{
223 struct MHD_HTTP_Header *pos;
224
225 if (NULL == connection)
226 return NULL;
227 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
228 if ((0 != (pos->kind & kind)) &&
229 ( (key == pos->header) ||
230 ( (NULL != pos->header) &&
231 (NULL != key) &&
232 (0 == strcasecmp (key, pos->header))) ))
233 return pos->value;
234 return NULL;
235}
236
237
238/**
239 * Queue a response to be transmitted to the client (as soon as
240 * possible but after MHD_AccessHandlerCallback returns).
241 *
242 * @param connection the connection identifying the client
243 * @param status_code HTTP status code (i.e. 200 for OK)
244 * @param response response to transmit
245 * @return MHD_NO on error (i.e. reply already sent),
246 * MHD_YES on success or if message has been queued
247 */
248int
249MHD_queue_response (struct MHD_Connection *connection,
250 unsigned int status_code, struct MHD_Response *response)
251{
252 if ( (NULL == connection) ||
253 (NULL == response) ||
254 (NULL != connection->response) ||
255 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
256 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
257 return MHD_NO;
258 MHD_increment_response_rc (response);
259 connection->response = response;
260 connection->responseCode = status_code;
261 if ( (NULL != connection->method) &&
262 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) )
263 {
264 /* if this is a "HEAD" request, pretend that we
265 have already sent the full message body */
266 connection->response_write_position = response->total_size;
267 }
268 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
269 {
270 /* response was queued "early",
271 refuse to read body / footers or further
272 requests! */
273 (void) SHUTDOWN (connection->socket_fd, SHUT_RD);
274 connection->read_closed = MHD_YES;
275 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
276 }
277 return MHD_YES;
278}
279
280
281/**
282 * Do we (still) need to send a 100 continue
283 * message for this connection?
284 *
285 * @param connection connection to test
286 * @return 0 if we don't need 100 CONTINUE, 1 if we do
287 */
288static int
289need_100_continue (struct MHD_Connection *connection)
290{
291 const char *expect;
292
293 return ( (NULL == connection->response) &&
294 (NULL != connection->version) &&
295 (0 == strcasecmp (connection->version,
296 MHD_HTTP_VERSION_1_1)) &&
297 (NULL != (expect = MHD_lookup_connection_value (connection,
298 MHD_HEADER_KIND,
299 MHD_HTTP_HEADER_EXPECT))) &&
300 (0 == strcasecmp (expect, "100-continue")) &&
301 (connection->continue_message_write_offset <
302 strlen (HTTP_100_CONTINUE)) );
303}
304
305
306/**
307 * Close the given connection and give the
308 * specified termination code to the user.
309 *
310 * @param connection connection to close
311 * @param termination_code termination reason to give
312 */
313void
314MHD_connection_close (struct MHD_Connection *connection,
315 enum MHD_RequestTerminationCode termination_code)
316{
317 struct MHD_Daemon *daemon;
318
319 daemon = connection->daemon;
320 SHUTDOWN (connection->socket_fd,
321 (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
322 connection->state = MHD_CONNECTION_CLOSED;
323 if ( (NULL != daemon->notify_completed) &&
324 (MHD_YES == connection->client_aware) )
325 daemon->notify_completed (daemon->notify_completed_cls,
326 connection,
327 &connection->client_context,
328 termination_code);
329 connection->client_aware = MHD_NO;
330}
331
332
333/**
334 * A serious error occured, close the
335 * connection (and notify the application).
336 *
337 * @param connection connection to close with error
338 * @param emsg error message (can be NULL)
339 */
340static void
341connection_close_error (struct MHD_Connection *connection,
342 const char *emsg)
343{
344#if HAVE_MESSAGES
345 if (NULL != emsg)
346 MHD_DLOG (connection->daemon, emsg);
347#endif
348 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
349}
350
351
352/**
353 * Macro to only include error message in call to
354 * "connection_close_error" if we have HAVE_MESSAGES.
355 */
356#if HAVE_MESSAGES
357#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
358#else
359#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
360#endif
361
362
363/**
364 * Prepare the response buffer of this connection for
365 * sending. Assumes that the response mutex is
366 * already held. If the transmission is complete,
367 * this function may close the socket (and return
368 * MHD_NO).
369 *
370 * @param connection the connection
371 * @return MHD_NO if readying the response failed
372 */
373static int
374try_ready_normal_body (struct MHD_Connection *connection)
375{
376 ssize_t ret;
377 struct MHD_Response *response;
378
379 response = connection->response;
380 if (NULL == response->crc)
381 return MHD_YES;
382 if (0 == response->total_size)
383 return MHD_YES; /* 0-byte response is always ready */
384 if ( (response->data_start <=
385 connection->response_write_position) &&
386 (response->data_size + response->data_start >
387 connection->response_write_position) )
388 return MHD_YES; /* response already ready */
389#if LINUX
390 if ( (-1 != response->fd) &&
391 (0 == (connection->daemon->options & MHD_USE_SSL)) )
392 {
393 /* will use sendfile, no need to bother response crc */
394 return MHD_YES;
395 }
396#endif
397
398 ret = response->crc (response->crc_cls,
399 connection->response_write_position,
400 response->data,
401 MHD_MIN (response->data_buffer_size,
402 response->total_size -
403 connection->response_write_position));
404 if ((0 == ret) &&
405 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
406 mhd_panic (mhd_panic_cls, __FILE__, __LINE__
407#if HAVE_MESSAGES
408 , "API violation"
409#else
410 , NULL
411#endif
412 );
413 if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
414 (MHD_CONTENT_READER_END_WITH_ERROR == ret) )
415 {
416 /* either error or http 1.0 transfer, close socket! */
417 response->total_size = connection->response_write_position;
418 CONNECTION_CLOSE_ERROR (connection,
419 (ret == MHD_CONTENT_READER_END_OF_STREAM)
420 ? "Closing connection (end of response)\n"
421 : "Closing connection (stream error)\n");
422 return MHD_NO;
423 }
424 response->data_start = connection->response_write_position;
425 response->data_size = ret;
426 if (0 == ret)
427 {
428 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
429 return MHD_NO;
430 }
431 return MHD_YES;
432}
433
434
435/**
436 * Prepare the response buffer of this connection for sending.
437 * Assumes that the response mutex is already held. If the
438 * transmission is complete, this function may close the socket (and
439 * return MHD_NO).
440 *
441 * @param connection the connection
442 * @return MHD_NO if readying the response failed
443 */
444static int
445try_ready_chunked_body (struct MHD_Connection *connection)
446{
447 ssize_t ret;
448 char *buf;
449 struct MHD_Response *response;
450 size_t size;
451 char cbuf[10]; /* 10: max strlen of "%x\r\n" */
452 int cblen;
453
454 response = connection->response;
455 if (0 == connection->write_buffer_size)
456 {
457 size = connection->daemon->pool_size;
458 do
459 {
460 size /= 2;
461 if (size < 128)
462 {
463 /* not enough memory */
464 CONNECTION_CLOSE_ERROR (connection,
465 "Closing connection (out of memory)\n");
466 return MHD_NO;
467 }
468 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
469 }
470 while (NULL == buf);
471 connection->write_buffer_size = size;
472 connection->write_buffer = buf;
473 }
474
475 if ( (response->data_start <=
476 connection->response_write_position) &&
477 (response->data_size + response->data_start >
478 connection->response_write_position) )
479 {
480 /* buffer already ready, use what is there for the chunk */
481 ret = response->data_size + response->data_start - connection->response_write_position;
482 if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
483 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
484 memcpy (&connection->write_buffer[sizeof (cbuf)],
485 &response->data[connection->response_write_position - response->data_start],
486 ret);
487 }
488 else
489 {
490 /* buffer not in range, try to fill it */
491 if (0 == response->total_size)
492 ret = 0; /* response must be empty, don't bother calling crc */
493 else
494 ret = response->crc (response->crc_cls,
495 connection->response_write_position,
496 &connection->write_buffer[sizeof (cbuf)],
497 connection->write_buffer_size - sizeof (cbuf) - 2);
498 }
499 if (MHD_CONTENT_READER_END_WITH_ERROR == ret)
500 {
501 /* error, close socket! */
502 response->total_size = connection->response_write_position;
503 CONNECTION_CLOSE_ERROR (connection,
504 "Closing connection (error generating response)\n");
505 return MHD_NO;
506 }
507 if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
508 (0 == response->total_size) )
509 {
510 /* end of message, signal other side! */
511 strcpy (connection->write_buffer, "0\r\n");
512 connection->write_buffer_append_offset = 3;
513 connection->write_buffer_send_offset = 0;
514 response->total_size = connection->response_write_position;
515 return MHD_YES;
516 }
517 if (0 == ret)
518 {
519 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
520 return MHD_NO;
521 }
522 if (ret > 0xFFFFFF)
523 ret = 0xFFFFFF;
524 snprintf (cbuf,
525 sizeof (cbuf),
526 "%X\r\n", (unsigned int) ret);
527 cblen = strlen (cbuf);
528 EXTRA_CHECK (cblen <= sizeof (cbuf));
529 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
530 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
531 connection->response_write_position += ret;
532 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
533 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
534 return MHD_YES;
535}
536
537
538/**
539 * Check if we need to set some additional headers
540 * for http-compiliance.
541 *
542 * @param connection connection to check (and possibly modify)
543 */
544static void
545add_extra_headers (struct MHD_Connection *connection)
546{
547 const char *have_close;
548 const char *client_close;
549 const char *have_encoding;
550 char buf[128];
551 int add_close;
552
553 client_close = MHD_lookup_connection_value (connection,
554 MHD_HEADER_KIND,
555 MHD_HTTP_HEADER_CONNECTION);
556 /* we only care about 'close', everything else is ignored */
557 if ( (NULL != client_close) && (0 != strcasecmp (client_close, "close")) )
558 client_close = NULL;
559 have_close = MHD_get_response_header (connection->response,
560 MHD_HTTP_HEADER_CONNECTION);
561 if ( (NULL != have_close) && (0 != strcasecmp (have_close, "close")) )
562 have_close = NULL;
563 connection->have_chunked_upload = MHD_NO;
564 add_close = MHD_NO;
565 if (MHD_SIZE_UNKNOWN == connection->response->total_size)
566 {
567 /* size is unknown, need to either to HTTP 1.1 chunked encoding or
568 close the connection */
569 if (NULL == have_close)
570 {
571 /* 'close' header doesn't exist yet, see if we need to add one;
572 if the client asked for a close, no need to start chunk'ing */
573 if ((NULL == client_close) &&
574 (NULL != connection->version) &&
575 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
576 {
577 connection->have_chunked_upload = MHD_YES;
578 have_encoding = MHD_get_response_header (connection->response,
579 MHD_HTTP_HEADER_TRANSFER_ENCODING);
580 if (NULL == have_encoding)
581 MHD_add_response_header (connection->response,
582 MHD_HTTP_HEADER_TRANSFER_ENCODING,
583 "chunked");
584 else if (0 != strcasecmp (have_encoding, "chunked"))
585 add_close = MHD_YES; /* application already set some strange encoding, can't do 'chunked' */
586 }
587 else
588 {
589 /* HTTP not 1.1 or client asked for close => set close header */
590 add_close = MHD_YES;
591 }
592 }
593 }
594 else
595 {
596 /* check if we should add a 'close' anyway */
597 if ( (NULL != client_close) &&
598 (NULL == have_close) )
599 add_close = MHD_YES; /* client asked for it, so add it */
600
601 /* if not present, add content length */
602 if (NULL == MHD_get_response_header (connection->response,
603 MHD_HTTP_HEADER_CONTENT_LENGTH))
604 {
605 SPRINTF (buf,
606 MHD_UNSIGNED_LONG_LONG_PRINTF,
607 (MHD_UNSIGNED_LONG_LONG) connection->response->total_size);
608 MHD_add_response_header (connection->response,
609 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
610 }
611 }
612 if (MHD_YES == add_close)
613 MHD_add_response_header (connection->response,
614 MHD_HTTP_HEADER_CONNECTION, "close");
615}
616
617
618/**
619 * Produce HTTP "Date:" header.
620 *
621 * @param date where to write the header, with
622 * at least 128 bytes available space.
623 */
624static void
625get_date_string (char *date)
626{
627 static const char *const days[] =
628 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
629 static const char *const mons[] =
630 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
631 "Nov", "Dec"
632 };
633 struct tm now;
634 time_t t;
635
636 time (&t);
637 gmtime_r (&t, &now);
638 SPRINTF (date,
639 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
640 days[now.tm_wday % 7],
641 (unsigned int) now.tm_mday,
642 mons[now.tm_mon % 12],
643 (unsigned int) (1900 + now.tm_year),
644 (unsigned int) now.tm_hour,
645 (unsigned int) now.tm_min,
646 (unsigned int) now.tm_sec);
647}
648
649
650/**
651 * Try growing the read buffer. We initially claim half the
652 * available buffer space for the read buffer (the other half
653 * being left for management data structures; the write
654 * buffer can in the end take virtually everything as the
655 * read buffer can be reduced to the minimum necessary at that
656 * point.
657 *
658 * @param connection the connection
659 * @return MHD_YES on success, MHD_NO on failure
660 */
661static int
662try_grow_read_buffer (struct MHD_Connection *connection)
663{
664 void *buf;
665 size_t new_size;
666
667 if (0 == connection->read_buffer_size)
668 new_size = connection->daemon->pool_size / 2;
669 else
670 new_size = connection->read_buffer_size + MHD_BUF_INC_SIZE;
671 buf = MHD_pool_reallocate (connection->pool,
672 connection->read_buffer,
673 connection->read_buffer_size,
674 new_size);
675 if (NULL == buf)
676 return MHD_NO;
677 /* we can actually grow the buffer, do it! */
678 connection->read_buffer = buf;
679 connection->read_buffer_size = new_size;
680 return MHD_YES;
681}
682
683
684/**
685 * Allocate the connection's write buffer and fill it with all of the
686 * headers (or footers, if we have already sent the body) from the
687 * HTTPd's response.
688 *
689 * @param connection the connection
690 */
691static int
692build_header_response (struct MHD_Connection *connection)
693{
694 size_t size;
695 size_t off;
696 struct MHD_HTTP_Header *pos;
697 char code[256];
698 char date[128];
699 char *data;
700 enum MHD_ValueKind kind;
701 const char *reason_phrase;
702 uint32_t rc;
703 int must_add_close;
704
705 EXTRA_CHECK (NULL != connection->version);
706 if (0 == strlen(connection->version))
707 {
708 data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
709 connection->write_buffer = data;
710 connection->write_buffer_append_offset = 0;
711 connection->write_buffer_send_offset = 0;
712 connection->write_buffer_size = 0;
713 return MHD_YES;
714 }
715 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
716 {
717 add_extra_headers (connection);
718 rc = connection->responseCode & (~MHD_ICY_FLAG);
719 reason_phrase = MHD_get_reason_phrase_for (rc);
720 SPRINTF (code,
721 "%s %u %s\r\n",
722 (0 != (connection->responseCode & MHD_ICY_FLAG))
723 ? "ICY"
724 : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
725 connection->version))
726 ? MHD_HTTP_VERSION_1_0
727 : MHD_HTTP_VERSION_1_1),
728 rc,
729 reason_phrase);
730 off = strlen (code);
731 /* estimate size */
732 size = off + 2; /* extra \r\n at the end */
733 kind = MHD_HEADER_KIND;
734 if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) &&
735 (NULL == MHD_get_response_header (connection->response,
736 MHD_HTTP_HEADER_DATE)) )
737 get_date_string (date);
738 else
739 date[0] = '\0';
740 size += strlen (date);
741 }
742 else
743 {
744 size = 2;
745 kind = MHD_FOOTER_KIND;
746 off = 0;
747 }
748 must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) &&
749 (connection->read_closed == MHD_YES) &&
750 (0 == strcasecmp (connection->version,
751 MHD_HTTP_VERSION_1_1)) &&
752 (NULL == MHD_get_response_header (connection->response,
753 MHD_HTTP_HEADER_CONNECTION)) );
754 if (must_add_close)
755 size += strlen ("Connection: close\r\n");
756 for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
757 if (pos->kind == kind)
758 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
759 /* produce data */
760 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
761 if (NULL == data)
762 {
763#if HAVE_MESSAGES
764 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
765#endif
766 return MHD_NO;
767 }
768 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
769 {
770 memcpy (data, code, off);
771 }
772 if (must_add_close)
773 {
774 /* we must add the 'close' header because circumstances forced us to
775 stop reading from the socket; however, we are not adding the header
776 to the response as the response may be used in a different context
777 as well */
778 memcpy (&data[off], "Connection: close\r\n",
779 strlen ("Connection: close\r\n"));
780 off += strlen ("Connection: close\r\n");
781 }
782 for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
783 if (pos->kind == kind)
784 off += SPRINTF (&data[off],
785 "%s: %s\r\n",
786 pos->header,
787 pos->value);
788 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
789 {
790 strcpy (&data[off], date);
791 off += strlen (date);
792 }
793 memcpy (&data[off], "\r\n", 2);
794 off += 2;
795
796 if (off != size)
797 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
798 connection->write_buffer = data;
799 connection->write_buffer_append_offset = size;
800 connection->write_buffer_send_offset = 0;
801 connection->write_buffer_size = size + 1;
802 return MHD_YES;
803}
804
805
806/**
807 * We encountered an error processing the request.
808 * Handle it properly by stopping to read data
809 * and sending the indicated response code and message.
810 *
811 * @param connection the connection
812 * @param status_code the response code to send (400, 413 or 414)
813 * @param message the error message to send
814 */
815static void
816transmit_error_response (struct MHD_Connection *connection,
817 unsigned int status_code,
818 const char *message)
819{
820 struct MHD_Response *response;
821
822 if (NULL == connection->version)
823 {
824 /* we were unable to process the full header line, so we don't
825 really know what version the client speaks; assume 1.0 */
826 connection->version = MHD_HTTP_VERSION_1_0;
827 }
828 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
829 connection->read_closed = MHD_YES;
830#if HAVE_MESSAGES
831 MHD_DLOG (connection->daemon,
832 "Error %u (`%s') processing request, closing connection.\n",
833 status_code, message);
834#endif
835 EXTRA_CHECK (connection->response == NULL);
836 response = MHD_create_response_from_buffer (strlen (message),
837 (void *) message,
838 MHD_RESPMEM_PERSISTENT);
839 MHD_queue_response (connection, status_code, response);
840 EXTRA_CHECK (connection->response != NULL);
841 MHD_destroy_response (response);
842 if (MHD_NO == build_header_response (connection))
843 {
844 /* oops - close! */
845 CONNECTION_CLOSE_ERROR (connection,
846 "Closing connection (failed to create response header)\n");
847 }
848 else
849 {
850 connection->state = MHD_CONNECTION_HEADERS_SENDING;
851 }
852}
853
854
855/**
856 * Add "fd" to the "fd_set". If "fd" is
857 * greater than "*max", set "*max" to fd.
858 *
859 * @param fd file descriptor to add to the set
860 * @param set set to modify
861 * @param max_fd maximum value to potentially update
862 */
863static void
864add_to_fd_set (int fd,
865 fd_set *set,
866 int *max_fd)
867{
868 FD_SET (fd, set);
869 if ( (NULL != max_fd) &&
870 (fd > *max_fd) )
871 *max_fd = fd;
872}
873
874
875/**
876 * Obtain the select sets for this connection. The given
877 * sets (and the maximum) are updated and must have
878 * already been initialized.
879 *
880 * @param connection connetion to get select sets for
881 * @param read_fd_set read set to initialize
882 * @param write_fd_set write set to initialize
883 * @param except_fd_set except set to initialize (never changed)
884 * @param max_fd where to store largest FD put into any set
885 * @return MHD_YES on success
886 */
887int
888MHD_connection_get_fdset (struct MHD_Connection *connection,
889 fd_set *read_fd_set,
890 fd_set *write_fd_set,
891 fd_set *except_fd_set,
892 int *max_fd)
893{
894 int ret;
895 struct MHD_Pollfd p;
896
897 /* we use the 'poll fd' as a convenient way to re-use code
898 when determining the select sets */
899 memset (&p, 0, sizeof(struct MHD_Pollfd));
900 ret = MHD_connection_get_pollfd (connection, &p);
901 if ( (MHD_YES == ret) && (p.fd >= 0) ) {
902 if (0 != (p.events & MHD_POLL_ACTION_IN))
903 add_to_fd_set(p.fd, read_fd_set, max_fd);
904 if (0 != (p.events & MHD_POLL_ACTION_OUT))
905 add_to_fd_set(p.fd, write_fd_set, max_fd);
906 }
907 return ret;
908}
909
910
911/**
912 * Obtain the pollfd for this connection
913 *
914 * @param connection connetion to get poll set for
915 * @param p where to store the polling information
916 * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this
917 * connection is not waiting for any read or write events
918 */
919int
920MHD_connection_get_pollfd (struct MHD_Connection *connection,
921 struct MHD_Pollfd *p)
922{
923 int fd;
924
925 if (NULL == connection->pool)
926 connection->pool = MHD_pool_create (connection->daemon->pool_size);
927 if (NULL == connection->pool)
928 {
929 CONNECTION_CLOSE_ERROR (connection,
930 "Failed to create memory pool!\n");
931 return MHD_YES;
932 }
933 fd = connection->socket_fd;
934 p->fd = fd;
935 if (-1 == fd)
936 return MHD_YES;
937 while (1)
938 {
939#if DEBUG_STATES
940 MHD_DLOG (connection->daemon, "%s: state: %s\n",
941 __FUNCTION__, MHD_state_to_string (connection->state));
942#endif
943 switch (connection->state)
944 {
945#if HTTPS_SUPPORT
946 case MHD_TLS_CONNECTION_INIT:
947 if (0 == gnutls_record_get_direction (connection->tls_session))
948 p->events |= MHD_POLL_ACTION_IN;
949 else
950 p->events |= MHD_POLL_ACTION_OUT;
951 break;
952#endif
953 case MHD_CONNECTION_INIT:
954 case MHD_CONNECTION_URL_RECEIVED:
955 case MHD_CONNECTION_HEADER_PART_RECEIVED:
956 /* while reading headers, we always grow the
957 read buffer if needed, no size-check required */
958 if ((connection->read_closed) &&
959 (0 == connection->read_buffer_offset))
960 {
961 CONNECTION_CLOSE_ERROR (connection,
962 "Connection buffer to small for request\n");
963 continue;
964 }
965 if ((connection->read_buffer_offset == connection->read_buffer_size)
966 && (MHD_NO == try_grow_read_buffer (connection)))
967 {
968 transmit_error_response (connection,
969 (connection->url != NULL)
970 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
971 : MHD_HTTP_REQUEST_URI_TOO_LONG,
972 REQUEST_TOO_BIG);
973 continue;
974 }
975 if (MHD_NO == connection->read_closed)
976 p->events |= MHD_POLL_ACTION_IN;
977 break;
978 case MHD_CONNECTION_HEADERS_RECEIVED:
979 /* we should never get here */
980 EXTRA_CHECK (0);
981 break;
982 case MHD_CONNECTION_HEADERS_PROCESSED:
983 EXTRA_CHECK (0);
984 break;
985 case MHD_CONNECTION_CONTINUE_SENDING:
986 p->events |= MHD_POLL_ACTION_OUT;
987 break;
988 case MHD_CONNECTION_CONTINUE_SENT:
989 if (connection->read_buffer_offset == connection->read_buffer_size)
990 {
991 if ((MHD_YES != try_grow_read_buffer (connection)) &&
992 (0 != (connection->daemon->options &
993 (MHD_USE_SELECT_INTERNALLY |
994 MHD_USE_THREAD_PER_CONNECTION))))
995 {
996 /* failed to grow the read buffer, and the
997 client which is supposed to handle the
998 received data in a *blocking* fashion
999 (in this mode) did not handle the data as
1000 it was supposed to!
1001 => we would either have to do busy-waiting
1002 (on the client, which would likely fail),
1003 or if we do nothing, we would just timeout
1004 on the connection (if a timeout is even
1005 set!).
1006 Solution: we kill the connection with an error */
1007 transmit_error_response (connection,
1008 MHD_HTTP_INTERNAL_SERVER_ERROR,
1009 INTERNAL_ERROR);
1010 continue;
1011 }
1012 }
1013 if ((connection->read_buffer_offset < connection->read_buffer_size)
1014 && (MHD_NO == connection->read_closed))
1015 p->events |= MHD_POLL_ACTION_IN;
1016 break;
1017 case MHD_CONNECTION_BODY_RECEIVED:
1018 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
1019 /* while reading footers, we always grow the
1020 read buffer if needed, no size-check required */
1021 if (MHD_YES == connection->read_closed)
1022 {
1023 CONNECTION_CLOSE_ERROR (connection,
1024 NULL);
1025 continue;
1026 }
1027 p->events |= MHD_POLL_ACTION_IN;
1028 /* transition to FOOTERS_RECEIVED
1029 happens in read handler */
1030 break;
1031 case MHD_CONNECTION_FOOTERS_RECEIVED:
1032 /* no socket action, wait for client
1033 to provide response */
1034 break;
1035 case MHD_CONNECTION_HEADERS_SENDING:
1036 /* headers in buffer, keep writing */
1037 p->events |= MHD_POLL_ACTION_OUT;
1038 break;
1039 case MHD_CONNECTION_HEADERS_SENT:
1040 EXTRA_CHECK (0);
1041 break;
1042 case MHD_CONNECTION_NORMAL_BODY_READY:
1043 p->events |= MHD_POLL_ACTION_OUT;
1044 break;
1045 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
1046 /* not ready, no socket action */
1047 break;
1048 case MHD_CONNECTION_CHUNKED_BODY_READY:
1049 p->events |= MHD_POLL_ACTION_OUT;
1050 break;
1051 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
1052 /* not ready, no socket action */
1053 break;
1054 case MHD_CONNECTION_BODY_SENT:
1055 EXTRA_CHECK (0);
1056 break;
1057 case MHD_CONNECTION_FOOTERS_SENDING:
1058 p->events |= MHD_POLL_ACTION_OUT;
1059 break;
1060 case MHD_CONNECTION_FOOTERS_SENT:
1061 EXTRA_CHECK (0);
1062 break;
1063 case MHD_CONNECTION_CLOSED:
1064 return MHD_YES; /* do nothing, not even reading */
1065 default:
1066 EXTRA_CHECK (0);
1067 }
1068 break;
1069 }
1070 return MHD_YES;
1071}
1072
1073
1074/**
1075 * Parse a single line of the HTTP header. Advance
1076 * read_buffer (!) appropriately. If the current line does not
1077 * fit, consider growing the buffer. If the line is
1078 * far too long, close the connection. If no line is
1079 * found (incomplete, buffer too small, line too long),
1080 * return NULL. Otherwise return a pointer to the line.
1081 */
1082static char *
1083get_next_header_line (struct MHD_Connection *connection)
1084{
1085 char *rbuf;
1086 size_t pos;
1087
1088 if (0 == connection->read_buffer_offset)
1089 return NULL;
1090 pos = 0;
1091 rbuf = connection->read_buffer;
1092 while ((pos < connection->read_buffer_offset - 1) &&
1093 ('\r' != rbuf[pos]) && ('\n' != rbuf[pos]))
1094 pos++;
1095 if (pos == connection->read_buffer_offset - 1)
1096 {
1097 /* not found, consider growing... */
1098 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
1099 (MHD_NO ==
1100 try_grow_read_buffer (connection)) )
1101 {
1102 transmit_error_response (connection,
1103 (NULL != connection->url)
1104 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
1105 : MHD_HTTP_REQUEST_URI_TOO_LONG,
1106 REQUEST_TOO_BIG);
1107 }
1108 return NULL;
1109 }
1110 /* found, check if we have proper LFCR */
1111 if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
1112 rbuf[pos++] = '\0'; /* skip both r and n */
1113 rbuf[pos++] = '\0';
1114 connection->read_buffer += pos;
1115 connection->read_buffer_size -= pos;
1116 connection->read_buffer_offset -= pos;
1117 return rbuf;
1118}
1119
1120
1121/**
1122 * Add an entry to the HTTP headers of a connection. If this fails,
1123 * transmit an error response (request too big).
1124 *
1125 * @param connection the connection for which a
1126 * value should be set
1127 * @param kind kind of the value
1128 * @param key key for the value
1129 * @param value the value itself
1130 * @return MHD_NO on failure (out of memory), MHD_YES for success
1131 */
1132static int
1133connection_add_header (struct MHD_Connection *connection,
1134 char *key, char *value, enum MHD_ValueKind kind)
1135{
1136 if (MHD_NO == MHD_set_connection_value (connection,
1137 kind,
1138 key, value))
1139 {
1140#if HAVE_MESSAGES
1141 MHD_DLOG (connection->daemon,
1142 "Not enough memory to allocate header record!\n");
1143#endif
1144 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
1145 REQUEST_TOO_BIG);
1146 return MHD_NO;
1147 }
1148 return MHD_YES;
1149}
1150
1151
1152/**
1153 * Parse and unescape the arguments given by the client as part
1154 * of the HTTP request URI.
1155 *
1156 * @param kind header kind to use for adding to the connection
1157 * @param connection connection to add headers to
1158 * @param args argument URI string (after "?" in URI)
1159 * @return MHD_NO on failure (out of memory), MHD_YES for success
1160 */
1161static int
1162parse_arguments (enum MHD_ValueKind kind,
1163 struct MHD_Connection *connection,
1164 char *args)
1165{
1166 char *equals;
1167 char *amper;
1168
1169 while (NULL != args)
1170 {
1171 equals = strchr (args, '=');
1172 amper = strchr (args, '&');
1173 if (NULL == amper)
1174 {
1175 /* last argument */
1176 if (NULL == equals)
1177 {
1178 /* got 'foo', add key 'foo' with NULL for value */
1179 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1180 connection,
1181 args);
1182 return connection_add_header (connection,
1183 args,
1184 NULL,
1185 kind);
1186 }
1187 /* got 'foo=bar' */
1188 equals[0] = '\0';
1189 equals++;
1190 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1191 connection,
1192 args);
1193 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1194 connection,
1195 equals);
1196 return connection_add_header (connection, args, equals, kind);
1197 }
1198 /* amper is non-NULL here */
1199 amper[0] = '\0';
1200 amper++;
1201 if ( (NULL == equals) ||
1202 (equals >= amper) )
1203 {
1204 /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
1205 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1206 connection,
1207 args);
1208 if (MHD_NO ==
1209 connection_add_header (connection,
1210 args,
1211 NULL,
1212 kind))
1213 return MHD_NO;
1214 /* continue with 'bar' */
1215 args = amper;
1216 continue;
1217
1218 }
1219 /* equals and amper are non-NULL here, and equals < amper,
1220 so we got regular 'foo=value&bar...'-kind of argument */
1221 equals[0] = '\0';
1222 equals++;
1223 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1224 connection,
1225 args);
1226 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1227 connection,
1228 equals);
1229 if (MHD_NO == connection_add_header (connection, args, equals, kind))
1230 return MHD_NO;
1231 args = amper;
1232 }
1233 return MHD_YES;
1234}
1235
1236
1237/**
1238 * Parse the cookie header (see RFC 2109).
1239 *
1240 * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
1241 */
1242static int
1243parse_cookie_header (struct MHD_Connection *connection)
1244{
1245 const char *hdr;
1246 char *cpy;
1247 char *pos;
1248 char *sce;
1249 char *semicolon;
1250 char *equals;
1251 char *ekill;
1252 char old;
1253 int quotes;
1254
1255 hdr = MHD_lookup_connection_value (connection,
1256 MHD_HEADER_KIND,
1257 MHD_HTTP_HEADER_COOKIE);
1258 if (hdr == NULL)
1259 return MHD_YES;
1260 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
1261 if (cpy == NULL)
1262 {
1263#if HAVE_MESSAGES
1264 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
1265#endif
1266 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
1267 REQUEST_TOO_BIG);
1268 return MHD_NO;
1269 }
1270 memcpy (cpy, hdr, strlen (hdr) + 1);
1271 pos = cpy;
1272 while (pos != NULL)
1273 {
1274 while (*pos == ' ')
1275 pos++; /* skip spaces */
1276
1277 sce = pos;
1278 while (((*sce) != '\0') &&
1279 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
1280 sce++;
1281 /* remove tailing whitespace (if any) from key */
1282 ekill = sce - 1;
1283 while ((*ekill == ' ') && (ekill >= pos))
1284 *(ekill--) = '\0';
1285 old = *sce;
1286 *sce = '\0';
1287 if (old != '=')
1288 {
1289 /* value part omitted, use empty string... */
1290 if (MHD_NO ==
1291 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
1292 return MHD_NO;
1293 if (old == '\0')
1294 break;
1295 pos = sce + 1;
1296 continue;
1297 }
1298 equals = sce + 1;
1299 quotes = 0;
1300 semicolon = equals;
1301 while ((semicolon[0] != '\0') &&
1302 ((quotes != 0) ||
1303 ((semicolon[0] != ';') && (semicolon[0] != ','))))
1304 {
1305 if (semicolon[0] == '"')
1306 quotes = (quotes + 1) & 1;
1307 semicolon++;
1308 }
1309 if (semicolon[0] == '\0')
1310 semicolon = NULL;
1311 if (semicolon != NULL)
1312 {
1313 semicolon[0] = '\0';
1314 semicolon++;
1315 }
1316 /* remove quotes */
1317 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
1318 {
1319 equals[strlen (equals) - 1] = '\0';
1320 equals++;
1321 }
1322 if (MHD_NO == connection_add_header (connection,
1323 pos, equals, MHD_COOKIE_KIND))
1324 return MHD_NO;
1325 pos = semicolon;
1326 }
1327 return MHD_YES;
1328}
1329
1330
1331/**
1332 * Parse the first line of the HTTP HEADER.
1333 *
1334 * @param connection the connection (updated)
1335 * @param line the first line
1336 * @return MHD_YES if the line is ok, MHD_NO if it is malformed
1337 */
1338static int
1339parse_initial_message_line (struct MHD_Connection *connection, char *line)
1340{
1341 char *uri;
1342 char *httpVersion;
1343 char *args;
1344
1345 if (NULL == (uri = strchr (line, ' ')))
1346 return MHD_NO; /* serious error */
1347 uri[0] = '\0';
1348 connection->method = line;
1349 uri++;
1350 while (uri[0] == ' ')
1351 uri++;
1352 httpVersion = strchr (uri, ' ');
1353 if (httpVersion != NULL)
1354 {
1355 httpVersion[0] = '\0';
1356 httpVersion++;
1357 }
1358 if (connection->daemon->uri_log_callback != NULL)
1359 connection->client_context
1360 =
1361 connection->daemon->uri_log_callback (connection->daemon->
1362 uri_log_callback_cls, uri);
1363 args = strchr (uri, '?');
1364 if (NULL != args)
1365 {
1366 args[0] = '\0';
1367 args++;
1368 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
1369 }
1370 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
1371 connection,
1372 uri);
1373 connection->url = uri;
1374 if (NULL == httpVersion)
1375 connection->version = "";
1376 else
1377 connection->version = httpVersion;
1378 return MHD_YES;
1379}
1380
1381
1382/**
1383 * Call the handler of the application for this
1384 * connection. Handles chunking of the upload
1385 * as well as normal uploads.
1386 */
1387static void
1388call_connection_handler (struct MHD_Connection *connection)
1389{
1390 size_t processed;
1391
1392 if (NULL != connection->response)
1393 return; /* already queued a response */
1394 processed = 0;
1395 connection->client_aware = MHD_YES;
1396 if (MHD_NO ==
1397 connection->daemon->default_handler (connection->daemon->
1398 default_handler_cls,
1399 connection, connection->url,
1400 connection->method,
1401 connection->version,
1402 NULL, &processed,
1403 &connection->client_context))
1404 {
1405 /* serious internal error, close connection */
1406 CONNECTION_CLOSE_ERROR (connection,
1407 "Internal application error, closing connection.\n");
1408 return;
1409 }
1410}
1411
1412
1413
1414/**
1415 * Call the handler of the application for this
1416 * connection. Handles chunking of the upload
1417 * as well as normal uploads.
1418 */
1419static void
1420process_request_body (struct MHD_Connection *connection)
1421{
1422 size_t processed;
1423 size_t available;
1424 size_t used;
1425 size_t i;
1426 int instant_retry;
1427 int malformed;
1428 char *buffer_head;
1429 char *end;
1430
1431 if (NULL != connection->response)
1432 return; /* already queued a response */
1433
1434 buffer_head = connection->read_buffer;
1435 available = connection->read_buffer_offset;
1436 do
1437 {
1438 instant_retry = MHD_NO;
1439 if ((connection->have_chunked_upload == MHD_YES) &&
1440 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
1441 {
1442 if ((connection->current_chunk_offset ==
1443 connection->current_chunk_size)
1444 && (connection->current_chunk_offset != 0) && (available >= 2))
1445 {
1446 /* skip new line at the *end* of a chunk */
1447 i = 0;
1448 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
1449 i++; /* skip 1st part of line feed */
1450 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
1451 i++; /* skip 2nd part of line feed */
1452 if (i == 0)
1453 {
1454 /* malformed encoding */
1455 CONNECTION_CLOSE_ERROR (connection,
1456 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
1457 return;
1458 }
1459 available -= i;
1460 buffer_head += i;
1461 connection->current_chunk_offset = 0;
1462 connection->current_chunk_size = 0;
1463 }
1464 if (connection->current_chunk_offset <
1465 connection->current_chunk_size)
1466 {
1467 /* we are in the middle of a chunk, give
1468 as much as possible to the client (without
1469 crossing chunk boundaries) */
1470 processed =
1471 connection->current_chunk_size -
1472 connection->current_chunk_offset;
1473 if (processed > available)
1474 processed = available;
1475 if (available > processed)
1476 instant_retry = MHD_YES;
1477 }
1478 else
1479 {
1480 /* we need to read chunk boundaries */
1481 i = 0;
1482 while (i < available)
1483 {
1484 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
1485 break;
1486 i++;
1487 if (i >= 6)
1488 break;
1489 }
1490 /* take '\n' into account; if '\n'
1491 is the unavailable character, we
1492 will need to wait until we have it
1493 before going further */
1494 if ((i + 1 >= available) &&
1495 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
1496 break; /* need more data... */
1497 malformed = (i >= 6);
1498 if (!malformed)
1499 {
1500 buffer_head[i] = '\0';
1501 connection->current_chunk_size = strtoul (buffer_head, &end, 16);
1502 malformed = ('\0' != *end);
1503 }
1504 if (malformed)
1505 {
1506 /* malformed encoding */
1507 CONNECTION_CLOSE_ERROR (connection,
1508 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
1509 return;
1510 }
1511 i++;
1512 if ((i < available) &&
1513 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
1514 i++; /* skip 2nd part of line feed */
1515
1516 buffer_head += i;
1517 available -= i;
1518 connection->current_chunk_offset = 0;
1519
1520 if (available > 0)
1521 instant_retry = MHD_YES;
1522 if (connection->current_chunk_size == 0)
1523 {
1524 connection->remaining_upload_size = 0;
1525 break;
1526 }
1527 continue;
1528 }
1529 }
1530 else
1531 {
1532 /* no chunked encoding, give all to the client */
1533 if ( (0 != connection->remaining_upload_size) &&
1534 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
1535 (connection->remaining_upload_size < available) )
1536 {
1537 processed = connection->remaining_upload_size;
1538 }
1539 else
1540 {
1541 /**
1542 * 1. no chunked encoding, give all to the client
1543 * 2. client may send large chunked data, but only a smaller part is available at one time.
1544 */
1545 processed = available;
1546 }
1547 }
1548 used = processed;
1549 connection->client_aware = MHD_YES;
1550 if (MHD_NO ==
1551 connection->daemon->default_handler (connection->daemon->
1552 default_handler_cls,
1553 connection, connection->url,
1554 connection->method,
1555 connection->version,
1556 buffer_head, &processed,
1557 &connection->client_context))
1558 {
1559 /* serious internal error, close connection */
1560 CONNECTION_CLOSE_ERROR (connection,
1561 "Internal application error, closing connection.\n");
1562 return;
1563 }
1564 if (processed > used)
1565 mhd_panic (mhd_panic_cls, __FILE__, __LINE__
1566#if HAVE_MESSAGES
1567 , "API violation"
1568#else
1569 , NULL
1570#endif
1571 );
1572 if (processed != 0)
1573 instant_retry = MHD_NO; /* client did not process everything */
1574 used -= processed;
1575 if (connection->have_chunked_upload == MHD_YES)
1576 connection->current_chunk_offset += used;
1577 /* dh left "processed" bytes in buffer for next time... */
1578 buffer_head += used;
1579 available -= used;
1580 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
1581 connection->remaining_upload_size -= used;
1582 }
1583 while (MHD_YES == instant_retry);
1584 if (available > 0)
1585 memmove (connection->read_buffer, buffer_head, available);
1586 connection->read_buffer_offset = available;
1587}
1588
1589
1590/**
1591 * Try reading data from the socket into the
1592 * read buffer of the connection.
1593 *
1594 * @return MHD_YES if something changed,
1595 * MHD_NO if we were interrupted or if
1596 * no space was available
1597 */
1598static int
1599do_read (struct MHD_Connection *connection)
1600{
1601 int bytes_read;
1602
1603 if (connection->read_buffer_size == connection->read_buffer_offset)
1604 return MHD_NO;
1605
1606 bytes_read = connection->recv_cls (connection,
1607 &connection->read_buffer
1608 [connection->read_buffer_offset],
1609 connection->read_buffer_size -
1610 connection->read_buffer_offset);
1611 if (bytes_read < 0)
1612 {
1613 if ((EINTR == errno) || (EAGAIN == errno))
1614 return MHD_NO;
1615#if HAVE_MESSAGES
1616#if HTTPS_SUPPORT
1617 if (0 != (connection->daemon->options & MHD_USE_SSL))
1618 MHD_DLOG (connection->daemon,
1619 "Failed to receive data: %s\n",
1620 gnutls_strerror (bytes_read));
1621 else
1622#endif
1623 MHD_DLOG (connection->daemon,
1624 "Failed to receive data: %s\n", STRERROR (errno));
1625#endif
1626 CONNECTION_CLOSE_ERROR (connection, NULL);
1627 return MHD_YES;
1628 }
1629 if (0 == bytes_read)
1630 {
1631 /* other side closed connection */
1632 connection->read_closed = MHD_YES;
1633 SHUTDOWN (connection->socket_fd, SHUT_RD);
1634 return MHD_YES;
1635 }
1636 connection->read_buffer_offset += bytes_read;
1637 return MHD_YES;
1638}
1639
1640/**
1641 * Try writing data to the socket from the
1642 * write buffer of the connection.
1643 *
1644 * @return MHD_YES if something changed,
1645 * MHD_NO if we were interrupted
1646 */
1647static int
1648do_write (struct MHD_Connection *connection)
1649{
1650 int ret;
1651
1652 ret = connection->send_cls (connection,
1653 &connection->write_buffer
1654 [connection->write_buffer_send_offset],
1655 connection->write_buffer_append_offset
1656 - connection->write_buffer_send_offset);
1657
1658 if (ret < 0)
1659 {
1660 if ((EINTR == errno) || (EAGAIN == errno))
1661 return MHD_NO;
1662#if HAVE_MESSAGES
1663#if HTTPS_SUPPORT
1664 if (0 != (connection->daemon->options & MHD_USE_SSL))
1665 MHD_DLOG (connection->daemon,
1666 "Failed to send data: %s\n",
1667 gnutls_strerror (ret));
1668 else
1669#endif
1670 MHD_DLOG (connection->daemon,
1671 "Failed to send data: %s\n", STRERROR (errno));
1672#endif
1673 CONNECTION_CLOSE_ERROR (connection, NULL);
1674 return MHD_YES;
1675 }
1676#if DEBUG_SEND_DATA
1677 FPRINTF (stderr,
1678 "Sent response: `%.*s'\n",
1679 ret,
1680 &connection->write_buffer[connection->write_buffer_send_offset]);
1681#endif
1682 connection->write_buffer_send_offset += ret;
1683 return MHD_YES;
1684}
1685
1686
1687/**
1688 * Check if we are done sending the write-buffer.
1689 * If so, transition into "next_state".
1690 *
1691 * @param connection connection to check write status for
1692 * @param next_state the next state to transition to
1693 * @return MHY_NO if we are not done, MHD_YES if we are
1694 */
1695static int
1696check_write_done (struct MHD_Connection *connection,
1697 enum MHD_CONNECTION_STATE next_state)
1698{
1699 if (connection->write_buffer_append_offset !=
1700 connection->write_buffer_send_offset)
1701 return MHD_NO;
1702 connection->write_buffer_append_offset = 0;
1703 connection->write_buffer_send_offset = 0;
1704 connection->state = next_state;
1705 MHD_pool_reallocate (connection->pool, connection->write_buffer,
1706 connection->write_buffer_size, 0);
1707 connection->write_buffer = NULL;
1708 connection->write_buffer_size = 0;
1709 return MHD_YES;
1710}
1711
1712
1713/**
1714 * We have received (possibly the beginning of) a line in the
1715 * header (or footer). Validate (check for ":") and prepare
1716 * to process.
1717 */
1718static int
1719process_header_line (struct MHD_Connection *connection, char *line)
1720{
1721 char *colon;
1722
1723 /* line should be normal header line, find colon */
1724 colon = strchr (line, ':');
1725 if (colon == NULL)
1726 {
1727 /* error in header line, die hard */
1728 CONNECTION_CLOSE_ERROR (connection,
1729 "Received malformed line (no colon), closing connection.\n");
1730 return MHD_NO;
1731 }
1732 /* zero-terminate header */
1733 colon[0] = '\0';
1734 colon++; /* advance to value */
1735 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
1736 colon++;
1737 /* we do the actual adding of the connection
1738 header at the beginning of the while
1739 loop since we need to be able to inspect
1740 the *next* header line (in case it starts
1741 with a space...) */
1742 connection->last = line;
1743 connection->colon = colon;
1744 return MHD_YES;
1745}
1746
1747
1748/**
1749 * Process a header value that spans multiple lines.
1750 * The previous line(s) are in connection->last.
1751 *
1752 * @param connection connection we're processing
1753 * @param line the current input line
1754 * @param kind if the line is complete, add a header
1755 * of the given kind
1756 * @return MHD_YES if the line was processed successfully
1757 */
1758static int
1759process_broken_line (struct MHD_Connection *connection,
1760 char *line, enum MHD_ValueKind kind)
1761{
1762 char *last;
1763 char *tmp;
1764 size_t last_len;
1765 size_t tmp_len;
1766
1767 last = connection->last;
1768 if ((line[0] == ' ') || (line[0] == '\t'))
1769 {
1770 /* value was continued on the next line, see
1771 http://www.jmarshall.com/easy/http/ */
1772 last_len = strlen (last);
1773 /* skip whitespace at start of 2nd line */
1774 tmp = line;
1775 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
1776 tmp++;
1777 tmp_len = strlen (tmp);
1778 last = MHD_pool_reallocate (connection->pool,
1779 last,
1780 last_len + 1,
1781 last_len + tmp_len + 1);
1782 if (last == NULL)
1783 {
1784 transmit_error_response (connection,
1785 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
1786 REQUEST_TOO_BIG);
1787 return MHD_NO;
1788 }
1789 memcpy (&last[last_len], tmp, tmp_len + 1);
1790 connection->last = last;
1791 return MHD_YES; /* possibly more than 2 lines... */
1792 }
1793 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
1794 if ((MHD_NO == connection_add_header (connection,
1795 last, connection->colon, kind)))
1796 {
1797 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
1798 REQUEST_TOO_BIG);
1799 return MHD_NO;
1800 }
1801 /* we still have the current line to deal with... */
1802 if (strlen (line) != 0)
1803 {
1804 if (MHD_NO == process_header_line (connection, line))
1805 {
1806 transmit_error_response (connection,
1807 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
1808 return MHD_NO;
1809 }
1810 }
1811 return MHD_YES;
1812}
1813
1814
1815/**
1816 * Parse the various headers; figure out the size
1817 * of the upload and make sure the headers follow
1818 * the protocol. Advance to the appropriate state.
1819 */
1820static void
1821parse_connection_headers (struct MHD_Connection *connection)
1822{
1823 const char *clen;
1824 MHD_UNSIGNED_LONG_LONG cval;
1825 struct MHD_Response *response;
1826 const char *enc;
1827 char *end;
1828
1829 parse_cookie_header (connection);
1830 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
1831 && (NULL != connection->version)
1832 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
1833 && (NULL ==
1834 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
1835 MHD_HTTP_HEADER_HOST)))
1836 {
1837 /* die, http 1.1 request without host and we are pedantic */
1838 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
1839 connection->read_closed = MHD_YES;
1840#if HAVE_MESSAGES
1841 MHD_DLOG (connection->daemon,
1842 "Received `%s' request without `%s' header.\n",
1843 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
1844#endif
1845 EXTRA_CHECK (connection->response == NULL);
1846 response =
1847 MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
1848 REQUEST_LACKS_HOST,
1849 MHD_RESPMEM_PERSISTENT);
1850 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
1851 MHD_destroy_response (response);
1852 return;
1853 }
1854
1855 connection->remaining_upload_size = 0;
1856 enc = MHD_lookup_connection_value (connection,
1857 MHD_HEADER_KIND,
1858 MHD_HTTP_HEADER_TRANSFER_ENCODING);
1859 if (enc != NULL)
1860 {
1861 connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
1862 if (0 == strcasecmp (enc, "chunked"))
1863 connection->have_chunked_upload = MHD_YES;
1864 }
1865 else
1866 {
1867 clen = MHD_lookup_connection_value (connection,
1868 MHD_HEADER_KIND,
1869 MHD_HTTP_HEADER_CONTENT_LENGTH);
1870 if (clen != NULL)
1871 {
1872 cval = strtoul (clen, &end, 10);
1873 if ( ('\0' != *end) ||
1874 ( (LONG_MAX == cval) && (errno == ERANGE) ) )
1875 {
1876#if HAVE_MESSAGES
1877 MHD_DLOG (connection->daemon,
1878 "Failed to parse `%s' header `%s', closing connection.\n",
1879 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
1880#endif
1881 CONNECTION_CLOSE_ERROR (connection, NULL);
1882 return;
1883 }
1884 connection->remaining_upload_size = cval;
1885 }
1886 }
1887}
1888
1889
1890/**
1891 * This function handles a particular connection when it has been
1892 * determined that there is data to be read off a socket. All
1893 * implementations (multithreaded, external select, internal select)
1894 * call this function to handle reads.
1895 *
1896 * @param connection connection to handle
1897 * @return always MHD_YES (we should continue to process the
1898 * connection)
1899 */
1900int
1901MHD_connection_handle_read (struct MHD_Connection *connection)
1902{
1903 connection->last_activity = MHD_monotonic_time();
1904 if (connection->state == MHD_CONNECTION_CLOSED)
1905 return MHD_YES;
1906 /* make sure "read" has a reasonable number of bytes
1907 in buffer to use per system call (if possible) */
1908 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
1909 connection->read_buffer_size)
1910 try_grow_read_buffer (connection);
1911 if (MHD_NO == do_read (connection))
1912 return MHD_YES;
1913 while (1)
1914 {
1915#if DEBUG_STATES
1916 MHD_DLOG (connection->daemon, "%s: state: %s\n",
1917 __FUNCTION__, MHD_state_to_string (connection->state));
1918#endif
1919 switch (connection->state)
1920 {
1921 case MHD_CONNECTION_INIT:
1922 case MHD_CONNECTION_URL_RECEIVED:
1923 case MHD_CONNECTION_HEADER_PART_RECEIVED:
1924 case MHD_CONNECTION_HEADERS_RECEIVED:
1925 case MHD_CONNECTION_HEADERS_PROCESSED:
1926 case MHD_CONNECTION_CONTINUE_SENDING:
1927 case MHD_CONNECTION_CONTINUE_SENT:
1928 case MHD_CONNECTION_BODY_RECEIVED:
1929 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
1930 /* nothing to do but default action */
1931 if (MHD_YES == connection->read_closed)
1932 {
1933 MHD_connection_close (connection,
1934 MHD_REQUEST_TERMINATED_READ_ERROR);
1935 continue;
1936 }
1937 break;
1938 case MHD_CONNECTION_CLOSED:
1939 return MHD_YES;
1940 default:
1941 /* shrink read buffer to how much is actually used */
1942 MHD_pool_reallocate (connection->pool,
1943 connection->read_buffer,
1944 connection->read_buffer_size + 1,
1945 connection->read_buffer_offset);
1946 break;
1947 }
1948 break;
1949 }
1950 return MHD_YES;
1951}
1952
1953
1954/**
1955 * This function was created to handle writes to sockets when it has
1956 * been determined that the socket can be written to. All
1957 * implementations (multithreaded, external select, internal select)
1958 * call this function
1959 *
1960 * @param connection connection to handle
1961 * @return always MHD_YES (we should continue to process the
1962 * connection)
1963 */
1964int
1965MHD_connection_handle_write (struct MHD_Connection *connection)
1966{
1967 struct MHD_Response *response;
1968 int ret;
1969 connection->last_activity = MHD_monotonic_time();
1970 while (1)
1971 {
1972#if DEBUG_STATES
1973 MHD_DLOG (connection->daemon, "%s: state: %s\n",
1974 __FUNCTION__, MHD_state_to_string (connection->state));
1975#endif
1976 switch (connection->state)
1977 {
1978 case MHD_CONNECTION_INIT:
1979 case MHD_CONNECTION_URL_RECEIVED:
1980 case MHD_CONNECTION_HEADER_PART_RECEIVED:
1981 case MHD_CONNECTION_HEADERS_RECEIVED:
1982 EXTRA_CHECK (0);
1983 break;
1984 case MHD_CONNECTION_HEADERS_PROCESSED:
1985 break;
1986 case MHD_CONNECTION_CONTINUE_SENDING:
1987 ret = connection->send_cls (connection,
1988 &HTTP_100_CONTINUE
1989 [connection->continue_message_write_offset],
1990 strlen (HTTP_100_CONTINUE) -
1991 connection->continue_message_write_offset);
1992 if (ret < 0)
1993 {
1994 if ((errno == EINTR) || (errno == EAGAIN))
1995 break;
1996#if HAVE_MESSAGES
1997 MHD_DLOG (connection->daemon,
1998 "Failed to send data: %s\n", STRERROR (errno));
1999#endif
2000 CONNECTION_CLOSE_ERROR (connection, NULL);
2001 return MHD_YES;
2002 }
2003#if DEBUG_SEND_DATA
2004 FPRINTF (stderr,
2005 "Sent 100 continue response: `%.*s'\n",
2006 ret,
2007 &HTTP_100_CONTINUE
2008 [connection->continue_message_write_offset]);
2009#endif
2010 connection->continue_message_write_offset += ret;
2011 break;
2012 case MHD_CONNECTION_CONTINUE_SENT:
2013 case MHD_CONNECTION_BODY_RECEIVED:
2014 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
2015 case MHD_CONNECTION_FOOTERS_RECEIVED:
2016 EXTRA_CHECK (0);
2017 break;
2018 case MHD_CONNECTION_HEADERS_SENDING:
2019 do_write (connection);
2020 if (connection->state != MHD_CONNECTION_HEADERS_SENDING)
2021 break;
2022 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
2023 break;
2024 case MHD_CONNECTION_HEADERS_SENT:
2025 EXTRA_CHECK (0);
2026 break;
2027 case MHD_CONNECTION_NORMAL_BODY_READY:
2028 response = connection->response;
2029 if (response->crc != NULL)
2030 pthread_mutex_lock (&response->mutex);
2031 if (MHD_YES != try_ready_normal_body (connection))
2032 {
2033 if (response->crc != NULL)
2034 pthread_mutex_unlock (&response->mutex);
2035 break;
2036 }
2037 ret = connection->send_cls (connection,
2038 &response->data
2039 [connection->response_write_position
2040 - response->data_start],
2041 response->data_size -
2042 (connection->response_write_position
2043 - response->data_start));
2044#if DEBUG_SEND_DATA
2045 if (ret > 0)
2046 FPRINTF (stderr,
2047 "Sent DATA response: `%.*s'\n",
2048 ret,
2049 &response->data[connection->response_write_position -
2050 response->data_start]);
2051#endif
2052 if (response->crc != NULL)
2053 pthread_mutex_unlock (&response->mutex);
2054 if (ret < 0)
2055 {
2056 if ((errno == EINTR) || (errno == EAGAIN))
2057 return MHD_YES;
2058#if HAVE_MESSAGES
2059 MHD_DLOG (connection->daemon,
2060 "Failed to send data: %s\n", STRERROR (errno));
2061#endif
2062 CONNECTION_CLOSE_ERROR (connection, NULL);
2063 return MHD_YES;
2064 }
2065 connection->response_write_position += ret;
2066 if (connection->response_write_position ==
2067 connection->response->total_size)
2068 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */
2069 break;
2070 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
2071 EXTRA_CHECK (0);
2072 break;
2073 case MHD_CONNECTION_CHUNKED_BODY_READY:
2074 do_write (connection);
2075 if (connection->state != MHD_CONNECTION_CHUNKED_BODY_READY)
2076 break;
2077 check_write_done (connection,
2078 (connection->response->total_size ==
2079 connection->response_write_position) ?
2080 MHD_CONNECTION_BODY_SENT :
2081 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
2082 break;
2083 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
2084 case MHD_CONNECTION_BODY_SENT:
2085 EXTRA_CHECK (0);
2086 break;
2087 case MHD_CONNECTION_FOOTERS_SENDING:
2088 do_write (connection);
2089 if (connection->state != MHD_CONNECTION_FOOTERS_SENDING)
2090 break;
2091 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
2092 break;
2093 case MHD_CONNECTION_FOOTERS_SENT:
2094 EXTRA_CHECK (0);
2095 break;
2096 case MHD_CONNECTION_CLOSED:
2097 return MHD_YES;
2098 case MHD_TLS_CONNECTION_INIT:
2099 EXTRA_CHECK (0);
2100 break;
2101 default:
2102 EXTRA_CHECK (0);
2103 CONNECTION_CLOSE_ERROR (connection, "Internal error\n");
2104 return MHD_YES;
2105 }
2106 break;
2107 }
2108 return MHD_YES;
2109}
2110
2111
2112/**
2113 * This function was created to handle per-connection processing that
2114 * has to happen even if the socket cannot be read or written to. All
2115 * implementations (multithreaded, external select, internal select)
2116 * call this function.
2117 *
2118 * @param connection connection to handle
2119 * @return MHD_YES if we should continue to process the
2120 * connection (not dead yet), MHD_NO if it died
2121 */
2122int
2123MHD_connection_handle_idle (struct MHD_Connection *connection)
2124{
2125 struct MHD_Daemon *daemon;
2126 unsigned int timeout;
2127 const char *end;
2128 int rend;
2129 char *line;
2130
2131 while (1)
2132 {
2133#if DEBUG_STATES
2134 MHD_DLOG (connection->daemon, "%s: state: %s\n",
2135 __FUNCTION__, MHD_state_to_string (connection->state));
2136#endif
2137 switch (connection->state)
2138 {
2139 case MHD_CONNECTION_INIT:
2140 line = get_next_header_line (connection);
2141 if (line == NULL)
2142 {
2143 if (connection->state != MHD_CONNECTION_INIT)
2144 continue;
2145 if (connection->read_closed)
2146 {
2147 CONNECTION_CLOSE_ERROR (connection,
2148 NULL);
2149 continue;
2150 }
2151 break;
2152 }
2153 if (MHD_NO == parse_initial_message_line (connection, line))
2154 CONNECTION_CLOSE_ERROR (connection, NULL);
2155 else
2156 connection->state = MHD_CONNECTION_URL_RECEIVED;
2157 continue;
2158 case MHD_CONNECTION_URL_RECEIVED:
2159 line = get_next_header_line (connection);
2160 if (line == NULL)
2161 {
2162 if (connection->state != MHD_CONNECTION_URL_RECEIVED)
2163 continue;
2164 if (connection->read_closed)
2165 {
2166 CONNECTION_CLOSE_ERROR (connection,
2167 NULL);
2168 continue;
2169 }
2170 break;
2171 }
2172 if (strlen (line) == 0)
2173 {
2174 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
2175 continue;
2176 }
2177 if (MHD_NO == process_header_line (connection, line))
2178 {
2179 transmit_error_response (connection,
2180 MHD_HTTP_BAD_REQUEST,
2181 REQUEST_MALFORMED);
2182 break;
2183 }
2184 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
2185 continue;
2186 case MHD_CONNECTION_HEADER_PART_RECEIVED:
2187 line = get_next_header_line (connection);
2188 if (line == NULL)
2189 {
2190 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
2191 continue;
2192 if (connection->read_closed)
2193 {
2194 CONNECTION_CLOSE_ERROR (connection,
2195 NULL);
2196 continue;
2197 }
2198 break;
2199 }
2200 if (MHD_NO ==
2201 process_broken_line (connection, line, MHD_HEADER_KIND))
2202 continue;
2203 if (strlen (line) == 0)
2204 {
2205 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
2206 continue;
2207 }
2208 continue;
2209 case MHD_CONNECTION_HEADERS_RECEIVED:
2210 parse_connection_headers (connection);
2211 if (connection->state == MHD_CONNECTION_CLOSED)
2212 continue;
2213 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
2214 continue;
2215 case MHD_CONNECTION_HEADERS_PROCESSED:
2216 call_connection_handler (connection); /* first call */
2217 if (connection->state == MHD_CONNECTION_CLOSED)
2218 continue;
2219 if (need_100_continue (connection))
2220 {
2221 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
2222 break;
2223 }
2224 if (connection->response != NULL)
2225 {
2226 /* we refused (no upload allowed!) */
2227 connection->remaining_upload_size = 0;
2228 /* force close, in case client still tries to upload... */
2229 connection->read_closed = MHD_YES;
2230 }
2231 connection->state = (connection->remaining_upload_size == 0)
2232 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
2233 continue;
2234 case MHD_CONNECTION_CONTINUE_SENDING:
2235 if (connection->continue_message_write_offset ==
2236 strlen (HTTP_100_CONTINUE))
2237 {
2238 connection->state = MHD_CONNECTION_CONTINUE_SENT;
2239 continue;
2240 }
2241 break;
2242 case MHD_CONNECTION_CONTINUE_SENT:
2243 if (connection->read_buffer_offset != 0)
2244 {
2245 process_request_body (connection); /* loop call */
2246 if (connection->state == MHD_CONNECTION_CLOSED)
2247 continue;
2248 }
2249 if ((connection->remaining_upload_size == 0) ||
2250 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
2251 (connection->read_buffer_offset == 0) &&
2252 (MHD_YES == connection->read_closed)))
2253 {
2254 if ((MHD_YES == connection->have_chunked_upload) &&
2255 (MHD_NO == connection->read_closed))
2256 connection->state = MHD_CONNECTION_BODY_RECEIVED;
2257 else
2258 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
2259 continue;
2260 }
2261 break;
2262 case MHD_CONNECTION_BODY_RECEIVED:
2263 line = get_next_header_line (connection);
2264 if (line == NULL)
2265 {
2266 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
2267 continue;
2268 if (connection->read_closed)
2269 {
2270 CONNECTION_CLOSE_ERROR (connection,
2271 NULL);
2272 continue;
2273 }
2274 break;
2275 }
2276 if (strlen (line) == 0)
2277 {
2278 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
2279 continue;
2280 }
2281 if (MHD_NO == process_header_line (connection, line))
2282 {
2283 transmit_error_response (connection,
2284 MHD_HTTP_BAD_REQUEST,
2285 REQUEST_MALFORMED);
2286 break;
2287 }
2288 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
2289 continue;
2290 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
2291 line = get_next_header_line (connection);
2292 if (line == NULL)
2293 {
2294 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
2295 continue;
2296 if (connection->read_closed)
2297 {
2298 CONNECTION_CLOSE_ERROR (connection,
2299 NULL);
2300 continue;
2301 }
2302 break;
2303 }
2304 if (MHD_NO ==
2305 process_broken_line (connection, line, MHD_FOOTER_KIND))
2306 continue;
2307 if (strlen (line) == 0)
2308 {
2309 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
2310 continue;
2311 }
2312 continue;
2313 case MHD_CONNECTION_FOOTERS_RECEIVED:
2314 call_connection_handler (connection); /* "final" call */
2315 if (connection->state == MHD_CONNECTION_CLOSED)
2316 continue;
2317 if (connection->response == NULL)
2318 break; /* try again next time */
2319 if (MHD_NO == build_header_response (connection))
2320 {
2321 /* oops - close! */
2322 CONNECTION_CLOSE_ERROR (connection,
2323 "Closing connection (failed to create response header)\n");
2324 continue;
2325 }
2326 connection->state = MHD_CONNECTION_HEADERS_SENDING;
2327
2328#if HAVE_DECL_TCP_CORK
2329 /* starting header send, set TCP cork */
2330 {
2331 const int val = 1;
2332 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
2333 sizeof (val));
2334 }
2335#endif
2336 break;
2337 case MHD_CONNECTION_HEADERS_SENDING:
2338 /* no default action */
2339 break;
2340 case MHD_CONNECTION_HEADERS_SENT:
2341 if (connection->have_chunked_upload)
2342 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
2343 else
2344 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
2345 continue;
2346 case MHD_CONNECTION_NORMAL_BODY_READY:
2347 /* nothing to do here */
2348 break;
2349 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
2350 if (connection->response->crc != NULL)
2351 pthread_mutex_lock (&connection->response->mutex);
2352 if (MHD_YES == try_ready_normal_body (connection))
2353 {
2354 if (connection->response->crc != NULL)
2355 pthread_mutex_unlock (&connection->response->mutex);
2356 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
2357 break;
2358 }
2359 if (connection->response->crc != NULL)
2360 pthread_mutex_unlock (&connection->response->mutex);
2361 /* not ready, no socket action */
2362 break;
2363 case MHD_CONNECTION_CHUNKED_BODY_READY:
2364 /* nothing to do here */
2365 break;
2366 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
2367 if (connection->response->crc != NULL)
2368 pthread_mutex_lock (&connection->response->mutex);
2369 if (MHD_YES == try_ready_chunked_body (connection))
2370 {
2371 if (connection->response->crc != NULL)
2372 pthread_mutex_unlock (&connection->response->mutex);
2373 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
2374 continue;
2375 }
2376 if (connection->response->crc != NULL)
2377 pthread_mutex_unlock (&connection->response->mutex);
2378 break;
2379 case MHD_CONNECTION_BODY_SENT:
2380 build_header_response (connection);
2381 if (connection->write_buffer_send_offset ==
2382 connection->write_buffer_append_offset)
2383 connection->state = MHD_CONNECTION_FOOTERS_SENT;
2384 else
2385 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
2386 continue;
2387 case MHD_CONNECTION_FOOTERS_SENDING:
2388 /* no default action */
2389 break;
2390 case MHD_CONNECTION_FOOTERS_SENT:
2391#if HAVE_DECL_TCP_CORK
2392 /* done sending, uncork */
2393 {
2394 const int val = 0;
2395 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
2396 sizeof (val));
2397 }
2398#endif
2399 end =
2400 MHD_get_response_header (connection->response,
2401 MHD_HTTP_HEADER_CONNECTION);
2402 rend = ( (end != NULL) && (0 == strcasecmp (end, "close")) );
2403 MHD_destroy_response (connection->response);
2404 connection->response = NULL;
2405 if (connection->daemon->notify_completed != NULL)
2406 connection->daemon->notify_completed (connection->daemon->
2407 notify_completed_cls,
2408 connection,
2409 &connection->client_context,
2410 MHD_REQUEST_TERMINATED_COMPLETED_OK);
2411 connection->client_aware = MHD_NO;
2412 end =
2413 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
2414 MHD_HTTP_HEADER_CONNECTION);
2415 connection->client_context = NULL;
2416 connection->continue_message_write_offset = 0;
2417 connection->responseCode = 0;
2418 connection->headers_received = NULL;
2419 connection->headers_received_tail = NULL;
2420 connection->response_write_position = 0;
2421 connection->have_chunked_upload = MHD_NO;
2422 connection->method = NULL;
2423 connection->url = NULL;
2424 connection->write_buffer = NULL;
2425 connection->write_buffer_size = 0;
2426 connection->write_buffer_send_offset = 0;
2427 connection->write_buffer_append_offset = 0;
2428 if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) )
2429 {
2430 connection->read_closed = MHD_YES;
2431 connection->read_buffer_offset = 0;
2432 }
2433 if (((MHD_YES == connection->read_closed) &&
2434 (0 == connection->read_buffer_offset)) ||
2435 (connection->version == NULL) ||
2436 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
2437 {
2438 /* http 1.0, version-less requests cannot be pipelined */
2439 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK);
2440 MHD_pool_destroy (connection->pool);
2441 connection->pool = NULL;
2442 connection->read_buffer = NULL;
2443 connection->read_buffer_size = 0;
2444 connection->read_buffer_offset = 0;
2445 }
2446 else
2447 {
2448 connection->version = NULL;
2449 connection->state = MHD_CONNECTION_INIT;
2450 connection->read_buffer
2451 = MHD_pool_reset (connection->pool,
2452 connection->read_buffer,
2453 connection->read_buffer_size);
2454 }
2455 continue;
2456 case MHD_CONNECTION_CLOSED:
2457 if (connection->response != NULL)
2458 {
2459 MHD_destroy_response (connection->response);
2460 connection->response = NULL;
2461 }
2462 daemon = connection->daemon;
2463 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
2464 {
2465 MHD_PANIC ("Failed to acquire cleanup mutex\n");
2466 }
2467 DLL_remove (daemon->connections_head,
2468 daemon->connections_tail,
2469 connection);
2470 DLL_insert (daemon->cleanup_head,
2471 daemon->cleanup_tail,
2472 connection);
2473 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
2474 {
2475 MHD_PANIC ("Failed to release cleanup mutex\n");
2476 }
2477 return MHD_NO;
2478 default:
2479 EXTRA_CHECK (0);
2480 break;
2481 }
2482 break;
2483 }
2484 timeout = connection->connection_timeout;
2485 if ( (timeout != 0) &&
2486 (timeout <= (MHD_monotonic_time() - connection->last_activity)) )
2487 {
2488 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
2489 return MHD_YES;
2490 }
2491 return MHD_YES;
2492}
2493
2494
2495/**
2496 * Set callbacks for this connection to those for HTTP.
2497 *
2498 * @param connection connection to initialize
2499 */
2500void
2501MHD_set_http_callbacks_ (struct MHD_Connection *connection)
2502{
2503 connection->read_handler = &MHD_connection_handle_read;
2504 connection->write_handler = &MHD_connection_handle_write;
2505 connection->idle_handler = &MHD_connection_handle_idle;
2506}
2507
2508
2509/**
2510 * Obtain information about the given connection.
2511 *
2512 * @param connection what connection to get information about
2513 * @param infoType what information is desired?
2514 * @param ... depends on infoType
2515 * @return NULL if this information is not available
2516 * (or if the infoType is unknown)
2517 */
2518const union MHD_ConnectionInfo *
2519MHD_get_connection_info (struct MHD_Connection *connection,
2520 enum MHD_ConnectionInfoType infoType, ...)
2521{
2522 switch (infoType)
2523 {
2524#if HTTPS_SUPPORT
2525 case MHD_CONNECTION_INFO_CIPHER_ALGO:
2526 if (connection->tls_session == NULL)
2527 return NULL;
2528 connection->cipher = gnutls_cipher_get (connection->tls_session);
2529 return (const union MHD_ConnectionInfo *) &connection->cipher;
2530 case MHD_CONNECTION_INFO_PROTOCOL:
2531 if (connection->tls_session == NULL)
2532 return NULL;
2533 connection->protocol = gnutls_protocol_get_version (connection->tls_session);
2534 return (const union MHD_ConnectionInfo *) &connection->protocol;
2535 case MHD_CONNECTION_INFO_GNUTLS_SESSION:
2536 if (connection->tls_session == NULL)
2537 return NULL;
2538 return (const union MHD_ConnectionInfo *) &connection->tls_session;
2539#endif
2540 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
2541 return (const union MHD_ConnectionInfo *) &connection->addr;
2542 case MHD_CONNECTION_INFO_DAEMON:
2543 return (const union MHD_ConnectionInfo *) &connection->daemon;
2544 default:
2545 return NULL;
2546 };
2547}
2548
2549
2550/**
2551 * Set a custom option for the given connection, overriding defaults.
2552 *
2553 * @param connection connection to modify
2554 * @param option option to set
2555 * @param ... arguments to the option, depending on the option type
2556 * @return MHD_YES on success, MHD_NO if setting the option failed
2557 */
2558int
2559MHD_set_connection_option (struct MHD_Connection *connection,
2560 enum MHD_CONNECTION_OPTION option,
2561 ...)
2562{
2563 va_list ap;
2564
2565 switch (option)
2566 {
2567 case MHD_CONNECTION_OPTION_TIMEOUT:
2568 va_start (ap, option);
2569 connection->connection_timeout = va_arg (ap, unsigned int);
2570 va_end (ap);
2571 return MHD_YES;
2572 default:
2573 return MHD_NO;
2574 }
2575}
2576
2577
2578/* end of connection.c */
diff --git a/src/microhttpd/connection.h b/src/microhttpd/connection.h
new file mode 100644
index 00000000..e639691f
--- /dev/null
+++ b/src/microhttpd/connection.h
@@ -0,0 +1,128 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file connection.h
22 * @brief Methods for managing connections
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#ifndef CONNECTION_H
28#define CONNECTION_H
29
30#include "internal.h"
31
32
33/**
34 * Obtain the select sets for this connection. The given
35 * sets (and the maximum) are updated and must have
36 * already been initialized.
37 *
38 * @param connection connetion to get select sets for
39 * @param read_fd_set read set to initialize
40 * @param write_fd_set write set to initialize
41 * @param except_fd_set except set to initialize (never changed)
42 * @param max_fd where to store largest FD put into any set
43 * @return MHD_YES on success
44 */
45int
46MHD_connection_get_fdset (struct MHD_Connection *connection,
47 fd_set * read_fd_set,
48 fd_set * write_fd_set,
49 fd_set * except_fd_set, int *max_fd);
50
51
52/**
53 * Obtain the pollfd for this connection. The poll interface allows large
54 * file descriptors. Select goes stupid when the fd overflows fdset (which
55 * is fixed).
56 *
57 * @param connection connetion to get poll set for
58 * @param p where to store the polling information
59 */
60int
61MHD_connection_get_pollfd (struct MHD_Connection *connection,
62 struct MHD_Pollfd *p);
63
64
65/**
66 * Set callbacks for this connection to those for HTTP.
67 *
68 * @param connection connection to initialize
69 */
70void
71MHD_set_http_callbacks_ (struct MHD_Connection *connection);
72
73
74/**
75 * This function handles a particular connection when it has been
76 * determined that there is data to be read off a socket. All
77 * implementations (multithreaded, external select, internal select)
78 * call this function to handle reads.
79 *
80 * @param connection connection to handle
81 * @return always MHD_YES (we should continue to process the
82 * connection)
83 */
84int
85MHD_connection_handle_read (struct MHD_Connection *connection);
86
87
88/**
89 * This function was created to handle writes to sockets when it has
90 * been determined that the socket can be written to. All
91 * implementations (multithreaded, external select, internal select)
92 * call this function
93 *
94 * @param connection connection to handle
95 * @return always MHD_YES (we should continue to process the
96 * connection)
97 */
98int
99MHD_connection_handle_write (struct MHD_Connection *connection);
100
101
102/**
103 * This function was created to handle per-connection processing that
104 * has to happen even if the socket cannot be read or written to. All
105 * implementations (multithreaded, external select, internal select)
106 * call this function.
107 *
108 * @param connection connection to handle
109 * @return MHD_YES if we should continue to process the
110 * connection (not dead yet), MHD_NO if it died
111 */
112int
113MHD_connection_handle_idle (struct MHD_Connection *connection);
114
115
116/**
117 * Close the given connection and give the
118 * specified termination code to the user.
119 *
120 * @param connection connection to close
121 * @param termination_code termination reason to give
122 */
123void
124MHD_connection_close (struct MHD_Connection *connection,
125 enum MHD_RequestTerminationCode termination_code);
126
127
128#endif
diff --git a/src/microhttpd/connection_https.c b/src/microhttpd/connection_https.c
new file mode 100644
index 00000000..b0be3ced
--- /dev/null
+++ b/src/microhttpd/connection_https.c
@@ -0,0 +1,175 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2008, 2010 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file connection_https.c
23 * @brief Methods for managing SSL/TLS connections. This file is only
24 * compiled if ENABLE_HTTPS is set.
25 * @author Sagie Amir
26 * @author Christian Grothoff
27 */
28
29#include "internal.h"
30#include "connection.h"
31#include "memorypool.h"
32#include "response.h"
33#include "reason_phrase.h"
34#include <gnutls/gnutls.h>
35
36
37/**
38 * Give gnuTLS chance to work on the TLS handshake.
39 *
40 * @param connection connection to handshake on
41 * @return MHD_YES on error or if the handshake is progressing
42 * MHD_NO if the handshake has completed successfully
43 * and we should start to read/write data
44 */
45static int
46run_tls_handshake (struct MHD_Connection *connection)
47{
48 int ret;
49
50 connection->last_activity = MHD_monotonic_time();
51 if (connection->state == MHD_TLS_CONNECTION_INIT)
52 {
53 ret = gnutls_handshake (connection->tls_session);
54 if (ret == GNUTLS_E_SUCCESS)
55 {
56 /* set connection state to enable HTTP processing */
57 connection->state = MHD_CONNECTION_INIT;
58 return MHD_YES;
59 }
60 if ( (ret == GNUTLS_E_AGAIN) ||
61 (ret == GNUTLS_E_INTERRUPTED) )
62 {
63 /* handshake not done */
64 return MHD_YES;
65 }
66 /* handshake failed */
67#if HAVE_MESSAGES
68 MHD_DLOG (connection->daemon,
69 "Error: received handshake message out of context\n");
70#endif
71 MHD_connection_close (connection,
72 MHD_REQUEST_TERMINATED_WITH_ERROR);
73 return MHD_YES;
74 }
75 return MHD_NO;
76}
77
78
79/**
80 * This function handles a particular SSL/TLS connection when
81 * it has been determined that there is data to be read off a
82 * socket. Message processing is done by message type which is
83 * determined by peeking into the first message type byte of the
84 * stream.
85 *
86 * Error message handling: all fatal level messages cause the
87 * connection to be terminated.
88 *
89 * Application data is forwarded to the underlying daemon for
90 * processing.
91 *
92 * @param connection the source connection
93 * @return always MHD_YES (we should continue to process the connection)
94 */
95static int
96MHD_tls_connection_handle_read (struct MHD_Connection *connection)
97{
98 if (MHD_YES == run_tls_handshake (connection))
99 return MHD_YES;
100 return MHD_connection_handle_read (connection);
101}
102
103
104/**
105 * This function was created to handle writes to sockets when it has
106 * been determined that the socket can be written to. This function
107 * will forward all write requests to the underlying daemon unless
108 * the connection has been marked for closing.
109 *
110 * @return always MHD_YES (we should continue to process the connection)
111 */
112static int
113MHD_tls_connection_handle_write (struct MHD_Connection *connection)
114{
115 if (MHD_YES == run_tls_handshake (connection))
116 return MHD_YES;
117 return MHD_connection_handle_write (connection);
118}
119
120
121/**
122 * This function was created to handle per-connection processing that
123 * has to happen even if the socket cannot be read or written to. All
124 * implementations (multithreaded, external select, internal select)
125 * call this function.
126 *
127 * @param connection being handled
128 * @return MHD_YES if we should continue to process the
129 * connection (not dead yet), MHD_NO if it died
130 */
131static int
132MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
133{
134 unsigned int timeout;
135
136#if DEBUG_STATES
137 MHD_DLOG (connection->daemon, "%s: state: %s\n",
138 __FUNCTION__, MHD_state_to_string (connection->state));
139#endif
140 timeout = connection->connection_timeout;
141 if ( (timeout != 0) && (timeout <= (MHD_monotonic_time() - connection->last_activity)))
142 MHD_connection_close (connection,
143 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
144 switch (connection->state)
145 {
146 /* on newly created connections we might reach here before any reply has been received */
147 case MHD_TLS_CONNECTION_INIT:
148 return MHD_YES;
149 /* close connection if necessary */
150 case MHD_CONNECTION_CLOSED:
151 gnutls_bye (connection->tls_session, GNUTLS_SHUT_RDWR);
152 return MHD_connection_handle_idle (connection);
153 default:
154 if ( (0 != gnutls_record_check_pending (connection->tls_session)) &&
155 (MHD_YES != MHD_tls_connection_handle_read (connection)) )
156 return MHD_YES;
157 return MHD_connection_handle_idle (connection);
158 }
159 return MHD_YES;
160}
161
162
163/**
164 * Set connection callback function to be used through out
165 * the processing of this secure connection.
166 */
167void
168MHD_set_https_callbacks (struct MHD_Connection *connection)
169{
170 connection->read_handler = &MHD_tls_connection_handle_read;
171 connection->write_handler = &MHD_tls_connection_handle_write;
172 connection->idle_handler = &MHD_tls_connection_handle_idle;
173}
174
175/* end of connection_https.c */
diff --git a/src/microhttpd/connection_https.h b/src/microhttpd/connection_https.h
new file mode 100644
index 00000000..8a5cf380
--- /dev/null
+++ b/src/microhttpd/connection_https.h
@@ -0,0 +1,35 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2008 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file connection_https.h
22 * @brief Methods for managing connections
23 * @author Christian Grothoff
24 */
25
26#ifndef CONNECTION_HTTPS_H
27#define CONNECTION_HTTPS_H
28
29#include "internal.h"
30
31#if HTTPS_SUPPORT
32void MHD_set_https_callbacks (struct MHD_Connection *connection);
33#endif
34
35#endif
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
new file mode 100644
index 00000000..ef69d14b
--- /dev/null
+++ b/src/microhttpd/daemon.c
@@ -0,0 +1,2947 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file daemon.c
23 * @brief A minimal-HTTP server library
24 * @author Daniel Pittman
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "internal.h"
29#include "response.h"
30#include "connection.h"
31#include "memorypool.h"
32#include <limits.h>
33
34#if HAVE_SEARCH_H
35#include <search.h>
36#else
37#include "tsearch.h"
38#endif
39
40#if HTTPS_SUPPORT
41#include "connection_https.h"
42#include <gnutls/gnutls.h>
43#include <gcrypt.h>
44#endif
45
46#ifdef HAVE_POLL_H
47#include <poll.h>
48#endif
49
50#ifdef LINUX
51#include <sys/sendfile.h>
52#endif
53
54/**
55 * Default connection limit.
56 */
57#ifndef WINDOWS
58#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE - 4
59#else
60#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE
61#endif
62
63/**
64 * Default memory allowed per connection.
65 */
66#define MHD_POOL_SIZE_DEFAULT (32 * 1024)
67
68/**
69 * Print extra messages with reasons for closing
70 * sockets? (only adds non-error messages).
71 */
72#define DEBUG_CLOSE MHD_NO
73
74/**
75 * Print extra messages when establishing
76 * connections? (only adds non-error messages).
77 */
78#define DEBUG_CONNECT MHD_NO
79
80#ifndef LINUX
81#ifndef MSG_NOSIGNAL
82#define MSG_NOSIGNAL 0
83#endif
84#endif
85
86#ifndef SOCK_CLOEXEC
87#define SOCK_CLOEXEC 0
88#endif
89
90
91/**
92 * Default implementation of the panic function,
93 * prints an error message and aborts.
94 *
95 * @param cls unused
96 * @param file name of the file with the problem
97 * @param line line number with the problem
98 * @param reason error message with details
99 */
100static void
101mhd_panic_std (void *cls,
102 const char *file,
103 unsigned int line,
104 const char *reason)
105{
106#if HAVE_MESSAGES
107 fprintf (stderr, "Fatal error in GNU libmicrohttpd %s:%u: %s\n",
108 file, line, reason);
109#endif
110 abort ();
111}
112
113
114/**
115 * Handler for fatal errors.
116 */
117MHD_PanicCallback mhd_panic;
118
119/**
120 * Closure argument for "mhd_panic".
121 */
122void *mhd_panic_cls;
123
124
125/**
126 * Trace up to and return master daemon. If the supplied daemon
127 * is a master, then return the daemon itself.
128 *
129 * @param daemon handle to a daemon
130 * @return master daemon handle
131 */
132static struct MHD_Daemon*
133MHD_get_master (struct MHD_Daemon *daemon)
134{
135 while (NULL != daemon->master)
136 daemon = daemon->master;
137 return daemon;
138}
139
140
141/**
142 * Maintain connection count for single address.
143 */
144struct MHD_IPCount
145{
146 /**
147 * Address family. AF_INET or AF_INET6 for now.
148 */
149 int family;
150
151 /**
152 * Actual address.
153 */
154 union
155 {
156 /**
157 * IPv4 address.
158 */
159 struct in_addr ipv4;
160#if HAVE_IPV6
161 /**
162 * IPv6 address.
163 */
164 struct in6_addr ipv6;
165#endif
166 } addr;
167
168 /**
169 * Counter.
170 */
171 unsigned int count;
172};
173
174
175/**
176 * Lock shared structure for IP connection counts and connection DLLs.
177 *
178 * @param daemon handle to daemon where lock is
179 */
180static void
181MHD_ip_count_lock(struct MHD_Daemon *daemon)
182{
183 if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
184 {
185 MHD_PANIC ("Failed to acquire IP connection limit mutex\n");
186 }
187}
188
189
190/**
191 * Unlock shared structure for IP connection counts and connection DLLs.
192 *
193 * @param daemon handle to daemon where lock is
194 */
195static void
196MHD_ip_count_unlock(struct MHD_Daemon *daemon)
197{
198 if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
199 {
200 MHD_PANIC ("Failed to release IP connection limit mutex\n");
201 }
202}
203
204
205/**
206 * Tree comparison function for IP addresses (supplied to tsearch() family).
207 * We compare everything in the struct up through the beginning of the
208 * 'count' field.
209 *
210 * @param a1 first address to compare
211 * @param a2 second address to compare
212 * @return -1, 0 or 1 depending on result of compare
213 */
214static int
215MHD_ip_addr_compare(const void *a1, const void *a2)
216{
217 return memcmp (a1, a2, offsetof (struct MHD_IPCount, count));
218}
219
220
221/**
222 * Parse address and initialize 'key' using the address.
223 *
224 * @param addr address to parse
225 * @param addrlen number of bytes in addr
226 * @param key where to store the parsed address
227 * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type)
228 */
229static int
230MHD_ip_addr_to_key(const struct sockaddr *addr,
231 socklen_t addrlen,
232 struct MHD_IPCount *key)
233{
234 memset(key, 0, sizeof(*key));
235
236 /* IPv4 addresses */
237 if (sizeof (struct sockaddr_in) == addrlen)
238 {
239 const struct sockaddr_in *addr4 = (const struct sockaddr_in*) addr;
240 key->family = AF_INET;
241 memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
242 return MHD_YES;
243 }
244
245#if HAVE_IPV6
246 /* IPv6 addresses */
247 if (sizeof (struct sockaddr_in6) == addrlen)
248 {
249 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*) addr;
250 key->family = AF_INET6;
251 memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
252 return MHD_YES;
253 }
254#endif
255
256 /* Some other address */
257 return MHD_NO;
258}
259
260
261/**
262 * Check if IP address is over its limit.
263 *
264 * @param daemon handle to daemon where connection counts are tracked
265 * @param addr address to add (or increment counter)
266 * @param addrlen number of bytes in addr
267 * @return Return MHD_YES if IP below limit, MHD_NO if IP has surpassed limit.
268 * Also returns MHD_NO if fails to allocate memory.
269 */
270static int
271MHD_ip_limit_add(struct MHD_Daemon *daemon,
272 const struct sockaddr *addr,
273 socklen_t addrlen)
274{
275 struct MHD_IPCount *key;
276 void **nodep;
277 void *node;
278 int result;
279
280 daemon = MHD_get_master (daemon);
281 /* Ignore if no connection limit assigned */
282 if (0 == daemon->per_ip_connection_limit)
283 return MHD_YES;
284
285 if (NULL == (key = malloc (sizeof(*key))))
286 return MHD_NO;
287
288 /* Initialize key */
289 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
290 {
291 /* Allow unhandled address types through */
292 free (key);
293 return MHD_YES;
294 }
295 MHD_ip_count_lock (daemon);
296
297 /* Search for the IP address */
298 if (NULL == (nodep = TSEARCH (key,
299 &daemon->per_ip_connection_count,
300 &MHD_ip_addr_compare)))
301 {
302#if HAVE_MESSAGES
303 MHD_DLOG (daemon,
304 "Failed to add IP connection count node\n");
305#endif
306 MHD_ip_count_unlock (daemon);
307 free (key);
308 return MHD_NO;
309 }
310 node = *nodep;
311 /* If we got an existing node back, free the one we created */
312 if (node != key)
313 free(key);
314 key = (struct MHD_IPCount *) node;
315 /* Test if there is room for another connection; if so,
316 * increment count */
317 result = (key->count < daemon->per_ip_connection_limit);
318 if (MHD_YES == result)
319 ++key->count;
320
321 MHD_ip_count_unlock (daemon);
322 return result;
323}
324
325
326/**
327 * Decrement connection count for IP address, removing from table
328 * count reaches 0
329 *
330 * @param daemon handle to daemon where connection counts are tracked
331 * @param addr address to remove (or decrement counter)
332 * @param addrlen number of bytes in addr
333 */
334static void
335MHD_ip_limit_del(struct MHD_Daemon *daemon,
336 const struct sockaddr *addr,
337 socklen_t addrlen)
338{
339 struct MHD_IPCount search_key;
340 struct MHD_IPCount *found_key;
341 void **nodep;
342
343 daemon = MHD_get_master (daemon);
344 /* Ignore if no connection limit assigned */
345 if (0 == daemon->per_ip_connection_limit)
346 return;
347 /* Initialize search key */
348 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
349 return;
350
351 MHD_ip_count_lock (daemon);
352
353 /* Search for the IP address */
354 if (NULL == (nodep = TFIND (&search_key,
355 &daemon->per_ip_connection_count,
356 &MHD_ip_addr_compare)))
357 {
358 /* Something's wrong if we couldn't find an IP address
359 * that was previously added */
360 MHD_PANIC ("Failed to find previously-added IP address\n");
361 }
362 found_key = (struct MHD_IPCount *) *nodep;
363 /* Validate existing count for IP address */
364 if (0 == found_key->count)
365 {
366 MHD_PANIC ("Previously-added IP address had 0 count\n");
367 }
368 /* Remove the node entirely if count reduces to 0 */
369 if (0 == --found_key->count)
370 {
371 TDELETE (found_key,
372 &daemon->per_ip_connection_count,
373 &MHD_ip_addr_compare);
374 free (found_key);
375 }
376
377 MHD_ip_count_unlock (daemon);
378}
379
380
381#if HTTPS_SUPPORT
382/**
383 * Callback for receiving data from the socket.
384 *
385 * @param connection the MHD connection structure
386 * @param other where to write received data to
387 * @param i maximum size of other (in bytes)
388 * @return number of bytes actually received
389 */
390static ssize_t
391recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
392{
393 int res;
394
395 connection->tls_read_ready = MHD_NO;
396 res = gnutls_record_recv (connection->tls_session, other, i);
397 if ( (GNUTLS_E_AGAIN == res) ||
398 (GNUTLS_E_INTERRUPTED == res) )
399 {
400 errno = EINTR;
401 return -1;
402 }
403 if (res < 0)
404 {
405 /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
406 disrupted); set errno to something caller will interpret
407 correctly as a hard error*/
408 errno = EPIPE;
409 return res;
410 }
411 if (res == i)
412 connection->tls_read_ready = MHD_YES;
413 return res;
414}
415
416
417/**
418 * Callback for writing data to the socket.
419 *
420 * @param connection the MHD connection structure
421 * @param other data to write
422 * @param i number of bytes to write
423 * @return actual number of bytes written
424 */
425static ssize_t
426send_tls_adapter (struct MHD_Connection *connection,
427 const void *other, size_t i)
428{
429 int res;
430
431 res = gnutls_record_send (connection->tls_session, other, i);
432 if ( (GNUTLS_E_AGAIN == res) ||
433 (GNUTLS_E_INTERRUPTED == res) )
434 {
435 errno = EINTR;
436 return -1;
437 }
438 return res;
439}
440
441
442/**
443 * Read and setup our certificate and key.
444 *
445 * @param daemon handle to daemon to initialize
446 * @return 0 on success
447 */
448static int
449MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
450{
451 gnutls_datum_t key;
452 gnutls_datum_t cert;
453
454 if (NULL != daemon->https_mem_trust)
455 {
456 cert.data = (unsigned char *) daemon->https_mem_trust;
457 cert.size = strlen (daemon->https_mem_trust);
458 if (gnutls_certificate_set_x509_trust_mem (daemon->x509_cred, &cert,
459 GNUTLS_X509_FMT_PEM) < 0)
460 {
461#if HAVE_MESSAGES
462 MHD_DLOG(daemon,
463 "Bad trust certificate format\n");
464#endif
465 return -1;
466 }
467 }
468
469 /* certificate & key loaded from memory */
470 if ( (NULL != daemon->https_mem_cert) &&
471 (NULL != daemon->https_mem_key) )
472 {
473 key.data = (unsigned char *) daemon->https_mem_key;
474 key.size = strlen (daemon->https_mem_key);
475 cert.data = (unsigned char *) daemon->https_mem_cert;
476 cert.size = strlen (daemon->https_mem_cert);
477
478 return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
479 &cert, &key,
480 GNUTLS_X509_FMT_PEM);
481 }
482#if HAVE_MESSAGES
483 MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
484#endif
485 return -1;
486}
487
488
489/**
490 * Initialize security aspects of the HTTPS daemon
491 *
492 * @param daemon handle to daemon to initialize
493 * @return 0 on success
494 */
495static int
496MHD_TLS_init (struct MHD_Daemon *daemon)
497{
498 switch (daemon->cred_type)
499 {
500 case GNUTLS_CRD_CERTIFICATE:
501 if (0 !=
502 gnutls_certificate_allocate_credentials (&daemon->x509_cred))
503 return GNUTLS_E_MEMORY_ERROR;
504 return MHD_init_daemon_certificate (daemon);
505 default:
506#if HAVE_MESSAGES
507 MHD_DLOG (daemon,
508 "Error: invalid credentials type %d specified.\n",
509 daemon->cred_type);
510#endif
511 return -1;
512 }
513}
514#endif
515
516
517/**
518 * Obtain the select sets for this daemon.
519 *
520 * @param daemon daemon to get sets from
521 * @param read_fd_set read set
522 * @param write_fd_set write set
523 * @param except_fd_set except set
524 * @param max_fd increased to largest FD added (if larger
525 * than existing value); can be NULL
526 * @return MHD_YES on success, MHD_NO if this
527 * daemon was not started with the right
528 * options for this call.
529 */
530int
531MHD_get_fdset (struct MHD_Daemon *daemon,
532 fd_set *read_fd_set,
533 fd_set *write_fd_set,
534 fd_set *except_fd_set,
535 int *max_fd)
536{
537 struct MHD_Connection *pos;
538 int fd;
539
540 if ( (NULL == daemon)
541 || (NULL == read_fd_set)
542 || (NULL == write_fd_set)
543 || (NULL == except_fd_set)
544 || (NULL == max_fd)
545 || (MHD_YES == daemon->shutdown)
546 || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
547 || (0 != (daemon->options & MHD_USE_POLL)))
548 return MHD_NO;
549 fd = daemon->socket_fd;
550 if (-1 != fd)
551 {
552 FD_SET (fd, read_fd_set);
553 /* update max file descriptor */
554 if ((*max_fd) < fd)
555 *max_fd = fd;
556 }
557 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
558 if (MHD_YES != MHD_connection_get_fdset (pos,
559 read_fd_set,
560 write_fd_set,
561 except_fd_set, max_fd))
562 return MHD_NO;
563#if DEBUG_CONNECT
564 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
565#endif
566 return MHD_YES;
567}
568
569
570/**
571 * Main function of the thread that handles an individual
572 * connection when MHD_USE_THREAD_PER_CONNECTION is set.
573 *
574 * @param data the 'struct MHD_Connection' this thread will handle
575 * @return always NULL
576 */
577static void *
578MHD_handle_connection (void *data)
579{
580 struct MHD_Connection *con = data;
581 int num_ready;
582 fd_set rs;
583 fd_set ws;
584 fd_set es;
585 int max;
586 struct timeval tv;
587 struct timeval *tvp;
588 unsigned int timeout;
589 time_t now;
590#ifdef HAVE_POLL_H
591 struct MHD_Pollfd mp;
592 struct pollfd p[1];
593#endif
594
595 timeout = con->daemon->connection_timeout;
596 while ( (MHD_YES != con->daemon->shutdown) &&
597 (MHD_CONNECTION_CLOSED != con->state) )
598 {
599 tvp = NULL;
600 if (timeout > 0)
601 {
602 now = MHD_monotonic_time();
603 if (now - con->last_activity > timeout)
604 tv.tv_sec = 0;
605 else
606 tv.tv_sec = timeout - (now - con->last_activity);
607 tv.tv_usec = 0;
608 tvp = &tv;
609 }
610 if ( (MHD_CONNECTION_NORMAL_BODY_UNREADY == con->state) ||
611 (MHD_CONNECTION_CHUNKED_BODY_UNREADY == con->state) )
612 {
613 /* do not block (we're waiting for our callback to succeed) */
614 tv.tv_sec = 0;
615 tv.tv_usec = 0;
616 tvp = &tv;
617 }
618#if HTTPS_SUPPORT
619 if (MHD_YES == con->tls_read_ready)
620 {
621 /* do not block (more data may be inside of TLS buffers waiting for us) */
622 tv.tv_sec = 0;
623 tv.tv_usec = 0;
624 tvp = &tv;
625 }
626#endif
627 if (0 == (con->daemon->options & MHD_USE_POLL))
628 {
629 /* use select */
630 FD_ZERO (&rs);
631 FD_ZERO (&ws);
632 FD_ZERO (&es);
633 max = 0;
634 MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
635 num_ready = SELECT (max + 1, &rs, &ws, &es, tvp);
636 if (num_ready < 0)
637 {
638 if (EINTR == errno)
639 continue;
640#if HAVE_MESSAGES
641 MHD_DLOG (con->daemon,
642 "Error during select (%d): `%s'\n",
643 max,
644 STRERROR (errno));
645#endif
646 break;
647 }
648 /* call appropriate connection handler if necessary */
649 if ( (FD_ISSET (con->socket_fd, &rs))
650#if HTTPS_SUPPORT
651 || (MHD_YES == con->tls_read_ready)
652#endif
653 )
654 con->read_handler (con);
655 if (FD_ISSET (con->socket_fd, &ws))
656 con->write_handler (con);
657 if (MHD_NO == con->idle_handler (con))
658 goto exit;
659 }
660#ifdef HAVE_POLL_H
661 else
662 {
663 /* use poll */
664 memset(&mp, 0, sizeof (struct MHD_Pollfd));
665 MHD_connection_get_pollfd(con, &mp);
666 memset(&p, 0, sizeof (p));
667 p[0].fd = mp.fd;
668 if (mp.events & MHD_POLL_ACTION_IN)
669 p[0].events |= POLLIN;
670 if (mp.events & MHD_POLL_ACTION_OUT)
671 p[0].events |= POLLOUT;
672 if (poll (p,
673 1,
674 (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0)
675 {
676 if (EINTR == errno)
677 continue;
678#if HAVE_MESSAGES
679 MHD_DLOG (con->daemon, "Error during poll: `%s'\n",
680 STRERROR (errno));
681#endif
682 break;
683 }
684 if ( (0 != (p[0].revents & POLLIN))
685#if HTTPS_SUPPORT
686 || (MHD_YES == con->tls_read_ready)
687#endif
688 )
689 con->read_handler (con);
690 if (0 != (p[0].revents & POLLOUT))
691 con->write_handler (con);
692 if (0 != (p[0].revents & (POLLERR | POLLHUP)))
693 MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR);
694 if (MHD_NO == con->idle_handler (con))
695 goto exit;
696 }
697#endif
698 }
699 if (MHD_CONNECTION_IN_CLEANUP != con->state)
700 {
701#if DEBUG_CLOSE
702#if HAVE_MESSAGES
703 MHD_DLOG (con->daemon,
704 "Processing thread terminating, closing connection\n");
705#endif
706#endif
707 if (MHD_CONNECTION_CLOSED != con->state)
708 MHD_connection_close (con,
709 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
710 con->idle_handler (con);
711 }
712exit:
713 if (NULL != con->response)
714 {
715 MHD_destroy_response (con->response);
716 con->response = NULL;
717 }
718 return NULL;
719}
720
721
722/**
723 * Callback for receiving data from the socket.
724 *
725 * @param connection the MHD connection structure
726 * @param other where to write received data to
727 * @param i maximum size of other (in bytes)
728 * @return number of bytes actually received
729 */
730static ssize_t
731recv_param_adapter (struct MHD_Connection *connection,
732 void *other,
733 size_t i)
734{
735 if ( (-1 == connection->socket_fd) ||
736 (MHD_CONNECTION_CLOSED == connection->state) )
737 {
738 errno = ENOTCONN;
739 return -1;
740 }
741 if (0 != (connection->daemon->options & MHD_USE_SSL))
742 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
743 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
744}
745
746
747/**
748 * Callback for writing data to the socket.
749 *
750 * @param connection the MHD connection structure
751 * @param other data to write
752 * @param i number of bytes to write
753 * @return actual number of bytes written
754 */
755static ssize_t
756send_param_adapter (struct MHD_Connection *connection,
757 const void *other,
758 size_t i)
759{
760#if LINUX
761 int fd;
762 off_t offset;
763 off_t left;
764 ssize_t ret;
765#endif
766 if ( (-1 == connection->socket_fd) ||
767 (MHD_CONNECTION_CLOSED == connection->state) )
768 {
769 errno = ENOTCONN;
770 return -1;
771 }
772 if (0 != (connection->daemon->options & MHD_USE_SSL))
773 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
774#if LINUX
775 if ( (connection->write_buffer_append_offset ==
776 connection->write_buffer_send_offset) &&
777 (NULL != connection->response) &&
778 (-1 != (fd = connection->response->fd)) )
779 {
780 /* can use sendfile */
781 offset = (off_t) connection->response_write_position + connection->response->fd_off;
782 left = connection->response->total_size - connection->response_write_position;
783 if (left > SSIZE_MAX)
784 left = SSIZE_MAX; /* cap at return value limit */
785 if (-1 != (ret = sendfile (connection->socket_fd,
786 fd,
787 &offset,
788 (size_t) left)))
789 return ret;
790 if ( (EINTR == errno) || (EAGAIN == errno) )
791 return 0;
792 if ( (EINVAL == errno) || (EBADF == errno) )
793 return -1;
794 /* None of the 'usual' sendfile errors occurred, so we should try
795 to fall back to 'SEND'; see also this thread for info on
796 odd libc/Linux behavior with sendfile:
797 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
798 }
799#endif
800 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
801}
802
803
804/**
805 * Signature of main function for a thread.
806 *
807 * @param cls closure argument for the function
808 * @return termination code from the thread
809 */
810typedef void *(*ThreadStartRoutine)(void *cls);
811
812
813/**
814 * Create a thread and set the attributes according to our options.
815 *
816 * @param thread handle to initialize
817 * @param daemon daemon with options
818 * @param start_routine main function of thread
819 * @param arg argument for start_routine
820 * @return 0 on success
821 */
822static int
823create_thread (pthread_t *thread,
824 const struct MHD_Daemon *daemon,
825 ThreadStartRoutine start_routine,
826 void *arg)
827{
828 pthread_attr_t attr;
829 pthread_attr_t *pattr;
830 int ret;
831
832 if (0 != daemon->thread_stack_size)
833 {
834 if (0 != (ret = pthread_attr_init (&attr)))
835 goto ERR;
836 if (0 != (ret = pthread_attr_setstacksize (&attr, daemon->thread_stack_size)))
837 {
838 pthread_attr_destroy (&attr);
839 goto ERR;
840 }
841 pattr = &attr;
842 }
843 else
844 {
845 pattr = NULL;
846 }
847 ret = pthread_create (thread, pattr,
848 start_routine, arg);
849 if (0 != daemon->thread_stack_size)
850 pthread_attr_destroy (&attr);
851 return ret;
852 ERR:
853#if HAVE_MESSAGES
854 MHD_DLOG (daemon,
855 "Failed to set thread stack size\n");
856#endif
857 errno = EINVAL;
858 return ret;
859}
860
861
862/**
863 * Add another client connection to the set of connections
864 * managed by MHD. This API is usually not needed (since
865 * MHD will accept inbound connections on the server socket).
866 * Use this API in special cases, for example if your HTTP
867 * server is behind NAT and needs to connect out to the
868 * HTTP client.
869 *
870 * The given client socket will be managed (and closed!) by MHD after
871 * this call and must no longer be used directly by the application
872 * afterwards.
873 *
874 * Per-IP connection limits are ignored when using this API.
875 *
876 * @param daemon daemon that manages the connection
877 * @param client_socket socket to manage (MHD will expect
878 * to receive an HTTP request from this socket next).
879 * @param addr IP address of the client
880 * @param addrlen number of bytes in addr
881 * @return MHD_YES on success, MHD_NO if this daemon could
882 * not handle the connection (i.e. malloc failed, etc).
883 * The socket will be closed in any case.
884 */
885int
886MHD_add_connection (struct MHD_Daemon *daemon,
887 int client_socket,
888 const struct sockaddr *addr,
889 socklen_t addrlen)
890{
891 struct MHD_Connection *connection;
892 int res_thread_create;
893#if OSX
894 static int on = 1;
895#endif
896
897#ifndef WINDOWS
898 if ( (client_socket >= FD_SETSIZE) &&
899 (0 == (daemon->options & MHD_USE_POLL)) )
900 {
901#if HAVE_MESSAGES
902 MHD_DLOG (daemon,
903 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
904 client_socket,
905 FD_SETSIZE);
906#endif
907 SHUTDOWN (client_socket, SHUT_RDWR);
908 CLOSE (client_socket);
909 return MHD_NO;
910 }
911#endif
912
913
914#if HAVE_MESSAGES
915#if DEBUG_CONNECT
916 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
917#endif
918#endif
919 if ( (0 == daemon->max_connections) ||
920 (MHD_NO == MHD_ip_limit_add (daemon, addr, addrlen)) )
921 {
922 /* above connection limit - reject */
923#if HAVE_MESSAGES
924 MHD_DLOG (daemon,
925 "Server reached connection limit (closing inbound connection)\n");
926#endif
927 SHUTDOWN (client_socket, SHUT_RDWR);
928 CLOSE (client_socket);
929 return MHD_NO;
930 }
931
932 /* apply connection acceptance policy if present */
933 if ( (NULL != daemon->apc) &&
934 (MHD_NO == daemon->apc (daemon->apc_cls,
935 addr, addrlen)) )
936 {
937#if DEBUG_CLOSE
938#if HAVE_MESSAGES
939 MHD_DLOG (daemon, "Connection rejected, closing connection\n");
940#endif
941#endif
942 SHUTDOWN (client_socket, SHUT_RDWR);
943 CLOSE (client_socket);
944 MHD_ip_limit_del (daemon, addr, addrlen);
945 return MHD_YES;
946 }
947
948#if OSX
949#ifdef SOL_SOCKET
950#ifdef SO_NOSIGPIPE
951 setsockopt (client_socket,
952 SOL_SOCKET, SO_NOSIGPIPE,
953 &on, sizeof (on));
954#endif
955#endif
956#endif
957
958 if (NULL == (connection = malloc (sizeof (struct MHD_Connection))))
959 {
960#if HAVE_MESSAGES
961 MHD_DLOG (daemon,
962 "Error allocating memory: %s\n",
963 STRERROR (errno));
964#endif
965 SHUTDOWN (client_socket, SHUT_RDWR);
966 CLOSE (client_socket);
967 MHD_ip_limit_del (daemon, addr, addrlen);
968 return MHD_NO;
969 }
970 memset (connection, 0, sizeof (struct MHD_Connection));
971 connection->connection_timeout = daemon->connection_timeout;
972 connection->pool = NULL;
973 if (NULL == (connection->addr = malloc (addrlen)))
974 {
975#if HAVE_MESSAGES
976 MHD_DLOG (daemon,
977 "Error allocating memory: %s\n",
978 STRERROR (errno));
979#endif
980 SHUTDOWN (client_socket, SHUT_RDWR);
981 CLOSE (client_socket);
982 MHD_ip_limit_del (daemon, addr, addrlen);
983 free (connection);
984 return MHD_NO;
985 }
986 memcpy (connection->addr, addr, addrlen);
987 connection->addr_len = addrlen;
988 connection->socket_fd = client_socket;
989 connection->daemon = daemon;
990 connection->last_activity = MHD_monotonic_time();
991
992 /* set default connection handlers */
993 MHD_set_http_callbacks_ (connection);
994 connection->recv_cls = &recv_param_adapter;
995 connection->send_cls = &send_param_adapter;
996 /* non-blocking sockets are required on most systems and for GNUtls;
997 however, they somehow cause serious problems on CYGWIN (#1824) */
998#ifdef CYGWIN
999 if (0 != (daemon->options & MHD_USE_SSL))
1000#endif
1001 {
1002 /* make socket non-blocking */
1003#ifndef MINGW
1004 int flags = fcntl (connection->socket_fd, F_GETFL);
1005 if ( (-1 == flags) ||
1006 (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) )
1007 {
1008#if HAVE_MESSAGES
1009 MHD_DLOG (daemon,
1010 "Failed to make socket %d non-blocking: %s\n",
1011 connection->socket_fd,
1012 STRERROR (errno));
1013#endif
1014 }
1015#else
1016 unsigned long flags = 1;
1017 if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags))
1018 {
1019#if HAVE_MESSAGES
1020 MHD_DLOG (daemon,
1021 "Failed to make socket non-blocking: %s\n",
1022 STRERROR (errno));
1023#endif
1024 }
1025#endif
1026 }
1027
1028#if HTTPS_SUPPORT
1029 if (0 != (daemon->options & MHD_USE_SSL))
1030 {
1031 connection->recv_cls = &recv_tls_adapter;
1032 connection->send_cls = &send_tls_adapter;
1033 connection->state = MHD_TLS_CONNECTION_INIT;
1034 MHD_set_https_callbacks (connection);
1035 gnutls_init (&connection->tls_session, GNUTLS_SERVER);
1036 gnutls_priority_set (connection->tls_session,
1037 daemon->priority_cache);
1038 switch (daemon->cred_type)
1039 {
1040 /* set needed credentials for certificate authentication. */
1041 case GNUTLS_CRD_CERTIFICATE:
1042 gnutls_credentials_set (connection->tls_session,
1043 GNUTLS_CRD_CERTIFICATE,
1044 daemon->x509_cred);
1045 break;
1046 default:
1047#if HAVE_MESSAGES
1048 MHD_DLOG (connection->daemon,
1049 "Failed to setup TLS credentials: unknown credential type %d\n",
1050 daemon->cred_type);
1051#endif
1052 SHUTDOWN (client_socket, SHUT_RDWR);
1053 CLOSE (client_socket);
1054 MHD_ip_limit_del (daemon, addr, addrlen);
1055 free (connection->addr);
1056 free (connection);
1057 MHD_PANIC ("Unknown credential type");
1058 return MHD_NO;
1059 }
1060 gnutls_transport_set_ptr (connection->tls_session,
1061 (gnutls_transport_ptr_t) connection);
1062 gnutls_transport_set_pull_function (connection->tls_session,
1063 (gnutls_pull_func) &recv_param_adapter);
1064 gnutls_transport_set_push_function (connection->tls_session,
1065 (gnutls_push_func) &send_param_adapter);
1066
1067 if (daemon->https_mem_trust)
1068 gnutls_certificate_server_set_request(connection->tls_session, GNUTLS_CERT_REQUEST);
1069 }
1070#endif
1071
1072 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
1073 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1074 DLL_insert (daemon->connections_head,
1075 daemon->connections_tail,
1076 connection);
1077 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
1078 MHD_PANIC ("Failed to release cleanup mutex\n");
1079
1080 /* attempt to create handler thread */
1081 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1082 {
1083 res_thread_create = create_thread (&connection->pid, daemon,
1084 &MHD_handle_connection, connection);
1085 if (0 != res_thread_create)
1086 {
1087#if HAVE_MESSAGES
1088 MHD_DLOG (daemon, "Failed to create a thread: %s\n",
1089 STRERROR (res_thread_create));
1090#endif
1091 SHUTDOWN (client_socket, SHUT_RDWR);
1092 CLOSE (client_socket);
1093 MHD_ip_limit_del (daemon, addr, addrlen);
1094 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
1095 {
1096 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1097 }
1098 DLL_remove (daemon->connections_head,
1099 daemon->connections_tail,
1100 connection);
1101 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
1102 {
1103 MHD_PANIC ("Failed to release cleanup mutex\n");
1104 }
1105 free (connection->addr);
1106 free (connection);
1107 return MHD_NO;
1108 }
1109 }
1110 daemon->max_connections--;
1111 return MHD_YES;
1112}
1113
1114
1115/**
1116 * Accept an incoming connection and create the MHD_Connection object for
1117 * it. This function also enforces policy by way of checking with the
1118 * accept policy callback.
1119 *
1120 * @param daemon handle with the listen socket
1121 * @return MHD_YES on success
1122 */
1123static int
1124MHD_accept_connection (struct MHD_Daemon *daemon)
1125{
1126#if HAVE_INET6
1127 struct sockaddr_in6 addrstorage;
1128#else
1129 struct sockaddr_in addrstorage;
1130#endif
1131 struct sockaddr *addr = (struct sockaddr *) &addrstorage;
1132 socklen_t addrlen;
1133 int s;
1134 int flags;
1135 int need_fcntl;
1136 int fd;
1137
1138 addrlen = sizeof (addrstorage);
1139 memset (addr, 0, sizeof (addrstorage));
1140 if (-1 == (fd = daemon->socket_fd))
1141 return MHD_NO;
1142#if HAVE_ACCEPT4
1143 s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC);
1144 need_fcntl = MHD_NO;
1145#else
1146 s = -1;
1147 need_fcntl = MHD_YES;
1148#endif
1149 if (-1 == s)
1150 {
1151 s = ACCEPT (fd, addr, &addrlen);
1152 need_fcntl = MHD_YES;
1153 }
1154 if ((-1 == s) || (addrlen <= 0))
1155 {
1156#if HAVE_MESSAGES
1157 /* This could be a common occurance with multiple worker threads */
1158 if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
1159 MHD_DLOG (daemon,
1160 "Error accepting connection: %s\n",
1161 STRERROR (errno));
1162#endif
1163 if (-1 != s)
1164 {
1165 SHUTDOWN (s, SHUT_RDWR);
1166 CLOSE (s);
1167 /* just in case */
1168 }
1169 return MHD_NO;
1170 }
1171 if (MHD_YES == need_fcntl)
1172 {
1173 /* make socket non-inheritable */
1174#ifdef WINDOWS
1175 DWORD dwFlags;
1176 if (!GetHandleInformation ((HANDLE) s, &dwFlags) ||
1177 ((dwFlags != dwFlags & ~HANDLE_FLAG_INHERIT) &&
1178 !SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0)))
1179 {
1180#if HAVE_MESSAGES
1181 SetErrnoFromWinError (GetLastError ());
1182 MHD_DLOG (daemon,
1183 "Failed to make socket non-inheritable: %s\n",
1184 STRERROR (errno));
1185#endif
1186 }
1187#else
1188 flags = fcntl (s, F_GETFD);
1189 if ( ( (-1 == flags) ||
1190 ( (flags != (flags | FD_CLOEXEC)) &&
1191 (0 != fcntl (s, F_SETFD, flags | FD_CLOEXEC)) ) ) )
1192 {
1193#if HAVE_MESSAGES
1194 MHD_DLOG (daemon,
1195 "Failed to make socket non-inheritable: %s\n",
1196 STRERROR (errno));
1197#endif
1198 }
1199#endif
1200 }
1201#if HAVE_MESSAGES
1202#if DEBUG_CONNECT
1203 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
1204#endif
1205#endif
1206 return MHD_add_connection (daemon, s,
1207 addr, addrlen);
1208}
1209
1210
1211/**
1212 * Free resources associated with all closed connections.
1213 * (destroy responses, free buffers, etc.). All closed
1214 * connections are kept in the "cleanup" doubly-linked list.
1215 *
1216 * @param daemon daemon to clean up
1217 */
1218static void
1219MHD_cleanup_connections (struct MHD_Daemon *daemon)
1220{
1221 struct MHD_Connection *pos;
1222 void *unused;
1223 int rc;
1224
1225 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
1226 {
1227 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1228 }
1229 while (NULL != (pos = daemon->cleanup_head))
1230 {
1231 DLL_remove (daemon->cleanup_head,
1232 daemon->cleanup_tail,
1233 pos);
1234 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1235 (MHD_NO == pos->thread_joined) )
1236 {
1237 if (0 != (rc = pthread_join (pos->pid, &unused)))
1238 {
1239 MHD_PANIC ("Failed to join a thread\n");
1240 }
1241 }
1242 MHD_pool_destroy (pos->pool);
1243#if HTTPS_SUPPORT
1244 if (pos->tls_session != NULL)
1245 gnutls_deinit (pos->tls_session);
1246#endif
1247 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
1248 if (NULL != pos->response)
1249 {
1250 MHD_destroy_response (pos->response);
1251 pos->response = NULL;
1252 }
1253 if (-1 != pos->socket_fd)
1254 CLOSE (pos->socket_fd);
1255 if (NULL != pos->addr)
1256 free (pos->addr);
1257 free (pos);
1258 daemon->max_connections++;
1259 }
1260 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
1261 {
1262 MHD_PANIC ("Failed to release cleanup mutex\n");
1263 }
1264}
1265
1266
1267/**
1268 * Obtain timeout value for select for this daemon
1269 * (only needed if connection timeout is used). The
1270 * returned value is how long select should at most
1271 * block, not the timeout value set for connections.
1272 *
1273 * @param daemon daemon to query for timeout
1274 * @param timeout set to the timeout (in milliseconds)
1275 * @return MHD_YES on success, MHD_NO if timeouts are
1276 * not used (or no connections exist that would
1277 * necessiate the use of a timeout right now).
1278 */
1279int
1280MHD_get_timeout (struct MHD_Daemon *daemon,
1281 MHD_UNSIGNED_LONG_LONG *timeout)
1282{
1283 time_t earliest_deadline;
1284 time_t now;
1285 struct MHD_Connection *pos;
1286 int have_timeout;
1287
1288 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1289 {
1290#if HAVE_MESSAGES
1291 MHD_DLOG (daemon, "Illegal call to MHD_get_timeout\n");
1292#endif
1293 return MHD_NO;
1294 }
1295 have_timeout = MHD_NO;
1296 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
1297 {
1298#if HTTPS_SUPPORT
1299 if (MHD_YES == pos->tls_read_ready)
1300 {
1301 earliest_deadline = 0;
1302 have_timeout = MHD_YES;
1303 break;
1304 }
1305#endif
1306 if (0 != pos->connection_timeout)
1307 {
1308 if ( (! have_timeout) ||
1309 (earliest_deadline > pos->last_activity + pos->connection_timeout) )
1310 earliest_deadline = pos->last_activity + pos->connection_timeout;
1311#if HTTPS_SUPPORT
1312 if ( (0 != (daemon->options & MHD_USE_SSL)) &&
1313 (0 != gnutls_record_check_pending (pos->tls_session)) )
1314 earliest_deadline = 0;
1315#endif
1316 have_timeout = MHD_YES;
1317 }
1318 }
1319 if (MHD_NO == have_timeout)
1320 return MHD_NO;
1321 now = MHD_monotonic_time();
1322 if (earliest_deadline < now)
1323 *timeout = 0;
1324 else
1325 *timeout = 1000 * (1 + earliest_deadline - now);
1326 return MHD_YES;
1327}
1328
1329
1330/**
1331 * Run webserver operations. This method should be called by clients
1332 * in combination with MHD_get_fdset if the client-controlled select
1333 * method is used.
1334 *
1335 * You can use this function instead of "MHD_run" if you called
1336 * 'select' on the result from "MHD_get_fdset". File descriptors in
1337 * the sets that are not controlled by MHD will be ignored. Calling
1338 * this function instead of "MHD_run" is more efficient as MHD will
1339 * not have to call 'select' again to determine which operations are
1340 * ready.
1341 *
1342 * @param daemon daemon to run select loop for
1343 * @param read_fd_set read set
1344 * @param write_fd_set write set
1345 * @param except_fd_set except set (not used, can be NULL)
1346 * @return MHD_NO on serious errors, MHD_YES on success
1347 */
1348int
1349MHD_run_from_select (struct MHD_Daemon *daemon,
1350 const fd_set *read_fd_set,
1351 const fd_set *write_fd_set,
1352 const fd_set *except_fd_set)
1353{
1354 int ds;
1355 int tmp;
1356 struct MHD_Connection *pos;
1357 struct MHD_Connection *next;
1358
1359 /* select connection thread handling type */
1360 if ( (-1 != (ds = daemon->socket_fd)) &&
1361 (FD_ISSET (ds, read_fd_set)) )
1362 MHD_accept_connection (daemon);
1363 /* drain signaling pipe to avoid spinning select */
1364 if ( (-1 != daemon->wpipe[0]) &&
1365 (FD_ISSET (daemon->wpipe[0], read_fd_set)) )
1366 (void) read (daemon->wpipe[0], &tmp, sizeof (tmp));
1367
1368 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1369 {
1370 /* do not have a thread per connection, process all connections now */
1371 next = daemon->connections_head;
1372 while (NULL != (pos = next))
1373 {
1374 next = pos->next;
1375 ds = pos->socket_fd;
1376 if (ds != -1)
1377 {
1378 if ( (FD_ISSET (ds, read_fd_set))
1379#if HTTPS_SUPPORT
1380 || (MHD_YES == pos->tls_read_ready)
1381#endif
1382 )
1383 pos->read_handler (pos);
1384 if (FD_ISSET (ds, write_fd_set))
1385 pos->write_handler (pos);
1386 pos->idle_handler (pos);
1387 }
1388 }
1389 }
1390 return MHD_YES;
1391}
1392
1393
1394/**
1395 * Main internal select call. Will compute select sets, call 'select'
1396 * and then MHD_run_from_select with the result.
1397 *
1398 * @param daemon daemon to run select loop for
1399 * @param may_block YES if blocking, NO if non-blocking
1400 * @return MHD_NO on serious errors, MHD_YES on success
1401 */
1402static int
1403MHD_select (struct MHD_Daemon *daemon,
1404 int may_block)
1405{
1406 int num_ready;
1407 fd_set rs;
1408 fd_set ws;
1409 fd_set es;
1410 int max;
1411 struct timeval timeout;
1412 struct timeval *tv;
1413 MHD_UNSIGNED_LONG_LONG ltimeout;
1414
1415 timeout.tv_sec = 0;
1416 timeout.tv_usec = 0;
1417 if (MHD_YES == daemon->shutdown)
1418 return MHD_NO;
1419 FD_ZERO (&rs);
1420 FD_ZERO (&ws);
1421 FD_ZERO (&es);
1422 max = -1;
1423 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1424 {
1425 /* single-threaded, go over everything */
1426 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
1427 return MHD_NO;
1428
1429 /* If we're at the connection limit, no need to
1430 accept new connections. */
1431 if ( (0 == daemon->max_connections) &&
1432 (-1 != daemon->socket_fd) )
1433 FD_CLR (daemon->socket_fd, &rs);
1434 }
1435 else
1436 {
1437 /* accept only, have one thread per connection */
1438 if (-1 != daemon->socket_fd)
1439 {
1440 max = daemon->socket_fd;
1441 FD_SET (daemon->socket_fd, &rs);
1442 }
1443 }
1444 if (-1 != daemon->wpipe[0])
1445 {
1446 FD_SET (daemon->wpipe[0], &rs);
1447 /* update max file descriptor */
1448 if (max < daemon->wpipe[0])
1449 max = daemon->wpipe[0];
1450 }
1451
1452 tv = NULL;
1453 if (MHD_NO == may_block)
1454 {
1455 timeout.tv_usec = 0;
1456 timeout.tv_sec = 0;
1457 tv = &timeout;
1458 }
1459 else if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1460 (MHD_YES == MHD_get_timeout (daemon, &ltimeout)) )
1461 {
1462 /* ltimeout is in ms */
1463 timeout.tv_usec = (ltimeout % 1000) * 1000;
1464 timeout.tv_sec = ltimeout / 1000;
1465 tv = &timeout;
1466 }
1467 if (-1 == max)
1468 return MHD_YES;
1469 num_ready = SELECT (max + 1, &rs, &ws, &es, tv);
1470 if (MHD_YES == daemon->shutdown)
1471 return MHD_NO;
1472 if (num_ready < 0)
1473 {
1474 if (EINTR == errno)
1475 return MHD_YES;
1476#if HAVE_MESSAGES
1477 MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
1478#endif
1479 return MHD_NO;
1480 }
1481 return MHD_run_from_select (daemon, &rs, &ws, &es);
1482}
1483
1484
1485#ifdef HAVE_POLL_H
1486/**
1487 * Process all of our connections and possibly the server
1488 * socket using 'poll'.
1489 *
1490 * @param daemon daemon to run poll loop for
1491 * @param may_block YES if blocking, NO if non-blocking
1492 * @return MHD_NO on serious errors, MHD_YES on success
1493 */
1494static int
1495MHD_poll_all (struct MHD_Daemon *daemon,
1496 int may_block)
1497{
1498 unsigned int num_connections;
1499 struct MHD_Connection *pos;
1500 struct MHD_Connection *next;
1501
1502 /* count number of connections and thus determine poll set size */
1503 num_connections = 0;
1504 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
1505 num_connections++;
1506
1507 {
1508 struct pollfd p[2 + num_connections];
1509 struct MHD_Pollfd mp;
1510 MHD_UNSIGNED_LONG_LONG ltimeout;
1511 unsigned int i;
1512 int timeout;
1513 unsigned int poll_server;
1514 int poll_listen;
1515
1516 memset (p, 0, sizeof (p));
1517 poll_server = 0;
1518 poll_listen = -1;
1519 if ( (-1 != daemon->socket_fd) &&
1520 (0 != daemon->max_connections) )
1521 {
1522 /* only listen if we are not at the connection limit */
1523 p[poll_server].fd = daemon->socket_fd;
1524 p[poll_server].events = POLLIN;
1525 p[poll_server].revents = 0;
1526 poll_listen = (int) poll_server;
1527 poll_server++;
1528 }
1529 if (-1 != daemon->wpipe[0])
1530 {
1531 p[poll_server].fd = daemon->wpipe[0];
1532 p[poll_server].events = POLLIN;
1533 p[poll_server].revents = 0;
1534 poll_server++;
1535 }
1536 if (may_block == MHD_NO)
1537 timeout = 0;
1538 else if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1539 (MHD_YES != MHD_get_timeout (daemon, &ltimeout)) )
1540 timeout = -1;
1541 else
1542 timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
1543
1544 i = 0;
1545 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
1546 {
1547 memset(&mp, 0, sizeof (struct MHD_Pollfd));
1548 MHD_connection_get_pollfd (pos, &mp);
1549 p[poll_server+i].fd = mp.fd;
1550 if (mp.events & MHD_POLL_ACTION_IN)
1551 p[poll_server+i].events |= POLLIN;
1552 if (mp.events & MHD_POLL_ACTION_OUT)
1553 p[poll_server+i].events |= POLLOUT;
1554 i++;
1555 }
1556 if (0 == poll_server + num_connections)
1557 return MHD_YES;
1558 if (poll (p, poll_server + num_connections, timeout) < 0)
1559 {
1560 if (EINTR == errno)
1561 return MHD_YES;
1562#if HAVE_MESSAGES
1563 MHD_DLOG (daemon,
1564 "poll failed: %s\n",
1565 STRERROR (errno));
1566#endif
1567 return MHD_NO;
1568 }
1569 /* handle shutdown */
1570 if (MHD_YES == daemon->shutdown)
1571 return MHD_NO;
1572 i = 0;
1573 next = daemon->connections_head;
1574 while (NULL != (pos = next))
1575 {
1576 next = pos->next;
1577 /* first, sanity checks */
1578 if (i >= num_connections)
1579 break; /* connection list changed somehow, retry later ... */
1580 MHD_connection_get_pollfd (pos, &mp);
1581 if (p[poll_server+i].fd != mp.fd)
1582 break; /* fd mismatch, something else happened, retry later ... */
1583
1584 /* normal handling */
1585 if (0 != (p[poll_server+i].revents & POLLIN))
1586 pos->read_handler (pos);
1587 if (0 != (p[poll_server+i].revents & POLLOUT))
1588 pos->write_handler (pos);
1589 pos->idle_handler (pos);
1590 i++;
1591 }
1592 if ( (-1 != poll_listen) &&
1593 (0 != (p[poll_listen].revents & POLLIN)) )
1594 MHD_accept_connection (daemon);
1595 }
1596 return MHD_YES;
1597}
1598
1599
1600/**
1601 * Process only the listen socket using 'poll'.
1602 *
1603 * @param daemon daemon to run poll loop for
1604 * @param may_block YES if blocking, NO if non-blocking
1605 * @return MHD_NO on serious errors, MHD_YES on success
1606 */
1607static int
1608MHD_poll_listen_socket (struct MHD_Daemon *daemon,
1609 int may_block)
1610{
1611 struct pollfd p[2];
1612 int timeout;
1613 unsigned int poll_count;
1614 int poll_listen;
1615
1616 memset (&p, 0, sizeof (p));
1617 poll_count = 0;
1618 poll_listen = -1;
1619 if (-1 != daemon->socket_fd)
1620 {
1621 p[poll_count].fd = daemon->socket_fd;
1622 p[poll_count].events = POLLIN;
1623 p[poll_count].revents = 0;
1624 poll_listen = poll_count;
1625 poll_count++;
1626 }
1627 if (-1 != daemon->wpipe[0])
1628 {
1629 p[poll_count].fd = daemon->wpipe[0];
1630 p[poll_count].events = POLLIN;
1631 p[poll_count].revents = 0;
1632 poll_count++;
1633 }
1634 if (MHD_NO == may_block)
1635 timeout = 0;
1636 else
1637 timeout = -1;
1638 if (0 == poll_count)
1639 return MHD_YES;
1640 if (poll (p, poll_count, timeout) < 0)
1641 {
1642 if (EINTR == errno)
1643 return MHD_YES;
1644#if HAVE_MESSAGES
1645 MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno));
1646#endif
1647 return MHD_NO;
1648 }
1649 /* handle shutdown */
1650 if (MHD_YES == daemon->shutdown)
1651 return MHD_NO;
1652 if ( (-1 != poll_listen) &&
1653 (0 != (p[poll_listen].revents & POLLIN)) )
1654 MHD_accept_connection (daemon);
1655 return MHD_YES;
1656}
1657#endif
1658
1659
1660/**
1661 * Do 'poll'-based processing.
1662 *
1663 * @param daemon daemon to run poll loop for
1664 * @param may_block YES if blocking, NO if non-blocking
1665 * @return MHD_NO on serious errors, MHD_YES on success
1666 */
1667static int
1668MHD_poll (struct MHD_Daemon *daemon,
1669 int may_block)
1670{
1671#ifdef HAVE_POLL_H
1672 if (MHD_YES == daemon->shutdown)
1673 return MHD_NO;
1674 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1675 return MHD_poll_all (daemon, may_block);
1676 else
1677 return MHD_poll_listen_socket (daemon, may_block);
1678#else
1679 return MHD_NO;
1680#endif
1681}
1682
1683
1684/**
1685 * Run webserver operations (without blocking unless
1686 * in client callbacks). This method should be called
1687 * by clients in combination with MHD_get_fdset
1688 * if the client-controlled select method is used.
1689 *
1690 * This function will work for external 'poll' and 'select' mode.
1691 * However, if using external 'select' mode, you may want to
1692 * instead use 'MHD_run_from_select', as it is more efficient.
1693 *
1694 * @return MHD_YES on success, MHD_NO if this
1695 * daemon was not started with the right
1696 * options for this call.
1697 */
1698int
1699MHD_run (struct MHD_Daemon *daemon)
1700{
1701 if ( (MHD_YES == daemon->shutdown) ||
1702 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1703 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
1704 return MHD_NO;
1705 if (0 == (daemon->options & MHD_USE_POLL))
1706 MHD_select (daemon, MHD_NO);
1707 else
1708 MHD_poll (daemon, MHD_NO);
1709 MHD_cleanup_connections (daemon);
1710 return MHD_YES;
1711}
1712
1713
1714/**
1715 * Thread that runs the select loop until the daemon
1716 * is explicitly shut down.
1717 *
1718 * @param cls 'struct MHD_Deamon' to run select loop in a thread for
1719 * @return always NULL (on shutdown)
1720 */
1721static void *
1722MHD_select_thread (void *cls)
1723{
1724 struct MHD_Daemon *daemon = cls;
1725
1726 while (MHD_YES != daemon->shutdown)
1727 {
1728 if (0 == (daemon->options & MHD_USE_POLL))
1729 MHD_select (daemon, MHD_YES);
1730 else
1731 MHD_poll (daemon, MHD_YES);
1732 MHD_cleanup_connections (daemon);
1733 }
1734 return NULL;
1735}
1736
1737
1738/**
1739 * Start a webserver on the given port.
1740 *
1741 * @param flags combination of MHD_FLAG values
1742 * @param port port to bind to
1743 * @param apc callback to call to check which clients
1744 * will be allowed to connect
1745 * @param apc_cls extra argument to apc
1746 * @param dh default handler for all URIs
1747 * @param dh_cls extra argument to dh
1748 * @return NULL on error, handle to daemon on success
1749 */
1750struct MHD_Daemon *
1751MHD_start_daemon (unsigned int flags,
1752 uint16_t port,
1753 MHD_AcceptPolicyCallback apc,
1754 void *apc_cls,
1755 MHD_AccessHandlerCallback dh, void *dh_cls, ...)
1756{
1757 struct MHD_Daemon *daemon;
1758 va_list ap;
1759
1760 va_start (ap, dh_cls);
1761 daemon = MHD_start_daemon_va (flags, port, apc, apc_cls, dh, dh_cls, ap);
1762 va_end (ap);
1763 return daemon;
1764}
1765
1766
1767/**
1768 * Stop accepting connections from the listening socket. Allows
1769 * clients to continue processing, but stops accepting new
1770 * connections. Note that the caller is responsible for closing the
1771 * returned socket; however, if MHD is run using threads (anything but
1772 * external select mode), it must not be closed until AFTER
1773 * "MHD_stop_daemon" has been called (as it is theoretically possible
1774 * that an existing thread is still using it).
1775 *
1776 * @param daemon daemon to stop accepting new connections for
1777 * @return old listen socket on success, -1 if the daemon was
1778 * already not listening anymore
1779 */
1780int
1781MHD_quiesce_daemon (struct MHD_Daemon *daemon)
1782{
1783 unsigned int i;
1784 int ret;
1785
1786 ret = daemon->socket_fd;
1787 if (NULL != daemon->worker_pool)
1788 for (i = 0; i < daemon->worker_pool_size; i++)
1789 daemon->worker_pool[i].socket_fd = -1;
1790 daemon->socket_fd = -1;
1791 return ret;
1792}
1793
1794
1795/**
1796 * Signature of the MHD custom logger function.
1797 *
1798 * @param cls closure
1799 * @param format format string
1800 * @param va arguments to the format string (fprintf-style)
1801 */
1802typedef void (*VfprintfFunctionPointerType)(void *cls,
1803 const char *format,
1804 va_list va);
1805
1806
1807/**
1808 * Parse a list of options given as varargs.
1809 *
1810 * @param daemon the daemon to initialize
1811 * @param servaddr where to store the server's listen address
1812 * @param ap the options
1813 * @return MHD_YES on success, MHD_NO on error
1814 */
1815static int
1816parse_options_va (struct MHD_Daemon *daemon,
1817 const struct sockaddr **servaddr,
1818 va_list ap);
1819
1820
1821/**
1822 * Parse a list of options given as varargs.
1823 *
1824 * @param daemon the daemon to initialize
1825 * @param servaddr where to store the server's listen address
1826 * @param ... the options
1827 * @return MHD_YES on success, MHD_NO on error
1828 */
1829static int
1830parse_options (struct MHD_Daemon *daemon,
1831 const struct sockaddr **servaddr,
1832 ...)
1833{
1834 va_list ap;
1835 int ret;
1836
1837 va_start (ap, servaddr);
1838 ret = parse_options_va (daemon, servaddr, ap);
1839 va_end (ap);
1840 return ret;
1841}
1842
1843
1844/**
1845 * Parse a list of options given as varargs.
1846 *
1847 * @param daemon the daemon to initialize
1848 * @param servaddr where to store the server's listen address
1849 * @param ap the options
1850 * @return MHD_YES on success, MHD_NO on error
1851 */
1852static int
1853parse_options_va (struct MHD_Daemon *daemon,
1854 const struct sockaddr **servaddr,
1855 va_list ap)
1856{
1857 enum MHD_OPTION opt;
1858 struct MHD_OptionItem *oa;
1859 unsigned int i;
1860#if HTTPS_SUPPORT
1861 int ret;
1862 const char *pstr;
1863#endif
1864
1865 while (MHD_OPTION_END != (opt = (enum MHD_OPTION) va_arg (ap, int)))
1866 {
1867 switch (opt)
1868 {
1869 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
1870 daemon->pool_size = va_arg (ap, size_t);
1871 break;
1872 case MHD_OPTION_CONNECTION_LIMIT:
1873 daemon->max_connections = va_arg (ap, unsigned int);
1874 break;
1875 case MHD_OPTION_CONNECTION_TIMEOUT:
1876 daemon->connection_timeout = va_arg (ap, unsigned int);
1877 break;
1878 case MHD_OPTION_NOTIFY_COMPLETED:
1879 daemon->notify_completed =
1880 va_arg (ap, MHD_RequestCompletedCallback);
1881 daemon->notify_completed_cls = va_arg (ap, void *);
1882 break;
1883 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
1884 daemon->per_ip_connection_limit = va_arg (ap, unsigned int);
1885 break;
1886 case MHD_OPTION_SOCK_ADDR:
1887 *servaddr = va_arg (ap, const struct sockaddr *);
1888 break;
1889 case MHD_OPTION_URI_LOG_CALLBACK:
1890 daemon->uri_log_callback =
1891 va_arg (ap, LogCallback);
1892 daemon->uri_log_callback_cls = va_arg (ap, void *);
1893 break;
1894 case MHD_OPTION_THREAD_POOL_SIZE:
1895 daemon->worker_pool_size = va_arg (ap, unsigned int);
1896 if (daemon->worker_pool_size >= (SIZE_MAX / sizeof (struct MHD_Daemon)))
1897 {
1898#if HAVE_MESSAGES
1899 MHD_DLOG (daemon,
1900 "Specified thread pool size (%u) too big\n",
1901 daemon->worker_pool_size);
1902#endif
1903 return MHD_NO;
1904 }
1905 break;
1906#if HTTPS_SUPPORT
1907 case MHD_OPTION_HTTPS_MEM_KEY:
1908 if (0 != (daemon->options & MHD_USE_SSL))
1909 daemon->https_mem_key = va_arg (ap, const char *);
1910#if HAVE_MESSAGES
1911 else
1912 MHD_DLOG (daemon,
1913 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
1914 opt);
1915#endif
1916 break;
1917 case MHD_OPTION_HTTPS_MEM_CERT:
1918 if (0 != (daemon->options & MHD_USE_SSL))
1919 daemon->https_mem_cert = va_arg (ap, const char *);
1920#if HAVE_MESSAGES
1921 else
1922 MHD_DLOG (daemon,
1923 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
1924 opt);
1925#endif
1926 break;
1927 case MHD_OPTION_HTTPS_MEM_TRUST:
1928 if (0 != (daemon->options & MHD_USE_SSL))
1929 daemon->https_mem_trust = va_arg (ap, const char *);
1930#if HAVE_MESSAGES
1931 else
1932 MHD_DLOG (daemon,
1933 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
1934 opt);
1935#endif
1936 break;
1937 case MHD_OPTION_HTTPS_CRED_TYPE:
1938 daemon->cred_type = (gnutls_credentials_type_t) va_arg (ap, int);
1939 break;
1940 case MHD_OPTION_HTTPS_PRIORITIES:
1941 if (0 != (daemon->options & MHD_USE_SSL))
1942 {
1943 gnutls_priority_deinit (daemon->priority_cache);
1944 ret = gnutls_priority_init (&daemon->priority_cache,
1945 pstr = va_arg (ap, const char*),
1946 NULL);
1947 if (ret != GNUTLS_E_SUCCESS)
1948 {
1949#if HAVE_MESSAGES
1950 MHD_DLOG (daemon,
1951 "Setting priorities to `%s' failed: %s\n",
1952 pstr,
1953 gnutls_strerror (ret));
1954#endif
1955 daemon->priority_cache = NULL;
1956 return MHD_NO;
1957 }
1958 }
1959 break;
1960#endif
1961#ifdef DAUTH_SUPPORT
1962 case MHD_OPTION_DIGEST_AUTH_RANDOM:
1963 daemon->digest_auth_rand_size = va_arg (ap, size_t);
1964 daemon->digest_auth_random = va_arg (ap, const char *);
1965 break;
1966 case MHD_OPTION_NONCE_NC_SIZE:
1967 daemon->nonce_nc_size = va_arg (ap, unsigned int);
1968 break;
1969#endif
1970 case MHD_OPTION_LISTEN_SOCKET:
1971 daemon->socket_fd = va_arg (ap, int);
1972 break;
1973 case MHD_OPTION_EXTERNAL_LOGGER:
1974#if HAVE_MESSAGES
1975 daemon->custom_error_log =
1976 va_arg (ap, VfprintfFunctionPointerType);
1977 daemon->custom_error_log_cls = va_arg (ap, void *);
1978#else
1979 va_arg (ap, VfprintfFunctionPointerType);
1980 va_arg (ap, void *);
1981#endif
1982 break;
1983 case MHD_OPTION_THREAD_STACK_SIZE:
1984 daemon->thread_stack_size = va_arg (ap, size_t);
1985 break;
1986 case MHD_OPTION_ARRAY:
1987 oa = va_arg (ap, struct MHD_OptionItem*);
1988 i = 0;
1989 while (MHD_OPTION_END != (opt = oa[i].option))
1990 {
1991 switch (opt)
1992 {
1993 /* all options taking 'size_t' */
1994 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
1995 case MHD_OPTION_THREAD_STACK_SIZE:
1996 if (MHD_YES != parse_options (daemon,
1997 servaddr,
1998 opt,
1999 (size_t) oa[i].value,
2000 MHD_OPTION_END))
2001 return MHD_NO;
2002 break;
2003 /* all options taking 'unsigned int' */
2004 case MHD_OPTION_NONCE_NC_SIZE:
2005 case MHD_OPTION_CONNECTION_LIMIT:
2006 case MHD_OPTION_CONNECTION_TIMEOUT:
2007 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
2008 case MHD_OPTION_THREAD_POOL_SIZE:
2009 if (MHD_YES != parse_options (daemon,
2010 servaddr,
2011 opt,
2012 (unsigned int) oa[i].value,
2013 MHD_OPTION_END))
2014 return MHD_NO;
2015 break;
2016 /* all options taking 'int' or 'enum' */
2017 case MHD_OPTION_HTTPS_CRED_TYPE:
2018 case MHD_OPTION_LISTEN_SOCKET:
2019 if (MHD_YES != parse_options (daemon,
2020 servaddr,
2021 opt,
2022 (int) oa[i].value,
2023 MHD_OPTION_END))
2024 return MHD_NO;
2025 break;
2026 /* all options taking one pointer */
2027 case MHD_OPTION_SOCK_ADDR:
2028 case MHD_OPTION_HTTPS_MEM_KEY:
2029 case MHD_OPTION_HTTPS_MEM_CERT:
2030 case MHD_OPTION_HTTPS_MEM_TRUST:
2031 case MHD_OPTION_HTTPS_PRIORITIES:
2032 case MHD_OPTION_ARRAY:
2033 if (MHD_YES != parse_options (daemon,
2034 servaddr,
2035 opt,
2036 oa[i].ptr_value,
2037 MHD_OPTION_END))
2038 return MHD_NO;
2039 break;
2040 /* all options taking two pointers */
2041 case MHD_OPTION_NOTIFY_COMPLETED:
2042 case MHD_OPTION_URI_LOG_CALLBACK:
2043 case MHD_OPTION_EXTERNAL_LOGGER:
2044 case MHD_OPTION_UNESCAPE_CALLBACK:
2045 if (MHD_YES != parse_options (daemon,
2046 servaddr,
2047 opt,
2048 (void *) oa[i].value,
2049 oa[i].ptr_value,
2050 MHD_OPTION_END))
2051 return MHD_NO;
2052 break;
2053 /* options taking size_t-number followed by pointer */
2054 case MHD_OPTION_DIGEST_AUTH_RANDOM:
2055 if (MHD_YES != parse_options (daemon,
2056 servaddr,
2057 opt,
2058 (size_t) oa[i].value,
2059 oa[i].ptr_value,
2060 MHD_OPTION_END))
2061 return MHD_NO;
2062 break;
2063 default:
2064 return MHD_NO;
2065 }
2066 i++;
2067 }
2068 break;
2069 case MHD_OPTION_UNESCAPE_CALLBACK:
2070 daemon->unescape_callback =
2071 va_arg (ap, UnescapeCallback);
2072 daemon->unescape_callback_cls = va_arg (ap, void *);
2073 break;
2074 default:
2075#if HAVE_MESSAGES
2076 if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
2077 (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == MHD_OPTION_HTTPS_MEM_TRUST))
2078 {
2079 MHD_DLOG (daemon,
2080 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
2081 opt);
2082 }
2083 else
2084 {
2085 MHD_DLOG (daemon,
2086 "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
2087 opt);
2088 }
2089#endif
2090 return MHD_NO;
2091 }
2092 }
2093 return MHD_YES;
2094}
2095
2096
2097/**
2098 * Create a listen socket, if possible with CLOEXEC flag set.
2099 *
2100 * @param domain socket domain (i.e. PF_INET)
2101 * @param type socket type (usually SOCK_STREAM)
2102 * @param protocol desired protocol, 0 for default
2103 */
2104static int
2105create_socket (int domain, int type, int protocol)
2106{
2107 static int sock_cloexec = SOCK_CLOEXEC;
2108 int ctype = SOCK_STREAM | sock_cloexec;
2109 int fd;
2110 int flags;
2111#ifdef WINDOWS
2112 DWORD dwFlags;
2113#endif
2114
2115 /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
2116 * implementations do not set ai_socktype, e.g. RHL6.2. */
2117 fd = SOCKET (domain, ctype, protocol);
2118 if ( (-1 == fd) && (EINVAL == errno) && (0 != sock_cloexec) )
2119 {
2120 sock_cloexec = 0;
2121 fd = SOCKET(domain, type, protocol);
2122 }
2123 if (-1 == fd)
2124 return -1;
2125 if (0 != sock_cloexec)
2126 return fd; /* this is it */
2127 /* flag was not set during 'socket' call, let's try setting it manually */
2128#ifndef WINDOWS
2129 flags = fcntl (fd, F_GETFD);
2130 if (flags < 0)
2131#else
2132 if (!GetHandleInformation ((HANDLE) fd, &dwFlags))
2133#endif
2134 {
2135#ifdef WINDOWS
2136 SetErrnoFromWinError (GetLastError ());
2137#endif
2138 return fd; /* good luck */
2139 }
2140#ifndef WINDOWS
2141 if (flags == (flags | FD_CLOEXEC))
2142 return fd; /* already set */
2143 flags |= FD_CLOEXEC;
2144 if (0 != fcntl (fd, F_SETFD, flags))
2145#else
2146 if (dwFlags != (dwFlags | HANDLE_FLAG_INHERIT))
2147 return fd; /* already unset */
2148 if (!SetHandleInformation ((HANDLE) fd, HANDLE_FLAG_INHERIT, 0))
2149#endif
2150 {
2151#ifdef WINDOWS
2152 SetErrnoFromWinError (GetLastError ());
2153#endif
2154 return fd; /* good luck */
2155 }
2156 return fd;
2157}
2158
2159
2160/**
2161 * Start a webserver on the given port.
2162 *
2163 * @param flags combination of MHD_FLAG values
2164 * @param port port to bind to
2165 * @param apc callback to call to check which clients
2166 * will be allowed to connect
2167 * @param apc_cls extra argument to apc
2168 * @param dh default handler for all URIs
2169 * @param dh_cls extra argument to dh
2170 * @param ap list of options (type-value pairs,
2171 * terminated with MHD_OPTION_END).
2172 * @return NULL on error, handle to daemon on success
2173 */
2174struct MHD_Daemon *
2175MHD_start_daemon_va (unsigned int flags,
2176 uint16_t port,
2177 MHD_AcceptPolicyCallback apc,
2178 void *apc_cls,
2179 MHD_AccessHandlerCallback dh, void *dh_cls,
2180 va_list ap)
2181{
2182 const int on = 1;
2183 struct MHD_Daemon *daemon;
2184 int socket_fd;
2185 struct sockaddr_in servaddr4;
2186#if HAVE_INET6
2187 struct sockaddr_in6 servaddr6;
2188#endif
2189 const struct sockaddr *servaddr = NULL;
2190 socklen_t addrlen;
2191 unsigned int i;
2192 int res_thread_create;
2193 int use_pipe;
2194
2195#ifndef HAVE_INET6
2196 if (0 != (flags & MHD_USE_IPv6))
2197 return NULL;
2198#endif
2199#ifndef HAVE_POLL_H
2200 if (0 != (flags & MHD_USE_POLL))
2201 return NULL;
2202#endif
2203#if ! HTTPS_SUPPORT
2204 if (0 != (flags & MHD_USE_SSL))
2205 return NULL;
2206#endif
2207 if (NULL == dh)
2208 return NULL;
2209 if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon))))
2210 return NULL;
2211 memset (daemon, 0, sizeof (struct MHD_Daemon));
2212 /* try to open listen socket */
2213#if HTTPS_SUPPORT
2214 if (0 != (flags & MHD_USE_SSL))
2215 {
2216 gnutls_priority_init (&daemon->priority_cache,
2217 "NORMAL",
2218 NULL);
2219 }
2220#endif
2221 daemon->socket_fd = -1;
2222 daemon->options = (enum MHD_OPTION) flags;
2223 daemon->port = port;
2224 daemon->apc = apc;
2225 daemon->apc_cls = apc_cls;
2226 daemon->default_handler = dh;
2227 daemon->default_handler_cls = dh_cls;
2228 daemon->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
2229 daemon->pool_size = MHD_POOL_SIZE_DEFAULT;
2230 daemon->unescape_callback = &MHD_http_unescape;
2231 daemon->connection_timeout = 0; /* no timeout */
2232 daemon->wpipe[0] = -1;
2233 daemon->wpipe[1] = -1;
2234#if HAVE_MESSAGES
2235 daemon->custom_error_log = (MHD_LogCallback) &vfprintf;
2236 daemon->custom_error_log_cls = stderr;
2237#endif
2238#ifdef HAVE_LISTEN_SHUTDOWN
2239 use_pipe = (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET));
2240#else
2241 use_pipe = 1; /* yes, must use pipe to signal shutdown */
2242#endif
2243 if ( (use_pipe) &&
2244 (0 != PIPE (daemon->wpipe)) )
2245 {
2246#if HAVE_MESSAGES
2247 MHD_DLOG (daemon,
2248 "Failed to create control pipe: %s\n",
2249 STRERROR (errno));
2250#endif
2251 free (daemon);
2252 return NULL;
2253 }
2254#ifndef WINDOWS
2255 if ( (0 == (flags & MHD_USE_POLL)) &&
2256 (daemon->wpipe[0] >= FD_SETSIZE) )
2257 {
2258#if HAVE_MESSAGES
2259 MHD_DLOG (daemon,
2260 "file descriptor for control pipe exceeds maximum value\n");
2261#endif
2262 CLOSE (daemon->wpipe[0]);
2263 CLOSE (daemon->wpipe[1]);
2264 free (daemon);
2265 return NULL;
2266 }
2267#endif
2268#ifdef DAUTH_SUPPORT
2269 daemon->digest_auth_rand_size = 0;
2270 daemon->digest_auth_random = NULL;
2271 daemon->nonce_nc_size = 4; /* tiny */
2272#endif
2273#if HTTPS_SUPPORT
2274 if (0 != (flags & MHD_USE_SSL))
2275 {
2276 daemon->cred_type = GNUTLS_CRD_CERTIFICATE;
2277 }
2278#endif
2279
2280
2281 if (MHD_YES != parse_options_va (daemon, &servaddr, ap))
2282 {
2283#if HTTPS_SUPPORT
2284 if ( (0 != (flags & MHD_USE_SSL)) &&
2285 (NULL != daemon->priority_cache) )
2286 gnutls_priority_deinit (daemon->priority_cache);
2287#endif
2288 free (daemon);
2289 return NULL;
2290 }
2291#ifdef DAUTH_SUPPORT
2292 if (daemon->nonce_nc_size > 0)
2293 {
2294 if ( ( (size_t) (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc))) /
2295 sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size)
2296 {
2297#if HAVE_MESSAGES
2298 MHD_DLOG (daemon,
2299 "Specified value for NC_SIZE too large\n");
2300#endif
2301#if HTTPS_SUPPORT
2302 if (0 != (flags & MHD_USE_SSL))
2303 gnutls_priority_deinit (daemon->priority_cache);
2304#endif
2305 free (daemon);
2306 return NULL;
2307 }
2308 daemon->nnc = malloc (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc));
2309 if (NULL == daemon->nnc)
2310 {
2311#if HAVE_MESSAGES
2312 MHD_DLOG (daemon,
2313 "Failed to allocate memory for nonce-nc map: %s\n",
2314 STRERROR (errno));
2315#endif
2316#if HTTPS_SUPPORT
2317 if (0 != (flags & MHD_USE_SSL))
2318 gnutls_priority_deinit (daemon->priority_cache);
2319#endif
2320 free (daemon);
2321 return NULL;
2322 }
2323 }
2324
2325 if (0 != pthread_mutex_init (&daemon->nnc_lock, NULL))
2326 {
2327#if HAVE_MESSAGES
2328 MHD_DLOG (daemon,
2329 "MHD failed to initialize nonce-nc mutex\n");
2330#endif
2331#if HTTPS_SUPPORT
2332 if (0 != (flags & MHD_USE_SSL))
2333 gnutls_priority_deinit (daemon->priority_cache);
2334#endif
2335 free (daemon->nnc);
2336 free (daemon);
2337 return NULL;
2338 }
2339#endif
2340
2341 /* Thread pooling currently works only with internal select thread model */
2342 if ( (0 == (flags & MHD_USE_SELECT_INTERNALLY)) &&
2343 (daemon->worker_pool_size > 0) )
2344 {
2345#if HAVE_MESSAGES
2346 MHD_DLOG (daemon,
2347 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
2348#endif
2349 goto free_and_fail;
2350 }
2351
2352#ifdef __SYMBIAN32__
2353 if (0 != (flags & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION)))
2354 {
2355#if HAVE_MESSAGES
2356 MHD_DLOG (daemon,
2357 "Threaded operations are not supported on Symbian.\n");
2358#endif
2359 goto free_and_fail;
2360 }
2361#endif
2362 if ( (-1 == daemon->socket_fd) &&
2363 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
2364 {
2365 /* try to open listen socket */
2366 if ((flags & MHD_USE_IPv6) != 0)
2367 socket_fd = create_socket (PF_INET6, SOCK_STREAM, 0);
2368 else
2369 socket_fd = create_socket (PF_INET, SOCK_STREAM, 0);
2370 if (-1 == socket_fd)
2371 {
2372#if HAVE_MESSAGES
2373 if (0 != (flags & MHD_USE_DEBUG))
2374 MHD_DLOG (daemon,
2375 "Call to socket failed: %s\n",
2376 STRERROR (errno));
2377#endif
2378 goto free_and_fail;
2379 }
2380 if ((SETSOCKOPT (socket_fd,
2381 SOL_SOCKET,
2382 SO_REUSEADDR,
2383 &on, sizeof (on)) < 0) && ((flags & MHD_USE_DEBUG) != 0))
2384 {
2385#if HAVE_MESSAGES
2386 MHD_DLOG (daemon,
2387 "setsockopt failed: %s\n",
2388 STRERROR (errno));
2389#endif
2390 }
2391
2392 /* check for user supplied sockaddr */
2393#if HAVE_INET6
2394 if (0 != (flags & MHD_USE_IPv6))
2395 addrlen = sizeof (struct sockaddr_in6);
2396 else
2397#endif
2398 addrlen = sizeof (struct sockaddr_in);
2399 if (NULL == servaddr)
2400 {
2401#if HAVE_INET6
2402 if (0 != (flags & MHD_USE_IPv6))
2403 {
2404 memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
2405 servaddr6.sin6_family = AF_INET6;
2406 servaddr6.sin6_port = htons (port);
2407#if HAVE_SOCKADDR_IN_SIN_LEN
2408 servaddr6.sin6_len = sizeof (struct sockaddr_in6);
2409#endif
2410 servaddr = (struct sockaddr *) &servaddr6;
2411 }
2412 else
2413#endif
2414 {
2415 memset (&servaddr4, 0, sizeof (struct sockaddr_in));
2416 servaddr4.sin_family = AF_INET;
2417 servaddr4.sin_port = htons (port);
2418#if HAVE_SOCKADDR_IN_SIN_LEN
2419 servaddr4.sin_len = sizeof (struct sockaddr_in);
2420#endif
2421 servaddr = (struct sockaddr *) &servaddr4;
2422 }
2423 }
2424 daemon->socket_fd = socket_fd;
2425
2426 if (0 != (flags & MHD_USE_IPv6))
2427 {
2428#ifdef IPPROTO_IPV6
2429#ifdef IPV6_V6ONLY
2430 /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see "IPPROTO_IPV6 Socket Options"
2431 (http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx);
2432 and may also be missing on older POSIX systems; good luck if you have any of those,
2433 your IPv6 socket may then also bind against IPv4... */
2434#ifndef WINDOWS
2435 const int on = 1;
2436 setsockopt (socket_fd,
2437 IPPROTO_IPV6, IPV6_V6ONLY,
2438 &on, sizeof (on));
2439#else
2440 const char on = 1;
2441 setsockopt (socket_fd,
2442 IPPROTO_IPV6, IPV6_V6ONLY,
2443 &on, sizeof (on));
2444#endif
2445#endif
2446#endif
2447 }
2448 if (-1 == BIND (socket_fd, servaddr, addrlen))
2449 {
2450#if HAVE_MESSAGES
2451 if (0 != (flags & MHD_USE_DEBUG))
2452 MHD_DLOG (daemon,
2453 "Failed to bind to port %u: %s\n",
2454 (unsigned int) port,
2455 STRERROR (errno));
2456#endif
2457 CLOSE (socket_fd);
2458 goto free_and_fail;
2459 }
2460
2461 if (LISTEN (socket_fd, 20) < 0)
2462 {
2463#if HAVE_MESSAGES
2464 if (0 != (flags & MHD_USE_DEBUG))
2465 MHD_DLOG (daemon,
2466 "Failed to listen for connections: %s\n",
2467 STRERROR (errno));
2468#endif
2469 CLOSE (socket_fd);
2470 goto free_and_fail;
2471 }
2472 }
2473 else
2474 {
2475 socket_fd = daemon->socket_fd;
2476 }
2477#ifndef WINDOWS
2478 if ( (socket_fd >= FD_SETSIZE) &&
2479 (0 == (flags & MHD_USE_POLL)) )
2480 {
2481#if HAVE_MESSAGES
2482 if ((flags & MHD_USE_DEBUG) != 0)
2483 MHD_DLOG (daemon,
2484 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
2485 socket_fd,
2486 FD_SETSIZE);
2487#endif
2488 CLOSE (socket_fd);
2489 goto free_and_fail;
2490 }
2491#endif
2492
2493 if (0 != pthread_mutex_init (&daemon->per_ip_connection_mutex, NULL))
2494 {
2495#if HAVE_MESSAGES
2496 MHD_DLOG (daemon,
2497 "MHD failed to initialize IP connection limit mutex\n");
2498#endif
2499 if (-1 != socket_fd)
2500 CLOSE (socket_fd);
2501 goto free_and_fail;
2502 }
2503 if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL))
2504 {
2505#if HAVE_MESSAGES
2506 MHD_DLOG (daemon,
2507 "MHD failed to initialize IP connection limit mutex\n");
2508#endif
2509 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2510 if (-1 != socket_fd)
2511 CLOSE (socket_fd);
2512 goto free_and_fail;
2513 }
2514
2515#if HTTPS_SUPPORT
2516 /* initialize HTTPS daemon certificate aspects & send / recv functions */
2517 if ((0 != (flags & MHD_USE_SSL)) && (0 != MHD_TLS_init (daemon)))
2518 {
2519#if HAVE_MESSAGES
2520 MHD_DLOG (daemon,
2521 "Failed to initialize TLS support\n");
2522#endif
2523 if (-1 != socket_fd)
2524 CLOSE (socket_fd);
2525 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2526 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2527 goto free_and_fail;
2528 }
2529#endif
2530 if ( ( (0 != (flags & MHD_USE_THREAD_PER_CONNECTION)) ||
2531 ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) &&
2532 (0 == daemon->worker_pool_size)) ) &&
2533 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) &&
2534 (0 != (res_thread_create =
2535 create_thread (&daemon->pid, daemon, &MHD_select_thread, daemon))))
2536 {
2537#if HAVE_MESSAGES
2538 MHD_DLOG (daemon,
2539 "Failed to create listen thread: %s\n",
2540 STRERROR (res_thread_create));
2541#endif
2542 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2543 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2544 if (-1 != socket_fd)
2545 CLOSE (socket_fd);
2546 goto free_and_fail;
2547 }
2548 if ( (daemon->worker_pool_size > 0) &&
2549 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
2550 {
2551#ifndef MINGW
2552 int sk_flags;
2553#else
2554 unsigned long sk_flags;
2555#endif
2556
2557 /* Coarse-grained count of connections per thread (note error
2558 * due to integer division). Also keep track of how many
2559 * connections are leftover after an equal split. */
2560 unsigned int conns_per_thread = daemon->max_connections
2561 / daemon->worker_pool_size;
2562 unsigned int leftover_conns = daemon->max_connections
2563 % daemon->worker_pool_size;
2564
2565 i = 0; /* we need this in case fcntl or malloc fails */
2566
2567 /* Accept must be non-blocking. Multiple children may wake up
2568 * to handle a new connection, but only one will win the race.
2569 * The others must immediately return. */
2570#ifndef MINGW
2571 sk_flags = fcntl (socket_fd, F_GETFL);
2572 if (sk_flags < 0)
2573 goto thread_failed;
2574 if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
2575 goto thread_failed;
2576#else
2577 sk_flags = 1;
2578#if HAVE_PLIBC_FD
2579 if (SOCKET_ERROR ==
2580 ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags))
2581 goto thread_failed;
2582#else
2583 if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
2584 goto thread_failed;
2585#endif // PLIBC_FD
2586#endif // MINGW
2587
2588 /* Allocate memory for pooled objects */
2589 daemon->worker_pool = malloc (sizeof (struct MHD_Daemon)
2590 * daemon->worker_pool_size);
2591 if (NULL == daemon->worker_pool)
2592 goto thread_failed;
2593
2594 /* Start the workers in the pool */
2595 for (i = 0; i < daemon->worker_pool_size; ++i)
2596 {
2597 /* Create copy of the Daemon object for each worker */
2598 struct MHD_Daemon *d = &daemon->worker_pool[i];
2599 memcpy (d, daemon, sizeof (struct MHD_Daemon));
2600
2601 /* Adjust pooling params for worker daemons; note that memcpy()
2602 has already copied MHD_USE_SELECT_INTERNALLY thread model into
2603 the worker threads. */
2604 d->master = daemon;
2605 d->worker_pool_size = 0;
2606 d->worker_pool = NULL;
2607
2608 /* Divide available connections evenly amongst the threads.
2609 * Thread indexes in [0, leftover_conns) each get one of the
2610 * leftover connections. */
2611 d->max_connections = conns_per_thread;
2612 if (i < leftover_conns)
2613 ++d->max_connections;
2614
2615 /* Must init cleanup connection mutex for each worker */
2616 if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL))
2617 {
2618#if HAVE_MESSAGES
2619 MHD_DLOG (daemon,
2620 "MHD failed to initialize cleanup connection mutex for thread worker %d\n", i);
2621#endif
2622 goto thread_failed;
2623 }
2624
2625 /* Spawn the worker thread */
2626 if (0 != (res_thread_create = create_thread (&d->pid, daemon, &MHD_select_thread, d)))
2627 {
2628#if HAVE_MESSAGES
2629 MHD_DLOG (daemon,
2630 "Failed to create pool thread: %s\n",
2631 STRERROR (res_thread_create));
2632#endif
2633 /* Free memory for this worker; cleanup below handles
2634 * all previously-created workers. */
2635 pthread_mutex_destroy (&d->cleanup_connection_mutex);
2636 goto thread_failed;
2637 }
2638 }
2639 }
2640 return daemon;
2641
2642thread_failed:
2643 /* If no worker threads created, then shut down normally. Calling
2644 MHD_stop_daemon (as we do below) doesn't work here since it
2645 assumes a 0-sized thread pool means we had been in the default
2646 MHD_USE_SELECT_INTERNALLY mode. */
2647 if (0 == i)
2648 {
2649 if (-1 != socket_fd)
2650 CLOSE (socket_fd);
2651 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2652 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2653 if (NULL != daemon->worker_pool)
2654 free (daemon->worker_pool);
2655 goto free_and_fail;
2656 }
2657
2658 /* Shutdown worker threads we've already created. Pretend
2659 as though we had fully initialized our daemon, but
2660 with a smaller number of threads than had been
2661 requested. */
2662 daemon->worker_pool_size = i - 1;
2663 MHD_stop_daemon (daemon);
2664 return NULL;
2665
2666 free_and_fail:
2667 /* clean up basic memory state in 'daemon' and return NULL to
2668 indicate failure */
2669#ifdef DAUTH_SUPPORT
2670 free (daemon->nnc);
2671 pthread_mutex_destroy (&daemon->nnc_lock);
2672#endif
2673#if HTTPS_SUPPORT
2674 if (0 != (flags & MHD_USE_SSL))
2675 gnutls_priority_deinit (daemon->priority_cache);
2676#endif
2677 free (daemon);
2678 return NULL;
2679}
2680
2681
2682/**
2683 * Close all connections for the daemon; must only be called after
2684 * all of the threads have been joined and there is no more concurrent
2685 * activity on the connection lists.
2686 *
2687 * @param daemon daemon to close down
2688 */
2689static void
2690close_all_connections (struct MHD_Daemon *daemon)
2691{
2692 struct MHD_Connection *pos;
2693 void *unused;
2694 int rc;
2695
2696 /* first, make sure all threads are aware of shutdown; need to
2697 traverse DLLs in peace... */
2698 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
2699 {
2700 MHD_PANIC ("Failed to acquire cleanup mutex\n");
2701 }
2702 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
2703 SHUTDOWN (pos->socket_fd,
2704 (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
2705 if (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex))
2706 {
2707 MHD_PANIC ("Failed to release cleanup mutex\n");
2708 }
2709
2710 /* now, collect threads */
2711 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
2712 {
2713 while (NULL != (pos = daemon->connections_head))
2714 {
2715 if (0 != (rc = pthread_join (pos->pid, &unused)))
2716 {
2717 MHD_PANIC ("Failed to join a thread\n");
2718 }
2719 pos->thread_joined = MHD_YES;
2720 }
2721 }
2722
2723 /* now that we're alone, move everyone to cleanup */
2724 while (NULL != (pos = daemon->connections_head))
2725 {
2726 MHD_connection_close (pos,
2727 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
2728 DLL_remove (daemon->connections_head,
2729 daemon->connections_tail,
2730 pos);
2731 DLL_insert (daemon->cleanup_head,
2732 daemon->cleanup_tail,
2733 pos);
2734 }
2735 MHD_cleanup_connections (daemon);
2736}
2737
2738
2739/**
2740 * Shutdown an http daemon
2741 *
2742 * @param daemon daemon to stop
2743 */
2744void
2745MHD_stop_daemon (struct MHD_Daemon *daemon)
2746{
2747 void *unused;
2748 int fd;
2749 unsigned int i;
2750 int rc;
2751
2752 if (NULL == daemon)
2753 return;
2754 daemon->shutdown = MHD_YES;
2755 fd = daemon->socket_fd;
2756 daemon->socket_fd = -1;
2757 /* Prepare workers for shutdown */
2758 if (NULL != daemon->worker_pool)
2759 {
2760 /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */
2761 for (i = 0; i < daemon->worker_pool_size; ++i)
2762 {
2763 daemon->worker_pool[i].shutdown = MHD_YES;
2764 daemon->worker_pool[i].socket_fd = -1;
2765 }
2766 }
2767 if (-1 != daemon->wpipe[1])
2768 {
2769 if (1 != WRITE (daemon->wpipe[1], "e", 1))
2770 MHD_PANIC ("failed to signal shutdownn via pipe");
2771 }
2772#ifdef HAVE_LISTEN_SHUTDOWN
2773 else
2774 {
2775 /* fd might be -1 here due to 'MHD_quiesce_daemon' */
2776 if (-1 != fd)
2777 (void) SHUTDOWN (fd, SHUT_RDWR);
2778 }
2779#endif
2780#if DEBUG_CLOSE
2781#if HAVE_MESSAGES
2782 MHD_DLOG (daemon, "MHD listen socket shutdown\n");
2783#endif
2784#endif
2785
2786
2787 /* Signal workers to stop and clean them up */
2788 if (NULL != daemon->worker_pool)
2789 {
2790 /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */
2791 for (i = 0; i < daemon->worker_pool_size; ++i)
2792 {
2793 if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))
2794 {
2795 MHD_PANIC ("Failed to join a thread\n");
2796 }
2797 close_all_connections (&daemon->worker_pool[i]);
2798 pthread_mutex_destroy (&daemon->worker_pool[i].cleanup_connection_mutex);
2799 }
2800 free (daemon->worker_pool);
2801 }
2802 else
2803 {
2804 /* clean up master threads */
2805 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
2806 ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
2807 && (0 == daemon->worker_pool_size)))
2808 {
2809 if (0 != (rc = pthread_join (daemon->pid, &unused)))
2810 {
2811 MHD_PANIC ("Failed to join a thread\n");
2812 }
2813 }
2814 }
2815 close_all_connections (daemon);
2816 if (-1 != fd)
2817 (void) CLOSE (fd);
2818
2819 /* TLS clean up */
2820#if HTTPS_SUPPORT
2821 if (0 != (daemon->options & MHD_USE_SSL))
2822 {
2823 gnutls_priority_deinit (daemon->priority_cache);
2824 if (daemon->x509_cred)
2825 gnutls_certificate_free_credentials (daemon->x509_cred);
2826 }
2827#endif
2828
2829#ifdef DAUTH_SUPPORT
2830 free (daemon->nnc);
2831 pthread_mutex_destroy (&daemon->nnc_lock);
2832#endif
2833 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2834 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2835
2836 if (-1 != daemon->wpipe[1])
2837 {
2838 (void) CLOSE (daemon->wpipe[0]);
2839 (void) CLOSE (daemon->wpipe[1]);
2840 }
2841 free (daemon);
2842}
2843
2844
2845/**
2846 * Obtain information about the given daemon
2847 * (not fully implemented!).
2848 *
2849 * @param daemon what daemon to get information about
2850 * @param infoType what information is desired?
2851 * @param ... depends on infoType
2852 * @return NULL if this information is not available
2853 * (or if the infoType is unknown)
2854 */
2855const union MHD_DaemonInfo *
2856MHD_get_daemon_info (struct MHD_Daemon *daemon,
2857 enum MHD_DaemonInfoType infoType, ...)
2858{
2859 switch (infoType)
2860 {
2861 case MHD_DAEMON_INFO_LISTEN_FD:
2862 return (const union MHD_DaemonInfo *) &daemon->socket_fd;
2863 default:
2864 return NULL;
2865 };
2866}
2867
2868
2869/**
2870 * Sets the global error handler to a different implementation. "cb"
2871 * will only be called in the case of typically fatal, serious
2872 * internal consistency issues. These issues should only arise in the
2873 * case of serious memory corruption or similar problems with the
2874 * architecture. While "cb" is allowed to return and MHD will then
2875 * try to continue, this is never safe.
2876 *
2877 * The default implementation that is used if no panic function is set
2878 * simply prints an error message and calls "abort". Alternative
2879 * implementations might call "exit" or other similar functions.
2880 *
2881 * @param cb new error handler
2882 * @param cls passed to error handler
2883 */
2884void
2885MHD_set_panic_func (MHD_PanicCallback cb, void *cls)
2886{
2887 mhd_panic = cb;
2888 mhd_panic_cls = cls;
2889}
2890
2891
2892/**
2893 * Obtain the version of this library
2894 *
2895 * @return static version string, e.g. "0.4.1"
2896 */
2897const char *
2898MHD_get_version (void)
2899{
2900 return PACKAGE_VERSION;
2901}
2902
2903
2904#ifdef __GNUC__
2905#define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor))
2906#define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor))
2907#else // !__GNUC__
2908#define ATTRIBUTE_CONSTRUCTOR
2909#define ATTRIBUTE_DESTRUCTOR
2910#endif // __GNUC__
2911
2912#if HTTPS_SUPPORT
2913GCRY_THREAD_OPTION_PTHREAD_IMPL;
2914#endif
2915
2916
2917/**
2918 * Initialize do setup work.
2919 */
2920void ATTRIBUTE_CONSTRUCTOR
2921MHD_init ()
2922{
2923 mhd_panic = &mhd_panic_std;
2924 mhd_panic_cls = NULL;
2925
2926#ifdef WINDOWS
2927 plibc_init ("GNU", "libmicrohttpd");
2928#endif
2929#if HTTPS_SUPPORT
2930 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
2931 gnutls_global_init ();
2932#endif
2933}
2934
2935
2936void ATTRIBUTE_DESTRUCTOR
2937MHD_fini ()
2938{
2939#if HTTPS_SUPPORT
2940 gnutls_global_deinit ();
2941#endif
2942#ifdef WINDOWS
2943 plibc_shutdown ();
2944#endif
2945}
2946
2947/* end of daemon.c */
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
new file mode 100644
index 00000000..d6c26114
--- /dev/null
+++ b/src/microhttpd/digestauth.c
@@ -0,0 +1,807 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19/**
20 * @file digestauth.c
21 * @brief Implements HTTP digest authentication
22 * @author Amr Ali
23 * @author Matthieu Speder
24 */
25#include "platform.h"
26#include <limits.h>
27#include "internal.h"
28#include "md5.h"
29
30#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
31
32/**
33 * Beginning string for any valid Digest authentication header.
34 */
35#define _BASE "Digest "
36
37/**
38 * Maximum length of a username for digest authentication.
39 */
40#define MAX_USERNAME_LENGTH 128
41
42/**
43 * Maximum length of a realm for digest authentication.
44 */
45#define MAX_REALM_LENGTH 256
46
47/**
48 * Maximum length of the response in digest authentication.
49 */
50#define MAX_AUTH_RESPONSE_LENGTH 128
51
52
53/**
54 * convert bin to hex
55 *
56 * @param bin binary data
57 * @param len number of bytes in bin
58 * @param hex pointer to len*2+1 bytes
59 */
60static void
61cvthex (const unsigned char *bin,
62 size_t len,
63 char *hex)
64{
65 size_t i;
66 unsigned int j;
67
68 for (i = 0; i < len; ++i)
69 {
70 j = (bin[i] >> 4) & 0x0f;
71 hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);
72 j = bin[i] & 0x0f;
73 hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
74 }
75 hex[len * 2] = '\0';
76}
77
78
79/**
80 * calculate H(A1) as per RFC2617 spec and store the
81 * result in 'sessionkey'.
82 *
83 * @param alg The hash algorithm used, can be "md5" or "md5-sess"
84 * @param username A `char *' pointer to the username value
85 * @param realm A `char *' pointer to the realm value
86 * @param password A `char *' pointer to the password value
87 * @param nonce A `char *' pointer to the nonce value
88 * @param cnonce A `char *' pointer to the cnonce value
89 * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
90 */
91static void
92digest_calc_ha1 (const char *alg,
93 const char *username,
94 const char *realm,
95 const char *password,
96 const char *nonce,
97 const char *cnonce,
98 char *sessionkey)
99{
100 struct MD5Context md5;
101 unsigned char ha1[MD5_DIGEST_SIZE];
102
103 MD5Init (&md5);
104 MD5Update (&md5, username, strlen (username));
105 MD5Update (&md5, ":", 1);
106 MD5Update (&md5, realm, strlen (realm));
107 MD5Update (&md5, ":", 1);
108 MD5Update (&md5, password, strlen (password));
109 MD5Final (ha1, &md5);
110 if (0 == strcasecmp (alg, "md5-sess"))
111 {
112 MD5Init (&md5);
113 MD5Update (&md5, ha1, sizeof (ha1));
114 MD5Update (&md5, ":", 1);
115 MD5Update (&md5, nonce, strlen (nonce));
116 MD5Update (&md5, ":", 1);
117 MD5Update (&md5, cnonce, strlen (cnonce));
118 MD5Final (ha1, &md5);
119 }
120 cvthex (ha1, sizeof (ha1), sessionkey);
121}
122
123
124/**
125 * Calculate request-digest/response-digest as per RFC2617 spec
126 *
127 * @param ha1 H(A1)
128 * @param nonce nonce from server
129 * @param noncecount 8 hex digits
130 * @param cnonce client nonce
131 * @param qop qop-value: "", "auth" or "auth-int"
132 * @param method method from request
133 * @param uri requested URL
134 * @param hentity H(entity body) if qop="auth-int"
135 * @param response request-digest or response-digest
136 */
137static void
138digest_calc_response (const char *ha1,
139 const char *nonce,
140 const char *noncecount,
141 const char *cnonce,
142 const char *qop,
143 const char *method,
144 const char *uri,
145 const char *hentity,
146 char *response)
147{
148 struct MD5Context md5;
149 unsigned char ha2[MD5_DIGEST_SIZE];
150 unsigned char resphash[MD5_DIGEST_SIZE];
151 char ha2hex[HASH_MD5_HEX_LEN + 1];
152
153 MD5Init (&md5);
154 MD5Update (&md5, method, strlen(method));
155 MD5Update (&md5, ":", 1);
156 MD5Update (&md5, uri, strlen(uri));
157#if 0
158 if (0 == strcasecmp(qop, "auth-int"))
159 {
160 /* This is dead code since the rest of this module does
161 not support auth-int. */
162 MD5Update (&md5, ":", 1);
163 if (NULL != hentity)
164 MD5Update (&md5, hentity, strlen(hentity));
165 }
166#endif
167 MD5Final (ha2, &md5);
168 cvthex (ha2, MD5_DIGEST_SIZE, ha2hex);
169 MD5Init (&md5);
170 /* calculate response */
171 MD5Update (&md5, ha1, HASH_MD5_HEX_LEN);
172 MD5Update (&md5, ":", 1);
173 MD5Update (&md5, nonce, strlen(nonce));
174 MD5Update (&md5, ":", 1);
175 if ('\0' != *qop)
176 {
177 MD5Update (&md5, noncecount, strlen(noncecount));
178 MD5Update (&md5, ":", 1);
179 MD5Update (&md5, cnonce, strlen(cnonce));
180 MD5Update (&md5, ":", 1);
181 MD5Update (&md5, qop, strlen(qop));
182 MD5Update (&md5, ":", 1);
183 }
184 MD5Update (&md5, ha2hex, HASH_MD5_HEX_LEN);
185 MD5Final (resphash, &md5);
186 cvthex (resphash, sizeof (resphash), response);
187}
188
189
190/**
191 * Lookup subvalue off of the HTTP Authorization header.
192 *
193 * A description of the input format for 'data' is at
194 * http://en.wikipedia.org/wiki/Digest_access_authentication
195 *
196 *
197 * @param dest where to store the result (possibly truncated if
198 * the buffer is not big enough).
199 * @param size size of dest
200 * @param data pointer to the Authorization header
201 * @param key key to look up in data
202 * @return size of the located value, 0 if otherwise
203 */
204static int
205lookup_sub_value (char *dest,
206 size_t size,
207 const char *data,
208 const char *key)
209{
210 size_t keylen;
211 size_t len;
212 const char *ptr;
213 const char *eq;
214 const char *q1;
215 const char *q2;
216 const char *qn;
217
218 if (0 == size)
219 return 0;
220 keylen = strlen (key);
221 ptr = data;
222 while ('\0' != *ptr)
223 {
224 if (NULL == (eq = strchr (ptr, '=')))
225 return 0;
226 q1 = eq + 1;
227 while (' ' == *q1)
228 q1++;
229 if ('\"' != *q1)
230 {
231 q2 = strchr (q1, ',');
232 qn = q2;
233 }
234 else
235 {
236 q1++;
237 q2 = strchr (q1, '\"');
238 if (NULL == q2)
239 return 0; /* end quote not found */
240 qn = q2 + 1;
241 }
242 if ( (0 == strncasecmp (ptr,
243 key,
244 keylen)) &&
245 (eq == &ptr[keylen]) )
246 {
247 if (NULL == q2)
248 {
249 len = strlen (q1) + 1;
250 if (size > len)
251 size = len;
252 size--;
253 strncpy (dest,
254 q1,
255 size);
256 dest[size] = '\0';
257 return size;
258 }
259 else
260 {
261 if (size > (q2 - q1) + 1)
262 size = (q2 - q1) + 1;
263 size--;
264 memcpy (dest,
265 q1,
266 size);
267 dest[size] = '\0';
268 return size;
269 }
270 }
271 if (NULL == qn)
272 return 0;
273 ptr = strchr (qn, ',');
274 if (NULL == ptr)
275 return 0;
276 ptr++;
277 while (' ' == *ptr)
278 ptr++;
279 }
280 return 0;
281}
282
283
284/**
285 * Check nonce-nc map array with either new nonce counter
286 * or a whole new nonce.
287 *
288 * @param connection The MHD connection structure
289 * @param nonce A pointer that referenced a zero-terminated array of nonce
290 * @param nc The nonce counter, zero to add the nonce to the array
291 * @return MHD_YES if successful, MHD_NO if invalid (or we have no NC array)
292 */
293static int
294check_nonce_nc (struct MHD_Connection *connection,
295 const char *nonce,
296 unsigned long int nc)
297{
298 uint32_t off;
299 uint32_t mod;
300 const char *np;
301
302 mod = connection->daemon->nonce_nc_size;
303 if (0 == mod)
304 return MHD_NO; /* no array! */
305 /* super-fast xor-based "hash" function for HT lookup in nonce array */
306 off = 0;
307 np = nonce;
308 while ('\0' != *np)
309 {
310 off = (off << 8) | (*np ^ (off >> 24));
311 np++;
312 }
313 off = off % mod;
314 /*
315 * Look for the nonce, if it does exist and its corresponding
316 * nonce counter is less than the current nonce counter by 1,
317 * then only increase the nonce counter by one.
318 */
319
320 pthread_mutex_lock (&connection->daemon->nnc_lock);
321 if (0 == nc)
322 {
323 strcpy(connection->daemon->nnc[off].nonce,
324 nonce);
325 connection->daemon->nnc[off].nc = 0;
326 pthread_mutex_unlock (&connection->daemon->nnc_lock);
327 return MHD_YES;
328 }
329 if ( (nc <= connection->daemon->nnc[off].nc) ||
330 (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) )
331 {
332 pthread_mutex_unlock (&connection->daemon->nnc_lock);
333#if HAVE_MESSAGES
334 MHD_DLOG (connection->daemon,
335 "Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n");
336#endif
337 return MHD_NO;
338 }
339 connection->daemon->nnc[off].nc = nc;
340 pthread_mutex_unlock (&connection->daemon->nnc_lock);
341 return MHD_YES;
342}
343
344
345/**
346 * Get the username from the authorization header sent by the client
347 *
348 * @param connection The MHD connection structure
349 * @return NULL if no username could be found, a pointer
350 * to the username if found
351 */
352char *
353MHD_digest_auth_get_username(struct MHD_Connection *connection)
354{
355 size_t len;
356 char user[MAX_USERNAME_LENGTH];
357 const char *header;
358
359 if (NULL == (header = MHD_lookup_connection_value (connection,
360 MHD_HEADER_KIND,
361 MHD_HTTP_HEADER_AUTHORIZATION)))
362 return NULL;
363 if (0 != strncmp (header, _BASE, strlen (_BASE)))
364 return NULL;
365 header += strlen (_BASE);
366 if (0 == (len = lookup_sub_value (user,
367 sizeof (user),
368 header,
369 "username")))
370 return NULL;
371 return strdup (user);
372}
373
374
375/**
376 * Calculate the server nonce so that it mitigates replay attacks
377 * The current format of the nonce is ...
378 * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
379 *
380 * @param nonce_time The amount of time in seconds for a nonce to be invalid
381 * @param method HTTP method
382 * @param rnd A pointer to a character array for the random seed
383 * @param rnd_size The size of the random seed array
384 * @param uri HTTP URI (in MHD, without the arguments ("?k=v")
385 * @param realm A string of characters that describes the realm of auth.
386 * @param nonce A pointer to a character array for the nonce to put in
387 */
388static void
389calculate_nonce (uint32_t nonce_time,
390 const char *method,
391 const char *rnd,
392 unsigned int rnd_size,
393 const char *uri,
394 const char *realm,
395 char *nonce)
396{
397 struct MD5Context md5;
398 unsigned char timestamp[4];
399 unsigned char tmpnonce[MD5_DIGEST_SIZE];
400 char timestamphex[sizeof(timestamp) * 2 + 1];
401
402 MD5Init (&md5);
403 timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
404 timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
405 timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
406 timestamp[3] = (nonce_time & 0x000000ff);
407 MD5Update (&md5, timestamp, 4);
408 MD5Update (&md5, ":", 1);
409 MD5Update (&md5, method, strlen(method));
410 MD5Update (&md5, ":", 1);
411 if (rnd_size > 0)
412 MD5Update (&md5, rnd, rnd_size);
413 MD5Update (&md5, ":", 1);
414 MD5Update (&md5, uri, strlen(uri));
415 MD5Update (&md5, ":", 1);
416 MD5Update (&md5, realm, strlen(realm));
417 MD5Final (tmpnonce, &md5);
418 cvthex (tmpnonce, sizeof (tmpnonce), nonce);
419 cvthex (timestamp, 4, timestamphex);
420 strncat (nonce, timestamphex, 8);
421}
422
423
424/**
425 * Test if the given key-value pair is in the headers for the
426 * given connection.
427 *
428 * @param connection the connection
429 * @param key the key
430 * @param value the value, can be NULL
431 * @return MHD_YES if the key-value pair is in the headers,
432 * MHD_NO if not
433 */
434static int
435test_header (struct MHD_Connection *connection,
436 const char *key,
437 const char *value)
438{
439 struct MHD_HTTP_Header *pos;
440
441 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
442 {
443 if (MHD_GET_ARGUMENT_KIND != pos->kind)
444 continue;
445 if (0 != strcmp (key, pos->header))
446 continue;
447 if ( (NULL == value) &&
448 (NULL == pos->value) )
449 return MHD_YES;
450 if ( (NULL == value) ||
451 (NULL == pos->value) ||
452 (0 != strcmp (value, pos->value)) )
453 continue;
454 return MHD_YES;
455 }
456 return MHD_NO;
457}
458
459
460/**
461 * Check that the arguments given by the client as part
462 * of the authentication header match the arguments we
463 * got as part of the HTTP request URI.
464 *
465 * @param connection connections with headers to compare against
466 * @param args argument URI string (after "?" in URI)
467 * @return MHD_YES if the arguments match,
468 * MHD_NO if not
469 */
470static int
471check_argument_match (struct MHD_Connection *connection,
472 const char *args)
473{
474 struct MHD_HTTP_Header *pos;
475 size_t slen = strlen (args) + 1;
476 char argb[slen];
477 char *argp;
478 char *equals;
479 char *amper;
480 unsigned int num_headers;
481
482 num_headers = 0;
483 memcpy (argb, args, slen);
484 argp = argb;
485 while ( (NULL != argp) &&
486 ('\0' != argp[0]) )
487 {
488 equals = strchr (argp, '=');
489 if (NULL == equals)
490 {
491 /* add with 'value' NULL */
492 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
493 connection,
494 argp);
495 if (MHD_YES != test_header (connection, argp, NULL))
496 return MHD_NO;
497 num_headers++;
498 break;
499 }
500 equals[0] = '\0';
501 equals++;
502 amper = strchr (equals, '&');
503 if (NULL != amper)
504 {
505 amper[0] = '\0';
506 amper++;
507 }
508 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
509 connection,
510 argp);
511 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
512 connection,
513 equals);
514 if (! test_header (connection, argp, equals))
515 return MHD_NO;
516 num_headers++;
517 argp = amper;
518 }
519
520 /* also check that the number of headers matches */
521 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
522 {
523 if (MHD_GET_ARGUMENT_KIND != pos->kind)
524 continue;
525 num_headers--;
526 }
527 if (0 != num_headers)
528 return MHD_NO;
529 return MHD_YES;
530}
531
532
533/**
534 * Authenticates the authorization header sent by the client
535 *
536 * @param connection The MHD connection structure
537 * @param realm The realm presented to the client
538 * @param username The username needs to be authenticated
539 * @param password The password used in the authentication
540 * @param nonce_timeout The amount of time for a nonce to be
541 * invalid in seconds
542 * @return MHD_YES if authenticated, MHD_NO if not,
543 * MHD_INVALID_NONCE if nonce is invalid
544 */
545int
546MHD_digest_auth_check (struct MHD_Connection *connection,
547 const char *realm,
548 const char *username,
549 const char *password,
550 unsigned int nonce_timeout)
551{
552 size_t len;
553 const char *header;
554 char *end;
555 char nonce[MAX_NONCE_LENGTH];
556 char cnonce[MAX_NONCE_LENGTH];
557 char qop[15]; /* auth,auth-int */
558 char nc[20];
559 char response[MAX_AUTH_RESPONSE_LENGTH];
560 const char *hentity = NULL; /* "auth-int" is not supported */
561 char ha1[HASH_MD5_HEX_LEN + 1];
562 char respexp[HASH_MD5_HEX_LEN + 1];
563 char noncehashexp[HASH_MD5_HEX_LEN + 9];
564 uint32_t nonce_time;
565 uint32_t t;
566 size_t left; /* number of characters left in 'header' for 'uri' */
567 unsigned long int nci;
568
569 header = MHD_lookup_connection_value (connection,
570 MHD_HEADER_KIND,
571 MHD_HTTP_HEADER_AUTHORIZATION);
572 if (NULL == header)
573 return MHD_NO;
574 if (0 != strncmp(header, _BASE, strlen(_BASE)))
575 return MHD_NO;
576 header += strlen (_BASE);
577 left = strlen (header);
578
579 {
580 char un[MAX_USERNAME_LENGTH];
581
582 len = lookup_sub_value (un,
583 sizeof (un),
584 header, "username");
585 if ( (0 == len) ||
586 (0 != strcmp(username, un)) )
587 return MHD_NO;
588 left -= strlen ("username") + len;
589 }
590
591 {
592 char r[MAX_REALM_LENGTH];
593
594 len = lookup_sub_value(r,
595 sizeof (r),
596 header, "realm");
597 if ( (0 == len) ||
598 (0 != strcmp(realm, r)) )
599 return MHD_NO;
600 left -= strlen ("realm") + len;
601 }
602
603 if (0 == (len = lookup_sub_value (nonce,
604 sizeof (nonce),
605 header, "nonce")))
606 return MHD_NO;
607 left -= strlen ("nonce") + len;
608
609 {
610 char uri[left];
611
612 if (0 == lookup_sub_value(uri,
613 sizeof (uri),
614 header, "uri"))
615 return MHD_NO;
616
617 /* 8 = 4 hexadecimal numbers for the timestamp */
618 nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16);
619 t = (uint32_t) MHD_monotonic_time();
620 /*
621 * First level vetting for the nonce validity if the timestamp
622 * attached to the nonce exceeds `nonce_timeout' then the nonce is
623 * invalid.
624 */
625 if ( (t > nonce_time + nonce_timeout) ||
626 (nonce_time + nonce_timeout < nonce_time) )
627 return MHD_INVALID_NONCE;
628 if (0 != strncmp (uri,
629 connection->url,
630 strlen (connection->url)))
631 {
632#if HAVE_MESSAGES
633 MHD_DLOG (connection->daemon,
634 "Authentication failed, URI does not match.\n");
635#endif
636 return MHD_NO;
637 }
638 {
639 const char *args = strchr (uri, '?');
640
641 if (NULL == args)
642 args = "";
643 else
644 args++;
645 if (MHD_YES !=
646 check_argument_match (connection,
647 args) )
648 {
649#if HAVE_MESSAGES
650 MHD_DLOG (connection->daemon,
651 "Authentication failed, arguments do not match.\n");
652#endif
653 return MHD_NO;
654 }
655 }
656 calculate_nonce (nonce_time,
657 connection->method,
658 connection->daemon->digest_auth_random,
659 connection->daemon->digest_auth_rand_size,
660 connection->url,
661 realm,
662 noncehashexp);
663 /*
664 * Second level vetting for the nonce validity
665 * if the timestamp attached to the nonce is valid
666 * and possibly fabricated (in case of an attack)
667 * the attacker must also know the random seed to be
668 * able to generate a "sane" nonce, which if he does
669 * not, the nonce fabrication process going to be
670 * very hard to achieve.
671 */
672
673 if (0 != strcmp (nonce, noncehashexp))
674 return MHD_INVALID_NONCE;
675 if ( (0 == lookup_sub_value (cnonce,
676 sizeof (cnonce),
677 header, "cnonce")) ||
678 (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) ||
679 ( (0 != strcmp (qop, "auth")) &&
680 (0 != strcmp (qop, "")) ) ||
681 (0 == lookup_sub_value (nc, sizeof (nc), header, "nc")) ||
682 (0 == lookup_sub_value (response, sizeof (response), header, "response")) )
683 {
684#if HAVE_MESSAGES
685 MHD_DLOG (connection->daemon,
686 "Authentication failed, invalid format.\n");
687#endif
688 return MHD_NO;
689 }
690 nci = strtoul (nc, &end, 16);
691 if ( ('\0' != *end) ||
692 ( (LONG_MAX == nci) &&
693 (ERANGE == errno) ) )
694 {
695#if HAVE_MESSAGES
696 MHD_DLOG (connection->daemon,
697 "Authentication failed, invalid format.\n");
698#endif
699 return MHD_NO; /* invalid nonce format */
700 }
701 /*
702 * Checking if that combination of nonce and nc is sound
703 * and not a replay attack attempt. Also adds the nonce
704 * to the nonce-nc map if it does not exist there.
705 */
706
707 if (MHD_YES != check_nonce_nc (connection, nonce, nci))
708 return MHD_NO;
709
710 digest_calc_ha1("md5",
711 username,
712 realm,
713 password,
714 nonce,
715 cnonce,
716 ha1);
717 digest_calc_response (ha1,
718 nonce,
719 nc,
720 cnonce,
721 qop,
722 connection->method,
723 uri,
724 hentity,
725 respexp);
726 return (0 == strcmp(response, respexp))
727 ? MHD_YES
728 : MHD_NO;
729 }
730}
731
732
733/**
734 * Queues a response to request authentication from the client
735 *
736 * @param connection The MHD connection structure
737 * @param realm the realm presented to the client
738 * @param opaque string to user for opaque value
739 * @param response reply to send; should contain the "access denied"
740 * body; note that this function will set the "WWW Authenticate"
741 * header and that the caller should not do this
742 * @param signal_stale MHD_YES if the nonce is invalid to add
743 * 'stale=true' to the authentication header
744 * @return MHD_YES on success, MHD_NO otherwise
745 */
746int
747MHD_queue_auth_fail_response (struct MHD_Connection *connection,
748 const char *realm,
749 const char *opaque,
750 struct MHD_Response *response,
751 int signal_stale)
752{
753 int ret;
754 size_t hlen;
755 char nonce[HASH_MD5_HEX_LEN + 9];
756
757 /* Generating the server nonce */
758 calculate_nonce ((uint32_t) MHD_monotonic_time(),
759 connection->method,
760 connection->daemon->digest_auth_random,
761 connection->daemon->digest_auth_rand_size,
762 connection->url,
763 realm,
764 nonce);
765 if (MHD_YES != check_nonce_nc (connection, nonce, 0))
766 {
767#if HAVE_MESSAGES
768 MHD_DLOG (connection->daemon,
769 "Could not register nonce (is the nonce array size zero?).\n");
770#endif
771 return MHD_NO;
772 }
773 /* Building the authentication header */
774 hlen = snprintf (NULL,
775 0,
776 "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
777 realm,
778 nonce,
779 opaque,
780 signal_stale
781 ? ",stale=\"true\""
782 : "");
783 {
784 char header[hlen + 1];
785
786 snprintf (header,
787 sizeof(header),
788 "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
789 realm,
790 nonce,
791 opaque,
792 signal_stale
793 ? ",stale=\"true\""
794 : "");
795 ret = MHD_add_response_header(response,
796 MHD_HTTP_HEADER_WWW_AUTHENTICATE,
797 header);
798 }
799 if (MHD_YES == ret)
800 ret = MHD_queue_response(connection,
801 MHD_HTTP_UNAUTHORIZED,
802 response);
803 return ret;
804}
805
806
807/* end of digestauth.c */
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
new file mode 100644
index 00000000..1730c0c9
--- /dev/null
+++ b/src/microhttpd/internal.c
@@ -0,0 +1,171 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file internal.h
22 * @brief internal shared structures
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#include "internal.h"
28
29#if HAVE_MESSAGES
30#if DEBUG_STATES
31/**
32 * State to string dictionary.
33 */
34const char *
35MHD_state_to_string (enum MHD_CONNECTION_STATE state)
36{
37 switch (state)
38 {
39 case MHD_CONNECTION_INIT:
40 return "connection init";
41 case MHD_CONNECTION_URL_RECEIVED:
42 return "connection url received";
43 case MHD_CONNECTION_HEADER_PART_RECEIVED:
44 return "header partially received";
45 case MHD_CONNECTION_HEADERS_RECEIVED:
46 return "headers received";
47 case MHD_CONNECTION_HEADERS_PROCESSED:
48 return "headers processed";
49 case MHD_CONNECTION_CONTINUE_SENDING:
50 return "continue sending";
51 case MHD_CONNECTION_CONTINUE_SENT:
52 return "continue sent";
53 case MHD_CONNECTION_BODY_RECEIVED:
54 return "body received";
55 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
56 return "footer partially received";
57 case MHD_CONNECTION_FOOTERS_RECEIVED:
58 return "footers received";
59 case MHD_CONNECTION_HEADERS_SENDING:
60 return "headers sending";
61 case MHD_CONNECTION_HEADERS_SENT:
62 return "headers sent";
63 case MHD_CONNECTION_NORMAL_BODY_READY:
64 return "normal body ready";
65 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
66 return "normal body unready";
67 case MHD_CONNECTION_CHUNKED_BODY_READY:
68 return "chunked body ready";
69 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
70 return "chunked body unready";
71 case MHD_CONNECTION_BODY_SENT:
72 return "body sent";
73 case MHD_CONNECTION_FOOTERS_SENDING:
74 return "footers sending";
75 case MHD_CONNECTION_FOOTERS_SENT:
76 return "footers sent";
77 case MHD_CONNECTION_CLOSED:
78 return "closed";
79 case MHD_TLS_CONNECTION_INIT:
80 return "secure connection init";
81 default:
82 return "unrecognized connection state";
83 }
84}
85#endif
86#endif
87
88#if HAVE_MESSAGES
89/**
90 * fprintf-like helper function for logging debug
91 * messages.
92 */
93void
94MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...)
95{
96 va_list va;
97
98 if ((daemon->options & MHD_USE_DEBUG) == 0)
99 return;
100 va_start (va, format);
101 daemon->custom_error_log (daemon->custom_error_log_cls, format, va);
102 va_end (va);
103}
104#endif
105
106
107/**
108 * Process escape sequences ('+'=space, %HH) Updates val in place; the
109 * result should be UTF-8 encoded and cannot be larger than the input.
110 * The result must also still be 0-terminated.
111 *
112 * @param cls closure (use NULL)
113 * @param connection handle to connection, not used
114 * @param val value to unescape (modified in the process)
115 * @return length of the resulting val (strlen(val) maybe
116 * shorter afterwards due to elimination of escape sequences)
117 */
118size_t
119MHD_http_unescape (void *cls,
120 struct MHD_Connection *connection,
121 char *val)
122{
123 char *rpos = val;
124 char *wpos = val;
125 char *end;
126 unsigned int num;
127 char buf3[3];
128
129 while ('\0' != *rpos)
130 {
131 switch (*rpos)
132 {
133 case '+':
134 *wpos = ' ';
135 wpos++;
136 rpos++;
137 break;
138 case '%':
139 buf3[0] = rpos[1];
140 buf3[1] = rpos[2];
141 buf3[2] = '\0';
142 num = strtoul (buf3, &end, 16);
143 if ('\0' == *end)
144 {
145 *wpos = (unsigned char) num;
146 wpos++;
147 rpos += 3;
148 break;
149 }
150 /* intentional fall through! */
151 default:
152 *wpos = *rpos;
153 wpos++;
154 rpos++;
155 }
156 }
157 *wpos = '\0'; /* add 0-terminator */
158 return wpos - val; /* = strlen(val) */
159}
160
161time_t MHD_monotonic_time(void)
162{
163#ifdef HAVE_CLOCK_GETTIME
164 struct timespec ts;
165 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
166 return ts.tv_sec;
167#endif
168 return time(NULL);
169}
170
171/* end of internal.c */
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
new file mode 100644
index 00000000..f76d6834
--- /dev/null
+++ b/src/microhttpd/internal.h
@@ -0,0 +1,1093 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file internal.h
22 * @brief internal shared structures
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#ifndef INTERNAL_H
28#define INTERNAL_H
29
30#include "platform.h"
31#include "microhttpd.h"
32#if HTTPS_SUPPORT
33#include <gnutls/gnutls.h>
34#endif
35
36/**
37 * Should we perform additional sanity checks at runtime (on our internal
38 * invariants)? This may lead to aborts, but can be useful for debugging.
39 */
40#define EXTRA_CHECKS MHD_NO
41
42#define MHD_MAX(a,b) ((a)<(b)) ? (b) : (a)
43#define MHD_MIN(a,b) ((a)<(b)) ? (a) : (b)
44
45
46/**
47 * Handler for fatal errors.
48 */
49extern MHD_PanicCallback mhd_panic;
50
51/**
52 * Closure argument for "mhd_panic".
53 */
54extern void *mhd_panic_cls;
55
56#if HAVE_MESSAGES
57/**
58 * Trigger 'panic' action based on fatal errors.
59 *
60 * @param msg error message (const char *)
61 */
62#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg)
63#else
64/**
65 * Trigger 'panic' action based on fatal errors.
66 *
67 * @param msg error message (const char *)
68 */
69#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL)
70#endif
71
72/**
73 * Events we care about with respect to poll/select
74 * for file descriptors.
75 */
76enum MHD_PollActions
77 {
78 /**
79 * No event interests us.
80 */
81 MHD_POLL_ACTION_NOTHING = 0,
82
83 /**
84 * We would like to read.
85 */
86 MHD_POLL_ACTION_IN = 1,
87
88 /**
89 * We would like to write.
90 */
91 MHD_POLL_ACTION_OUT = 2
92 };
93
94
95/**
96 * Socket descriptor and events we care about.
97 */
98struct MHD_Pollfd
99{
100 /**
101 * Socket descriptor.
102 */
103 int fd;
104
105 /**
106 * Which events do we care about for this socket?
107 */
108 enum MHD_PollActions events;
109};
110
111
112/**
113 * Maximum length of a nonce in digest authentication. 32(MD5 Hex) +
114 * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera
115 * (already) takes more (see Mantis #1633), so we've increased the
116 * value to support something longer...
117 */
118#define MAX_NONCE_LENGTH 129
119
120
121/**
122 * A structure representing the internal holder of the
123 * nonce-nc map.
124 */
125struct MHD_NonceNc
126{
127
128 /**
129 * Nonce counter, a value that increases for each subsequent
130 * request for the same nonce.
131 */
132 unsigned long int nc;
133
134 /**
135 * Nonce value:
136 */
137 char nonce[MAX_NONCE_LENGTH];
138
139};
140
141#if HAVE_MESSAGES
142/**
143 * fprintf-like helper function for logging debug
144 * messages.
145 */
146void
147MHD_DLOG (const struct MHD_Daemon *daemon,
148 const char *format, ...);
149
150#endif
151
152/**
153 * Process escape sequences ('+'=space, %HH) Updates val in place; the
154 * result should be UTF-8 encoded and cannot be larger than the input.
155 * The result must also still be 0-terminated.
156 *
157 * @param cls closure (use NULL)
158 * @param connection handle to connection, not used
159 * @param val value to unescape (modified in the process)
160 * @return length of the resulting val (strlen(val) maybe
161 * shorter afterwards due to elimination of escape sequences)
162 */
163size_t
164MHD_http_unescape (void *cls,
165 struct MHD_Connection *connection,
166 char *val);
167
168
169/**
170 * Header or cookie in HTTP request or response.
171 */
172struct MHD_HTTP_Header
173{
174 /**
175 * Headers are kept in a linked list.
176 */
177 struct MHD_HTTP_Header *next;
178
179 /**
180 * The name of the header (key), without
181 * the colon.
182 */
183 char *header;
184
185 /**
186 * The value of the header.
187 */
188 char *value;
189
190 /**
191 * Type of the header (where in the HTTP
192 * protocol is this header from).
193 */
194 enum MHD_ValueKind kind;
195
196};
197
198
199/**
200 * Representation of a response.
201 */
202struct MHD_Response
203{
204
205 /**
206 * Headers to send for the response. Initially
207 * the linked list is created in inverse order;
208 * the order should be inverted before sending!
209 */
210 struct MHD_HTTP_Header *first_header;
211
212 /**
213 * Buffer pointing to data that we are supposed
214 * to send as a response.
215 */
216 char *data;
217
218 /**
219 * Closure to give to the content reader
220 * free callback.
221 */
222 void *crc_cls;
223
224 /**
225 * How do we get more data? NULL if we are
226 * given all of the data up front.
227 */
228 MHD_ContentReaderCallback crc;
229
230 /**
231 * NULL if data must not be freed, otherwise
232 * either user-specified callback or "&free".
233 */
234 MHD_ContentReaderFreeCallback crfc;
235
236 /**
237 * Mutex to synchronize access to data/size and
238 * reference counts.
239 */
240 pthread_mutex_t mutex;
241
242 /**
243 * Set to MHD_SIZE_UNKNOWN if size is not known.
244 */
245 uint64_t total_size;
246
247 /**
248 * At what offset in the stream is the
249 * beginning of data located?
250 */
251 uint64_t data_start;
252
253 /**
254 * Offset to start reading from when using 'fd'.
255 */
256 off_t fd_off;
257
258 /**
259 * Size of data.
260 */
261 size_t data_size;
262
263 /**
264 * Size of the data buffer.
265 */
266 size_t data_buffer_size;
267
268 /**
269 * Reference count for this response. Free
270 * once the counter hits zero.
271 */
272 unsigned int reference_count;
273
274 /**
275 * File-descriptor if this response is FD-backed.
276 */
277 int fd;
278
279};
280
281
282/**
283 * States in a state machine for a connection.
284 *
285 * Transitions are any-state to CLOSED, any state to state+1,
286 * FOOTERS_SENT to INIT. CLOSED is the terminal state and
287 * INIT the initial state.
288 *
289 * Note that transitions for *reading* happen only after
290 * the input has been processed; transitions for
291 * *writing* happen after the respective data has been
292 * put into the write buffer (the write does not have
293 * to be completed yet). A transition to CLOSED or INIT
294 * requires the write to be complete.
295 */
296enum MHD_CONNECTION_STATE
297{
298 /**
299 * Connection just started (no headers received).
300 * Waiting for the line with the request type, URL and version.
301 */
302 MHD_CONNECTION_INIT = 0,
303
304 /**
305 * 1: We got the URL (and request type and version). Wait for a header line.
306 */
307 MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
308
309 /**
310 * 2: We got part of a multi-line request header. Wait for the rest.
311 */
312 MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
313
314 /**
315 * 3: We got the request headers. Process them.
316 */
317 MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
318
319 /**
320 * 4: We have processed the request headers. Send 100 continue.
321 */
322 MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
323
324 /**
325 * 5: We have processed the headers and need to send 100 CONTINUE.
326 */
327 MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
328
329 /**
330 * 6: We have sent 100 CONTINUE (or do not need to). Read the message body.
331 */
332 MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
333
334 /**
335 * 7: We got the request body. Wait for a line of the footer.
336 */
337 MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
338
339 /**
340 * 8: We got part of a line of the footer. Wait for the
341 * rest.
342 */
343 MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
344
345 /**
346 * 9: We received the entire footer. Wait for a response to be queued
347 * and prepare the response headers.
348 */
349 MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
350
351 /**
352 * 10: We have prepared the response headers in the writ buffer.
353 * Send the response headers.
354 */
355 MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
356
357 /**
358 * 11: We have sent the response headers. Get ready to send the body.
359 */
360 MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
361
362 /**
363 * 12: We are ready to send a part of a non-chunked body. Send it.
364 */
365 MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
366
367 /**
368 * 13: We are waiting for the client to provide more
369 * data of a non-chunked body.
370 */
371 MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
372
373 /**
374 * 14: We are ready to send a chunk.
375 */
376 MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
377
378 /**
379 * 15: We are waiting for the client to provide a chunk of the body.
380 */
381 MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
382
383 /**
384 * 16: We have sent the response body. Prepare the footers.
385 */
386 MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
387
388 /**
389 * 17: We have prepared the response footer. Send it.
390 */
391 MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
392
393 /**
394 * 18: We have sent the response footer. Shutdown or restart.
395 */
396 MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
397
398 /**
399 * 19: This connection is to be closed.
400 */
401 MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
402
403 /**
404 * 20: This connection is finished (only to be freed)
405 */
406 MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1,
407
408 /*
409 * SSL/TLS connection states
410 */
411
412 /**
413 * The initial connection state for all secure connectoins
414 * Handshake messages will be processed in this state & while
415 * in the 'MHD_TLS_HELLO_REQUEST' state
416 */
417 MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED + 1
418
419};
420
421/**
422 * Should all state transitions be printed to stderr?
423 */
424#define DEBUG_STATES MHD_NO
425
426
427#if HAVE_MESSAGES
428#if DEBUG_STATES
429const char *
430MHD_state_to_string (enum MHD_CONNECTION_STATE state);
431#endif
432#endif
433
434/**
435 * Function to receive plaintext data.
436 *
437 * @param conn the connection struct
438 * @param write_to where to write received data
439 * @param max_bytes maximum number of bytes to receive
440 * @return number of bytes written to write_to
441 */
442typedef ssize_t (*ReceiveCallback) (struct MHD_Connection * conn,
443 void *write_to, size_t max_bytes);
444
445
446/**
447 * Function to transmit plaintext data.
448 *
449 * @param conn the connection struct
450 * @param read_from where to read data to transmit
451 * @param max_bytes maximum number of bytes to transmit
452 * @return number of bytes transmitted
453 */
454typedef ssize_t (*TransmitCallback) (struct MHD_Connection * conn,
455 const void *write_to, size_t max_bytes);
456
457
458/**
459 * State kept for each HTTP request.
460 */
461struct MHD_Connection
462{
463
464 /**
465 * This is a doubly-linked list.
466 */
467 struct MHD_Connection *next;
468
469 /**
470 * This is a doubly-linked list.
471 */
472 struct MHD_Connection *prev;
473
474 /**
475 * Reference to the MHD_Daemon struct.
476 */
477 struct MHD_Daemon *daemon;
478
479 /**
480 * Linked list of parsed headers.
481 */
482 struct MHD_HTTP_Header *headers_received;
483
484 /**
485 * Tail of linked list of parsed headers.
486 */
487 struct MHD_HTTP_Header *headers_received_tail;
488
489 /**
490 * Response to transmit (initially NULL).
491 */
492 struct MHD_Response *response;
493
494 /**
495 * The memory pool is created whenever we first read
496 * from the TCP stream and destroyed at the end of
497 * each request (and re-created for the next request).
498 * In the meantime, this pointer is NULL. The
499 * pool is used for all connection-related data
500 * except for the response (which maybe shared between
501 * connections) and the IP address (which persists
502 * across individual requests).
503 */
504 struct MemoryPool *pool;
505
506 /**
507 * We allow the main application to associate some
508 * pointer with the connection. Here is where we
509 * store it. (MHD does not know or care what it
510 * is).
511 */
512 void *client_context;
513
514 /**
515 * Request method. Should be GET/POST/etc. Allocated
516 * in pool.
517 */
518 char *method;
519
520 /**
521 * Requested URL (everything after "GET" only). Allocated
522 * in pool.
523 */
524 char *url;
525
526 /**
527 * HTTP version string (i.e. http/1.1). Allocated
528 * in pool.
529 */
530 char *version;
531
532 /**
533 * Buffer for reading requests. Allocated
534 * in pool. Actually one byte larger than
535 * read_buffer_size (if non-NULL) to allow for
536 * 0-termination.
537 */
538 char *read_buffer;
539
540 /**
541 * Buffer for writing response (headers only). Allocated
542 * in pool.
543 */
544 char *write_buffer;
545
546 /**
547 * Last incomplete header line during parsing of headers.
548 * Allocated in pool. Only valid if state is
549 * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
550 */
551 char *last;
552
553 /**
554 * Position after the colon on the last incomplete header
555 * line during parsing of headers.
556 * Allocated in pool. Only valid if state is
557 * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
558 */
559 char *colon;
560
561 /**
562 * Foreign address (of length addr_len). MALLOCED (not
563 * in pool!).
564 */
565 struct sockaddr *addr;
566
567 /**
568 * Thread for this connection (if we are using
569 * one thread per connection).
570 */
571 pthread_t pid;
572
573 /**
574 * Size of read_buffer (in bytes). This value indicates
575 * how many bytes we're willing to read into the buffer;
576 * the real buffer is one byte longer to allow for
577 * adding zero-termination (when needed).
578 */
579 size_t read_buffer_size;
580
581 /**
582 * Position where we currently append data in
583 * read_buffer (last valid position).
584 */
585 size_t read_buffer_offset;
586
587 /**
588 * Size of write_buffer (in bytes).
589 */
590 size_t write_buffer_size;
591
592 /**
593 * Offset where we are with sending from write_buffer.
594 */
595 size_t write_buffer_send_offset;
596
597 /**
598 * Last valid location in write_buffer (where do we
599 * append and up to where is it safe to send?)
600 */
601 size_t write_buffer_append_offset;
602
603 /**
604 * How many more bytes of the body do we expect
605 * to read? "-1" for unknown.
606 */
607 uint64_t remaining_upload_size;
608
609 /**
610 * Current write position in the actual response
611 * (excluding headers, content only; should be 0
612 * while sending headers).
613 */
614 uint64_t response_write_position;
615
616 /**
617 * Position in the 100 CONTINUE message that
618 * we need to send when receiving http 1.1 requests.
619 */
620 size_t continue_message_write_offset;
621
622 /**
623 * Length of the foreign address.
624 */
625 socklen_t addr_len;
626
627 /**
628 * Last time this connection had any activity
629 * (reading or writing).
630 */
631 time_t last_activity;
632
633 /**
634 * After how many seconds of inactivity should
635 * this connection time out? Zero for no timeout.
636 */
637 unsigned int connection_timeout;
638
639 /**
640 * Did we ever call the "default_handler" on this connection?
641 * (this flag will determine if we call the 'notify_completed'
642 * handler when the connection closes down).
643 */
644 int client_aware;
645
646 /**
647 * Socket for this connection. Set to -1 if
648 * this connection has died (daemon should clean
649 * up in that case).
650 */
651 int socket_fd;
652
653 /**
654 * Has this socket been closed for reading (i.e.
655 * other side closed the connection)? If so,
656 * we must completely close the connection once
657 * we are done sending our response (and stop
658 * trying to read from this socket).
659 */
660 int read_closed;
661
662 /**
663 * Set to MHD_YES if the thread has been joined.
664 */
665 int thread_joined;
666
667 /**
668 * State in the FSM for this connection.
669 */
670 enum MHD_CONNECTION_STATE state;
671
672 /**
673 * HTTP response code. Only valid if response object
674 * is already set.
675 */
676 unsigned int responseCode;
677
678 /**
679 * Set to MHD_YES if the response's content reader
680 * callback failed to provide data the last time
681 * we tried to read from it. In that case, the
682 * write socket should be marked as unready until
683 * the CRC call succeeds.
684 */
685 int response_unready;
686
687 /**
688 * Are we receiving with chunked encoding? This will be set to
689 * MHD_YES after we parse the headers and are processing the body
690 * with chunks. After we are done with the body and we are
691 * processing the footers; once the footers are also done, this will
692 * be set to MHD_NO again (before the final call to the handler).
693 */
694 int have_chunked_upload;
695
696 /**
697 * If we are receiving with chunked encoding, where are we right
698 * now? Set to 0 if we are waiting to receive the chunk size;
699 * otherwise, this is the size of the current chunk. A value of
700 * zero is also used when we're at the end of the chunks.
701 */
702 unsigned int current_chunk_size;
703
704 /**
705 * If we are receiving with chunked encoding, where are we currently
706 * with respect to the current chunk (at what offset / position)?
707 */
708 unsigned int current_chunk_offset;
709
710 /**
711 * Handler used for processing read connection operations
712 */
713 int (*read_handler) (struct MHD_Connection * connection);
714
715 /**
716 * Handler used for processing write connection operations
717 */
718 int (*write_handler) (struct MHD_Connection * connection);
719
720 /**
721 * Handler used for processing idle connection operations
722 */
723 int (*idle_handler) (struct MHD_Connection * connection);
724
725 /**
726 * Function used for reading HTTP request stream.
727 */
728 ReceiveCallback recv_cls;
729
730 /**
731 * Function used for writing HTTP response stream.
732 */
733 TransmitCallback send_cls;
734
735#if HTTPS_SUPPORT
736 /**
737 * State required for HTTPS/SSL/TLS support.
738 */
739 gnutls_session_t tls_session;
740
741 /**
742 * Memory location to return for protocol session info.
743 */
744 int protocol;
745
746 /**
747 * Memory location to return for protocol session info.
748 */
749 int cipher;
750
751 /**
752 * Could it be that we are ready to read due to TLS buffers
753 * even though the socket is not?
754 */
755 int tls_read_ready;
756
757#endif
758};
759
760/**
761 * Signature of function called to log URI accesses.
762 *
763 * @param cls closure
764 * @param uri uri being accessed
765 * @return new closure
766 */
767typedef void * (*LogCallback)(void * cls, const char * uri);
768
769/**
770 * Signature of function called to unescape URIs. See also
771 * MHD_http_unescape.
772 *
773 * @param cls closure
774 * @param conn connection handle
775 * @param uri 0-terminated string to unescape (should be updated)
776 * @return length of the resulting string
777 */
778typedef size_t (*UnescapeCallback)(void *cls,
779 struct MHD_Connection *conn,
780 char *uri);
781
782
783/**
784 * State kept for each MHD daemon.
785 */
786struct MHD_Daemon
787{
788
789 /**
790 * Callback function for all requests.
791 */
792 MHD_AccessHandlerCallback default_handler;
793
794 /**
795 * Closure argument to default_handler.
796 */
797 void *default_handler_cls;
798
799 /**
800 * Tail of doubly-linked list of our current, active connections.
801 */
802 struct MHD_Connection *connections_head;
803
804 /**
805 * Tail of doubly-linked list of our current, active connections.
806 */
807 struct MHD_Connection *connections_tail;
808
809 /**
810 * Tail of doubly-linked list of connections to clean up.
811 */
812 struct MHD_Connection *cleanup_head;
813
814 /**
815 * Tail of doubly-linked list of connections to clean up.
816 */
817 struct MHD_Connection *cleanup_tail;
818
819 /**
820 * Function to call to check if we should
821 * accept or reject an incoming request.
822 * May be NULL.
823 */
824 MHD_AcceptPolicyCallback apc;
825
826 /**
827 * Closure argument to apc.
828 */
829 void *apc_cls;
830
831 /**
832 * Function to call when we are done processing
833 * a particular request. May be NULL.
834 */
835 MHD_RequestCompletedCallback notify_completed;
836
837 /**
838 * Closure argument to notify_completed.
839 */
840 void *notify_completed_cls;
841
842 /**
843 * Function to call with the full URI at the
844 * beginning of request processing. May be NULL.
845 * <p>
846 * Returns the initial pointer to internal state
847 * kept by the client for the request.
848 */
849 LogCallback uri_log_callback;
850
851 /**
852 * Closure argument to uri_log_callback.
853 */
854 void *uri_log_callback_cls;
855
856 /**
857 * Function to call when we unescape escape sequences.
858 */
859 UnescapeCallback unescape_callback;
860
861 /**
862 * Closure for unescape callback.
863 */
864 void *unescape_callback_cls;
865
866#if HAVE_MESSAGES
867 /**
868 * Function for logging error messages (if we
869 * support error reporting).
870 */
871 void (*custom_error_log) (void *cls, const char *fmt, va_list va);
872
873 /**
874 * Closure argument to custom_error_log.
875 */
876 void *custom_error_log_cls;
877#endif
878
879 /**
880 * Pointer to master daemon (NULL if this is the master)
881 */
882 struct MHD_Daemon *master;
883
884 /**
885 * Worker daemons (one per thread)
886 */
887 struct MHD_Daemon *worker_pool;
888
889 /**
890 * Table storing number of connections per IP
891 */
892 void *per_ip_connection_count;
893
894 /**
895 * Size of the per-connection memory pools.
896 */
897 size_t pool_size;
898
899 /**
900 * Size of threads created by MHD.
901 */
902 size_t thread_stack_size;
903
904 /**
905 * Number of worker daemons
906 */
907 unsigned int worker_pool_size;
908
909 /**
910 * PID of the select thread (if we have internal select)
911 */
912 pthread_t pid;
913
914 /**
915 * Mutex for per-IP connection counts.
916 */
917 pthread_mutex_t per_ip_connection_mutex;
918
919 /**
920 * Mutex for (modifying) access to the "cleanup" connection DLL.
921 */
922 pthread_mutex_t cleanup_connection_mutex;
923
924 /**
925 * Listen socket.
926 */
927 int socket_fd;
928
929 /**
930 * Pipe we use to signal shutdown, unless
931 * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen
932 * socket (which we can then 'shutdown' to stop listening).
933 */
934 int wpipe[2];
935
936 /**
937 * Are we shutting down?
938 */
939 int shutdown;
940
941 /**
942 * Limit on the number of parallel connections.
943 */
944 unsigned int max_connections;
945
946 /**
947 * After how many seconds of inactivity should
948 * connections time out? Zero for no timeout.
949 */
950 unsigned int connection_timeout;
951
952 /**
953 * Maximum number of connections per IP, or 0 for
954 * unlimited.
955 */
956 unsigned int per_ip_connection_limit;
957
958 /**
959 * Daemon's options.
960 */
961 enum MHD_OPTION options;
962
963 /**
964 * Listen port.
965 */
966 uint16_t port;
967
968#if HTTPS_SUPPORT
969 /**
970 * Desired cipher algorithms.
971 */
972 gnutls_priority_t priority_cache;
973
974 /**
975 * What kind of credentials are we offering
976 * for SSL/TLS?
977 */
978 gnutls_credentials_type_t cred_type;
979
980 /**
981 * Server x509 credentials
982 */
983 gnutls_certificate_credentials_t x509_cred;
984
985 /**
986 * Diffie-Hellman parameters
987 */
988 gnutls_dh_params_t dh_params;
989
990 /**
991 * Pointer to our SSL/TLS key (in ASCII) in memory.
992 */
993 const char *https_mem_key;
994
995 /**
996 * Pointer to our SSL/TLS certificate (in ASCII) in memory.
997 */
998 const char *https_mem_cert;
999
1000 /**
1001 * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
1002 */
1003 const char *https_mem_trust;
1004
1005#endif
1006
1007#ifdef DAUTH_SUPPORT
1008
1009 /**
1010 * Character array of random values.
1011 */
1012 const char *digest_auth_random;
1013
1014 /**
1015 * An array that contains the map nonce-nc.
1016 */
1017 struct MHD_NonceNc *nnc;
1018
1019 /**
1020 * A rw-lock for synchronizing access to `nnc'.
1021 */
1022 pthread_mutex_t nnc_lock;
1023
1024 /**
1025 * Size of `digest_auth_random.
1026 */
1027 unsigned int digest_auth_rand_size;
1028
1029 /**
1030 * Size of the nonce-nc array.
1031 */
1032 unsigned int nonce_nc_size;
1033
1034#endif
1035
1036};
1037
1038
1039#if EXTRA_CHECKS
1040#define EXTRA_CHECK(a) if (!(a)) abort();
1041#else
1042#define EXTRA_CHECK(a)
1043#endif
1044
1045
1046/**
1047 * Insert an element at the head of a DLL. Assumes that head, tail and
1048 * element are structs with prev and next fields.
1049 *
1050 * @param head pointer to the head of the DLL
1051 * @param tail pointer to the tail of the DLL
1052 * @param element element to insert
1053 */
1054#define DLL_insert(head,tail,element) do { \
1055 (element)->next = (head); \
1056 (element)->prev = NULL; \
1057 if ((tail) == NULL) \
1058 (tail) = element; \
1059 else \
1060 (head)->prev = element; \
1061 (head) = (element); } while (0)
1062
1063
1064/**
1065 * Remove an element from a DLL. Assumes
1066 * that head, tail and element are structs
1067 * with prev and next fields.
1068 *
1069 * @param head pointer to the head of the DLL
1070 * @param tail pointer to the tail of the DLL
1071 * @param element element to remove
1072 */
1073#define DLL_remove(head,tail,element) do { \
1074 if ((element)->prev == NULL) \
1075 (head) = (element)->next; \
1076 else \
1077 (element)->prev->next = (element)->next; \
1078 if ((element)->next == NULL) \
1079 (tail) = (element)->prev; \
1080 else \
1081 (element)->next->prev = (element)->prev; \
1082 (element)->next = NULL; \
1083 (element)->prev = NULL; } while (0)
1084
1085
1086/**
1087 * Equivalent to time(NULL) but tries to use some sort of monotonic
1088 * clock that isn't affected by someone setting the system real time
1089 * clock.
1090 */
1091time_t MHD_monotonic_time(void);
1092
1093#endif
diff --git a/src/microhttpd/md5.c b/src/microhttpd/md5.c
new file mode 100644
index 00000000..5daa0334
--- /dev/null
+++ b/src/microhttpd/md5.c
@@ -0,0 +1,267 @@
1/*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 */
17
18/* Brutally hacked by John Walker back from ANSI C to K&R (no
19 prototypes) to maintain the tradition that Netfone will compile
20 with Sun's original "cc". */
21
22#include "md5.h"
23
24
25#ifndef HIGHFIRST
26#define byteReverse(buf, len) /* Nothing */
27#else
28/*
29 * Note: this code is harmless on little-endian machines.
30 */
31static void
32byteReverse(unsigned char *buf,
33 unsigned longs)
34{
35 uint32_t t;
36 do {
37 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
38 ((unsigned) buf[1] << 8 | buf[0]);
39 *(uint32_t *) buf = t;
40 buf += 4;
41 } while (--longs);
42}
43#endif
44
45
46/* The four core functions - F1 is optimized somewhat */
47
48/* #define F1(x, y, z) (x & y | ~x & z) */
49#define F1(x, y, z) (z ^ (x & (y ^ z)))
50#define F2(x, y, z) F1(z, x, y)
51#define F3(x, y, z) (x ^ y ^ z)
52#define F4(x, y, z) (y ^ (x | ~z))
53
54/* This is the central step in the MD5 algorithm. */
55#define MD5STEP(f, w, x, y, z, data, s) \
56 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
57
58/*
59 * The core of the MD5 algorithm, this alters an existing MD5 hash to
60 * reflect the addition of 16 longwords of new data. MD5Update blocks
61 * the data and converts bytes into longwords for this routine.
62 */
63static void
64MD5Transform(uint32_t buf[4],
65 uint32_t in[16])
66{
67 uint32_t a, b, c, d;
68
69 a = buf[0];
70 b = buf[1];
71 c = buf[2];
72 d = buf[3];
73
74 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
75 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
76 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
77 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
78 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
79 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
80 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
81 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
82 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
83 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
84 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
85 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
86 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
87 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
88 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
89 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
90
91 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
92 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
93 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
94 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
95 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
96 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
97 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
98 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
99 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
100 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
101 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
102 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
103 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
104 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
105 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
106 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
107
108 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
109 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
110 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
111 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
112 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
113 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
114 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
115 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
116 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
117 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
118 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
119 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
120 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
121 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
122 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
123 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
124
125 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
126 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
127 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
128 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
129 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
130 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
131 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
132 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
133 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
134 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
135 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
136 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
137 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
138 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
139 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
140 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
141
142 buf[0] += a;
143 buf[1] += b;
144 buf[2] += c;
145 buf[3] += d;
146}
147
148
149/*
150 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
151 * initialization constants.
152 */
153void
154MD5Init(struct MD5Context *ctx)
155{
156 ctx->buf[0] = 0x67452301;
157 ctx->buf[1] = 0xefcdab89;
158 ctx->buf[2] = 0x98badcfe;
159 ctx->buf[3] = 0x10325476;
160
161 ctx->bits[0] = 0;
162 ctx->bits[1] = 0;
163}
164
165/*
166 * Update context to reflect the concatenation of another buffer full
167 * of bytes.
168 */
169void
170MD5Update(struct MD5Context *ctx,
171 const void *data,
172 unsigned len)
173{
174 const unsigned char *buf = data;
175 uint32_t t;
176
177 /* Update bitcount */
178
179 t = ctx->bits[0];
180 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
181 ctx->bits[1]++; /* Carry from low to high */
182 ctx->bits[1] += len >> 29;
183
184 t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
185
186 /* Handle any leading odd-sized chunks */
187
188 if (t) {
189 unsigned char *p = (unsigned char *) ctx->in + t;
190
191 t = 64 - t;
192 if (len < t) {
193 memcpy(p, buf, len);
194 return;
195 }
196 memcpy(p, buf, t);
197 byteReverse(ctx->in, 16);
198 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
199 buf += t;
200 len -= t;
201 }
202 /* Process data in 64-byte chunks */
203
204 while (len >= 64) {
205 memcpy(ctx->in, buf, 64);
206 byteReverse(ctx->in, 16);
207 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
208 buf += 64;
209 len -= 64;
210 }
211
212 /* Handle any remaining bytes of data. */
213
214 memcpy(ctx->in, buf, len);
215}
216
217/*
218 * Final wrapup - pad to 64-byte boundary with the bit pattern
219 * 1 0* (64-bit count of bits processed, MSB-first)
220 */
221void
222MD5Final(unsigned char digest[16],
223 struct MD5Context *ctx)
224{
225 unsigned count;
226 unsigned char *p;
227
228 /* Compute number of bytes mod 64 */
229 count = (ctx->bits[0] >> 3) & 0x3F;
230
231 /* Set the first char of padding to 0x80. This is safe since there is
232 always at least one byte free */
233 p = ctx->in + count;
234 *p++ = 0x80;
235
236 /* Bytes of padding needed to make 64 bytes */
237 count = 64 - 1 - count;
238
239 /* Pad out to 56 mod 64 */
240 if (count < 8)
241 {
242 /* Two lots of padding: Pad the first block to 64 bytes */
243 memset(p, 0, count);
244 byteReverse(ctx->in, 16);
245 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
246
247 /* Now fill the next block with 56 bytes */
248 memset(ctx->in, 0, 56);
249 }
250 else
251 {
252 /* Pad block to 56 bytes */
253 memset(p, 0, count - 8);
254 }
255 byteReverse(ctx->in, 14);
256
257 /* Append length in bits and transform */
258 ((uint32_t *) ctx->in)[14] = ctx->bits[0];
259 ((uint32_t *) ctx->in)[15] = ctx->bits[1];
260
261 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
262 byteReverse((unsigned char *) ctx->buf, 4);
263 memcpy(digest, ctx->buf, 16);
264 memset(ctx, 0, sizeof(struct MD5Context)); /* In case it's sensitive */
265}
266
267/* end of md5.c */
diff --git a/src/microhttpd/md5.h b/src/microhttpd/md5.h
new file mode 100644
index 00000000..15d620d7
--- /dev/null
+++ b/src/microhttpd/md5.h
@@ -0,0 +1,51 @@
1/*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 */
17
18/* Brutally hacked by John Walker back from ANSI C to K&R (no
19 prototypes) to maintain the tradition that Netfone will compile
20 with Sun's original "cc". */
21
22#ifndef MD5_H
23#define MD5_H
24
25#include "platform.h"
26#ifdef WORDS_BIGENDIAN
27#define HIGHFIRST
28#endif
29
30#define MD5_DIGEST_SIZE 16
31
32struct MD5Context
33{
34 uint32_t buf[4];
35 uint32_t bits[2];
36 unsigned char in[64];
37};
38
39
40void
41MD5Init(struct MD5Context *ctx);
42
43void
44MD5Update(struct MD5Context *ctx,
45 const void *buf,
46 unsigned len);
47
48void MD5Final(unsigned char digest[MD5_DIGEST_SIZE],
49 struct MD5Context *ctx);
50
51#endif /* !MD5_H */
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c
new file mode 100644
index 00000000..bd7c0c3a
--- /dev/null
+++ b/src/microhttpd/memorypool.c
@@ -0,0 +1,261 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file memorypool.c
22 * @brief memory pool
23 * @author Christian Grothoff
24 */
25#include "memorypool.h"
26
27/* define MAP_ANONYMOUS for Mac OS X */
28#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
29#define MAP_ANONYMOUS MAP_ANON
30#endif
31#ifndef MAP_FAILED
32#define MAP_FAILED ((void*)-1)
33#endif
34
35/**
36 * Align to 2x word size (as GNU libc does).
37 */
38#define ALIGN_SIZE (2 * sizeof(void*))
39
40/**
41 * Round up 'n' to a multiple of ALIGN_SIZE.
42 */
43#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
44
45
46/**
47 * Handle for a memory pool. Pools are not reentrant and must not be
48 * used by multiple threads.
49 */
50struct MemoryPool
51{
52
53 /**
54 * Pointer to the pool's memory
55 */
56 char *memory;
57
58 /**
59 * Size of the pool.
60 */
61 size_t size;
62
63 /**
64 * Offset of the first unallocated byte.
65 */
66 size_t pos;
67
68 /**
69 * Offset of the last unallocated byte.
70 */
71 size_t end;
72
73 /**
74 * MHD_NO if pool was malloc'ed, MHD_YES if mmapped.
75 */
76 int is_mmap;
77};
78
79
80/**
81 * Create a memory pool.
82 *
83 * @param max maximum size of the pool
84 * @return NULL on error
85 */
86struct MemoryPool *
87MHD_pool_create (size_t max)
88{
89 struct MemoryPool *pool;
90
91 pool = malloc (sizeof (struct MemoryPool));
92 if (pool == NULL)
93 return NULL;
94#ifdef MAP_ANONYMOUS
95 pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE,
96 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
97#else
98 pool->memory = MAP_FAILED;
99#endif
100 if ((pool->memory == MAP_FAILED) || (pool->memory == NULL))
101 {
102 pool->memory = malloc (max);
103 if (pool->memory == NULL)
104 {
105 free (pool);
106 return NULL;
107 }
108 pool->is_mmap = MHD_NO;
109 }
110 else
111 {
112 pool->is_mmap = MHD_YES;
113 }
114 pool->pos = 0;
115 pool->end = max;
116 pool->size = max;
117 return pool;
118}
119
120
121/**
122 * Destroy a memory pool.
123 *
124 * @param pool memory pool to destroy
125 */
126void
127MHD_pool_destroy (struct MemoryPool *pool)
128{
129 if (pool == NULL)
130 return;
131 if (pool->is_mmap == MHD_NO)
132 free (pool->memory);
133 else
134 MUNMAP (pool->memory, pool->size);
135 free (pool);
136}
137
138
139/**
140 * Allocate size bytes from the pool.
141 *
142 * @param pool memory pool to use for the operation
143 * @param size number of bytes to allocate
144 * @param from_end allocate from end of pool (set to MHD_YES);
145 * use this for small, persistent allocations that
146 * will never be reallocated
147 * @return NULL if the pool cannot support size more
148 * bytes
149 */
150void *
151MHD_pool_allocate (struct MemoryPool *pool,
152 size_t size, int from_end)
153{
154 void *ret;
155
156 size = ROUND_TO_ALIGN (size);
157 if ((pool->pos + size > pool->end) || (pool->pos + size < pool->pos))
158 return NULL;
159 if (from_end == MHD_YES)
160 {
161 ret = &pool->memory[pool->end - size];
162 pool->end -= size;
163 }
164 else
165 {
166 ret = &pool->memory[pool->pos];
167 pool->pos += size;
168 }
169 return ret;
170}
171
172
173/**
174 * Reallocate a block of memory obtained from the pool.
175 * This is particularly efficient when growing or
176 * shrinking the block that was last (re)allocated.
177 * If the given block is not the most recenlty
178 * (re)allocated block, the memory of the previous
179 * allocation may be leaked until the pool is
180 * destroyed (and copying the data maybe required).
181 *
182 * @param pool memory pool to use for the operation
183 * @param old the existing block
184 * @param old_size the size of the existing block
185 * @param new_size the new size of the block
186 * @return new address of the block, or
187 * NULL if the pool cannot support new_size
188 * bytes (old continues to be valid for old_size)
189 */
190void *
191MHD_pool_reallocate (struct MemoryPool *pool,
192 void *old,
193 size_t old_size,
194 size_t new_size)
195{
196 void *ret;
197
198 new_size = ROUND_TO_ALIGN (new_size);
199 if ((pool->end < old_size) || (pool->end < new_size))
200 return NULL; /* unsatisfiable or bogus request */
201
202 if ((pool->pos >= old_size) && (&pool->memory[pool->pos - old_size] == old))
203 {
204 /* was the previous allocation - optimize! */
205 if (pool->pos + new_size - old_size <= pool->end)
206 {
207 /* fits */
208 pool->pos += new_size - old_size;
209 if (new_size < old_size) /* shrinking - zero again! */
210 memset (&pool->memory[pool->pos], 0, old_size - new_size);
211 return old;
212 }
213 /* does not fit */
214 return NULL;
215 }
216 if (new_size <= old_size)
217 return old; /* cannot shrink, no need to move */
218 if ((pool->pos + new_size >= pool->pos) &&
219 (pool->pos + new_size <= pool->end))
220 {
221 /* fits */
222 ret = &pool->memory[pool->pos];
223 memcpy (ret, old, old_size);
224 pool->pos += new_size;
225 return ret;
226 }
227 /* does not fit */
228 return NULL;
229}
230
231
232/**
233 * Clear all entries from the memory pool except
234 * for "keep" of the given "size".
235 *
236 * @param pool memory pool to use for the operation
237 * @param keep pointer to the entry to keep (maybe NULL)
238 * @param size how many bytes need to be kept at this address
239 * @return addr new address of "keep" (if it had to change)
240 */
241void *
242MHD_pool_reset (struct MemoryPool *pool,
243 void *keep,
244 size_t size)
245{
246 size = ROUND_TO_ALIGN (size);
247 if (keep != NULL)
248 {
249 if (keep != pool->memory)
250 {
251 memmove (pool->memory, keep, size);
252 keep = pool->memory;
253 }
254 pool->pos = size;
255 }
256 pool->end = pool->size;
257 return keep;
258}
259
260
261/* end of memorypool.c */
diff --git a/src/microhttpd/memorypool.h b/src/microhttpd/memorypool.h
new file mode 100644
index 00000000..8187a91d
--- /dev/null
+++ b/src/microhttpd/memorypool.h
@@ -0,0 +1,114 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file memorypool.h
22 * @brief memory pool; mostly used for efficient (de)allocation
23 * for each connection and bounding memory use for each
24 * request
25 * @author Christian Grothoff
26 */
27
28#ifndef MEMORYPOOL_H
29#define MEMORYPOOL_H
30
31#include "internal.h"
32
33/**
34 * Opaque handle for a memory pool.
35 * Pools are not reentrant and must not be used
36 * by multiple threads.
37 */
38struct MemoryPool;
39
40
41/**
42 * Create a memory pool.
43 *
44 * @param max maximum size of the pool
45 * @return NULL on error
46 */
47struct MemoryPool *
48MHD_pool_create (size_t max);
49
50
51/**
52 * Destroy a memory pool.
53 *
54 * @param pool memory pool to destroy
55 */
56void
57MHD_pool_destroy (struct MemoryPool *pool);
58
59
60/**
61 * Allocate size bytes from the pool.
62 *
63 * @param pool memory pool to use for the operation
64 * @param size number of bytes to allocate
65 * @param from_end allocate from end of pool (set to MHD_YES);
66 * use this for small, persistent allocations that
67 * will never be reallocated
68 * @return NULL if the pool cannot support size more
69 * bytes
70 */
71void *
72MHD_pool_allocate (struct MemoryPool *pool,
73 size_t size, int from_end);
74
75
76/**
77 * Reallocate a block of memory obtained from the pool.
78 * This is particularly efficient when growing or
79 * shrinking the block that was last (re)allocated.
80 * If the given block is not the most recenlty
81 * (re)allocated block, the memory of the previous
82 * allocation may be leaked until the pool is
83 * destroyed (and copying the data maybe required).
84 *
85 * @param pool memory pool to use for the operation
86 * @param old the existing block
87 * @param old_size the size of the existing block
88 * @param new_size the new size of the block
89 * @return new address of the block, or
90 * NULL if the pool cannot support new_size
91 * bytes (old continues to be valid for old_size)
92 */
93void *
94MHD_pool_reallocate (struct MemoryPool *pool,
95 void *old,
96 size_t old_size,
97 size_t new_size);
98
99
100/**
101 * Clear all entries from the memory pool except
102 * for "keep" of the given "size".
103 *
104 * @param pool memory pool to use for the operation
105 * @param keep pointer to the entry to keep (maybe NULL)
106 * @param size how many bytes need to be kept at this address
107 * @return addr new address of "keep" (if it had to change)
108 */
109void *
110MHD_pool_reset (struct MemoryPool *pool,
111 void *keep,
112 size_t size);
113
114#endif
diff --git a/src/microhttpd/postprocessor.c b/src/microhttpd/postprocessor.c
new file mode 100644
index 00000000..6cd6d82d
--- /dev/null
+++ b/src/microhttpd/postprocessor.c
@@ -0,0 +1,1158 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file postprocessor.c
22 * @brief Methods for parsing POST data
23 * @author Christian Grothoff
24 */
25
26#include "internal.h"
27
28/**
29 * Size of on-stack buffer that we use for un-escaping of the value.
30 * We use a pretty small value to be nice to the stack on embedded
31 * systems.
32 */
33#define XBUF_SIZE 512
34
35/**
36 * States in the PP parser's state machine.
37 */
38enum PP_State
39{
40 /* general states */
41 PP_Error,
42 PP_Done,
43 PP_Init,
44 PP_NextBoundary,
45
46 /* url encoding-states */
47 PP_ProcessValue,
48 PP_ExpectNewLine,
49
50 /* post encoding-states */
51 PP_ProcessEntryHeaders,
52 PP_PerformCheckMultipart,
53 PP_ProcessValueToBoundary,
54 PP_PerformCleanup,
55
56 /* nested post-encoding states */
57 PP_Nested_Init,
58 PP_Nested_PerformMarking,
59 PP_Nested_ProcessEntryHeaders,
60 PP_Nested_ProcessValueToBoundary,
61 PP_Nested_PerformCleanup
62
63};
64
65
66enum RN_State
67{
68 /**
69 * No RN-preprocessing in this state.
70 */
71 RN_Inactive = 0,
72
73 /**
74 * If the next character is CR, skip it. Otherwise,
75 * just go inactive.
76 */
77 RN_OptN = 1,
78
79 /**
80 * Expect LFCR (and only LFCR). As always, we also
81 * expect only LF or only CR.
82 */
83 RN_Full = 2,
84
85 /**
86 * Expect either LFCR or '--'LFCR. If '--'LFCR, transition into dash-state
87 * for the main state machine
88 */
89 RN_Dash = 3,
90
91 /**
92 * Got a single dash, expect second dash.
93 */
94 RN_Dash2 = 4
95};
96
97
98/**
99 * Bits for the globally known fields that
100 * should not be deleted when we exit the
101 * nested state.
102 */
103enum NE_State
104{
105 NE_none = 0,
106 NE_content_name = 1,
107 NE_content_type = 2,
108 NE_content_filename = 4,
109 NE_content_transfer_encoding = 8
110};
111
112
113/**
114 * Internal state of the post-processor. Note that the fields
115 * are sorted by type to enable optimal packing by the compiler.
116 */
117struct MHD_PostProcessor
118{
119
120 /**
121 * The connection for which we are doing
122 * POST processing.
123 */
124 struct MHD_Connection *connection;
125
126 /**
127 * Function to call with POST data.
128 */
129 MHD_PostDataIterator ikvi;
130
131 /**
132 * Extra argument to ikvi.
133 */
134 void *cls;
135
136 /**
137 * Encoding as given by the headers of the
138 * connection.
139 */
140 const char *encoding;
141
142 /**
143 * Primary boundary (points into encoding string)
144 */
145 const char *boundary;
146
147 /**
148 * Nested boundary (if we have multipart/mixed encoding).
149 */
150 char *nested_boundary;
151
152 /**
153 * Pointer to the name given in disposition.
154 */
155 char *content_name;
156
157 /**
158 * Pointer to the (current) content type.
159 */
160 char *content_type;
161
162 /**
163 * Pointer to the (current) filename.
164 */
165 char *content_filename;
166
167 /**
168 * Pointer to the (current) encoding.
169 */
170 char *content_transfer_encoding;
171
172 /**
173 * Unprocessed value bytes due to escape
174 * sequences (URL-encoding only).
175 */
176 char xbuf[8];
177
178 /**
179 * Size of our buffer for the key.
180 */
181 size_t buffer_size;
182
183 /**
184 * Current position in the key buffer.
185 */
186 size_t buffer_pos;
187
188 /**
189 * Current position in xbuf.
190 */
191 size_t xbuf_pos;
192
193 /**
194 * Current offset in the value being processed.
195 */
196 uint64_t value_offset;
197
198 /**
199 * strlen(boundary) -- if boundary != NULL.
200 */
201 size_t blen;
202
203 /**
204 * strlen(nested_boundary) -- if nested_boundary != NULL.
205 */
206 size_t nlen;
207
208 /**
209 * Do we have to call the 'ikvi' callback when processing the
210 * multipart post body even if the size of the payload is zero?
211 * Set to MHD_YES whenever we parse a new multiparty entry header,
212 * and to MHD_NO the first time we call the 'ikvi' callback.
213 * Used to ensure that we do always call 'ikvi' even if the
214 * payload is empty (but not more than once).
215 */
216 int must_ikvi;
217
218 /**
219 * State of the parser.
220 */
221 enum PP_State state;
222
223 /**
224 * Side-state-machine: skip LRCR (or just LF).
225 * Set to 0 if we are not in skip mode. Set to 2
226 * if a LFCR is expected, set to 1 if a CR should
227 * be skipped if it is the next character.
228 */
229 enum RN_State skip_rn;
230
231 /**
232 * If we are in skip_rn with "dash" mode and
233 * do find 2 dashes, what state do we go into?
234 */
235 enum PP_State dash_state;
236
237 /**
238 * Which headers are global? (used to tell which
239 * headers were only valid for the nested multipart).
240 */
241 enum NE_State have;
242
243};
244
245
246/**
247 * Create a PostProcessor.
248 *
249 * A PostProcessor can be used to (incrementally)
250 * parse the data portion of a POST request.
251 *
252 * @param connection the connection on which the POST is
253 * happening (used to determine the POST format)
254 * @param buffer_size maximum number of bytes to use for
255 * internal buffering (used only for the parsing,
256 * specifically the parsing of the keys). A
257 * tiny value (256-1024) should be sufficient.
258 * Do NOT use 0.
259 * @param iter iterator to be called with the parsed data
260 * @param iter_cls first argument to iter
261 * @return NULL on error (out of memory, unsupported encoding),
262 * otherwise a PP handle
263 */
264struct MHD_PostProcessor *
265MHD_create_post_processor (struct MHD_Connection *connection,
266 size_t buffer_size,
267 MHD_PostDataIterator iter, void *iter_cls)
268{
269 struct MHD_PostProcessor *ret;
270 const char *encoding;
271 const char *boundary;
272 size_t blen;
273
274 if ((buffer_size < 256) || (connection == NULL) || (iter == NULL))
275 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
276 encoding = MHD_lookup_connection_value (connection,
277 MHD_HEADER_KIND,
278 MHD_HTTP_HEADER_CONTENT_TYPE);
279 if (encoding == NULL)
280 return NULL;
281 boundary = NULL;
282 if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
283 strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
284 {
285 if (0 !=
286 strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
287 strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
288 return NULL;
289 boundary =
290 &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
291 /* Q: should this be "strcasestr"? */
292 boundary = strstr (boundary, "boundary=");
293 if (NULL == boundary)
294 return NULL; /* failed to determine boundary */
295 boundary += strlen ("boundary=");
296 blen = strlen (boundary);
297 if ((blen == 0) || (blen * 2 + 2 > buffer_size))
298 return NULL; /* (will be) out of memory or invalid boundary */
299 if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
300 {
301 /* remove enclosing quotes */
302 ++boundary;
303 blen -= 2;
304 }
305 }
306 else
307 blen = 0;
308 buffer_size += 4; /* round up to get nice block sizes despite boundary search */
309
310 /* add +1 to ensure we ALWAYS have a zero-termination at the end */
311 if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
312 return NULL;
313 memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
314 ret->connection = connection;
315 ret->ikvi = iter;
316 ret->cls = iter_cls;
317 ret->encoding = encoding;
318 ret->buffer_size = buffer_size;
319 ret->state = PP_Init;
320 ret->blen = blen;
321 ret->boundary = boundary;
322 ret->skip_rn = RN_Inactive;
323 return ret;
324}
325
326
327/**
328 * Process url-encoded POST data.
329 *
330 * @param pp post processor context
331 * @param post_data upload data
332 * @param post_data_len number of bytes in upload_data
333 * @return MHD_YES on success, MHD_NO if there was an error processing the data
334 */
335static int
336post_process_urlencoded (struct MHD_PostProcessor *pp,
337 const char *post_data,
338 size_t post_data_len)
339{
340 size_t equals;
341 size_t amper;
342 size_t poff;
343 size_t xoff;
344 size_t delta;
345 int end_of_value_found;
346 char *buf;
347 char xbuf[XBUF_SIZE + 1];
348
349 buf = (char *) &pp[1];
350 poff = 0;
351 while (poff < post_data_len)
352 {
353 switch (pp->state)
354 {
355 case PP_Error:
356 return MHD_NO;
357 case PP_Done:
358 /* did not expect to receive more data */
359 pp->state = PP_Error;
360 return MHD_NO;
361 case PP_Init:
362 equals = 0;
363 while ((equals + poff < post_data_len) &&
364 (post_data[equals + poff] != '='))
365 equals++;
366 if (equals + pp->buffer_pos > pp->buffer_size)
367 {
368 pp->state = PP_Error; /* out of memory */
369 return MHD_NO;
370 }
371 memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
372 pp->buffer_pos += equals;
373 if (equals + poff == post_data_len)
374 return MHD_YES; /* no '=' yet */
375 buf[pp->buffer_pos] = '\0'; /* 0-terminate key */
376 pp->buffer_pos = 0; /* reset for next key */
377 MHD_http_unescape (NULL, NULL, buf);
378 poff += equals + 1;
379 pp->state = PP_ProcessValue;
380 pp->value_offset = 0;
381 break;
382 case PP_ProcessValue:
383 /* obtain rest of value from previous iteration */
384 memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
385 xoff = pp->xbuf_pos;
386 pp->xbuf_pos = 0;
387
388 /* find last position in input buffer that is part of the value */
389 amper = 0;
390 while ((amper + poff < post_data_len) &&
391 (amper < XBUF_SIZE) &&
392 (post_data[amper + poff] != '&') &&
393 (post_data[amper + poff] != '\n') &&
394 (post_data[amper + poff] != '\r'))
395 amper++;
396 end_of_value_found = ((amper + poff < post_data_len) &&
397 ((post_data[amper + poff] == '&') ||
398 (post_data[amper + poff] == '\n') ||
399 (post_data[amper + poff] == '\r')));
400 /* compute delta, the maximum number of bytes that we will be able to
401 process right now (either amper-limited of xbuf-size limited) */
402 delta = amper;
403 if (delta > XBUF_SIZE - xoff)
404 delta = XBUF_SIZE - xoff;
405
406 /* move input into processing buffer */
407 memcpy (&xbuf[xoff], &post_data[poff], delta);
408 xoff += delta;
409 poff += delta;
410
411 /* find if escape sequence is at the end of the processing buffer;
412 if so, exclude those from processing (reduce delta to point at
413 end of processed region) */
414 delta = xoff;
415 if ((delta > 0) && (xbuf[delta - 1] == '%'))
416 delta--;
417 else if ((delta > 1) && (xbuf[delta - 2] == '%'))
418 delta -= 2;
419
420 /* if we have an incomplete escape sequence, save it to
421 pp->xbuf for later */
422 if (delta < xoff)
423 {
424 memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
425 pp->xbuf_pos = xoff - delta;
426 xoff = delta;
427 }
428
429 /* If we have nothing to do (delta == 0) and
430 not just because the value is empty (are
431 waiting for more data), go for next iteration */
432 if ((xoff == 0) && (poff == post_data_len))
433 continue;
434
435 /* unescape */
436 xbuf[xoff] = '\0'; /* 0-terminate in preparation */
437 xoff = MHD_http_unescape (NULL, NULL, xbuf);
438 /* finally: call application! */
439 pp->must_ikvi = MHD_NO;
440 if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1], /* key */
441 NULL, NULL, NULL, xbuf, pp->value_offset,
442 xoff))
443 {
444 pp->state = PP_Error;
445 return MHD_NO;
446 }
447 pp->value_offset += xoff;
448
449 /* are we done with the value? */
450 if (end_of_value_found)
451 {
452 /* we found the end of the value! */
453 if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
454 {
455 pp->state = PP_ExpectNewLine;
456 }
457 else if (post_data[poff] == '&')
458 {
459 poff++; /* skip '&' */
460 pp->state = PP_Init;
461 }
462 }
463 break;
464 case PP_ExpectNewLine:
465 if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
466 {
467 poff++;
468 /* we are done, report error if we receive any more... */
469 pp->state = PP_Done;
470 return MHD_YES;
471 }
472 return MHD_NO;
473 default:
474 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */
475 }
476 }
477 return MHD_YES;
478}
479
480
481/**
482 * If the given line matches the prefix, strdup the
483 * rest of the line into the suffix ptr.
484 *
485 * @param prefix prefix to match
486 * @param line line to match prefix in
487 * @param suffix set to a copy of the rest of the line, starting at the end of the match
488 * @return MHD_YES if there was a match, MHD_NO if not
489 */
490static int
491try_match_header (const char *prefix, char *line, char **suffix)
492{
493 if (NULL != *suffix)
494 return MHD_NO;
495 while (*line != 0)
496 {
497 if (0 == strncasecmp (prefix, line, strlen (prefix)))
498 {
499 *suffix = strdup (&line[strlen (prefix)]);
500 return MHD_YES;
501 }
502 ++line;
503 }
504 return MHD_NO;
505}
506
507
508/**
509 *
510 * @param pp post processor context
511 * @param boundary boundary to look for
512 * @param blen number of bytes in boundary
513 * @param ioffptr set to the end of the boundary if found,
514 * otherwise incremented by one (FIXME: quirky API!)
515 * @param next_state state to which we should advance the post processor
516 * if the boundary is found
517 * @param next_dash_state dash_state to which we should advance the
518 * post processor if the boundary is found
519 * @return MHD_NO if the boundary is not found, MHD_YES if we did find it
520 */
521static int
522find_boundary (struct MHD_PostProcessor *pp,
523 const char *boundary,
524 size_t blen,
525 size_t *ioffptr,
526 enum PP_State next_state, enum PP_State next_dash_state)
527{
528 char *buf = (char *) &pp[1];
529
530 if (pp->buffer_pos < 2 + blen)
531 {
532 if (pp->buffer_pos == pp->buffer_size)
533 pp->state = PP_Error; /* out of memory */
534 ++(*ioffptr);
535 return MHD_NO; /* not enough data */
536 }
537 if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
538 {
539 if (pp->state != PP_Init)
540 pp->state = PP_Error;
541 return MHD_NO; /* expected boundary */
542 }
543 /* remove boundary from buffer */
544 (*ioffptr) += 2 + blen;
545 /* next: start with headers */
546 pp->skip_rn = RN_Dash;
547 pp->state = next_state;
548 pp->dash_state = next_dash_state;
549 return MHD_YES;
550}
551
552
553/**
554 * In buf, there maybe an expression '$key="$value"'. If that is the
555 * case, copy a copy of $value to destination.
556 *
557 * If destination is already non-NULL,
558 * do nothing.
559 */
560static void
561try_get_value (const char *buf,
562 const char *key,
563 char **destination)
564{
565 const char *spos;
566 const char *bpos;
567 const char *endv;
568 size_t klen;
569 size_t vlen;
570
571 if (NULL != *destination)
572 return;
573 bpos = buf;
574 klen = strlen (key);
575 while (NULL != (spos = strstr (bpos, key)))
576 {
577 if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
578 {
579 /* no match */
580 bpos = spos + 1;
581 continue;
582 }
583 if (spos[klen + 1] != '"')
584 return; /* not quoted */
585 if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
586 return; /* no end-quote */
587 vlen = endv - spos - klen - 1;
588 *destination = malloc (vlen);
589 if (NULL == *destination)
590 return; /* out of memory */
591 (*destination)[vlen - 1] = '\0';
592 memcpy (*destination, &spos[klen + 2], vlen - 1);
593 return; /* success */
594 }
595}
596
597
598/**
599 * Go over the headers of the part and update
600 * the fields in "pp" according to what we find.
601 * If we are at the end of the headers (as indicated
602 * by an empty line), transition into next_state.
603 *
604 * @param pp post processor context
605 * @param ioffptr set to how many bytes have been
606 * processed
607 * @param next_state state to which the post processor should
608 * be advanced if we find the end of the headers
609 * @return MHD_YES if we can continue processing,
610 * MHD_NO on error or if we do not have
611 * enough data yet
612 */
613static int
614process_multipart_headers (struct MHD_PostProcessor *pp,
615 size_t *ioffptr, enum PP_State next_state)
616{
617 char *buf = (char *) &pp[1];
618 size_t newline;
619
620 newline = 0;
621 while ((newline < pp->buffer_pos) &&
622 (buf[newline] != '\r') && (buf[newline] != '\n'))
623 newline++;
624 if (newline == pp->buffer_size)
625 {
626 pp->state = PP_Error;
627 return MHD_NO; /* out of memory */
628 }
629 if (newline == pp->buffer_pos)
630 return MHD_NO; /* will need more data */
631 if (0 == newline)
632 {
633 /* empty line - end of headers */
634 pp->skip_rn = RN_Full;
635 pp->state = next_state;
636 return MHD_YES;
637 }
638 /* got an actual header */
639 if (buf[newline] == '\r')
640 pp->skip_rn = RN_OptN;
641 buf[newline] = '\0';
642 if (0 == strncasecmp ("Content-disposition: ",
643 buf, strlen ("Content-disposition: ")))
644 {
645 try_get_value (&buf[strlen ("Content-disposition: ")],
646 "name", &pp->content_name);
647 try_get_value (&buf[strlen ("Content-disposition: ")],
648 "filename", &pp->content_filename);
649 }
650 else
651 {
652 try_match_header ("Content-type: ", buf, &pp->content_type);
653 try_match_header ("Content-Transfer-Encoding: ",
654 buf, &pp->content_transfer_encoding);
655 }
656 (*ioffptr) += newline + 1;
657 return MHD_YES;
658}
659
660
661/**
662 * We have the value until we hit the given boundary;
663 * process accordingly.
664 *
665 * @param pp post processor context
666 * @param ioffptr incremented based on the number of bytes processed
667 * @param boundary the boundary to look for
668 * @param blen strlen(boundary)
669 * @param next_state what state to go into after the
670 * boundary was found
671 * @param next_dash_state state to go into if the next
672 * boundary ends with "--"
673 * @return MHD_YES if we can continue processing,
674 * MHD_NO on error or if we do not have
675 * enough data yet
676 */
677static int
678process_value_to_boundary (struct MHD_PostProcessor *pp,
679 size_t *ioffptr,
680 const char *boundary,
681 size_t blen,
682 enum PP_State next_state,
683 enum PP_State next_dash_state)
684{
685 char *buf = (char *) &pp[1];
686 size_t newline;
687
688 /* all data in buf until the boundary
689 (\r\n--+boundary) is part of the value */
690 newline = 0;
691 while (1)
692 {
693 while ((newline + 4 < pp->buffer_pos) &&
694 (0 != memcmp ("\r\n--", &buf[newline], 4)))
695 newline++;
696 if (newline + pp->blen + 4 <= pp->buffer_pos)
697 {
698 /* can check boundary */
699 if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
700 {
701 /* no boundary, "\r\n--" is part of content, skip */
702 newline += 4;
703 continue;
704 }
705 else
706 {
707 /* boundary found, process until newline then
708 skip boundary and go back to init */
709 pp->skip_rn = RN_Dash;
710 pp->state = next_state;
711 pp->dash_state = next_dash_state;
712 (*ioffptr) += pp->blen + 4; /* skip boundary as well */
713 buf[newline] = '\0';
714 break;
715 }
716 }
717 else
718 {
719 /* cannot check for boundary, process content that
720 we have and check again later; except, if we have
721 no content, abort (out of memory) */
722 if ((0 == newline) && (pp->buffer_pos == pp->buffer_size))
723 {
724 pp->state = PP_Error;
725 return MHD_NO;
726 }
727 break;
728 }
729 }
730 /* newline is either at beginning of boundary or
731 at least at the last character that we are sure
732 is not part of the boundary */
733 if ( ( (MHD_YES == pp->must_ikvi) ||
734 (0 != newline) ) &&
735 (MHD_NO == pp->ikvi (pp->cls,
736 MHD_POSTDATA_KIND,
737 pp->content_name,
738 pp->content_filename,
739 pp->content_type,
740 pp->content_transfer_encoding,
741 buf, pp->value_offset, newline)) )
742 {
743 pp->state = PP_Error;
744 return MHD_NO;
745 }
746 pp->must_ikvi = MHD_NO;
747 pp->value_offset += newline;
748 (*ioffptr) += newline;
749 return MHD_YES;
750}
751
752
753/**
754 *
755 * @param pp post processor context
756 */
757static void
758free_unmarked (struct MHD_PostProcessor *pp)
759{
760 if ((NULL != pp->content_name) && (0 == (pp->have & NE_content_name)))
761 {
762 free (pp->content_name);
763 pp->content_name = NULL;
764 }
765 if ((NULL != pp->content_type) && (0 == (pp->have & NE_content_type)))
766 {
767 free (pp->content_type);
768 pp->content_type = NULL;
769 }
770 if ((NULL != pp->content_filename) &&
771 (0 == (pp->have & NE_content_filename)))
772 {
773 free (pp->content_filename);
774 pp->content_filename = NULL;
775 }
776 if ((NULL != pp->content_transfer_encoding) &&
777 (0 == (pp->have & NE_content_transfer_encoding)))
778 {
779 free (pp->content_transfer_encoding);
780 pp->content_transfer_encoding = NULL;
781 }
782}
783
784
785/**
786 * Decode multipart POST data.
787 *
788 * @param pp post processor context
789 * @param post_data data to decode
790 * @param post_data_len number of bytes in 'post_data'
791 * @return MHD_NO on error,
792 */
793static int
794post_process_multipart (struct MHD_PostProcessor *pp,
795 const char *post_data,
796 size_t post_data_len)
797{
798 char *buf;
799 size_t max;
800 size_t ioff;
801 size_t poff;
802 int state_changed;
803
804 buf = (char *) &pp[1];
805 ioff = 0;
806 poff = 0;
807 state_changed = 1;
808 while ((poff < post_data_len) ||
809 ((pp->buffer_pos > 0) && (state_changed != 0)))
810 {
811 /* first, move as much input data
812 as possible to our internal buffer */
813 max = pp->buffer_size - pp->buffer_pos;
814 if (max > post_data_len - poff)
815 max = post_data_len - poff;
816 memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
817 poff += max;
818 pp->buffer_pos += max;
819 if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
820 {
821 pp->state = PP_Error;
822 return MHD_NO; /* out of memory */
823 }
824 state_changed = 0;
825
826 /* first state machine for '\r'-'\n' and '--' handling */
827 switch (pp->skip_rn)
828 {
829 case RN_Inactive:
830 break;
831 case RN_OptN:
832 if (buf[0] == '\n')
833 {
834 ioff++;
835 pp->skip_rn = RN_Inactive;
836 goto AGAIN;
837 }
838 /* fall-through! */
839 case RN_Dash:
840 if (buf[0] == '-')
841 {
842 ioff++;
843 pp->skip_rn = RN_Dash2;
844 goto AGAIN;
845 }
846 pp->skip_rn = RN_Full;
847 /* fall-through! */
848 case RN_Full:
849 if (buf[0] == '\r')
850 {
851 if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
852 {
853 pp->skip_rn = RN_Inactive;
854 ioff += 2;
855 }
856 else
857 {
858 pp->skip_rn = RN_OptN;
859 ioff++;
860 }
861 goto AGAIN;
862 }
863 if (buf[0] == '\n')
864 {
865 ioff++;
866 pp->skip_rn = RN_Inactive;
867 goto AGAIN;
868 }
869 pp->skip_rn = RN_Inactive;
870 pp->state = PP_Error;
871 return MHD_NO; /* no '\r\n' */
872 case RN_Dash2:
873 if (buf[0] == '-')
874 {
875 ioff++;
876 pp->skip_rn = RN_Full;
877 pp->state = pp->dash_state;
878 goto AGAIN;
879 }
880 pp->state = PP_Error;
881 break;
882 }
883
884 /* main state engine */
885 switch (pp->state)
886 {
887 case PP_Error:
888 return MHD_NO;
889 case PP_Done:
890 /* did not expect to receive more data */
891 pp->state = PP_Error;
892 return MHD_NO;
893 case PP_Init:
894 /**
895 * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
896 * prior to the first multipart boundary:
897 *
898 * > There appears to be room for additional information prior
899 * > to the first boundary delimiter line and following the
900 * > final boundary delimiter line. These areas should
901 * > generally be left blank, and implementations must ignore
902 * > anything that appears before the first boundary delimiter
903 * > line or after the last one.
904 */
905 (void) find_boundary (pp,
906 pp->boundary,
907 pp->blen,
908 &ioff,
909 PP_ProcessEntryHeaders, PP_Done);
910 break;
911 case PP_NextBoundary:
912 if (MHD_NO == find_boundary (pp,
913 pp->boundary,
914 pp->blen,
915 &ioff,
916 PP_ProcessEntryHeaders, PP_Done))
917 {
918 if (pp->state == PP_Error)
919 return MHD_NO;
920 goto END;
921 }
922 break;
923 case PP_ProcessEntryHeaders:
924 pp->must_ikvi = MHD_YES;
925 if (MHD_NO ==
926 process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
927 {
928 if (pp->state == PP_Error)
929 return MHD_NO;
930 else
931 goto END;
932 }
933 state_changed = 1;
934 break;
935 case PP_PerformCheckMultipart:
936 if ((pp->content_type != NULL) &&
937 (0 == strncasecmp (pp->content_type,
938 "multipart/mixed",
939 strlen ("multipart/mixed"))))
940 {
941 pp->nested_boundary = strstr (pp->content_type, "boundary=");
942 if (pp->nested_boundary == NULL)
943 {
944 pp->state = PP_Error;
945 return MHD_NO;
946 }
947 pp->nested_boundary =
948 strdup (&pp->nested_boundary[strlen ("boundary=")]);
949 if (pp->nested_boundary == NULL)
950 {
951 /* out of memory */
952 pp->state = PP_Error;
953 return MHD_NO;
954 }
955 /* free old content type, we will need that field
956 for the content type of the nested elements */
957 free (pp->content_type);
958 pp->content_type = NULL;
959 pp->nlen = strlen (pp->nested_boundary);
960 pp->state = PP_Nested_Init;
961 state_changed = 1;
962 break;
963 }
964 pp->state = PP_ProcessValueToBoundary;
965 pp->value_offset = 0;
966 state_changed = 1;
967 break;
968 case PP_ProcessValueToBoundary:
969 if (MHD_NO == process_value_to_boundary (pp,
970 &ioff,
971 pp->boundary,
972 pp->blen,
973 PP_PerformCleanup,
974 PP_Done))
975 {
976 if (pp->state == PP_Error)
977 return MHD_NO;
978 break;
979 }
980 break;
981 case PP_PerformCleanup:
982 /* clean up state of one multipart form-data element! */
983 pp->have = NE_none;
984 free_unmarked (pp);
985 if (pp->nested_boundary != NULL)
986 {
987 free (pp->nested_boundary);
988 pp->nested_boundary = NULL;
989 }
990 pp->state = PP_ProcessEntryHeaders;
991 state_changed = 1;
992 break;
993 case PP_Nested_Init:
994 if (pp->nested_boundary == NULL)
995 {
996 pp->state = PP_Error;
997 return MHD_NO;
998 }
999 if (MHD_NO == find_boundary (pp,
1000 pp->nested_boundary,
1001 pp->nlen,
1002 &ioff,
1003 PP_Nested_PerformMarking,
1004 PP_NextBoundary /* or PP_Error? */ ))
1005 {
1006 if (pp->state == PP_Error)
1007 return MHD_NO;
1008 goto END;
1009 }
1010 break;
1011 case PP_Nested_PerformMarking:
1012 /* remember what headers were given
1013 globally */
1014 pp->have = NE_none;
1015 if (pp->content_name != NULL)
1016 pp->have |= NE_content_name;
1017 if (pp->content_type != NULL)
1018 pp->have |= NE_content_type;
1019 if (pp->content_filename != NULL)
1020 pp->have |= NE_content_filename;
1021 if (pp->content_transfer_encoding != NULL)
1022 pp->have |= NE_content_transfer_encoding;
1023 pp->state = PP_Nested_ProcessEntryHeaders;
1024 state_changed = 1;
1025 break;
1026 case PP_Nested_ProcessEntryHeaders:
1027 pp->value_offset = 0;
1028 if (MHD_NO ==
1029 process_multipart_headers (pp, &ioff,
1030 PP_Nested_ProcessValueToBoundary))
1031 {
1032 if (pp->state == PP_Error)
1033 return MHD_NO;
1034 else
1035 goto END;
1036 }
1037 state_changed = 1;
1038 break;
1039 case PP_Nested_ProcessValueToBoundary:
1040 if (MHD_NO == process_value_to_boundary (pp,
1041 &ioff,
1042 pp->nested_boundary,
1043 pp->nlen,
1044 PP_Nested_PerformCleanup,
1045 PP_NextBoundary))
1046 {
1047 if (pp->state == PP_Error)
1048 return MHD_NO;
1049 break;
1050 }
1051 break;
1052 case PP_Nested_PerformCleanup:
1053 free_unmarked (pp);
1054 pp->state = PP_Nested_ProcessEntryHeaders;
1055 state_changed = 1;
1056 break;
1057 default:
1058 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */
1059 }
1060 AGAIN:
1061 if (ioff > 0)
1062 {
1063 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1064 pp->buffer_pos -= ioff;
1065 ioff = 0;
1066 state_changed = 1;
1067 }
1068 }
1069END:
1070 if (ioff != 0)
1071 {
1072 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1073 pp->buffer_pos -= ioff;
1074 }
1075 if (poff < post_data_len)
1076 {
1077 pp->state = PP_Error;
1078 return MHD_NO; /* serious error */
1079 }
1080 return MHD_YES;
1081}
1082
1083
1084/**
1085 * Parse and process POST data.
1086 * Call this function when POST data is available
1087 * (usually during an MHD_AccessHandlerCallback)
1088 * with the upload_data and upload_data_size.
1089 * Whenever possible, this will then cause calls
1090 * to the MHD_IncrementalKeyValueIterator.
1091 *
1092 * @param pp the post processor
1093 * @param post_data post_data_len bytes of POST data
1094 * @param post_data_len length of post_data
1095 * @return MHD_YES on success, MHD_NO on error
1096 * (out-of-memory, iterator aborted, parse error)
1097 */
1098int
1099MHD_post_process (struct MHD_PostProcessor *pp,
1100 const char *post_data, size_t post_data_len)
1101{
1102 if (post_data_len == 0)
1103 return MHD_YES;
1104 if (pp == NULL)
1105 return MHD_NO;
1106 if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
1107 strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
1108 return post_process_urlencoded (pp, post_data, post_data_len);
1109 if (0 ==
1110 strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
1111 strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
1112 return post_process_multipart (pp, post_data, post_data_len);
1113 /* this should never be reached */
1114 return MHD_NO;
1115}
1116
1117
1118/**
1119 * Release PostProcessor resources.
1120 *
1121 * @param pp post processor context to destroy
1122 * @return MHD_YES if processing completed nicely,
1123 * MHD_NO if there were spurious characters / formatting
1124 * problems; it is common to ignore the return
1125 * value of this function
1126 */
1127int
1128MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1129{
1130 int ret;
1131
1132 if (NULL == pp)
1133 return MHD_YES;
1134 if (PP_ProcessValue == pp->state)
1135 {
1136 /* key without terminated value left at the end of the
1137 buffer; fake receiving a termination character to
1138 ensure it is also processed */
1139 post_process_urlencoded (pp, "\n", 1);
1140 }
1141 /* These internal strings need cleaning up since
1142 the post-processing may have been interrupted
1143 at any stage */
1144 if ((pp->xbuf_pos > 0) ||
1145 ( (pp->state != PP_Done) &&
1146 (pp->state != PP_ExpectNewLine)))
1147 ret = MHD_NO;
1148 else
1149 ret = MHD_YES;
1150 pp->have = NE_none;
1151 free_unmarked (pp);
1152 if (pp->nested_boundary != NULL)
1153 free (pp->nested_boundary);
1154 free (pp);
1155 return ret;
1156}
1157
1158/* end of postprocessor.c */
diff --git a/src/microhttpd/reason_phrase.c b/src/microhttpd/reason_phrase.c
new file mode 100644
index 00000000..843f47a9
--- /dev/null
+++ b/src/microhttpd/reason_phrase.c
@@ -0,0 +1,159 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2011 Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file reason_phrase.c
23 * @brief Tables of the string response phrases
24 * @author Elliot Glaysher
25 * @author Christian Grothoff (minor code clean up)
26 */
27
28#include "reason_phrase.h"
29
30#ifndef NULL
31#define NULL (void*)0
32#endif
33
34static const char *invalid_hundred[] = { NULL };
35
36static const char *const one_hundred[] = {
37 "Continue",
38 "Switching Protocols",
39 "Processing"
40};
41
42static const char *const two_hundred[] = {
43 "OK",
44 "Created",
45 "Accepted",
46 "Non-Authoritative Information",
47 "No Content",
48 "Reset Content",
49 "Partial Content",
50 "Multi Status"
51};
52
53static const char *const three_hundred[] = {
54 "Multiple Choices",
55 "Moved Permanently",
56 "Moved Temporarily",
57 "See Other",
58 "Not Modified",
59 "Use Proxy",
60 "Switch Proxy",
61 "Temporary Redirect"
62};
63
64static const char *const four_hundred[] = {
65 "Bad Request",
66 "Unauthorized",
67 "Payment Required",
68 "Forbidden",
69 "Not Found",
70 "Method Not Allowed",
71 "Not Acceptable",
72 "Proxy Authentication Required",
73 "Request Time-out",
74 "Conflict",
75 "Gone",
76 "Length Required",
77 "Precondition Failed",
78 "Request Entity Too Large",
79 "Request-URI Too Large",
80 "Unsupported Media Type",
81 "Requested Range Not Satisfiable",
82 "Expectation Failed",
83 "Unknown",
84 "Unknown",
85 "Unknown", /* 420 */
86 "Unknown",
87 "Unprocessable Entity",
88 "Locked",
89 "Failed Dependency",
90 "Unordered Collection",
91 "Upgrade Required",
92 "Unknown",
93 "Unknown",
94 "Unknown",
95 "Unknown", /* 430 */
96 "Unknown",
97 "Unknown",
98 "Unknown",
99 "Unknown",
100 "Unknown", /* 435 */
101 "Unknown",
102 "Unknown",
103 "Unknown",
104 "Unknown",
105 "Unknown", /* 440 */
106 "Unknown",
107 "Unknown",
108 "Unknown",
109 "No Response",
110 "Unknown", /* 445 */
111 "Unknown",
112 "Unknown",
113 "Unknown",
114 "Retry With",
115 "Blocked by Windows Parental Controls", /* 450 */
116 "Unavailable For Legal Reasons"
117};
118
119static const char *const five_hundred[] = {
120 "Internal Server Error",
121 "Not Implemented",
122 "Bad Gateway",
123 "Service Unavailable",
124 "Gateway Time-out",
125 "HTTP Version not supported",
126 "Variant Also Negotiates",
127 "Insufficient Storage",
128 "Unknown",
129 "Bandwidth Limit Exceeded",
130 "Not Extended"
131};
132
133
134struct MHD_Reason_Block
135{
136 unsigned int max;
137 const char *const*data;
138};
139
140#define BLOCK(m) { (sizeof(m) / sizeof(char*)), m }
141
142static const struct MHD_Reason_Block reasons[] = {
143 BLOCK (invalid_hundred),
144 BLOCK (one_hundred),
145 BLOCK (two_hundred),
146 BLOCK (three_hundred),
147 BLOCK (four_hundred),
148 BLOCK (five_hundred),
149};
150
151const char *
152MHD_get_reason_phrase_for (unsigned int code)
153{
154 if ( (code >= 100) &&
155 (code < 600) &&
156 (reasons[code / 100].max > (code % 100)) )
157 return reasons[code / 100].data[code % 100];
158 return "Unknown";
159}
diff --git a/src/microhttpd/reason_phrase.h b/src/microhttpd/reason_phrase.h
new file mode 100644
index 00000000..20c11d52
--- /dev/null
+++ b/src/microhttpd/reason_phrase.h
@@ -0,0 +1,37 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Lymba
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file reason_phrase.c
22 * @brief Tables of the string response phrases
23 * @author Elliot Glaysher
24 */
25
26#ifndef REASON_PHRASE_H
27#define REASON_PHRASE_H
28
29/**
30 * Returns the string reason phrase for a response code.
31 *
32 * If we don't have a string for a status code, we give the first
33 * message in that status code class.
34 */
35const char *MHD_get_reason_phrase_for (unsigned int code);
36
37#endif
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
new file mode 100644
index 00000000..5db03824
--- /dev/null
+++ b/src/microhttpd/response.c
@@ -0,0 +1,459 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file response.c
22 * @brief Methods for managing response objects
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#include "internal.h"
28#include "response.h"
29
30
31/**
32 * Add a header or footer line to the response.
33 *
34 * @param response response to add a header to
35 * @param kind header or footer
36 * @param header the header to add
37 * @param content value to add
38 * @return MHD_NO on error (i.e. invalid header or content format).
39 */
40static int
41add_response_entry (struct MHD_Response *response,
42 enum MHD_ValueKind kind,
43 const char *header,
44 const char *content)
45{
46 struct MHD_HTTP_Header *hdr;
47
48 if ( (NULL == response) ||
49 (NULL == header) ||
50 (NULL == content) ||
51 (0 == strlen (header)) ||
52 (0 == strlen (content)) ||
53 (NULL != strchr (header, '\t')) ||
54 (NULL != strchr (header, '\r')) ||
55 (NULL != strchr (header, '\n')) ||
56 (NULL != strchr (content, '\t')) ||
57 (NULL != strchr (content, '\r')) ||
58 (NULL != strchr (content, '\n')) )
59 return MHD_NO;
60 if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
61 return MHD_NO;
62 if (NULL == (hdr->header = strdup (header)))
63 {
64 free (hdr);
65 return MHD_NO;
66 }
67 if (NULL == (hdr->value = strdup (content)))
68 {
69 free (hdr->header);
70 free (hdr);
71 return MHD_NO;
72 }
73 hdr->kind = kind;
74 hdr->next = response->first_header;
75 response->first_header = hdr;
76 return MHD_YES;
77}
78
79
80/**
81 * Add a header line to the response.
82 *
83 * @param response response to add a header to
84 * @param header the header to add
85 * @param content value to add
86 * @return MHD_NO on error (i.e. invalid header or content format).
87 */
88int
89MHD_add_response_header (struct MHD_Response *response,
90 const char *header, const char *content)
91{
92 return add_response_entry (response,
93 MHD_HEADER_KIND,
94 header,
95 content);
96}
97
98
99/**
100 * Add a footer line to the response.
101 *
102 * @param response response to remove a header from
103 * @param footer the footer to delete
104 * @param content value to delete
105 * @return MHD_NO on error (i.e. invalid footer or content format).
106 */
107int
108MHD_add_response_footer (struct MHD_Response *response,
109 const char *footer, const char *content)
110{
111 return add_response_entry (response,
112 MHD_FOOTER_KIND,
113 footer,
114 content);
115}
116
117
118/**
119 * Delete a header line from the response.
120 *
121 * @param response response to remove a header from
122 * @param header the header to delete
123 * @param content value to delete
124 * @return MHD_NO on error (no such header known)
125 */
126int
127MHD_del_response_header (struct MHD_Response *response,
128 const char *header, const char *content)
129{
130 struct MHD_HTTP_Header *pos;
131 struct MHD_HTTP_Header *prev;
132
133 if ( (NULL == header) || (NULL == content) )
134 return MHD_NO;
135 prev = NULL;
136 pos = response->first_header;
137 while (pos != NULL)
138 {
139 if ((0 == strcmp (header, pos->header)) &&
140 (0 == strcmp (content, pos->value)))
141 {
142 free (pos->header);
143 free (pos->value);
144 if (NULL == prev)
145 response->first_header = pos->next;
146 else
147 prev->next = pos->next;
148 free (pos);
149 return MHD_YES;
150 }
151 prev = pos;
152 pos = pos->next;
153 }
154 return MHD_NO;
155}
156
157
158/**
159 * Get all of the headers added to a response.
160 *
161 * @param response response to query
162 * @param iterator callback to call on each header;
163 * maybe NULL (then just count headers)
164 * @param iterator_cls extra argument to iterator
165 * @return number of entries iterated over
166 */
167int
168MHD_get_response_headers (struct MHD_Response *response,
169 MHD_KeyValueIterator iterator, void *iterator_cls)
170{
171 struct MHD_HTTP_Header *pos;
172 int numHeaders = 0;
173
174 for (pos = response->first_header; NULL != pos; pos = pos->next)
175 {
176 numHeaders++;
177 if ((NULL != iterator) &&
178 (MHD_YES != iterator (iterator_cls,
179 pos->kind, pos->header, pos->value)))
180 break;
181 }
182 return numHeaders;
183}
184
185
186/**
187 * Get a particular header from the response.
188 *
189 * @param response response to query
190 * @param key which header to get
191 * @return NULL if header does not exist
192 */
193const char *
194MHD_get_response_header (struct MHD_Response *response,
195 const char *key)
196{
197 struct MHD_HTTP_Header *pos;
198
199 if (NULL == key)
200 return NULL;
201 for (pos = response->first_header; NULL != pos; pos = pos->next)
202 if (0 == strcmp (key, pos->header))
203 return pos->value;
204 return NULL;
205}
206
207
208/**
209 * Create a response object. The response object can be extended with
210 * header information and then be used any number of times.
211 *
212 * @param size size of the data portion of the response, MHD_SIZE_UNKNOWN for unknown
213 * @param block_size preferred block size for querying crc (advisory only,
214 * MHD may still call crc using smaller chunks); this
215 * is essentially the buffer size used for IO, clients
216 * should pick a value that is appropriate for IO and
217 * memory performance requirements
218 * @param crc callback to use to obtain response data
219 * @param crc_cls extra argument to crc
220 * @param crfc callback to call to free crc_cls resources
221 * @return NULL on error (i.e. invalid arguments, out of memory)
222 */
223struct MHD_Response *
224MHD_create_response_from_callback (uint64_t size,
225 size_t block_size,
226 MHD_ContentReaderCallback crc,
227 void *crc_cls,
228 MHD_ContentReaderFreeCallback crfc)
229{
230 struct MHD_Response *response;
231
232 if ((NULL == crc) || (0 == block_size))
233 return NULL;
234 if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size)))
235 return NULL;
236 memset (response, 0, sizeof (struct MHD_Response));
237 response->fd = -1;
238 response->data = (void *) &response[1];
239 response->data_buffer_size = block_size;
240 if (0 != pthread_mutex_init (&response->mutex, NULL))
241 {
242 free (response);
243 return NULL;
244 }
245 response->crc = crc;
246 response->crfc = crfc;
247 response->crc_cls = crc_cls;
248 response->reference_count = 1;
249 response->total_size = size;
250 return response;
251}
252
253
254/**
255 * Given a file descriptor, read data from the file
256 * to generate the response.
257 *
258 * @param cls pointer to the response
259 * @param pos offset in the file to access
260 * @param buf where to write the data
261 * @param max number of bytes to write at most
262 * @return number of bytes written
263 */
264static ssize_t
265file_reader (void *cls, uint64_t pos, char *buf, size_t max)
266{
267 struct MHD_Response *response = cls;
268 ssize_t n;
269
270 (void) lseek (response->fd, pos + response->fd_off, SEEK_SET);
271 n = read (response->fd, buf, max);
272 if (0 == n)
273 return MHD_CONTENT_READER_END_OF_STREAM;
274 if (n < 0)
275 return MHD_CONTENT_READER_END_WITH_ERROR;
276 return n;
277}
278
279
280/**
281 * Destroy file reader context. Closes the file
282 * descriptor.
283 *
284 * @param cls pointer to file descriptor
285 */
286static void
287free_callback (void *cls)
288{
289 struct MHD_Response *response = cls;
290
291 (void) close (response->fd);
292 response->fd = -1;
293}
294
295
296/**
297 * Create a response object. The response object can be extended with
298 * header information and then be used any number of times.
299 *
300 * @param size size of the data portion of the response
301 * @param fd file descriptor referring to a file on disk with the data
302 * @param offset offset to start reading from in the file
303 * @return NULL on error (i.e. invalid arguments, out of memory)
304 */
305struct MHD_Response *MHD_create_response_from_fd_at_offset (size_t size,
306 int fd,
307 off_t offset)
308{
309 struct MHD_Response *response;
310
311 response = MHD_create_response_from_callback (size,
312 4 * 1024,
313 &file_reader,
314 NULL,
315 &free_callback);
316 if (NULL == response)
317 return NULL;
318 response->fd = fd;
319 response->fd_off = offset;
320 response->crc_cls = response;
321 return response;
322}
323
324
325/**
326 * Create a response object. The response object can be extended with
327 * header information and then be used any number of times.
328 *
329 * @param size size of the data portion of the response
330 * @param fd file descriptor referring to a file on disk with the data
331 * @return NULL on error (i.e. invalid arguments, out of memory)
332 */
333struct MHD_Response *MHD_create_response_from_fd (size_t size,
334 int fd)
335{
336 return MHD_create_response_from_fd_at_offset (size, fd, 0);
337}
338
339
340/**
341 * Create a response object. The response object can be extended with
342 * header information and then be used any number of times.
343 *
344 * @param size size of the data portion of the response
345 * @param data the data itself
346 * @param must_free libmicrohttpd should free data when done
347 * @param must_copy libmicrohttpd must make a copy of data
348 * right away, the data maybe released anytime after
349 * this call returns
350 * @return NULL on error (i.e. invalid arguments, out of memory)
351 * @deprecated use MHD_create_response_from_buffer instead
352 */
353struct MHD_Response *
354MHD_create_response_from_data (size_t size,
355 void *data, int must_free, int must_copy)
356{
357 struct MHD_Response *response;
358 void *tmp;
359
360 if ((NULL == data) && (size > 0))
361 return NULL;
362 if (NULL == (response = malloc (sizeof (struct MHD_Response))))
363 return NULL;
364 memset (response, 0, sizeof (struct MHD_Response));
365 response->fd = -1;
366 if (0 != pthread_mutex_init (&response->mutex, NULL))
367 {
368 free (response);
369 return NULL;
370 }
371 if ((must_copy) && (size > 0))
372 {
373 if (NULL == (tmp = malloc (size)))
374 {
375 pthread_mutex_destroy (&response->mutex);
376 free (response);
377 return NULL;
378 }
379 memcpy (tmp, data, size);
380 must_free = MHD_YES;
381 data = tmp;
382 }
383 response->crc = NULL;
384 response->crfc = must_free ? &free : NULL;
385 response->crc_cls = must_free ? data : NULL;
386 response->reference_count = 1;
387 response->total_size = size;
388 response->data = data;
389 response->data_size = size;
390 return response;
391}
392
393
394/**
395 * Create a response object. The response object can be extended with
396 * header information and then be used any number of times.
397 *
398 * @param size size of the data portion of the response
399 * @param buffer size bytes containing the response's data portion
400 * @param mode flags for buffer management
401 * @return NULL on error (i.e. invalid arguments, out of memory)
402 */
403struct MHD_Response *
404MHD_create_response_from_buffer (size_t size,
405 void *buffer,
406 enum MHD_ResponseMemoryMode mode)
407{
408 return MHD_create_response_from_data (size,
409 buffer,
410 mode == MHD_RESPMEM_MUST_FREE,
411 mode == MHD_RESPMEM_MUST_COPY);
412}
413
414
415/**
416 * Destroy a response object and associated resources. Note that
417 * libmicrohttpd may keep some of the resources around if the response
418 * is still in the queue for some clients, so the memory may not
419 * necessarily be freed immediatley.
420 */
421void
422MHD_destroy_response (struct MHD_Response *response)
423{
424 struct MHD_HTTP_Header *pos;
425
426 if (NULL == response)
427 return;
428 pthread_mutex_lock (&response->mutex);
429 if (0 != --(response->reference_count))
430 {
431 pthread_mutex_unlock (&response->mutex);
432 return;
433 }
434 pthread_mutex_unlock (&response->mutex);
435 pthread_mutex_destroy (&response->mutex);
436 if (response->crfc != NULL)
437 response->crfc (response->crc_cls);
438 while (NULL != response->first_header)
439 {
440 pos = response->first_header;
441 response->first_header = pos->next;
442 free (pos->header);
443 free (pos->value);
444 free (pos);
445 }
446 free (response);
447}
448
449
450void
451MHD_increment_response_rc (struct MHD_Response *response)
452{
453 pthread_mutex_lock (&response->mutex);
454 (response->reference_count)++;
455 pthread_mutex_unlock (&response->mutex);
456}
457
458
459/* end of response.c */
diff --git a/src/microhttpd/response.h b/src/microhttpd/response.h
new file mode 100644
index 00000000..ec1b3878
--- /dev/null
+++ b/src/microhttpd/response.h
@@ -0,0 +1,37 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file response.h
22 * @brief Methods for managing response objects
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#ifndef RESPONSE_H
28#define RESPONSE_H
29
30/**
31 * Increment response RC. Should this be part of the
32 * public API?
33 */
34void MHD_increment_response_rc (struct MHD_Response *response);
35
36
37#endif
diff --git a/src/microhttpd/test_daemon.c b/src/microhttpd/test_daemon.c
new file mode 100644
index 00000000..4140fb4f
--- /dev/null
+++ b/src/microhttpd/test_daemon.c
@@ -0,0 +1,168 @@
1/*
2 This file is part of libmicrohttpd
3 (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_daemon.c
23 * @brief Testcase for libmicrohttpd starts and stops
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "platform.h"
29#include "microhttpd.h"
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33
34#ifndef WINDOWS
35#include <unistd.h>
36#endif
37
38
39static int
40testStartError ()
41{
42 struct MHD_Daemon *d;
43
44 d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL);
45 if (d != NULL)
46 return 1;
47 return 0;
48}
49
50static int
51apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen)
52{
53 return MHD_NO;
54}
55
56static int
57apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
58{
59 return MHD_YES;
60}
61
62static int
63ahc_nothing (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 return MHD_NO;
72}
73
74static int
75testStartStop ()
76{
77 struct MHD_Daemon *d;
78
79 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
80 1080,
81 &apc_nothing,
82 NULL, &ahc_nothing, NULL, MHD_OPTION_END);
83 if (d == NULL)
84 return 2;
85 MHD_stop_daemon (d);
86 return 0;
87}
88
89static int
90testExternalRun ()
91{
92 struct MHD_Daemon *d;
93 fd_set rs;
94 int maxfd;
95 int i;
96
97 d = MHD_start_daemon (MHD_USE_DEBUG,
98 1081,
99 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
100
101 if (d == NULL)
102 return 4;
103 i = 0;
104 while (i < 15)
105 {
106 maxfd = 0;
107 FD_ZERO (&rs);
108 if (MHD_YES != MHD_get_fdset (d, &rs, &rs, &rs, &maxfd))
109 {
110 MHD_stop_daemon (d);
111 return 256;
112 }
113 if (MHD_run (d) == MHD_NO)
114 {
115 MHD_stop_daemon (d);
116 return 8;
117 }
118 i++;
119 }
120 MHD_stop_daemon (d);
121 return 0;
122}
123
124static int
125testThread ()
126{
127 struct MHD_Daemon *d;
128 d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY,
129 1082,
130 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
131
132 if (d == NULL)
133 return 16;
134 if (MHD_run (d) != MHD_NO)
135 return 32;
136 MHD_stop_daemon (d);
137 return 0;
138}
139
140static int
141testMultithread ()
142{
143 struct MHD_Daemon *d;
144 d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
145 1083,
146 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
147
148 if (d == NULL)
149 return 64;
150 if (MHD_run (d) != MHD_NO)
151 return 128;
152 MHD_stop_daemon (d);
153 return 0;
154}
155
156int
157main (int argc, char *const *argv)
158{
159 int errorCount = 0;
160 errorCount += testStartError ();
161 errorCount += testStartStop ();
162 errorCount += testExternalRun ();
163 errorCount += testThread ();
164 errorCount += testMultithread ();
165 if (errorCount != 0)
166 fprintf (stderr, "Error (code: %u)\n", errorCount);
167 return errorCount != 0; /* 0 == pass */
168}
diff --git a/src/microhttpd/test_postprocessor.c b/src/microhttpd/test_postprocessor.c
new file mode 100644
index 00000000..eb412b72
--- /dev/null
+++ b/src/microhttpd/test_postprocessor.c
@@ -0,0 +1,271 @@
1/*
2 This file is part of libmicrohttpd
3 (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_postprocessor.c
23 * @brief Testcase for postprocessor
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "microhttpd.h"
29#include "internal.h"
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33
34#ifndef WINDOWS
35#include <unistd.h>
36#endif
37
38/**
39 * Array of values that the value checker "wants".
40 * Each series of checks should be terminated by
41 * five NULL-entries.
42 */
43const char *want[] = {
44#define URL_DATA "abc=def&x=5"
45#define URL_START 0
46 "abc", NULL, NULL, NULL, "def",
47 "x", NULL, NULL, NULL, "5",
48#define URL_END (URL_START + 10)
49 NULL, NULL, NULL, NULL, NULL,
50#define FORM_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJoe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata\r\n--AaB03x--\r\n"
51#define FORM_START (URL_END + 5)
52 "field1", NULL, NULL, NULL, "Joe Blow",
53 "pics", "file1.txt", "text/plain", "binary", "filedata",
54#define FORM_END (FORM_START + 10)
55 NULL, NULL, NULL, NULL, NULL,
56#define FORM_NESTED_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"\r\nContent-type: multipart/mixed, boundary=BbC04y\r\n\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file2.gif\"\r\nContent-type: image/gif\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata2\r\n--BbC04y--\r\n--AaB03x--"
57#define FORM_NESTED_START (FORM_END + 5)
58 "field1", NULL, NULL, NULL, "Jane Blow",
59 "pics", "file1.txt", "text/plain", NULL, "filedata1",
60 "pics", "file2.gif", "image/gif", "binary", "filedata2",
61#define FORM_NESTED_END (FORM_NESTED_START + 15)
62 NULL, NULL, NULL, NULL, NULL,
63#define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3="
64#define URL_EMPTY_VALUE_START (FORM_NESTED_END + 5)
65 "key1", NULL, NULL, NULL, "value1",
66 "key2", NULL, NULL, NULL, "",
67 "key3", NULL, NULL, NULL, "",
68#define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 15)
69 NULL, NULL, NULL, NULL, NULL
70};
71
72static int
73mismatch (const char *a, const char *b)
74{
75 if (a == b)
76 return 0;
77 if ((a == NULL) || (b == NULL))
78 return 1;
79 return 0 != strcmp (a, b);
80}
81
82static int
83value_checker (void *cls,
84 enum MHD_ValueKind kind,
85 const char *key,
86 const char *filename,
87 const char *content_type,
88 const char *transfer_encoding,
89 const char *data, uint64_t off, size_t size)
90{
91 int *want_off = cls;
92 int idx = *want_off;
93
94#if 0
95 fprintf (stderr,
96 "VC: `%s' `%s' `%s' `%s' `%.*s'\n",
97 key, filename, content_type, transfer_encoding, size, data);
98#endif
99 if ( (0 != off) && (0 == size) )
100 return MHD_YES;
101 if ((idx < 0) ||
102 (want[idx] == NULL) ||
103 (0 != strcmp (key, want[idx])) ||
104 (mismatch (filename, want[idx + 1])) ||
105 (mismatch (content_type, want[idx + 2])) ||
106 (mismatch (transfer_encoding, want[idx + 3])) ||
107 (0 != memcmp (data, &want[idx + 4][off], size)))
108 {
109 *want_off = -1;
110 return MHD_NO;
111 }
112 if (off + size == strlen (want[idx + 4]))
113 *want_off = idx + 5;
114 return MHD_YES;
115
116}
117
118
119static int
120test_urlencoding ()
121{
122 struct MHD_Connection connection;
123 struct MHD_HTTP_Header header;
124 struct MHD_PostProcessor *pp;
125 unsigned int want_off = URL_START;
126 int i;
127 int delta;
128 size_t size;
129
130 memset (&connection, 0, sizeof (struct MHD_Connection));
131 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
132 connection.headers_received = &header;
133 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
134 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
135 header.kind = MHD_HEADER_KIND;
136 pp = MHD_create_post_processor (&connection,
137 1024, &value_checker, &want_off);
138 i = 0;
139 size = strlen (URL_DATA);
140 while (i < size)
141 {
142 delta = 1 + RANDOM () % (size - i);
143 MHD_post_process (pp, &URL_DATA[i], delta);
144 i += delta;
145 }
146 MHD_destroy_post_processor (pp);
147 if (want_off != URL_END)
148 return 1;
149 return 0;
150}
151
152
153static int
154test_multipart ()
155{
156 struct MHD_Connection connection;
157 struct MHD_HTTP_Header header;
158 struct MHD_PostProcessor *pp;
159 unsigned int want_off = FORM_START;
160 int i;
161 int delta;
162 size_t size;
163
164 memset (&connection, 0, sizeof (struct MHD_Connection));
165 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
166 connection.headers_received = &header;
167 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
168 header.value =
169 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
170 header.kind = MHD_HEADER_KIND;
171 pp = MHD_create_post_processor (&connection,
172 1024, &value_checker, &want_off);
173 i = 0;
174 size = strlen (FORM_DATA);
175 while (i < size)
176 {
177 delta = 1 + RANDOM () % (size - i);
178 MHD_post_process (pp, &FORM_DATA[i], delta);
179 i += delta;
180 }
181 MHD_destroy_post_processor (pp);
182 if (want_off != FORM_END)
183 return 2;
184 return 0;
185}
186
187
188static int
189test_nested_multipart ()
190{
191 struct MHD_Connection connection;
192 struct MHD_HTTP_Header header;
193 struct MHD_PostProcessor *pp;
194 unsigned int want_off = FORM_NESTED_START;
195 int i;
196 int delta;
197 size_t size;
198
199 memset (&connection, 0, sizeof (struct MHD_Connection));
200 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
201 connection.headers_received = &header;
202 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
203 header.value =
204 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
205 header.kind = MHD_HEADER_KIND;
206 pp = MHD_create_post_processor (&connection,
207 1024, &value_checker, &want_off);
208 i = 0;
209 size = strlen (FORM_NESTED_DATA);
210 while (i < size)
211 {
212 delta = 1 + RANDOM () % (size - i);
213 MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
214 i += delta;
215 }
216 MHD_destroy_post_processor (pp);
217 if (want_off != FORM_NESTED_END)
218 return 4;
219 return 0;
220}
221
222
223static int
224test_empty_value ()
225{
226 struct MHD_Connection connection;
227 struct MHD_HTTP_Header header;
228 struct MHD_PostProcessor *pp;
229 unsigned int want_off = URL_EMPTY_VALUE_START;
230 int i;
231 int delta;
232 size_t size;
233
234 memset (&connection, 0, sizeof (struct MHD_Connection));
235 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
236 connection.headers_received = &header;
237 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
238 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
239 header.kind = MHD_HEADER_KIND;
240 pp = MHD_create_post_processor (&connection,
241 1024, &value_checker, &want_off);
242 i = 0;
243 size = strlen (URL_EMPTY_VALUE_DATA);
244 while (i < size)
245 {
246 delta = 1 + RANDOM () % (size - i);
247 MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
248 i += delta;
249 }
250 MHD_destroy_post_processor (pp);
251 if (want_off != URL_EMPTY_VALUE_END)
252 return 8;
253 return 0;
254}
255
256
257
258
259int
260main (int argc, char *const *argv)
261{
262 unsigned int errorCount = 0;
263
264 errorCount += test_urlencoding ();
265 errorCount += test_multipart ();
266 errorCount += test_nested_multipart ();
267 errorCount += test_empty_value ();
268 if (errorCount != 0)
269 fprintf (stderr, "Error (code: %u)\n", errorCount);
270 return errorCount != 0; /* 0 == pass */
271}
diff --git a/src/microhttpd/test_postprocessor_amp.c b/src/microhttpd/test_postprocessor_amp.c
new file mode 100644
index 00000000..73f72f92
--- /dev/null
+++ b/src/microhttpd/test_postprocessor_amp.c
@@ -0,0 +1,47 @@
1#include "platform.h"
2#include "microhttpd.h"
3#include "internal.h"
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7
8
9int check_post(void *cls, enum MHD_ValueKind kind, const char* key,
10 const char* filename, const char* content_type,
11 const char* content_encoding, const char* data,
12 uint64_t off, size_t size)
13{
14 if ((0 != strcmp(key, "a")) && (0 != strcmp(key, "b")))
15 {
16 printf("ERROR: got unexpected '%s'\n", key);
17 }
18
19 return MHD_YES;
20}
21
22
23int
24main (int argc, char *const *argv)
25{
26 struct MHD_Connection connection;
27 struct MHD_HTTP_Header header;
28 struct MHD_PostProcessor *pp;
29
30 memset (&connection, 0, sizeof (struct MHD_Connection));
31 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
32 connection.headers_received = &header;
33 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
34 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
35 header.kind = MHD_HEADER_KIND;
36
37 pp = MHD_create_post_processor (&connection,
38 4096, &check_post, NULL);
39
40 const char* post = "a=xx+xx+xxx+xxxxx+xxxx+xxxxxxxx+xxx+xxxxxx+xxx+xxx+xxxxxxx+xxxxx%0A+++++++xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0A+++++++--%3E%0A++++++++++++++%3Cxxxxx+xxxxx%3D%22xxx%25%22%3E%0A+++++++++++%3Cxx%3E%0A+++++++++++++++%3Cxx+xxxxxxx%3D%22x%22+xxxxx%3D%22xxxxx%22%3E%0A+++++++++++++++++++%3Cxxxxx+xxxxx%3D%22xxx%25%22%3E%0A+++++++++++++++++++++++%3Cxx%3E%0A+++++++++++++++++++++++++++%3Cxx+xxxxx%3D%22xxxx%22%3E%0A+++++++++++++++++++++++++++++++%3Cx+xxxxx%3D%22xxxx-xxxxx%3Axxxxx%22%3Exxxxx%3A%3C%2Fx%3E%0A%0A+++++++++++++++++++++++++++++++%3Cx+xxxxx%3D%22xxxx-xxxxx%3Axxxxx%22%3Exxx%3A%3C%2Fx%3E%0A%0A+++++++++++++++++++++++++++++++%3Cx+xxxxx%3D%22xxxx-xxxxx%3Axxxxx%3B+xxxx-xxxxxx%3A+xxxx%3B%22%3Exxxxx+xxxxx%3A%3C%2Fx%3E%0A+++++++++++++++++++++++++++%3C%2Fxx%3E%0A+++++++++++++++++++++++%3C%2Fxx%3E%0A+++++++++++++++++++%3C%2Fxxxxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A+++++++++++++++%3Cxx+xxxxx%3D%22xxxx-xxxxx%3A+xxxxx%3B+xxxxx%3A+xxxx%22%3E%26xxxxx%3B+%3Cxxxx%0A+++++++++++++++++++++++xxxxx%3D%22xxxxxxxxxxxxxxx%22%3Exxxx.xx%3C%2Fxxxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A+++++++++++%3C%2Fxx%3E%0A++++++++++++++++++++++++++%3Cxx%3E%0A+++++++++++++++++++%3Cxx+xxxxx%3D%22xxxx-xxxxx%3A+xxxxx%3B+xxxxx%3A+xxxx%22%3E%26xxxxx%3B+%3Cxxxx%0A+++++++++++++++++++++++++++xxxxx%3D%22xxxxxxxxxxxxxxx%22%3Exxx.xx%3C%2Fxxxx%3E%0A+++++++++++++++++++%3C%2Fxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A++++++++++++++++++++++%3Cxx%3E%0A+++++++++++++++%3Cxx+xxxxx%3D%22xxxx-xxxxx%3A+xxxxx%3Bxxxx-xxxxxx%3A+xxxx%3B+xxxxx%3A+xxxx%22%3E%26xxxxx%3B+%3Cxxxx%0A+++++++++++++++++++++++xxxxx%3D%22xxxxxxxxxxxxxxx%22%3Exxxx.xx%3C%2Fxxxx%3E%3C%2Fxx%3E%0A+++++++++++%3C%2Fxx%3E%0A+++++++%3C%2Fxxxxx%3E%0A+++++++%3C%21--%0A+++++++xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0A+++++++xxx+xx+xxxxx+xxxxxxx+xxxxxxx%0A+++++++xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0A+++++++--%3E%0A+++%3C%2Fxxx%3E%0A%0A%0A%0A+++%3Cxxx+xxxxx%3D%22xxxxxxxxx%22+xx%3D%22xxxxxxxxx%22%3E%3C%2Fxxx%3E%0A%0A+++%3Cxxx+xx%3D%22xxxx%22+xxxxx%3D%22xxxx%22%3E%0A+++++++%3Cxxxxx+xxxxx%3D%22xxxxxxxxx%22%3E%0A+++++++++++%3Cxx%3E%0A+++++++++++++++%3Cxx+xxxxxxx%3D%22x%22+xx%3D%22xxxxxxxxxxxxx%22+xxxxx%3D%22xxxxxxxxxxxxx%22%3E%0A+++++++++++++++++++%3Cxxx+xx%3D%22xxxxxx%22%3E%3C%2Fxxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A+++++++++++%3C%2Fxx%3E%0A+++++++++++%3Cxx%3E%0A+++++++++++++++%3Cxx+xx%3D%22xxxxxxxxxxxxxxxxx%22+xxxxx%3D%22xxxxxxxxxxxxxxxxx%22%3E%3C%2Fxx%3E%0A+++++++++++++++%3Cxx+xx%3D%22xxxxxxxxxxxxxx%22+xxxxx%3D%22xxxxxxxxxxxxxx%22%3E%0A+++++++++++++++++++%3Cxxx+xx%3D%22xxxxxxx%22%3E%3C%2Fxxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A+++++++++++%3C%2Fxx%3E%0A+++++++++++%3Cxx%3E%0A+++++++++++++++%3Cxx+xxxxxxx%3D%22x%22+xx%3D%22xxxxxxxxxxxxx%22+xxxxx%3D%22xxxxxxxxxxxxx%22%3E%0A+++++++++++++++++++%3Cxxx+xx%3D%22xxxxxx%22%3E%3C%2Fxxx%3E%0A+++++++++++++++%3C%2Fxx%3E%0A+++++++++++%3C%2Fxx%3E%0A+++++++%3C%2Fxxxxx%3E%0A+++%3C%2Fxxx%3E%0A%3C%2Fxxx%3E%0A%0A%3Cxxx+xx%3D%22xxxxxx%22%3E%3C%2Fxxx%3E%0A%0A%3C%2Fxxxx%3E%0A%3C%2Fxxxx%3E+&b=value";
41
42 MHD_post_process (pp, post, strlen(post));
43 MHD_destroy_post_processor (pp);
44
45 return 0;
46}
47
diff --git a/src/microhttpd/test_postprocessor_large.c b/src/microhttpd/test_postprocessor_large.c
new file mode 100644
index 00000000..2af84dcc
--- /dev/null
+++ b/src/microhttpd/test_postprocessor_large.c
@@ -0,0 +1,105 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 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_postprocessor_large.c
23 * @brief Testcase with very large input for postprocessor
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "microhttpd.h"
29#include "internal.h"
30
31#ifndef WINDOWS
32#include <unistd.h>
33#endif
34
35static int
36value_checker (void *cls,
37 enum MHD_ValueKind kind,
38 const char *key,
39 const char *filename,
40 const char *content_type,
41 const char *transfer_encoding,
42 const char *data, uint64_t off, size_t size)
43{
44 unsigned int *pos = cls;
45#if 0
46 fprintf (stderr,
47 "VC: %llu %u `%s' `%s' `%s' `%s' `%.*s'\n",
48 off, size,
49 key, filename, content_type, transfer_encoding, size, data);
50#endif
51 if (size == 0)
52 return MHD_YES;
53 *pos += size;
54 return MHD_YES;
55
56}
57
58
59static int
60test_simple_large ()
61{
62 struct MHD_Connection connection;
63 struct MHD_HTTP_Header header;
64 struct MHD_PostProcessor *pp;
65 int i;
66 int delta;
67 size_t size;
68 char data[102400];
69 unsigned int pos;
70
71 pos = 0;
72 memset (data, 'A', sizeof (data));
73 memcpy (data, "key=", 4);
74 data[sizeof (data) - 1] = '\0';
75 memset (&connection, 0, sizeof (struct MHD_Connection));
76 memset (&header, 0, sizeof (struct MHD_HTTP_Header));
77 connection.headers_received = &header;
78 header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
79 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
80 header.kind = MHD_HEADER_KIND;
81 pp = MHD_create_post_processor (&connection, 1024, &value_checker, &pos);
82 i = 0;
83 size = strlen (data);
84 while (i < size)
85 {
86 delta = 1 + RANDOM () % (size - i);
87 MHD_post_process (pp, &data[i], delta);
88 i += delta;
89 }
90 MHD_destroy_post_processor (pp);
91 if (pos != sizeof (data) - 5) /* minus 0-termination and 'key=' */
92 return 1;
93 return 0;
94}
95
96int
97main (int argc, char *const *argv)
98{
99 unsigned int errorCount = 0;
100
101 errorCount += test_simple_large ();
102 if (errorCount != 0)
103 fprintf (stderr, "Error (code: %u)\n", errorCount);
104 return errorCount != 0; /* 0 == pass */
105}
diff --git a/src/microhttpd/tsearch.c b/src/microhttpd/tsearch.c
new file mode 100644
index 00000000..2ab9a467
--- /dev/null
+++ b/src/microhttpd/tsearch.c
@@ -0,0 +1,123 @@
1/* $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $ */
2
3/*
4 * Tree search generalized from Knuth (6.2.2) Algorithm T just like
5 * the AT&T man page says.
6 *
7 * The node_t structure is for internal use only, lint doesn't grok it.
8 *
9 * Written by reading the System V Interface Definition, not the code.
10 *
11 * Totally public domain.
12 */
13
14#include <sys/cdefs.h>
15#define _SEARCH_PRIVATE
16#include <tsearch.h>
17#include <stdlib.h>
18
19/* find or insert datum into search tree */
20void *
21tsearch(vkey, vrootp, compar)
22 const void *vkey; /* key to be located */
23 void **vrootp; /* address of tree root */
24 int (*compar)(const void *, const void *);
25{
26 node_t *q;
27 node_t **rootp = (node_t **)vrootp;
28
29 if (rootp == NULL)
30 return NULL;
31
32 while (*rootp != NULL) { /* Knuth's T1: */
33 int r;
34
35 if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
36 return *rootp; /* we found it! */
37
38 rootp = (r < 0) ?
39 &(*rootp)->llink : /* T3: follow left branch */
40 &(*rootp)->rlink; /* T4: follow right branch */
41 }
42
43 q = malloc(sizeof(node_t)); /* T5: key not found */
44 if (q != 0) { /* make new node */
45 *rootp = q; /* link new node to old */
46 /* LINTED const castaway ok */
47 q->key = (void *)vkey; /* initialize new node */
48 q->llink = q->rlink = NULL;
49 }
50 return q;
51}
52
53/* find a node, or return 0 */
54void *
55tfind(vkey, vrootp, compar)
56 const void *vkey; /* key to be found */
57 void * const *vrootp; /* address of the tree root */
58 int (*compar)(const void *, const void *);
59{
60 node_t **rootp = (node_t **)vrootp;
61
62 if (rootp == NULL)
63 return NULL;
64
65 while (*rootp != NULL) { /* T1: */
66 int r;
67
68 if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
69 return *rootp; /* key found */
70 rootp = (r < 0) ?
71 &(*rootp)->llink : /* T3: follow left branch */
72 &(*rootp)->rlink; /* T4: follow right branch */
73 }
74 return NULL;
75}
76
77/*
78 * delete node with given key
79 *
80 * vkey: key to be deleted
81 * vrootp: address of the root of the tree
82 * compar: function to carry out node comparisons
83 */
84void *
85tdelete(const void * __restrict vkey, void ** __restrict vrootp,
86 int (*compar)(const void *, const void *))
87{
88 node_t **rootp = (node_t **)vrootp;
89 node_t *p, *q, *r;
90 int cmp;
91
92 if (rootp == NULL || (p = *rootp) == NULL)
93 return NULL;
94
95 while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
96 p = *rootp;
97 rootp = (cmp < 0) ?
98 &(*rootp)->llink : /* follow llink branch */
99 &(*rootp)->rlink; /* follow rlink branch */
100 if (*rootp == NULL)
101 return NULL; /* key not found */
102 }
103 r = (*rootp)->rlink; /* D1: */
104 if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
105 q = r;
106 else if (r != NULL) { /* Right link is NULL? */
107 if (r->llink == NULL) { /* D2: Find successor */
108 r->llink = q;
109 q = r;
110 } else { /* D3: Find NULL link */
111 for (q = r->llink; q->llink != NULL; q = r->llink)
112 r = q;
113 r->llink = q->rlink;
114 q->llink = (*rootp)->llink;
115 q->rlink = (*rootp)->rlink;
116 }
117 }
118 free(*rootp); /* D4: Free node */
119 *rootp = q; /* link parent to new node */
120 return p;
121}
122
123/* end of tsearch.c */
diff --git a/src/microhttpd/tsearch.h b/src/microhttpd/tsearch.h
new file mode 100644
index 00000000..824f9a2d
--- /dev/null
+++ b/src/microhttpd/tsearch.h
@@ -0,0 +1,39 @@
1/*-
2 * Written by J.T. Conklin <jtc@netbsd.org>
3 * Public domain.
4 *
5 * $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $
6 * $FreeBSD: release/9.0.0/include/search.h 105250 2002-10-16 14:29:23Z robert $
7 */
8
9#ifndef _SEARCH_H_
10#define _SEARCH_H_
11
12#include <sys/cdefs.h>
13#include <sys/types.h>
14
15typedef enum {
16 preorder,
17 postorder,
18 endorder,
19 leaf
20} VISIT;
21
22#ifdef _SEARCH_PRIVATE
23typedef struct node {
24 char *key;
25 struct node *llink, *rlink;
26} node_t;
27#endif
28
29__BEGIN_DECLS
30void *tdelete(const void * __restrict, void ** __restrict,
31 int (*)(const void *, const void *));
32void *tfind(const void *, void * const *,
33 int (*)(const void *, const void *));
34void *tsearch(const void *, void **, int (*)(const void *, const void *));
35void twalk(const void *, void (*)(const void *, VISIT, int));
36void tdestroy(void *, void (*)(void *));
37__END_DECLS
38
39#endif /* !_SEARCH_H_ */