diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-01-01 13:47:44 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-01-01 13:47:44 +0000 |
commit | 3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6 (patch) | |
tree | fe9ede8fc028e6b7ebd2c683be623214b365f1a7 | |
parent | 964326eb5348b5acf7d1cff7fb2f3c0d44ff4716 (diff) | |
download | libmicrohttpd-3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6.tar.gz libmicrohttpd-3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6.zip |
updating docs
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | configure.ac | 20 | ||||
-rw-r--r-- | doc/chapters/basicauthentication.inc | 148 | ||||
-rw-r--r-- | doc/chapters/tlsauthentication.inc | 18 | ||||
-rw-r--r-- | doc/examples/basicauthentication.c | 179 | ||||
-rw-r--r-- | src/include/microhttpd.h | 2 |
6 files changed, 115 insertions, 255 deletions
@@ -1,3 +1,6 @@ | |||
1 | Sun Dec 26 00:02:15 CET 2010 | ||
2 | Releasing libmicrohttpd 0.9.4. -CG | ||
3 | |||
1 | Sat Dec 25 21:57:14 CET 2010 | 4 | Sat Dec 25 21:57:14 CET 2010 |
2 | Adding support for basic authentication. | 5 | Adding support for basic authentication. |
3 | Documented how to obtain client SSL certificates in tutorial. -MS | 6 | Documented how to obtain client SSL certificates in tutorial. -MS |
diff --git a/configure.ac b/configure.ac index b2a53fed..204d32ac 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -21,15 +21,15 @@ | |||
21 | # | 21 | # |
22 | # | 22 | # |
23 | AC_PREREQ(2.57) | 23 | AC_PREREQ(2.57) |
24 | AC_INIT([libmicrohttpd], [0.9.3],[libmicrohttpd@gnu.org]) | 24 | AC_INIT([libmicrohttpd], [0.9.4],[libmicrohttpd@gnu.org]) |
25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.9.3]) | 25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.9.4]) |
26 | AM_CONFIG_HEADER([MHD_config.h]) | 26 | AM_CONFIG_HEADER([MHD_config.h]) |
27 | AC_CONFIG_MACRO_DIR([m4]) | 27 | AC_CONFIG_MACRO_DIR([m4]) |
28 | AH_TOP([#define _GNU_SOURCE 1]) | 28 | AH_TOP([#define _GNU_SOURCE 1]) |
29 | 29 | ||
30 | LIB_VERSION_CURRENT=11 | 30 | LIB_VERSION_CURRENT=12 |
31 | LIB_VERSION_REVISION=0 | 31 | LIB_VERSION_REVISION=0 |
32 | LIB_VERSION_AGE=1 | 32 | LIB_VERSION_AGE=2 |
33 | AC_SUBST(LIB_VERSION_CURRENT) | 33 | AC_SUBST(LIB_VERSION_CURRENT) |
34 | AC_SUBST(LIB_VERSION_REVISION) | 34 | AC_SUBST(LIB_VERSION_REVISION) |
35 | AC_SUBST(LIB_VERSION_AGE) | 35 | AC_SUBST(LIB_VERSION_AGE) |
@@ -201,7 +201,7 @@ AC_MSG_CHECKING(whether to use libcurl for testing) | |||
201 | AC_ARG_ENABLE([curl], | 201 | AC_ARG_ENABLE([curl], |
202 | [AS_HELP_STRING([--disable-curl],[disable cURL based testcases])], | 202 | [AS_HELP_STRING([--disable-curl],[disable cURL based testcases])], |
203 | [enable_curl=${enableval}], | 203 | [enable_curl=${enableval}], |
204 | [enable_curl=no]) | 204 | [enable_curl=yes]) |
205 | AC_MSG_RESULT($enable_curl) | 205 | AC_MSG_RESULT($enable_curl) |
206 | curl=0 | 206 | curl=0 |
207 | if test "$enable_curl" = "yes" | 207 | if test "$enable_curl" = "yes" |
@@ -230,7 +230,7 @@ AC_ARG_ENABLE([messages], | |||
230 | [AS_HELP_STRING([--disable-messages], | 230 | [AS_HELP_STRING([--disable-messages], |
231 | [disable MHD error messages])], | 231 | [disable MHD error messages])], |
232 | [enable_messages=${enableval}], | 232 | [enable_messages=${enableval}], |
233 | [enable_messages=no]) | 233 | [enable_messages=yes]) |
234 | AC_MSG_RESULT($enable_messages) | 234 | AC_MSG_RESULT($enable_messages) |
235 | if test "$enable_messages" = "yes" | 235 | if test "$enable_messages" = "yes" |
236 | then | 236 | then |
@@ -246,7 +246,7 @@ AC_ARG_ENABLE([postprocessor], | |||
246 | [AS_HELP_STRING([--disable-postprocessor], | 246 | [AS_HELP_STRING([--disable-postprocessor], |
247 | [disable MHD PostProcessor functionality])], | 247 | [disable MHD PostProcessor functionality])], |
248 | [enable_postprocessor=${enableval}], | 248 | [enable_postprocessor=${enableval}], |
249 | [enable_postprocessor=no]) | 249 | [enable_postprocessor=yes]) |
250 | AC_MSG_RESULT($disable_postprocessor) | 250 | AC_MSG_RESULT($disable_postprocessor) |
251 | AM_CONDITIONAL([HAVE_POSTPROCESSOR],test x$enable_postprocessor != xno) | 251 | AM_CONDITIONAL([HAVE_POSTPROCESSOR],test x$enable_postprocessor != xno) |
252 | 252 | ||
@@ -305,7 +305,7 @@ AC_ARG_ENABLE([https], | |||
305 | [AS_HELP_STRING([--disable-https], | 305 | [AS_HELP_STRING([--disable-https], |
306 | [disable HTTPS support])], | 306 | [disable HTTPS support])], |
307 | [enable_https=${enableval}], | 307 | [enable_https=${enableval}], |
308 | [enable_https=no]) | 308 | [enable_https=yes]) |
309 | if test "$enable_https" = "yes" | 309 | if test "$enable_https" = "yes" |
310 | then | 310 | then |
311 | if test "$gcrypt" = "true" -a "$gnutls" = "true" | 311 | if test "$gcrypt" = "true" -a "$gnutls" = "true" |
@@ -330,7 +330,7 @@ AC_ARG_ENABLE([dauth], | |||
330 | AS_HELP_STRING([--disable-dauth], | 330 | AS_HELP_STRING([--disable-dauth], |
331 | [disable HTTP basic and digest Auth support]), | 331 | [disable HTTP basic and digest Auth support]), |
332 | [enable_dauth=${enableval}], | 332 | [enable_dauth=${enableval}], |
333 | [enable_dauth=no]) | 333 | [enable_dauth=yes]) |
334 | 334 | ||
335 | if test "$enable_dauth" = "yes" | 335 | if test "$enable_dauth" = "yes" |
336 | then | 336 | then |
@@ -360,7 +360,7 @@ AC_ARG_ENABLE([coverage], | |||
360 | AS_HELP_STRING([--enable-coverage], | 360 | AS_HELP_STRING([--enable-coverage], |
361 | [compile the library with code coverage support]), | 361 | [compile the library with code coverage support]), |
362 | [use_gcov=${enableval}], | 362 | [use_gcov=${enableval}], |
363 | [use_gcov=yes]) | 363 | [use_gcov=no]) |
364 | AM_CONDITIONAL([USE_COVERAGE], [test "x$use_gcov" = "xyes"]) | 364 | AM_CONDITIONAL([USE_COVERAGE], [test "x$use_gcov" = "xyes"]) |
365 | 365 | ||
366 | 366 | ||
diff --git a/doc/chapters/basicauthentication.inc b/doc/chapters/basicauthentication.inc index 2b68fc4c..8c7c241c 100644 --- a/doc/chapters/basicauthentication.inc +++ b/doc/chapters/basicauthentication.inc | |||
@@ -69,112 +69,62 @@ Let us assume we had only files not intended to be handed out without the correc | |||
69 | so every "GET" request will be challenged. | 69 | so every "GET" request will be challenged. |
70 | @emph{RFC 2617} describes how the server shall ask for authentication by adding a | 70 | @emph{RFC 2617} describes how the server shall ask for authentication by adding a |
71 | @emph{WWW-Authenticate} response header with the name of the @emph{realm} protected. | 71 | @emph{WWW-Authenticate} response header with the name of the @emph{realm} protected. |
72 | 72 | MHD can generate and queue such a failure response for you using | |
73 | We let an extra function function do this. | 73 | the @code{MHD_queue_basic_auth_fail_response} API. The only thing you need to do |
74 | is construct a response with the error page to be shown to the user | ||
75 | if he aborts basic authentication. But first, you should check if the | ||
76 | proper credentials were already supplied using the | ||
77 | @code{MHD_basic_auth_get_username_password} call. | ||
78 | |||
79 | Your code would then look like this: | ||
74 | @verbatim | 80 | @verbatim |
75 | static int | 81 | static int |
76 | ask_for_authentication (struct MHD_Connection *connection, const char *realm) | 82 | answer_to_connection (void *cls, struct MHD_Connection *connection, |
83 | const char *url, const char *method, | ||
84 | const char *version, const char *upload_data, | ||
85 | size_t *upload_data_size, void **con_cls) | ||
77 | { | 86 | { |
78 | int ret; | 87 | char *user; |
88 | char *pass; | ||
89 | int fail; | ||
79 | struct MHD_Response *response; | 90 | struct MHD_Response *response; |
80 | char *headervalue; | 91 | |
81 | const char *strbase = "Basic realm="; | 92 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) |
82 | 93 | return MHD_NO; | |
83 | response = MHD_create_response_from_data (0, NULL, MHD_NO, MHD_NO); | 94 | if (NULL == *con_cls) |
84 | if (!response) return MHD_NO; | 95 | { |
85 | 96 | *con_cls = connection; | |
86 | headervalue = malloc (strlen (strbase) + strlen (realm) + 1); | 97 | return MHD_YES; |
87 | if (!headervalue) return MHD_NO; | 98 | } |
88 | 99 | pass = NULL; | |
89 | strcpy (headervalue, strbase); | 100 | user = MHD_basic_auth_get_username_password (connection, &pass); |
90 | strcat (headervalue, realm); | 101 | fail = ( (user == NULL) || |
91 | 102 | (0 != strcmp (user, "root")) || | |
92 | ret = MHD_add_response_header (response, "WWW-Authenticate", headervalue); | 103 | (0 != strcmp (pass, "pa$$w0rd") ) ); |
93 | free (headervalue); | 104 | if (user != NULL) free (user); |
94 | if (!ret) {MHD_destroy_response (response); return MHD_NO;} | 105 | if (pass != NULL) free (pass); |
95 | 106 | if (fail) | |
96 | ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response); | 107 | { |
108 | const char *page = "<html><body>Go away.</body></html>"; | ||
109 | response = | ||
110 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
111 | MHD_NO); | ||
112 | ret = MHD_queue_basic_auth_fail_response (connection, | ||
113 | "my realm", | ||
114 | response); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | const char *page = "<html><body>A secret.</body></html>"; | ||
119 | response = | ||
120 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
121 | MHD_NO); | ||
122 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
123 | } | ||
97 | MHD_destroy_response (response); | 124 | MHD_destroy_response (response); |
98 | return ret; | 125 | return ret; |
99 | } | 126 | } |
100 | @end verbatim | 127 | @end verbatim |
101 | @noindent | ||
102 | |||
103 | @code{#define} the realm name according to your own taste, e.g. "Maintenance" or "Area51" but | ||
104 | it will need to have extra quotes. | ||
105 | |||
106 | Since the client may send the authentication right away, it would be wrong to ask for | ||
107 | it without checking the request's header--where the authentication is expected to be found. | ||
108 | |||
109 | @heading Authentication in detail | ||
110 | Checking @emph{RFC 2617} again, we find that the client will pack the username and password, by | ||
111 | whatever means he might have obtained them, in a line separated by a colon---and then encodes | ||
112 | them to @emph{Base64}. The actual implementation of this encoding are not within the scope of | ||
113 | this tutorial although a working function is included in the complete source file of the example. | ||
114 | |||
115 | An unencoded word describing the authentication method (here "Basic") will precede the code | ||
116 | and the resulting line is the value of a request header of the type "Authorization". | ||
117 | |||
118 | This header line thus is of interest to the function checking a connection for a given username/password: | ||
119 | @verbatim | ||
120 | static int | ||
121 | is_authenticated (struct MHD_Connection *connection, | ||
122 | const char *username, const char *password) | ||
123 | { | ||
124 | const char *headervalue; | ||
125 | ... | ||
126 | |||
127 | headervalue = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | ||
128 | "Authorization"); | ||
129 | if (NULL == headervalue) return 0; | ||
130 | @end verbatim | ||
131 | @noindent | ||
132 | |||
133 | where, firstly, the authentication method will be checked. | ||
134 | @verbatim | ||
135 | const char *strbase = "Basic "; | ||
136 | ... | ||
137 | if (0 != strncmp (headervalue, strbase, strlen (strbase))) return 0; | ||
138 | @end verbatim | ||
139 | @noindent | ||
140 | |||
141 | Of course, we could decode the passed credentials in the next step and compare them directly to | ||
142 | the given strings. But as this would involve string parsing, which is more complicated then string | ||
143 | composing, it is done the other way around---the clear text credentials will be encoded to @emph{Base64} | ||
144 | and then compared against the headerline. The authentication method string will be left out here as | ||
145 | it has been checked already at this point. | ||
146 | @verbatim | ||
147 | char *expected_b64, *expected; | ||
148 | int authenticated; | ||
149 | |||
150 | ... | ||
151 | strcpy (expected, username); | ||
152 | strcat (expected, ":"); | ||
153 | strcat (expected, password); | ||
154 | |||
155 | expected_b64 = string_to_base64 (expected); | ||
156 | if (NULL == expected_b64) return 0; | ||
157 | |||
158 | strcpy (expected, strbase); | ||
159 | authenticated = (strcmp (headervalue + strlen (strbase), expected_b64) == 0); | ||
160 | |||
161 | free (expected_b64); | ||
162 | |||
163 | return authenticated; | ||
164 | } | ||
165 | @end verbatim | ||
166 | @noindent | ||
167 | |||
168 | These two functions---together with a response function in case of positive authentication doing little | ||
169 | new---allow the rest of the callback function to be rather short. | ||
170 | @verbatim | ||
171 | if (!is_authenticated (connection, USER, PASSWORD)) | ||
172 | return ask_for_authentication (connection, REALM); | ||
173 | |||
174 | return secret_page (connection); | ||
175 | } | ||
176 | @end verbatim | ||
177 | @noindent | ||
178 | 128 | ||
179 | See the @code{examples} directory for the complete example file. | 129 | See the @code{examples} directory for the complete example file. |
180 | 130 | ||
diff --git a/doc/chapters/tlsauthentication.inc b/doc/chapters/tlsauthentication.inc index 4f9c4443..278a3ba5 100644 --- a/doc/chapters/tlsauthentication.inc +++ b/doc/chapters/tlsauthentication.inc | |||
@@ -135,8 +135,22 @@ both of uncritically @emph{HTTP} parts and secured @emph{HTTPS}. | |||
135 | You can also use MHD to authenticate the client via SSL/TLS certificates | 135 | You can also use MHD to authenticate the client via SSL/TLS certificates |
136 | (as an alternative to using the password-based Basic or Digest authentication). | 136 | (as an alternative to using the password-based Basic or Digest authentication). |
137 | To do this, you will need to link your application against @emph{gnutls}. | 137 | To do this, you will need to link your application against @emph{gnutls}. |
138 | For this, you first need to obtain the raw GnuTLS session handle from | 138 | Next, when you start the MHD daemon, you must specify the root CA that you're |
139 | @emph{MHD} using @code{MHD_get_connection_info}. | 139 | willing to trust: |
140 | @verbatim | ||
141 | daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, | ||
142 | PORT, NULL, NULL, | ||
143 | &answer_to_connection, NULL, | ||
144 | MHD_OPTION_HTTPS_MEM_KEY, key_pem, | ||
145 | MHD_OPTION_HTTPS_MEM_CERT, cert_pem, | ||
146 | MHD_OPTION_HTTPS_MEM_TRUST, root_ca_pem, | ||
147 | MHD_OPTION_END); | ||
148 | @end verbatim | ||
149 | |||
150 | With this, you can then obtain client certificates for each session. | ||
151 | In order to obtain the identity of the client, you first need to | ||
152 | obtain the raw GnuTLS session handle from @emph{MHD} using | ||
153 | @code{MHD_get_connection_info}. | ||
140 | 154 | ||
141 | @verbatim | 155 | @verbatim |
142 | #include <gnutls/gnutls.h> | 156 | #include <gnutls/gnutls.h> |
diff --git a/doc/examples/basicauthentication.c b/doc/examples/basicauthentication.c index 389242da..0b5ce62c 100644 --- a/doc/examples/basicauthentication.c +++ b/doc/examples/basicauthentication.c | |||
@@ -3,108 +3,12 @@ | |||
3 | #include <sys/socket.h> | 3 | #include <sys/socket.h> |
4 | #include <microhttpd.h> | 4 | #include <microhttpd.h> |
5 | #include <time.h> | 5 | #include <time.h> |
6 | #include <string.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <stdio.h> | ||
6 | 9 | ||
7 | #define PORT 8888 | 10 | #define PORT 8888 |
8 | 11 | ||
9 | #define REALM "\"Maintenance\"" | ||
10 | #define USER "a legitimate user" | ||
11 | #define PASSWORD "and his password" | ||
12 | |||
13 | |||
14 | char *string_to_base64 (const char *message); | ||
15 | |||
16 | |||
17 | static int | ||
18 | ask_for_authentication (struct MHD_Connection *connection, const char *realm) | ||
19 | { | ||
20 | int ret; | ||
21 | struct MHD_Response *response; | ||
22 | char *headervalue; | ||
23 | const char *strbase = "Basic realm="; | ||
24 | |||
25 | response = MHD_create_response_from_data (0, NULL, MHD_NO, MHD_NO); | ||
26 | if (!response) | ||
27 | return MHD_NO; | ||
28 | |||
29 | headervalue = malloc (strlen (strbase) + strlen (realm) + 1); | ||
30 | if (!headervalue) | ||
31 | return MHD_NO; | ||
32 | |||
33 | strcpy (headervalue, strbase); | ||
34 | strcat (headervalue, realm); | ||
35 | |||
36 | ret = MHD_add_response_header (response, "WWW-Authenticate", headervalue); | ||
37 | free (headervalue); | ||
38 | if (!ret) | ||
39 | { | ||
40 | MHD_destroy_response (response); | ||
41 | return MHD_NO; | ||
42 | } | ||
43 | |||
44 | ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response); | ||
45 | |||
46 | MHD_destroy_response (response); | ||
47 | |||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | static int | ||
52 | is_authenticated (struct MHD_Connection *connection, | ||
53 | const char *username, const char *password) | ||
54 | { | ||
55 | const char *headervalue; | ||
56 | char *expected_b64, *expected; | ||
57 | const char *strbase = "Basic "; | ||
58 | int authenticated; | ||
59 | |||
60 | headervalue = | ||
61 | MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | ||
62 | "Authorization"); | ||
63 | if (NULL == headervalue) | ||
64 | return 0; | ||
65 | if (0 != strncmp (headervalue, strbase, strlen (strbase))) | ||
66 | return 0; | ||
67 | |||
68 | expected = malloc (strlen (username) + 1 + strlen (password) + 1); | ||
69 | if (NULL == expected) | ||
70 | return 0; | ||
71 | |||
72 | strcpy (expected, username); | ||
73 | strcat (expected, ":"); | ||
74 | strcat (expected, password); | ||
75 | |||
76 | expected_b64 = string_to_base64 (expected); | ||
77 | free (expected); | ||
78 | if (NULL == expected_b64) | ||
79 | return 0; | ||
80 | |||
81 | authenticated = | ||
82 | (strcmp (headervalue + strlen (strbase), expected_b64) == 0); | ||
83 | |||
84 | free (expected_b64); | ||
85 | return authenticated; | ||
86 | } | ||
87 | |||
88 | |||
89 | static int | ||
90 | secret_page (struct MHD_Connection *connection) | ||
91 | { | ||
92 | int ret; | ||
93 | struct MHD_Response *response; | ||
94 | const char *page = "<html><body>A secret.</body></html>"; | ||
95 | |||
96 | response = | ||
97 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
98 | MHD_NO); | ||
99 | if (!response) | ||
100 | return MHD_NO; | ||
101 | |||
102 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
103 | MHD_destroy_response (response); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | 12 | ||
109 | static int | 13 | static int |
110 | answer_to_connection (void *cls, struct MHD_Connection *connection, | 14 | answer_to_connection (void *cls, struct MHD_Connection *connection, |
@@ -112,6 +16,12 @@ answer_to_connection (void *cls, struct MHD_Connection *connection, | |||
112 | const char *version, const char *upload_data, | 16 | const char *version, const char *upload_data, |
113 | size_t *upload_data_size, void **con_cls) | 17 | size_t *upload_data_size, void **con_cls) |
114 | { | 18 | { |
19 | char *user; | ||
20 | char *pass; | ||
21 | int fail; | ||
22 | int ret; | ||
23 | struct MHD_Response *response; | ||
24 | |||
115 | if (0 != strcmp (method, "GET")) | 25 | if (0 != strcmp (method, "GET")) |
116 | return MHD_NO; | 26 | return MHD_NO; |
117 | if (NULL == *con_cls) | 27 | if (NULL == *con_cls) |
@@ -119,11 +29,33 @@ answer_to_connection (void *cls, struct MHD_Connection *connection, | |||
119 | *con_cls = connection; | 29 | *con_cls = connection; |
120 | return MHD_YES; | 30 | return MHD_YES; |
121 | } | 31 | } |
122 | 32 | pass = NULL; | |
123 | if (!is_authenticated (connection, USER, PASSWORD)) | 33 | user = MHD_basic_auth_get_username_password (connection, &pass); |
124 | return ask_for_authentication (connection, REALM); | 34 | fail = ( (user == NULL) || |
125 | 35 | (0 != strcmp (user, "root")) || | |
126 | return secret_page (connection); | 36 | (0 != strcmp (pass, "pa$$w0rd") ) ); |
37 | if (user != NULL) free (user); | ||
38 | if (pass != NULL) free (pass); | ||
39 | if (fail) | ||
40 | { | ||
41 | const char *page = "<html><body>Go away.</body></html>"; | ||
42 | response = | ||
43 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
44 | MHD_NO); | ||
45 | ret = MHD_queue_basic_auth_fail_response (connection, | ||
46 | "my realm", | ||
47 | response); | ||
48 | } | ||
49 | else | ||
50 | { | ||
51 | const char *page = "<html><body>A secret.</body></html>"; | ||
52 | response = | ||
53 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
54 | MHD_NO); | ||
55 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
56 | } | ||
57 | MHD_destroy_response (response); | ||
58 | return ret; | ||
127 | } | 59 | } |
128 | 60 | ||
129 | 61 | ||
@@ -142,42 +74,3 @@ main () | |||
142 | MHD_stop_daemon (daemon); | 74 | MHD_stop_daemon (daemon); |
143 | return 0; | 75 | return 0; |
144 | } | 76 | } |
145 | |||
146 | |||
147 | char * | ||
148 | string_to_base64 (const char *message) | ||
149 | { | ||
150 | const char *lookup = | ||
151 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
152 | unsigned long l; | ||
153 | int i; | ||
154 | char *tmp; | ||
155 | size_t length = strlen (message); | ||
156 | |||
157 | tmp = malloc (length * 2); | ||
158 | if (NULL == tmp) | ||
159 | return tmp; | ||
160 | |||
161 | tmp[0] = 0; | ||
162 | |||
163 | for (i = 0; i < length; i += 3) | ||
164 | { | ||
165 | l = (((unsigned long) message[i]) << 16) | ||
166 | | (((i + 1) < length) ? (((unsigned long) message[i + 1]) << 8) : 0) | ||
167 | | (((i + 2) < length) ? ((unsigned long) message[i + 2]) : 0); | ||
168 | |||
169 | |||
170 | strncat (tmp, &lookup[(l >> 18) & 0x3F], 1); | ||
171 | strncat (tmp, &lookup[(l >> 12) & 0x3F], 1); | ||
172 | |||
173 | if (i + 1 < length) | ||
174 | strncat (tmp, &lookup[(l >> 6) & 0x3F], 1); | ||
175 | if (i + 2 < length) | ||
176 | strncat (tmp, &lookup[l & 0x3F], 1); | ||
177 | } | ||
178 | |||
179 | if (length % 3) | ||
180 | strncat (tmp, "===", 3 - length % 3); | ||
181 | |||
182 | return tmp; | ||
183 | } | ||
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 36961275..f123969b 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -106,7 +106,7 @@ extern "C" | |||
106 | /** | 106 | /** |
107 | * Current version of the library. | 107 | * Current version of the library. |
108 | */ | 108 | */ |
109 | #define MHD_VERSION 0x00090301 | 109 | #define MHD_VERSION 0x00090400 |
110 | 110 | ||
111 | /** | 111 | /** |
112 | * MHD-internal return code for "YES". | 112 | * MHD-internal return code for "YES". |