diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-05-05 18:07:33 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-05-05 18:07:33 +0000 |
commit | 9eb27c8dbe1939344ccced9c498895f0e92e8197 (patch) | |
tree | a97d1b7caf1e5dc79c22b08d58be70bc8c205cba /src/microhttpd | |
parent | 1725bcf3c546fccbf22d7794bf7290fcc28c385d (diff) | |
download | libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.tar.gz libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.zip |
-changing directory name
Diffstat (limited to 'src/microhttpd')
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 @@ | |||
1 | MHD_start_daemon | ||
2 | MHD_start_daemon_va | ||
3 | MHD_stop_daemon | ||
4 | MHD_get_fdset | ||
5 | MHD_get_timeout | ||
6 | MHD_run | ||
7 | MHD_run_from_select | ||
8 | MHD_get_connection_values | ||
9 | MHD_set_connection_value | ||
10 | MHD_lookup_connection_value | ||
11 | MHD_queue_response | ||
12 | MHD_create_response_from_callback | ||
13 | MHD_create_response_from_data | ||
14 | MHD_create_response_from_fd | ||
15 | MHD_create_response_from_fd_at_offset | ||
16 | MHD_create_response_from_buffer | ||
17 | MHD_destroy_response | ||
18 | MHD_add_response_header | ||
19 | MHD_add_response_footer | ||
20 | MHD_del_response_header | ||
21 | MHD_get_response_headers | ||
22 | MHD_get_response_header | ||
23 | MHD_create_post_processor | ||
24 | MHD_post_process | ||
25 | MHD_quiesce_daemon | ||
26 | MHD_destroy_post_processor | ||
27 | MHD_get_daemon_info | ||
28 | MHD_get_connection_info | ||
29 | MHD_set_panic_func | ||
30 | MHD_get_version | ||
31 | MHD_digest_auth_get_username | ||
32 | MHD_digest_auth_check | ||
33 | MHD_queue_auth_fail_response | ||
34 | MHD_basic_auth_get_username_password | ||
35 | MHD_queue_basic_auth_fail_response | ||
36 | MHD_add_connection | ||
37 | MHD_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 @@ | |||
1 | if USE_PRIVATE_PLIBC_H | ||
2 | PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc | ||
3 | endif | ||
4 | |||
5 | AM_CPPFLAGS = \ | ||
6 | $(PLIBC_INCLUDE) \ | ||
7 | -I$(top_srcdir)/src/include \ | ||
8 | -I$(top_srcdir)/src/daemon \ | ||
9 | @LIBGCRYPT_CFLAGS@ | ||
10 | |||
11 | EXTRA_DIST = EXPORT.sym | ||
12 | |||
13 | lib_LTLIBRARIES = \ | ||
14 | libmicrohttpd.la | ||
15 | |||
16 | |||
17 | libmicrohttpd_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 | ||
24 | libmicrohttpd_la_LDFLAGS = \ | ||
25 | $(MHD_LIB_LDFLAGS) \ | ||
26 | -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@ | ||
27 | |||
28 | if USE_COVERAGE | ||
29 | AM_CFLAGS = --coverage | ||
30 | endif | ||
31 | |||
32 | if !HAVE_TSEARCH | ||
33 | libmicrohttpd_la_SOURCES += \ | ||
34 | tsearch.c tsearch.h | ||
35 | endif | ||
36 | |||
37 | if HAVE_POSTPROCESSOR | ||
38 | libmicrohttpd_la_SOURCES += \ | ||
39 | postprocessor.c | ||
40 | endif | ||
41 | |||
42 | if ENABLE_DAUTH | ||
43 | libmicrohttpd_la_SOURCES += \ | ||
44 | digestauth.c \ | ||
45 | md5.c md5.h | ||
46 | endif | ||
47 | |||
48 | if ENABLE_BAUTH | ||
49 | libmicrohttpd_la_SOURCES += \ | ||
50 | basicauth.c \ | ||
51 | base64.c base64.h | ||
52 | endif | ||
53 | |||
54 | if ENABLE_HTTPS | ||
55 | libmicrohttpd_la_SOURCES += \ | ||
56 | connection_https.c connection_https.h | ||
57 | libmicrohttpd_la_LIBADD = -lgnutls @LIBGCRYPT_LIBS@ | ||
58 | endif | ||
59 | |||
60 | |||
61 | |||
62 | check_PROGRAMS = \ | ||
63 | test_daemon | ||
64 | |||
65 | if HAVE_POSTPROCESSOR | ||
66 | check_PROGRAMS += \ | ||
67 | test_postprocessor \ | ||
68 | test_postprocessor_large \ | ||
69 | test_postprocessor_amp | ||
70 | endif | ||
71 | |||
72 | TESTS = $(check_PROGRAMS) | ||
73 | |||
74 | test_daemon_SOURCES = \ | ||
75 | test_daemon.c | ||
76 | test_daemon_LDADD = \ | ||
77 | $(top_builddir)/src/daemon/libmicrohttpd.la | ||
78 | |||
79 | test_postprocessor_SOURCES = \ | ||
80 | test_postprocessor.c | ||
81 | test_postprocessor_LDADD = \ | ||
82 | $(top_builddir)/src/daemon/libmicrohttpd.la | ||
83 | |||
84 | test_postprocessor_amp_SOURCES = \ | ||
85 | test_postprocessor_amp.c | ||
86 | test_postprocessor_amp_LDADD = \ | ||
87 | $(top_builddir)/src/daemon/libmicrohttpd.la | ||
88 | |||
89 | test_postprocessor_large_SOURCES = \ | ||
90 | test_postprocessor_large.c | ||
91 | test_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 | |||
11 | static const char base64_chars[] = | ||
12 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
13 | |||
14 | static 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 | |||
29 | char * | ||
30 | BASE64Decode(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 | |||
14 | char * | ||
15 | BASE64Decode(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 | */ | ||
44 | char * | ||
45 | MHD_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 | */ | ||
113 | int | ||
114 | MHD_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>"Host:" header required</title></head><body>In HTTP 1.1, requests must include a "Host:" 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 | */ | ||
127 | int | ||
128 | MHD_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 | */ | ||
180 | int | ||
181 | MHD_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 | */ | ||
219 | const char * | ||
220 | MHD_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 | */ | ||
248 | int | ||
249 | MHD_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 | */ | ||
288 | static int | ||
289 | need_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 | */ | ||
313 | void | ||
314 | MHD_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 | */ | ||
340 | static void | ||
341 | connection_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 | */ | ||
373 | static int | ||
374 | try_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 | */ | ||
444 | static int | ||
445 | try_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 | */ | ||
544 | static void | ||
545 | add_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 | */ | ||
624 | static void | ||
625 | get_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 | */ | ||
661 | static int | ||
662 | try_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 | */ | ||
691 | static int | ||
692 | build_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 | */ | ||
815 | static void | ||
816 | transmit_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 | */ | ||
863 | static void | ||
864 | add_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 | */ | ||
887 | int | ||
888 | MHD_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 | */ | ||
919 | int | ||
920 | MHD_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 | */ | ||
1082 | static char * | ||
1083 | get_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 | */ | ||
1132 | static int | ||
1133 | connection_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 | */ | ||
1161 | static int | ||
1162 | parse_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 | */ | ||
1242 | static int | ||
1243 | parse_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 | */ | ||
1338 | static int | ||
1339 | parse_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 | */ | ||
1387 | static void | ||
1388 | call_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 | */ | ||
1419 | static void | ||
1420 | process_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 | */ | ||
1598 | static int | ||
1599 | do_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 | */ | ||
1647 | static int | ||
1648 | do_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 | */ | ||
1695 | static int | ||
1696 | check_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 | */ | ||
1718 | static int | ||
1719 | process_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 | */ | ||
1758 | static int | ||
1759 | process_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 | */ | ||
1820 | static void | ||
1821 | parse_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 | */ | ||
1900 | int | ||
1901 | MHD_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 | */ | ||
1964 | int | ||
1965 | MHD_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 | */ | ||
2122 | int | ||
2123 | MHD_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 | */ | ||
2500 | void | ||
2501 | MHD_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 | */ | ||
2518 | const union MHD_ConnectionInfo * | ||
2519 | MHD_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 | */ | ||
2558 | int | ||
2559 | MHD_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 | */ | ||
45 | int | ||
46 | MHD_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 | */ | ||
60 | int | ||
61 | MHD_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 | */ | ||
70 | void | ||
71 | MHD_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 | */ | ||
84 | int | ||
85 | MHD_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 | */ | ||
98 | int | ||
99 | MHD_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 | */ | ||
112 | int | ||
113 | MHD_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 | */ | ||
123 | void | ||
124 | MHD_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 | */ | ||
45 | static int | ||
46 | run_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 | */ | ||
95 | static int | ||
96 | MHD_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 | */ | ||
112 | static int | ||
113 | MHD_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 | */ | ||
131 | static int | ||
132 | MHD_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 | */ | ||
167 | void | ||
168 | MHD_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 | ||
32 | void 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 | */ | ||
100 | static void | ||
101 | mhd_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 | */ | ||
117 | MHD_PanicCallback mhd_panic; | ||
118 | |||
119 | /** | ||
120 | * Closure argument for "mhd_panic". | ||
121 | */ | ||
122 | void *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 | */ | ||
132 | static struct MHD_Daemon* | ||
133 | MHD_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 | */ | ||
144 | struct 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 | */ | ||
180 | static void | ||
181 | MHD_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 | */ | ||
195 | static void | ||
196 | MHD_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 | */ | ||
214 | static int | ||
215 | MHD_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 | */ | ||
229 | static int | ||
230 | MHD_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 | */ | ||
270 | static int | ||
271 | MHD_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 | */ | ||
334 | static void | ||
335 | MHD_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 | */ | ||
390 | static ssize_t | ||
391 | recv_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 | */ | ||
425 | static ssize_t | ||
426 | send_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 | */ | ||
448 | static int | ||
449 | MHD_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 | */ | ||
495 | static int | ||
496 | MHD_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 | */ | ||
530 | int | ||
531 | MHD_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 | */ | ||
577 | static void * | ||
578 | MHD_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 | } | ||
712 | exit: | ||
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 | */ | ||
730 | static ssize_t | ||
731 | recv_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 | */ | ||
755 | static ssize_t | ||
756 | send_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 | */ | ||
810 | typedef 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 | */ | ||
822 | static int | ||
823 | create_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 | */ | ||
885 | int | ||
886 | MHD_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 | */ | ||
1123 | static int | ||
1124 | MHD_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 | */ | ||
1218 | static void | ||
1219 | MHD_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 | */ | ||
1279 | int | ||
1280 | MHD_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 | */ | ||
1348 | int | ||
1349 | MHD_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 | */ | ||
1402 | static int | ||
1403 | MHD_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, <imeout)) ) | ||
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 | */ | ||
1494 | static int | ||
1495 | MHD_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, <imeout)) ) | ||
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 | */ | ||
1607 | static int | ||
1608 | MHD_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 | */ | ||
1667 | static int | ||
1668 | MHD_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 | */ | ||
1698 | int | ||
1699 | MHD_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 | */ | ||
1721 | static void * | ||
1722 | MHD_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 | */ | ||
1750 | struct MHD_Daemon * | ||
1751 | MHD_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 | */ | ||
1780 | int | ||
1781 | MHD_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 | */ | ||
1802 | typedef 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 | */ | ||
1815 | static int | ||
1816 | parse_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 | */ | ||
1829 | static int | ||
1830 | parse_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 | */ | ||
1852 | static int | ||
1853 | parse_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 | */ | ||
2104 | static int | ||
2105 | create_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 | */ | ||
2174 | struct MHD_Daemon * | ||
2175 | MHD_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 | |||
2642 | thread_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 | */ | ||
2689 | static void | ||
2690 | close_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 | */ | ||
2744 | void | ||
2745 | MHD_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 | */ | ||
2855 | const union MHD_DaemonInfo * | ||
2856 | MHD_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 | */ | ||
2884 | void | ||
2885 | MHD_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 | */ | ||
2897 | const char * | ||
2898 | MHD_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 | ||
2913 | GCRY_THREAD_OPTION_PTHREAD_IMPL; | ||
2914 | #endif | ||
2915 | |||
2916 | |||
2917 | /** | ||
2918 | * Initialize do setup work. | ||
2919 | */ | ||
2920 | void ATTRIBUTE_CONSTRUCTOR | ||
2921 | MHD_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 | |||
2936 | void ATTRIBUTE_DESTRUCTOR | ||
2937 | MHD_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 | */ | ||
60 | static void | ||
61 | cvthex (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 | */ | ||
91 | static void | ||
92 | digest_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 | */ | ||
137 | static void | ||
138 | digest_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 | */ | ||
204 | static int | ||
205 | lookup_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 | */ | ||
293 | static int | ||
294 | check_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 | */ | ||
352 | char * | ||
353 | MHD_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 | */ | ||
388 | static void | ||
389 | calculate_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 | */ | ||
434 | static int | ||
435 | test_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 | */ | ||
470 | static int | ||
471 | check_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 | */ | ||
545 | int | ||
546 | MHD_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 | */ | ||
746 | int | ||
747 | MHD_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 | */ | ||
34 | const char * | ||
35 | MHD_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 | */ | ||
93 | void | ||
94 | MHD_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 | */ | ||
118 | size_t | ||
119 | MHD_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 | |||
161 | time_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 | */ | ||
49 | extern MHD_PanicCallback mhd_panic; | ||
50 | |||
51 | /** | ||
52 | * Closure argument for "mhd_panic". | ||
53 | */ | ||
54 | extern 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 | */ | ||
76 | enum 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 | */ | ||
98 | struct 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 | */ | ||
125 | struct 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 | */ | ||
146 | void | ||
147 | MHD_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 | */ | ||
163 | size_t | ||
164 | MHD_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 | */ | ||
172 | struct 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 | */ | ||
202 | struct 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 | */ | ||
296 | enum 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 | ||
429 | const char * | ||
430 | MHD_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 | */ | ||
442 | typedef 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 | */ | ||
454 | typedef 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 | */ | ||
461 | struct 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 | */ | ||
767 | typedef 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 | */ | ||
778 | typedef size_t (*UnescapeCallback)(void *cls, | ||
779 | struct MHD_Connection *conn, | ||
780 | char *uri); | ||
781 | |||
782 | |||
783 | /** | ||
784 | * State kept for each MHD daemon. | ||
785 | */ | ||
786 | struct 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 | */ | ||
1091 | time_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 | */ | ||
31 | static void | ||
32 | byteReverse(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 | */ | ||
63 | static void | ||
64 | MD5Transform(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 | */ | ||
153 | void | ||
154 | MD5Init(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 | */ | ||
169 | void | ||
170 | MD5Update(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 | */ | ||
221 | void | ||
222 | MD5Final(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 | |||
32 | struct MD5Context | ||
33 | { | ||
34 | uint32_t buf[4]; | ||
35 | uint32_t bits[2]; | ||
36 | unsigned char in[64]; | ||
37 | }; | ||
38 | |||
39 | |||
40 | void | ||
41 | MD5Init(struct MD5Context *ctx); | ||
42 | |||
43 | void | ||
44 | MD5Update(struct MD5Context *ctx, | ||
45 | const void *buf, | ||
46 | unsigned len); | ||
47 | |||
48 | void 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 | */ | ||
50 | struct 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 | */ | ||
86 | struct MemoryPool * | ||
87 | MHD_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 | */ | ||
126 | void | ||
127 | MHD_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 | */ | ||
150 | void * | ||
151 | MHD_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 | */ | ||
190 | void * | ||
191 | MHD_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 | */ | ||
241 | void * | ||
242 | MHD_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 | */ | ||
38 | struct MemoryPool; | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Create a memory pool. | ||
43 | * | ||
44 | * @param max maximum size of the pool | ||
45 | * @return NULL on error | ||
46 | */ | ||
47 | struct MemoryPool * | ||
48 | MHD_pool_create (size_t max); | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Destroy a memory pool. | ||
53 | * | ||
54 | * @param pool memory pool to destroy | ||
55 | */ | ||
56 | void | ||
57 | MHD_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 | */ | ||
71 | void * | ||
72 | MHD_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 | */ | ||
93 | void * | ||
94 | MHD_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 | */ | ||
109 | void * | ||
110 | MHD_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 | */ | ||
38 | enum 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 | |||
66 | enum 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 | */ | ||
103 | enum 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 | */ | ||
117 | struct 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 | */ | ||
264 | struct MHD_PostProcessor * | ||
265 | MHD_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 | */ | ||
335 | static int | ||
336 | post_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 | */ | ||
490 | static int | ||
491 | try_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 | */ | ||
521 | static int | ||
522 | find_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 | */ | ||
560 | static void | ||
561 | try_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 | */ | ||
613 | static int | ||
614 | process_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 | */ | ||
677 | static int | ||
678 | process_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 | */ | ||
757 | static void | ||
758 | free_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 | */ | ||
793 | static int | ||
794 | post_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 | } | ||
1069 | END: | ||
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 | */ | ||
1098 | int | ||
1099 | MHD_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 | */ | ||
1127 | int | ||
1128 | MHD_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 | |||
34 | static const char *invalid_hundred[] = { NULL }; | ||
35 | |||
36 | static const char *const one_hundred[] = { | ||
37 | "Continue", | ||
38 | "Switching Protocols", | ||
39 | "Processing" | ||
40 | }; | ||
41 | |||
42 | static 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 | |||
53 | static 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 | |||
64 | static 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 | |||
119 | static 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 | |||
134 | struct 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 | |||
142 | static 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 | |||
151 | const char * | ||
152 | MHD_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 | */ | ||
35 | const 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 | */ | ||
40 | static int | ||
41 | add_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 | */ | ||
88 | int | ||
89 | MHD_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 | */ | ||
107 | int | ||
108 | MHD_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 | */ | ||
126 | int | ||
127 | MHD_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 | */ | ||
167 | int | ||
168 | MHD_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 | */ | ||
193 | const char * | ||
194 | MHD_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 | */ | ||
223 | struct MHD_Response * | ||
224 | MHD_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 | */ | ||
264 | static ssize_t | ||
265 | file_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 | */ | ||
286 | static void | ||
287 | free_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 | */ | ||
305 | struct 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 | */ | ||
333 | struct 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 | */ | ||
353 | struct MHD_Response * | ||
354 | MHD_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 | */ | ||
403 | struct MHD_Response * | ||
404 | MHD_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 | */ | ||
421 | void | ||
422 | MHD_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 | |||
450 | void | ||
451 | MHD_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 | */ | ||
34 | void 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 | |||
39 | static int | ||
40 | testStartError () | ||
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 | |||
50 | static int | ||
51 | apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen) | ||
52 | { | ||
53 | return MHD_NO; | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) | ||
58 | { | ||
59 | return MHD_YES; | ||
60 | } | ||
61 | |||
62 | static int | ||
63 | ahc_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 | |||
74 | static int | ||
75 | testStartStop () | ||
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 | |||
89 | static int | ||
90 | testExternalRun () | ||
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 | |||
124 | static int | ||
125 | testThread () | ||
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 | |||
140 | static int | ||
141 | testMultithread () | ||
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 | |||
156 | int | ||
157 | main (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 | */ | ||
43 | const 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 | |||
72 | static int | ||
73 | mismatch (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 | |||
82 | static int | ||
83 | value_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 | |||
119 | static int | ||
120 | test_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 | |||
153 | static int | ||
154 | test_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 | |||
188 | static int | ||
189 | test_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 | |||
223 | static int | ||
224 | test_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 | |||
259 | int | ||
260 | main (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 | |||
9 | int 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 | |||
23 | int | ||
24 | main (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 | |||
35 | static int | ||
36 | value_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 | |||
59 | static int | ||
60 | test_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 | |||
96 | int | ||
97 | main (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 */ | ||
20 | void * | ||
21 | tsearch(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 */ | ||
54 | void * | ||
55 | tfind(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 | */ | ||
84 | void * | ||
85 | tdelete(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 | |||
15 | typedef enum { | ||
16 | preorder, | ||
17 | postorder, | ||
18 | endorder, | ||
19 | leaf | ||
20 | } VISIT; | ||
21 | |||
22 | #ifdef _SEARCH_PRIVATE | ||
23 | typedef struct node { | ||
24 | char *key; | ||
25 | struct node *llink, *rlink; | ||
26 | } node_t; | ||
27 | #endif | ||
28 | |||
29 | __BEGIN_DECLS | ||
30 | void *tdelete(const void * __restrict, void ** __restrict, | ||
31 | int (*)(const void *, const void *)); | ||
32 | void *tfind(const void *, void * const *, | ||
33 | int (*)(const void *, const void *)); | ||
34 | void *tsearch(const void *, void **, int (*)(const void *, const void *)); | ||
35 | void twalk(const void *, void (*)(const void *, VISIT, int)); | ||
36 | void tdestroy(void *, void (*)(void *)); | ||
37 | __END_DECLS | ||
38 | |||
39 | #endif /* !_SEARCH_H_ */ | ||