ready for 0.9.0

This commit is contained in:
Christian Grothoff
2010-07-26 16:57:47 +00:00
parent 8157744d45
commit 761267757c
34 changed files with 930 additions and 413 deletions
+3 -2
View File
@@ -1,5 +1,6 @@
Primary developers:
Christian Grothoff <christian@grothoff.org>
Christian Grothoff <christian@grothoff.org> (maintainer)
Nils Durner <durner@gnunet.org> (W32 port)
Sagie Amir (TLS/SSL support using GNUtls)
Richard Alimi <rich@velvetsea.net> (performance)
@@ -8,7 +9,6 @@ Chris GauthierDickey <chrisg@cs.du.edu>
Elliot Glaysher
Daniel Pittman <depittman@gmail.com>
John Popplewell <john@johnnypops.demon.co.uk>
Nils Durner <durner@gnunet.org>
Heikki Lindholm <holin@iki.fi>
Alex Sadovsky <alexeysad@gmail.com>
Greg Schohn <greg.schohn@gmail.com>
@@ -27,3 +27,4 @@ Geoffrey McRae <geoff@spacevs.com>
Documentation contributions also came from:
Marco Maggi <marco.maggi-ipsu@poste.it>
Sebastian Gerhardt <sebgerhardt@gmx.net>
+5 -1
View File
@@ -1,7 +1,11 @@
Mon Jul 26 10:46:57 CEST 2010
Releasing libmicrohttpd 0.9.0. -CG
Sun Jul 25 14:57:47 CEST 2010
Adding support for sendfile on Linux. Adding support
for systemd-style passing of an existing listen socket
as an option. -CG
as an option. IPv6 sockets now only bind to IPv6
(if platform supports this). -CG
Sun Jul 25 11:10:45 CEST 2010
Changed code to use external libgnutls code instead of
-4
View File
@@ -95,7 +95,6 @@ Functions not covered by "make check":
- MHD_del_response_header
- MHD_get_response_headers
- MHD_tls_connection_close
- MHD_create_response_from_fd & sendfile support (!)
Missing documentation:
@@ -104,7 +103,4 @@ Missing documentation:
- manual:
* document configuration options
* document details on porting MHD (plibc, z/OS)
- tutorial:
* clean up English
* make sure everything is accurate
+23 -21
View File
@@ -12,9 +12,10 @@ GET /picture.png?mypassword
@end verbatim
@noindent
In a situation where the client is customized enough and the connection occurs
through secured lines (e.g., a embedded device directly attached to another via wire),
this can be a reasonable choice.
In the rare situation where the client is customized enough and the connection occurs
through secured lines (e.g., a embedded device directly attached to another via wire)
and where the ability to embedd a password in the URI or to pass on a URI with a
password are desired, this can be a reasonable choice.
But when it is assumed that the user connecting does so with an ordinary Internet browser,
this implementation brings some problems about. For example, the URI including the password
@@ -37,15 +38,16 @@ also be "remembered" on the next call (for the same connection).
Thus, we will generate no response until the parameter is non-null---implying the callback was
called before at least once. We do not need to share information between different calls of the callback,
so we can set the parameter to any adress that is assured to be not null. The pointer to the
@code{connection} structure will be pointing to a legal adress, so we take this.
@code{connection} structure will be pointing to a legal address, so we take this.
Not even the headers will be looked at on the first iteration.
The first time @code{answer_to_connection} is called, we will not even look at the headers.
@verbatim
int answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method, const char *version,
const char *upload_data, size_t *upload_data_size,
void **con_cls)
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method, const char *version,
const char *upload_data, size_t *upload_data_size,
void **con_cls)
{
if (0 != strcmp(method, "GET")) return MHD_NO;
if (NULL == *con_cls) {*con_cls = connection; return MHD_YES;}
@@ -57,9 +59,9 @@ int answer_to_connection (void *cls, struct MHD_Connection *connection,
@end verbatim
@noindent
Note how we lop off the connection on the first condition, but return asking for more on
Note how we lop off the connection on the first condition (no "GET" request), but return asking for more on
the other one with @code{MHD_YES}.
With the framework improved, we can proceed to implement the actual authentication process.
With this minor change, we can proceed to implement the actual authentication process.
@heading Request for authentication
@@ -70,7 +72,8 @@ so every "GET" request will be challenged.
We let an extra function function do this.
@verbatim
int ask_for_authentication (struct MHD_Connection *connection, const char *realm)
static int
ask_for_authentication (struct MHD_Connection *connection, const char *realm)
{
int ret;
struct MHD_Response *response;
@@ -91,9 +94,7 @@ int ask_for_authentication (struct MHD_Connection *connection, const char *realm
if (!ret) {MHD_destroy_response (response); return MHD_NO;}
ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
MHD_destroy_response (response);
return ret;
}
@end verbatim
@@ -102,7 +103,7 @@ int ask_for_authentication (struct MHD_Connection *connection, const char *realm
@code{#define} the realm name according to your own taste, e.g. "Maintenance" or "Area51" but
it will need to have extra quotes.
But the client may send the authentication right away, so it would be wrong to ask for
Since the client may send the authentication right away, it would be wrong to ask for
it without checking the request's header--where the authentication is expected to be found.
@heading Authentication in detail
@@ -116,8 +117,9 @@ and the resulting line is the value of a request header of the type "Authorizati
This header line thus is of interest to the function checking a connection for a given username/password:
@verbatim
int is_authenticated (struct MHD_Connection *connection,
const char *username, const char *password)
static int
is_authenticated (struct MHD_Connection *connection,
const char *username, const char *password)
{
const char *headervalue;
...
@@ -185,21 +187,21 @@ authentication methods as @emph{400 bad request}.
@heading Exercises
@itemize @bullet
@item
Make the server respond to wrong credentials (but else correct requests) with the recommended
Make the server respond to wrong credentials (but otherwise well-formed requests) with the recommended
@emph{401 unauthorized} status code. If the client still does not authenticate correctly within the
same connection, close it and store the client's IP address for a certain time. (It is OK to check for
expiration not until the main thread wakes up again on the next connection.) If the client fails
authenticating three times during this period, add it to another list whose entries the
authenticating three times during this period, add it to another list for which the
@code{AcceptPolicyCallback} function denies connection (temporally).
@item
With the network utility @emph{netcat} connect and log the response of a "GET" request as you
With the network utility @code{netcat} connect and log the response of a "GET" request as you
did in the exercise of the first example, this time to a file. Now stop the server and let @emph{netcat}
listen on the same port the server used to listen on and have it fake being the proper server by giving
the file's content as the response (e.g. @code{cat log | nc -l -p 8888}). Pretending to think your were
connecting to the actual server, browse to the eavesdropper and give the correct credentials.
Copy and paste the encoded string you see in netcat's output to some of the Base64 decode tools available online
Copy and paste the encoded string you see in @code{netcat}'s output to some of the Base64 decode tools available online
and see how both the user's name and password could be completely restored.
@end itemize
+29 -23
View File
@@ -9,9 +9,12 @@ just return MHD_NO after we have probed the request. This way, the connection is
without much ado by the server.
@verbatim
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
...
return MHD_NO;
@@ -22,25 +25,26 @@ The ellipsis marks the position where the following instructions shall be insert
We begin with the most obvious information available to the server, the request line. You should
already have noted that a request consists of a command (or "method") and a URI (e.g. a filename).
already have noted that a request consists of a command (or "HTTP method") and a URI (e.g. a filename).
It also contains a string for the version of the protocol which can be found in @code{version}.
To call it a "new request" is justified because we return only @code{MHD_NO}, thus ensuring the
function will not be called again for this connection.
@verbatim
printf ("New request %s for %s using version %s\n", method, url, version);
printf ("New %s request for %s using version %s\n", method, url, version);
@end verbatim
@noindent
The rest of the information is a bit more hidden. Nevertheless, there is lot of it sent from common
Internet browsers. It is stored in "key-name" pairs and we want to list what we find in the header.
As there is no mandatory set of keys a client has to send, each key--name pair is printed out one by
Internet browsers. It is stored in "key-value" pairs and we want to list what we find in the header.
As there is no mandatory set of keys a client has to send, each key-value pair is printed out one by
one until there are no more left. We do this by writing a separate function which will be called for
each pair just like the above function is called for each HTTP request.
It can then print out the content of this pair.
@verbatim
int print_out_key (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
int print_out_key (void *cls, enum MHD_ValueKind kind,
const char *key, const char *value)
{
printf ("%s = %s\n", key, value);
printf ("%s: %s\n", key, value);
return MHD_YES;
}
@end verbatim
@@ -48,29 +52,30 @@ int print_out_key (void *cls, enum MHD_ValueKind kind, const char *key, const ch
To start the iteration process that calls our new function for every key, the line
@verbatim
MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key, NULL);
MHD_get_connection_values (connection, MHD_HEADER_KIND, &print_out_key, NULL);
@end verbatim
@noindent
needs to be inserted in the connection callback function too. The second parameter tells the function
that we are only interested in keys from the general HTTP header of the request. Our iterating
function @code{PrintOutKey} does not rely on any additional information to fulfill its duties
function @code{print_out_key} does not rely on any additional information to fulfill its duties
so the last parameter can be NULL.
All in all, this constitutes the complete @code{logger.c} program for this chapter which can be
All in all, this constitutes the complete @code{logging.c} program for this chapter which can be
found in the @code{examples} section.
Connecting with any modern Internet browser should yield a handful of keys. You should try to
interpret them with the aid of @emph{RFC 2616}.
Especially worth mentioning is the host key which is often used to serve several different websites
hosted under one single IP address but reachable by different domain names.
Especially worth mentioning is the "Host" key which is often used to serve several different websites
hosted under one single IP address but reachable by different domain names (this is called virtual hosting).
@heading Conclusion
The introduced capabilities to itemize the content of a simple GET request---especially the
URI---should already allow the server to satisfy clients' requests for small specific resources
(e.g. files) or even induce alteration of how the server operates. However, the latter is not
recommended as the GET method (including its header data) is by convention considered a "SAFE"
operation, which should not change the server's state in a significant way, but temporally actions
like searching for a passed string is fine.
(e.g. files) or even induce alteration of server state. However, the latter is not
recommended as the GET method (including its header data) is by convention considered a "safe"
operation, which should not change the server's state in a significant way. By convention,
GET operations can thus be performed by crawlers and other automatic software. Naturally
actions like searching for a passed string are fine.
Of course, no transmission can occur while the return value is still set to @code{MHD_NO} in the
callback function.
@@ -88,16 +93,17 @@ returned accompanied by an informative message.
A very interesting information has still been ignored by our logger---the client's IP address.
Implement a callback function
@verbatim
int on_client_connect (void *cls,
const struct sockaddr *addr,socklen_t addrlen)
static int on_client_connect (void *cls,
const struct sockaddr *addr,
socklen_t addrlen)
@end verbatim
@noindent
that prints out the IP address in an appropriate format. You might want to use the posix function
that prints out the IP address in an appropriate format. You might want to use the POSIX function
@code{inet_ntoa} but bear in mind that @code{addr} is actually just a structure containing other
substructures and is @emph{not} the variable this function expects.
Make sure to return @code{MHD_YES} so that the library knows the client is allowed to connect
(and to request). If one wanted to limit access basing on IP addresses, this would be the place
to do it. The address of your function will then be passed as the third parameter of the
(and to then process the request). If one wanted to limit access basing on IP addresses, this would be the place
to do it. The address of your @code{on_client_connect} function must be passed as the third parameter to the
@code{MHD_start_daemon} call.
@end itemize
+18 -15
View File
@@ -1,7 +1,7 @@
The most basic task for a HTTP server is to deliver a static text message to any client connecting to it.
Given that this is also easy to implement, it is an excellent problem to start with.
For now, the particular filename the client asks for shall have no effect on the message that will
For now, the particular URI the client asks for shall have no effect on the message that will
be returned. In addition, the server shall end the connection after the message has been sent so that
the client will know there is nothing more to expect.
@@ -11,7 +11,9 @@ lines in by yourself as they will be discussed and explained in detail.
After the necessary includes and the definition of the port which our server should listen on
@verbatim
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
@@ -35,16 +37,17 @@ daemon to sent the reply.
Talking about the reply, it is defined as a string right after the function header
@verbatim
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
int answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
const char *page = "<html><body>Hello, browser!</body></html>";
@end verbatim
@noindent
HTTP is a rather strict protocol and the client would certainly consider it "inappropriate" if we
just sent the answer string "as is". Instead, it has to be wrapped in certain layers, called headers,
of additional information. Luckily, most of the work in this area is done by the library for us---we
just sent the answer string "as is". Instead, it has to be wrapped with additional information stored in so-called headers and footers. Most of the work in this area is done by the library for us---we
just have to ask. Our reply string packed in the necessary layers will be called a "response".
To obtain such a response we hand our data (the reply--string) and its size over to the
@code{MHD_create_response_from_data} function. The last two parameters basically tell @emph{MHD}
@@ -92,13 +95,13 @@ int main ()
The first parameter is one of three possible modes of operation. Here we want the daemon to run in
a separate thread and to manage all incoming connections in the same thread. This means that while
producing the response for one connection, the other connections will be put on hold. In this
chapter, where the reply is already known and therefore the request is served quickly, this poses no problem.
example, where the reply is already known and therefore the request is served quickly, this poses no problem.
We will allow all clients to connect regardless of their name or location, therefore we do not check
them on connection and set the forth and fifth parameter to NULL.
Parameter six is the address of the function we want to be called whenever a new connection has been
established. Our @code{AnswerToConnection} knows best what the client wants and needs no additional
established. Our @code{answer_to_connection} knows best what the client wants and needs no additional
information (which could be passed via the next parameter) so the next parameter is NULL. Likewise,
we do not need to pass extra options to the daemon so we just write the MHD_OPTION_END as the last parameter.
@@ -121,11 +124,11 @@ The first example is now complete.
Compile it with
@verbatim
cc hellobrowser.c -o hellobrowser -I$PATH_TO_LIBMHD_INCLUDES
-L$PATH_TO_LIBMHD_INCLUDES -static -lmicrohttpd -pthread
-L$PATH_TO_LIBMHD_INCLUDES -lmicrohttpd
@end verbatim
with the two paths set accordingly and run it.
Now open your favorite Internet browser and go to the address @code{localhost:8888}, provided that
Now open your favorite Internet browser and go to the address @code{http://localhost:8888/}, provided that 8888
is the port you chose. If everything works as expected, the browser will present the message of the
static HTML page it got from our minimal server.
@@ -146,7 +149,7 @@ received if a response is queued in the first iteration. Furthermore, the connec
right after the response has been transferred then.
Both of these issues you will find addressed in the official @code{minimal_example.c} residing in
the @code{src/examples} directory of the @emph{GNU libmicrohttpd} package. The source code of this
the @code{src/examples} directory of the @emph{MHD} package. The source code of this
program should look very familiar to you by now and easy to understand.
For our example, the @code{must_copy} and @code{must_free} parameter at the response construction
@@ -163,10 +166,10 @@ its own copy of it.
@heading Exercises
@itemize @bullet
@item
While the server is running, use a program like telnet or netcat to connect to it. Try to form a
valid HTTP1.1 request yourself like
While the server is running, use a program like @code{telnet} or @code{netcat} to connect to it. Try to form a
valid HTTP 1.1 request yourself like
@verbatim
GET /dontcare HTTP1.1
GET /dontcare HTTP/1.1
Host: itsme
<enter>
@end verbatim
@@ -197,7 +200,7 @@ former static string.
@item
@emph{Demanding:} Write a separate function returning a string containing some useful information,
for example, the time. Pass the function's address as the sixth parameter and evaluate this function
on every request anew in @code{AnswerToConnection}. Remember to free the memory of the string
on every request anew in @code{answer_to_connection}. Remember to free the memory of the string
every time after satisfying the request.
@end itemize
+6
View File
@@ -15,3 +15,9 @@ is written for version @value{VERSION}. At the time being,
this tutorial has only been tested on @emph{GNU/Linux} machines even though
efforts were made not to rely on anything that would prevent the samples from being
built on similar systems.
@section History
This tutorial was originally written by Sebastian Gerhardt for MHD
0.4.0. It was slighly polished and updated to MHD 0.9.0 by Christian
Grothoff.
+46 -26
View File
@@ -13,14 +13,15 @@ total number of clients that are uploading.
@verbatim
#define MAXCLIENTS 2
static unsigned char nr_of_uploading_clients = 0;
static unsigned int nr_of_uploading_clients = 0;
@end verbatim
@noindent
If there are too many clients uploading, we want the server to respond to all requests with a busy
message.
@verbatim
const char* busypage = "<html><body>This server is busy, please try again later.</body></html>";
const char* busypage =
"<html><body>This server is busy, please try again later.</body></html>";
@end verbatim
@noindent
@@ -29,8 +30,9 @@ and ask her to pick a file on her local filesystem which is to be uploaded.
@verbatim
const char* askpage = "<html><body>\n\
Upload a file, please!<br>\n\
There are %d clients uploading at the moment.<br>\n\
<form action=\"/filepost\" method=\"post\" enctype=\"multipart/form-data\">\n\
There are %u clients uploading at the moment.<br>\n\
<form action=\"/filepost\" method=\"post\" \
enctype=\"multipart/form-data\">\n\
<input name=\"file\" type=\"file\">\n\
<input type=\"submit\" value=\" Send \"></form>\n\
</body></html>";
@@ -46,8 +48,10 @@ const char* completepage = "<html><body>The upload has been completed.</body></h
We want the server to report internal errors, such as memory shortage or file access problems,
adequately.
@verbatim
const char* servererrorpage = "<html><body>An internal server error has occured.</body></html>";
const char* fileexistspage = "<html><body>This file already exists.</body></html>";
const char* servererrorpage
= "<html><body>An internal server error has occured.</body></html>";
const char* fileexistspage
= "<html><body>This file already exists.</body></html>";
@end verbatim
@noindent
@@ -56,13 +60,15 @@ status code but in order to improve the @code{HTTP} conformance of our server a
@code{send_page} function so that it accepts individual status codes.
@verbatim
int send_page (struct MHD_Connection *connection, const char* page, int status_code)
static int
send_page (struct MHD_Connection *connection,
const char* page, int status_code)
{
int ret;
struct MHD_Response *response;
response = MHD_create_response_from_data (strlen (page), (void*) page, MHD_NO, MHD_YES);
response = MHD_create_response_from_data (strlen (page), (void*) page,
MHD_NO, MHD_YES);
if (!response) return MHD_NO;
ret = MHD_queue_response (connection, status_code, response);
@@ -84,9 +90,12 @@ queued at this point, and @code{MHD_YES} returned, @emph{MHD} will not sent any
a postprocessor has been created and the post iterator is called at least once.
@verbatim
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
if (NULL == *con_cls)
{
@@ -127,8 +136,9 @@ the structure is initialized to "no error".
@verbatim
if (0 == strcmp (method, "POST"))
{
con_info->postprocessor = MHD_create_post_processor (connection, POSTBUFFERSIZE,
iterate_post, (void*) con_info);
con_info->postprocessor
= MHD_create_post_processor (connection, POSTBUFFERSIZE,
iterate_post, (void*) con_info);
if (NULL == con_info->postprocessor)
{
@@ -153,7 +163,7 @@ own copy of it for as long as it is needed.
if (0 == strcmp (method, "GET"))
{
int ret;
char buffer[1024] = {0};
char buffer[1024];
sprintf (buffer, askpage, nr_of_uploading_clients);
return send_page (connection, buffer, MHD_HTTP_OK);
@@ -173,12 +183,15 @@ constituted no expected request method.
if (0 != *upload_data_size)
{
MHD_post_process(con_info->postprocessor, upload_data, *upload_data_size);
MHD_post_process (con_info->postprocessor,
upload_data, *upload_data_size);
*upload_data_size = 0;
return MHD_YES;
}
else return send_page (connection, con_info->answerstring, con_info->answercode);
else
return send_page (connection, con_info->answerstring,
con_info->answercode);
}
return send_page(connection, errorpage, MHD_HTTP_BAD_REQUEST);
@@ -193,11 +206,14 @@ several times now. This means that for any given connection (there might be seve
the posted data has to be written to the correct file. That is why we store a file handle in every
@code{connection_info}, so that the it is preserved between successive iterations.
@verbatim
int iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data, uint64_t off, size_t size)
static int
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data,
uint64_t off, size_t size)
{
struct connection_info_struct *con_info = (struct connection_info_struct*) coninfo_cls;
struct connection_info_struct *con_info = coninfo_cls;
@end verbatim
@noindent
@@ -221,7 +237,8 @@ would be an error.
If the iterator is called for the first time, no file will have been opened yet. The @code{filename}
string contains the name of the file (without any paths) the user selected on his system. We want to
take this as the name the file will be stored on the server and make sure no file of that name exists
(or is being uploaded) before we create one.
(or is being uploaded) before we create one (note that the code below technically contains a
race between the two "fopen" calls, but we will overlook this for portability sake).
@verbatim
if (!con_info->fp)
{
@@ -245,7 +262,8 @@ server only needs to write data to the file if there is some.
@verbatim
if (size > 0)
{
if (!fwrite (data, size, sizeof(char), con_info->fp)) return MHD_NO;
if (!fwrite (data, size, sizeof(char), con_info->fp))
return MHD_NO;
}
@end verbatim
@noindent
@@ -265,10 +283,11 @@ be set to success again. If the upload has finished, this iterator function will
The new client was registered when the postprocessor was created. Likewise, we unregister the client
on destroying the postprocessor when the request is completed.
@verbatim
void request_completed (void *cls, struct MHD_Connection *connection, void **con_cls,
void request_completed (void *cls, struct MHD_Connection *connection,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info = (struct connection_info_struct*) *con_cls;
struct connection_info_struct *con_info = *con_cls;
if (NULL == con_info) return;
@@ -296,4 +315,5 @@ This is essentially the whole example @code{largepost.c}.
@heading Remarks
Now that the clients are able to create files on the server, security aspects are becoming even more
important than before. Aside from proper client authentication, the server should always make sure
explicitly that no files will be created outside of a dedicated upload directory.
explicitly that no files will be created outside of a dedicated upload directory. In particular,
filenames must be checked to not contain strings like "../".
+32 -25
View File
@@ -4,8 +4,8 @@ the server operates. To induce changes on the server, the @emph{POST} method is
and is much more powerful than @emph{GET} and will be introduced in this chapter.
We are going to write an application that asks for the visitor's name and, after the user has posted it,
composes an individual response text. Even though it was not mandatory to use the @emph{post} method here,
as there is no permanent change caused by the post, it is an illustrative example on how to share data
composes an individual response text. Even though it was not mandatory to use the @emph{POST} method here,
as there is no permanent change caused by the POST, it is an illustrative example on how to share data
between different functions for the same connection. Furthermore, the reader should be able to extend
it easily.
@@ -37,8 +37,9 @@ const char* errorpage="<html><body>This doesn't seem to be right.</body></html>"
@noindent
Whenever we need to send a page, we use an extra function
@code{int SendPage(struct MHD_Connection *connection, const char* page)}
for this, which does not contain anything new and whose implementation is therefore left out here.
@code{int send_page(struct MHD_Connection *connection, const char* page)}
for this, which does not contain anything new and whose implementation is therefore
not discussed further in the tutorial.
@heading POST request
@@ -73,12 +74,13 @@ chunks, we had to expand the namestring dynamically as additional parts of it wi
came in. But in this example, the name is assumed to fit entirely inside one single packet.
@verbatim
int iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data, uint64_t off, size_t size)
static int
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data,
uint64_t off, size_t size)
{
struct connection_info_struct *con_info = (struct connection_info_struct*) coninfo_cls;
struct connection_info_struct *con_info = coninfo_cls;
if (0 == strcmp (key, "name"))
{
@@ -108,14 +110,13 @@ string. This cleanup function must take into account that it will also be called
requests other than @emph{POST} requests.
@verbatim
void request_completed (void *cls, struct MHD_Connection *connection, void **con_cls,
void request_completed (void *cls, struct MHD_Connection *connection,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info = (struct connection_info_struct*) *con_cls;
struct connection_info_struct *con_info = *con_cls;
if (NULL == con_info) return;
if (con_info->connectiontype == POST)
{
MHD_destroy_post_processor (con_info->postprocessor);
@@ -134,8 +135,9 @@ in the main function.
@verbatim
...
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
&answer_to_connection, NULL, MHD_OPTION_NOTIFY_COMPLETED,
request_completed, NULL, MHD_OPTION_END);
&answer_to_connection, NULL,
MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
MHD_OPTION_END);
...
@end verbatim
@noindent
@@ -144,13 +146,16 @@ daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
With all other functions prepared, we can now discuss the actual request handling.
On the first iteration for a new request, we start by allocating a new instance of a
@code{ConnectionInfoStruct} structure, which will store all necessary information for later
@code{struct connection_info_struct} structure, which will store all necessary information for later
iterations and other functions.
@verbatim
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
if(NULL == *con_cls)
{
@@ -167,15 +172,15 @@ of the request is stored for convenience.
@verbatim
if (0 == strcmp (method, "POST"))
{
con_info->postprocessor = MHD_create_post_processor (connection, POSTBUFFERSIZE,
iterate_post, (void*) con_info);
con_info->postprocessor
= MHD_create_post_processor (connection, POSTBUFFERSIZE,
iterate_post, (void*) con_info);
if (NULL == con_info->postprocessor)
{
free (con_info);
return MHD_NO;
}
con_info->connectiontype = POST;
}
else con_info->connectiontype = GET;
@@ -211,17 +216,19 @@ considered---all of it.
if (*upload_data_size != 0)
{
MHD_post_process(con_info->postprocessor, upload_data, *upload_data_size);
MHD_post_process (con_info->postprocessor, upload_data,
*upload_data_size);
*upload_data_size = 0;
return MHD_YES;
}
else if (NULL != con_info->answerstring) return send_page (connection, con_info->answerstring);
else if (NULL != con_info->answerstring)
return send_page (connection, con_info->answerstring);
}
@end verbatim
@noindent
If they are neither @emph{GET} nor @emph{POST} requests, the error page is returned finally.
Finally, if they are neither @emph{GET} nor @emph{POST} requests, the error page is returned.
@verbatim
return send_page(connection, errorpage);
}
+59 -43
View File
@@ -9,7 +9,7 @@ This will lead to an application capable of correctly serving different types of
When we responded with HTML page packed in the static string previously, the client had no choice
but guessing about how to handle the response, because the server hadn't told him.
but guessing about how to handle the response, because the server had not told him.
What if we had sent a picture or a sound file? Would the message have been understood
or merely been displayed as an endless stream of random characters in the browser?
This is what the mime content types are for. The header of the response is extended
@@ -23,47 +23,60 @@ Once again, we can base the new example on the @code{hellobrowser} program.
#define FILENAME "picture.png"
#define MIMETYPE "image/png"
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url,
const char *method, const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
unsigned char *buffer = NULL;
struct MHD_Response *response;
@end verbatim
@noindent
We want the program to load the graphics file into memory:
We want the program to open the file for reading and determine its size:
@verbatim
long size;
FILE *fp;
int ret = 0;
int fd;
int ret;
struct stat sbuf;
if (0 != strcmp(method, "GET")) return MHD_NO;
size = get_file_size (FILENAME);
if (size != 0)
if (0 != strcmp (method, "GET"))
return MHD_NO;
if ( (-1 == (fd = open (FILENAME, O_RDONLY))) ||
(0 != fstat (fd, &sbuf)) )
{
fp = fopen (FILENAME, "rb");
if (fp)
{
buffer = malloc (size);
if (buffer)
if (size == fread (buffer, 1, size, fp)) ret = 1;
fclose(fp);
}
/* error accessing file */
/* ... (see below) */
}
/* ... (see below) */
@end verbatim
@noindent
The @code{GetFileSize} function, which returns a size of zero if the file could not be opened or
found, is left out on this page for tidiness.
When dealing with files and allocating memory, there is a lot that could go wrong on the
When dealing with files, there is a lot that could go wrong on the
server side and if so, the client should be informed with @code{MHD_HTTP_INTERNAL_SERVER_ERROR}.
@verbatim
@verbatim
/* error accessing file */
if (fd != -1) close (fd);
const char *errorstr =
"<html><body>An internal server error has occured!\
</body></html>";
response =
MHD_create_response_from_data (strlen (errorstr),
(void *) errorstr,
MHD_NO, MHD_NO);
if (response)
{
ret =
MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
response);
MHD_destroy_response (response);
return MHD_YES;
}
else
return MHD_NO;
if (!ret)
{
const char *errorstr = "<html><body>An internal server error has occured!\
@@ -76,7 +89,9 @@ server side and if so, the client should be informed with @code{MHD_HTTP_INTERNA
if (response)
{
ret = MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
ret = MHD_queue_response (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
response);
MHD_destroy_response (response);
return MHD_YES;
@@ -90,19 +105,22 @@ Note that we nevertheless have to create a response object even for sending a si
Otherwise, the connection would just be closed without comment, leaving the client curious about
what has happened.
But in the case of success a response will be constructed that contains the buffer filled with the
file's content.
But in the case of success a response will be constructed directly from the file descriptor:
@verbatim
response = MHD_create_response_from_data (size, (void*)buffer, MHD_YES, MHD_NO);
/* error accessing file */
/* ... (see above) */
}
response =
MHD_create_response_from_fd (fd, sbuf.st_size);
MHD_add_response_header (response, "Content-Type", MIMETYPE);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
@end verbatim
@noindent
Contrary to the above case where a static string will be sent, this time we have to
keep track of the dynamically allocated buffer. As discussed in the @ref{Hello browser example},
the buffer cannot be safely freed as soon as the function call returns. Instead, we ask the function
to keep charge of freeing the buffer itself when it is not longer needed. Thus, no further @code{free}
command is invoked by us.
Note that the response object will take care of closing the file desciptor for us.
Up to this point, there was little new. The actual novelty is that we enhance the header with the
meta data about the content. Aware of the field's name we want to add, it is as easy as that:
@@ -135,17 +153,15 @@ to these custom header is up to the receiver. Likewise, the client is allowed to
headers to the server as well, opening up yet more possibilities how client and server could
communicate with each other.
The method of creating the response from one big chunk of data is only feasible for smaller files.
A public file server satisfying many request at the same time would be choking under these high
demands on memory very soon. Serving responses in smaller parts would be more adequate here and
will be a topic of a future chapter.
The method of creating the response from a file on disk only works for static content.
Serving dynamically created responses will be a topic of a future chapter.
@heading Exercises
@itemize @bullet
@item
Remember that the original program was written under a few assumptions---a small, static response
being one of them. In order to simulate a very large or hard to reach file that cannot be provided
Remember that the original program was written under a few assumptions---a static response
using a local file being one of them. In order to simulate a very large or hard to reach file that cannot be provided
instantly, postpone the queuing in the callback with the @code{sleep} function for 30 seconds
@emph{if} the file @code{/big.png} is requested (but deliver the same as above). A request for
@code{/picture.png} should provide just the same but without any artificial delays.
@@ -163,7 +179,7 @@ program's start time @code{t} and implement a response simulating a countdown th
@code{t+60}. Returning a message saying on which point the countdown is, the response should
ultimately be to reply "Done" if the program has been running long enough,
A non official, but widely understood, response header line is @code{Refresh: DELAY; url=URL} with
An unofficial, but widely understood, response header line is @code{Refresh: DELAY; url=URL} with
the uppercase words substituted to tell the client it should request the given resource after
the given delay again. Improve your program in that the browser (any modern browser should work)
automatically reconnects and asks for the status again every 5 seconds or so. The URL would have
+3 -3
View File
@@ -68,7 +68,8 @@ main ()
and then we point the @emph{MHD} daemon to it upon initalization.
@verbatim
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, PORT, NULL, NULL,
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL,
PORT, NULL, NULL,
&answer_to_connection, NULL,
MHD_OPTION_HTTPS_MEM_KEY, key_pem,
MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
@@ -125,6 +126,5 @@ hardcode certificates in embedded devices.
The cryptographic facilities consume memory space and computing time. For this reason, websites usually consists
both of uncritically @emph{HTTP} parts and secured @emph{HTTPS}.
@end itemize
+7 -5
View File
@@ -1,4 +1,6 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#include <time.h>
@@ -12,7 +14,7 @@
char *string_to_base64 (const char *message);
int
static int
ask_for_authentication (struct MHD_Connection *connection, const char *realm)
{
int ret;
@@ -46,7 +48,7 @@ ask_for_authentication (struct MHD_Connection *connection, const char *realm)
return ret;
}
int
static int
is_authenticated (struct MHD_Connection *connection,
const char *username, const char *password)
{
@@ -84,7 +86,7 @@ is_authenticated (struct MHD_Connection *connection,
}
int
static int
secret_page (struct MHD_Connection *connection)
{
int ret;
@@ -104,7 +106,7 @@ secret_page (struct MHD_Connection *connection)
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
+4 -2
View File
@@ -1,9 +1,11 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
+12 -13
View File
@@ -1,4 +1,6 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
@@ -8,7 +10,7 @@
#define GET 0
#define POST 1
static unsigned char nr_of_uploading_clients = 0;
static unsigned int nr_of_uploading_clients = 0;
struct connection_info_struct
{
@@ -21,7 +23,7 @@ struct connection_info_struct
const char *askpage = "<html><body>\n\
Upload a file, please!<br>\n\
There are %d clients uploading at the moment.<br>\n\
There are %u clients uploading at the moment.<br>\n\
<form action=\"/filepost\" method=\"post\" enctype=\"multipart/form-data\">\n\
<input name=\"file\" type=\"file\">\n\
<input type=\"submit\" value=\" Send \"></form>\n\
@@ -41,14 +43,13 @@ const char *fileexistspage =
"<html><body>This file already exists.</body></html>";
int
static int
send_page (struct MHD_Connection *connection, const char *page,
int status_code)
{
int ret;
struct MHD_Response *response;
response =
MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO,
MHD_YES);
@@ -62,15 +63,14 @@ send_page (struct MHD_Connection *connection, const char *page,
}
int
static int
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data, uint64_t off,
size_t size)
{
struct connection_info_struct *con_info = coninfo_cls;
FILE *fp;
struct connection_info_struct *con_info =
(struct connection_info_struct *) coninfo_cls;
con_info->answerstring = servererrorpage;
con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
@@ -105,12 +105,11 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
return MHD_YES;
}
void
static void
request_completed (void *cls, struct MHD_Connection *connection,
void **con_cls, enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info =
(struct connection_info_struct *) *con_cls;
struct connection_info_struct *con_info = *con_cls;
if (NULL == con_info)
return;
@@ -132,7 +131,7 @@ request_completed (void *cls, struct MHD_Connection *connection,
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
@@ -180,7 +179,7 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
if (0 == strcmp (method, "GET"))
{
int ret;
char buffer[1024] = { 0 };
char buffer[1024];
sprintf (buffer, askpage, nr_of_uploading_clients);
return send_page (connection, buffer, MHD_HTTP_OK);
+7 -5
View File
@@ -1,24 +1,26 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
int
static int
print_out_key (void *cls, enum MHD_ValueKind kind, const char *key,
const char *value)
{
printf ("%s = %s\n", key, value);
printf ("%s: %s\n", key, value);
return MHD_YES;
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
printf ("New request %s for %s using version %s\n", method, url, version);
printf ("New %s request for %s using version %s\n", method, url, version);
MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key,
NULL);
+15 -57
View File
@@ -1,4 +1,6 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#include <time.h>
@@ -6,73 +8,32 @@
#define FILENAME "picture.png"
#define MIMETYPE "image/png"
long
get_file_size (const char *filename)
{
FILE *fp;
fp = fopen (filename, "rb");
if (fp)
{
long size;
if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
size = 0;
fclose (fp);
return size;
}
else
return 0;
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
unsigned char *buffer = NULL;
struct MHD_Response *response;
long size;
FILE *fp;
int ret = 0;
int fd;
int ret;
struct stat sbuf;
if (0 != strcmp (method, "GET"))
return MHD_NO;
size = get_file_size (FILENAME);
if (size != 0)
{
fp = fopen (FILENAME, "rb");
if (fp)
{
buffer = malloc (size);
if (buffer)
if (size == fread (buffer, 1, size, fp))
ret = 1;
fclose (fp);
}
}
if (!ret)
if ( (-1 == (fd = open (FILENAME, O_RDONLY))) ||
(0 != fstat (fd, &sbuf)) )
{
/* error accessing file */
if (fd != -1) close (fd);
const char *errorstr =
"<html><body>An internal server error has occured!\
</body></html>";
if (buffer)
free (buffer);
response =
MHD_create_response_from_data (strlen (errorstr), (void *) errorstr,
MHD_NO, MHD_NO);
MHD_create_response_from_data (strlen (errorstr),
(void *) errorstr,
MHD_NO, MHD_NO);
if (response)
{
ret =
@@ -85,12 +46,9 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
else
return MHD_NO;
}
response =
MHD_create_response_from_data (size, (void *) buffer, MHD_YES, MHD_NO);
MHD_create_response_from_fd (fd, sbuf.st_size);
MHD_add_response_header (response, "Content-Type", MIMETYPE);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
+9 -12
View File
@@ -1,4 +1,6 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
@@ -30,7 +32,7 @@ const char *errorpage =
"<html><body>This doesn't seem to be right.</body></html>";
int
static int
send_page (struct MHD_Connection *connection, const char *page)
{
int ret;
@@ -50,15 +52,13 @@ send_page (struct MHD_Connection *connection, const char *page)
}
int
static int
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
const char *transfer_encoding, const char *data, uint64_t off,
size_t size)
{
struct connection_info_struct *con_info =
(struct connection_info_struct *) coninfo_cls;
struct connection_info_struct *con_info = coninfo_cls;
if (0 == strcmp (key, "name"))
{
@@ -81,13 +81,11 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
return MHD_YES;
}
void
static void
request_completed (void *cls, struct MHD_Connection *connection,
void **con_cls, enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info =
(struct connection_info_struct *) *con_cls;
struct connection_info_struct *con_info = *con_cls;
if (NULL == con_info)
return;
@@ -104,7 +102,7 @@ request_completed (void *cls, struct MHD_Connection *connection,
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
@@ -170,7 +168,6 @@ main ()
{
struct MHD_Daemon *daemon;
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
&answer_to_connection, NULL,
MHD_OPTION_NOTIFY_COMPLETED, request_completed,
+9 -7
View File
@@ -1,4 +1,6 @@
#include <platform.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#define PORT 8888
@@ -50,7 +52,7 @@ string_to_base64 (const char *message)
}
long
static long
get_file_size (const char *filename)
{
FILE *fp;
@@ -71,7 +73,7 @@ get_file_size (const char *filename)
return 0;
}
char *
static char *
load_file (const char *filename)
{
FILE *fp;
@@ -103,7 +105,7 @@ load_file (const char *filename)
return buffer;
}
int
static int
ask_for_authentication (struct MHD_Connection *connection, const char *realm)
{
int ret;
@@ -137,7 +139,7 @@ ask_for_authentication (struct MHD_Connection *connection, const char *realm)
return ret;
}
int
static int
is_authenticated (struct MHD_Connection *connection,
const char *username, const char *password)
{
@@ -176,7 +178,7 @@ is_authenticated (struct MHD_Connection *connection,
}
int
static int
secret_page (struct MHD_Connection *connection)
{
int ret;
@@ -196,7 +198,7 @@ secret_page (struct MHD_Connection *connection)
}
int
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
+6 -6
View File
@@ -3,10 +3,10 @@
GNU libmicrohttpd \- library for embedding HTTP servers
.SH "SYNOPSIS"
\fB#include <sys/types.h>
\fB#include <sys/select.h>
\fB#include <sys/socket.h>
\fB#include <microhttpd.h>
\fB#include <sys/types.h>
\fB#include <sys/select.h>
\fB#include <sys/socket.h>
\fB#include <microhttpd.h>
.SH "DESCRIPTION"
.P
@@ -31,10 +31,10 @@ libmicrohttpd.so
libmicrohttpd library
.SH "REPORTING BUGS"
Report bugs by using mantis <https://gnunet.org/mantis/>.
Report bugs by using mantis <https://gnunet.org/bugs/>.
.SH "AUTHORS"
GNU libmicrohttpd was originally designed by Christian Grothoff <christian@grothoff.org> and Chris GauthierDickey <chrisg@cs.du.edu>. The original implementation was done by Daniel Pittman <depittman@gmail.com> and Christian Grothoff. SSL/TLS support was added by Sagie Amir using code from gnutls. See the AUTHORS file in the distribution for a more detailed list of contributors.
GNU libmicrohttpd was originally designed by Christian Grothoff <christian@grothoff.org> and Chris GauthierDickey <chrisg@cs.du.edu>. The original implementation was done by Daniel Pittman <depittman@gmail.com> and Christian Grothoff. SSL/TLS support was added by Sagie Amir using code from GnuTLS. See the AUTHORS file in the distribution for a more detailed list of contributors.
.SH "AVAILABILITY"
You can obtain the latest version from http://www.gnu.org/software/libmicrohttpd/.
+41 -45
View File
@@ -2,8 +2,6 @@
@setfilename microhttpd.info
@include version.texi
@settitle The GNU libmicrohttpd Reference Manual
@c Unify some of the indices.
@c %**end of header
@copying
This manual documents GNU libmicrohttpd version @value{VERSION}, last
updated @value{UPDATED}. It is built upon the documentation in the
@@ -21,6 +19,7 @@ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
@end quotation
GNU libmicrohttpd is a GNU package.
@end copying
@dircategory GNU Libraries
@@ -31,7 +30,6 @@ Free Documentation License".
@c
@c Titlepage
@c
@setchapternewpage odd
@titlepage
@title The GNU libmicrohttpd Reference Manual
@subtitle Version @value{VERSION}
@@ -46,7 +44,6 @@ Free Documentation License".
@summarycontents
@contents
@page
@macro gnu{}
@@ -111,8 +108,6 @@ Free Documentation License".
@insertcopying
@end ifnottex
GNU libmicrohttpd is a GNU package.
@menu
* microhttpd-intro:: Introduction.
* microhttpd-const:: Constants.
@@ -188,6 +183,44 @@ Additionally, clients can specify resource limits on the overall
number of connections, number of connections per IP address and memory
used per connection to avoid resource exhaustion.
@section SIGPIPE
@cindex signals
@mhd{} does not install a signal handler for SIGPIPE. On platforms
where this is possible (such as GNU/Linux), it disables SIGPIPE for
its I/O operations (by passing MSG_NOSIGNAL). On other platforms,
SIGPIPE signals may be generated from network operations by
@mhd{} and will cause the process to die unless the developer
explicitly installs a signal handler for SIGPIPE.
Hence portable code using MHD must install a SIGPIPE handler or
explicitly block the SIGPIPE signal. MHD does not do so in order
to avoid messing with other parts of the application that may
need to handle SIGPIPE in a particular way. You can make your application handle SIGPIPE by calling the following function in @code{main}:
@verbatim
static void
catcher (int sig)
{
}
static void
ignore_sigpipe ()
{
struct sigaction oldsig;
struct sigaction sig;
sig.sa_handler = &catcher;
sigemptyset (&sig.sa_mask);
#ifdef SA_INTERRUPT
sig.sa_flags = SA_INTERRUPT; /* SunOS */
#else
sig.sa_flags = SA_RESTART;
#endif
if (0 != sigaction (SIGPIPE, &sig, &oldsig))
fprintf (stderr,
"Failed to install SIGPIPE handler: %s\n", strerror (errno));
}
@end verbatim
@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -357,12 +390,12 @@ HTTPS daemon. This option should be followed by an
"const char*" argument.
This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'.
@item MHD_OPTION_CRED_TYPE
@item MHD_OPTION_HTTPS_CRED_TYPE
@cindex SSL
@cindex TLS
Daemon credentials type. Either certificate or anonymous,
this option should be followed by one of the values listed in
"enum MHD_GNUTLS_CredentialsType".
"enum gnutls_credentials_type_t".
@item MHD_OPTION_HTTPS_PRIORITIES
@cindex SSL
@@ -503,43 +536,6 @@ We had to close the session since @mhd{} was being shut down.
@end table
@end deftp
@deftp {Enumeration} MHD_GNUTLS_Protocol
SSL/TLS Protocol types. Note that not all listed algorithms are
necessarily supported by all builds of MHD.
@table @code
@item MHD_GNUTLS_PROTOCOL_END
@item MHD_GNUTLS_PROTOCOL_SSL3
@item MHD_GNUTLS_PROTOCOL_TLS1_0
@item MHD_GNUTLS_PROTOCOL_TLS1_1
@item MHD_GNUTLS_PROTOCOL_TLS1_2
@item MHD_GNUTLS_PROTOCOL_UNKNOWN
@end table
@end deftp
@deftp {Enumeration} MHD_GNUTLS_CipherAlgorithm
List of symmetric ciphers.
Note that not all listed algorithms are necessarily supported by
all builds of MHD.
@table @code
@item MHD_GNUTLS_CIPHER_UNKNOWN
@item MHD_GNUTLS_CIPHER_NULL
@item MHD_GNUTLS_CIPHER_ARCFOUR_128
@item MHD_GNUTLS_CIPHER_3DES_CBC
@item MHD_GNUTLS_CIPHER_AES_128_CBC
@item MHD_GNUTLS_CIPHER_AES_256_CBC
@end table
@end deftp
@deftp {Enumeration} MHD_ConnectionInfoType
+23 -12
View File
@@ -1,33 +1,44 @@
\input texinfo @c -*-texinfo-*-
@finalout
@setfilename microhttpd-tutorial.info
@include version.texi
@settitle A tutorial for GNU libmicrohttpd
@afourpaper
@set VERSION 0.4.0
@dircategory GNU Libraries
@direntry
* libmicrohttpdtutorial: (microhttpd). A tutorial for GNU libmicrohttpd.
@end direntry
@titlepage
@title A Tutorial for GNU libmicrohttpd
@subtitle written for version @value{VERSION}
@author Sebastian Gerhardt (@email{sebgerhardt@@gmx.net})
@page
@vskip 0pt plus 1filll
@end titlepage
@copying
This tutorial documents GNU libmicrohttpd version @value{VERSION}, last
updated @value{UPDATED}.
@verbatim
Copyright (c) 2008 Sebastian Gerhardt.
Copyright (c) 2010 Christian Grothoff.
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
@end verbatim
@end quotation
@end copying
@titlepage
@title A Tutorial for GNU libmicrohttpd
@subtitle Version @value{VERSION}
@subtitle @value{UPDATED}
@author Sebastian Gerhardt (@email{sebgerhardt@@gmx.net})
@author Christian Grothoff (@email{christian@@grothoff.org})
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@contents
+1
View File
@@ -10,6 +10,7 @@ MHD_lookup_connection_value
MHD_queue_response
MHD_create_response_from_callback
MHD_create_response_from_data
MHD_create_response_from_fd
MHD_destroy_response
MHD_add_response_header
MHD_del_response_header
+5 -2
View File
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
(C) 2007, 2008 Daniel Pittman and Christian Grothoff
(C) 2007, 2008, 2009, 2010 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -336,7 +336,10 @@ try_ready_normal_body (struct MHD_Connection *connection)
#if LINUX
if ( (response->fd != -1) &&
(0 == (connection->daemon->options & MHD_USE_SSL)) )
return MHD_YES; /* will use sendfile */
{
/* will use sendfile, no need to bother response crc */
return MHD_YES;
}
#endif
ret = response->crc (response->crc_cls,
connection->response_write_position,
+1 -1
View File
@@ -198,7 +198,7 @@ MHD_tls_connection_handle_write (struct MHD_Connection *connection)
* the processing of this secure connection.
*/
void
MHD_set_https_calbacks (struct MHD_Connection *connection)
MHD_set_https_callbacks (struct MHD_Connection *connection)
{
connection->read_handler = &MHD_tls_connection_handle_read;
connection->write_handler = &MHD_tls_connection_handle_write;
+1 -1
View File
@@ -29,7 +29,7 @@
#include "internal.h"
#if HTTPS_SUPPORT
void MHD_set_https_calbacks (struct MHD_Connection *connection);
void MHD_set_https_callbacks (struct MHD_Connection *connection);
#endif
#endif
+20 -10
View File
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
(C) 2007, 2008, 2009 Daniel Pittman and Christian Grothoff
(C) 2007, 2008, 2009, 2010 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -387,8 +387,8 @@ MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
cert.size = strlen (daemon->https_mem_cert);
return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
&cert, &key,
GNUTLS_X509_FMT_PEM);
&cert, &key,
GNUTLS_X509_FMT_PEM);
}
#if HAVE_MESSAGES
MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
@@ -625,21 +625,28 @@ send_param_adapter (struct MHD_Connection *connection,
#if LINUX
int fd;
off_t offset;
int ret;
#endif
if (connection->socket_fd == -1)
return -1;
if (0 != (connection->daemon->options & MHD_USE_SSL))
return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
#if LINUX
if ( (NULL != connection->response) &&
if ( (connection->write_buffer_append_offset ==
connection->write_buffer_send_offset) &&
(NULL != connection->response) &&
(-1 != (fd = connection->response->fd)) )
{
/* can use sendfile */
offset = (off_t) connection->response_write_position;
return sendfile (connection->socket_fd,
fd,
&offset,
i);
ret = sendfile (connection->socket_fd,
fd,
&offset,
connection->response->total_size - offset);
if ( (ret == -1) &&
(errno == EINTR) )
return 0;
return ret;
}
#endif
return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
@@ -819,7 +826,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
connection->recv_cls = &recv_tls_adapter;
connection->send_cls = &send_tls_adapter;
connection->state = MHD_TLS_CONNECTION_INIT;
MHD_set_https_calbacks (connection);
MHD_set_https_callbacks (connection);
gnutls_init (&connection->tls_session, GNUTLS_SERVER);
gnutls_priority_set (connection->tls_session,
daemon->priority_cache);
@@ -1664,7 +1671,10 @@ MHD_start_daemon_va (unsigned int options,
return NULL;
}
}
else
{
socket_fd = retVal->socket_fd;
}
#ifndef WINDOWS
if ( (socket_fd >= FD_SETSIZE) &&
(0 == (options & MHD_USE_POLL)) )
+17 -17
View File
@@ -1,21 +1,21 @@
/*
This file is part of libmicrohttpd
(C) 2007 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
This file is part of libmicrohttpd
(C) 2007, 2008, 2009, 2010 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file internal.h
+13 -9
View File
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
(C) 2007, 2009 Daniel Pittman and Christian Grothoff
(C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -210,7 +210,7 @@ MHD_create_response_from_callback (uint64_t size,
* Given a file descriptor, read data from the file
* to generate the response.
*
* @param cls pointer to the file descriptor
* @param cls pointer to the response
* @param pos offset in the file to access
* @param buf where to write the data
* @param max number of bytes to write at most
@@ -219,10 +219,14 @@ MHD_create_response_from_callback (uint64_t size,
static int
file_reader (void *cls, uint64_t pos, char *buf, int max)
{
int *fd = cls;
struct MHD_Response *response = cls;
int ret;
(void) lseek (*fd, pos, SEEK_SET);
return read (*fd, buf, max);
pthread_mutex_lock (&response->mutex);
(void) lseek (response->fd, pos, SEEK_SET);
ret = read (response->fd, buf, max);
pthread_mutex_unlock (&response->mutex);
return ret;
}
@@ -235,9 +239,9 @@ file_reader (void *cls, uint64_t pos, char *buf, int max)
static void
free_callback (void *cls)
{
int *fd = cls;
close (*fd);
*fd = -1;
struct MHD_Response *response = cls;
(void) close (response->fd);
response->fd = -1;
}
@@ -262,7 +266,7 @@ struct MHD_Response *MHD_create_response_from_fd (size_t size,
if (ret == NULL)
return NULL;
ret->fd = fd;
ret->crc_cls = &ret->fd;
ret->crc_cls = ret;
return ret;
}
+1 -1
View File
@@ -81,7 +81,7 @@ extern "C"
/**
* Current version of the library.
*/
#define MHD_VERSION 0x00040600
#define MHD_VERSION 0x00090000
/**
* MHD-internal return code for "YES".
+14
View File
@@ -16,6 +16,7 @@ $(LIBCURL_CPPFLAGS)
check_PROGRAMS = \
daemontest_get \
daemontest_get_sendfile \
daemontest_post \
daemontest_postform \
daemontest_post_loop \
@@ -25,6 +26,7 @@ check_PROGRAMS = \
daemontest_parse_cookies \
daemontest_large_put \
daemontest_get11 \
daemontest_get_sendfile11 \
daemontest_post11 \
daemontest_postform11 \
daemontest_post_loop11 \
@@ -57,6 +59,12 @@ daemontest_get_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
daemontest_get_sendfile_SOURCES = \
daemontest_get_sendfile.c
daemontest_get_sendfile_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
daemontest_get_chunked_SOURCES = \
daemontest_get_chunked.c
daemontest_get_chunked_LDADD = \
@@ -117,6 +125,12 @@ daemontest_get11_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
daemontest_get_sendfile11_SOURCES = \
daemontest_get_sendfile.c
daemontest_get_sendfile11_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
daemontest_post11_SOURCES = \
daemontest_post.c
daemontest_post11_LDADD = \
+463
View File
@@ -0,0 +1,463 @@
/* DO NOT CHANGE THIS LINE */
/*
This file is part of libmicrohttpd
(C) 2007, 2009 Christian Grothoff
libmicrohttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file daemontest_get_sendfile.c
* @brief Testcase for libmicrohttpd response from FD
* @author Christian Grothoff
*/
#include "MHD_config.h"
#include "platform.h"
#include <curl/curl.h>
#include <microhttpd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#ifndef WINDOWS
#include <unistd.h>
#endif
#define TESTSTR "/* DO NOT CHANGE THIS LINE */"
static int oneone;
struct CBC
{
char *buf;
size_t pos;
size_t size;
};
static size_t
copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
{
struct CBC *cbc = ctx;
if (cbc->pos + size * nmemb > cbc->size)
return 0; /* overflow */
memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
cbc->pos += size * nmemb;
return size * nmemb;
}
static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data, size_t *upload_data_size,
void **unused)
{
static int ptr;
const char *me = cls;
struct MHD_Response *response;
int ret;
int fd;
if (0 != strcmp (me, method))
return MHD_NO; /* unexpected method */
if (&ptr != *unused)
{
*unused = &ptr;
return MHD_YES;
}
*unused = NULL;
fd = open ("daemontest_get_sendfile.c", O_RDONLY);
if (fd == -1)
abort ();
response = MHD_create_response_from_fd (strlen (TESTSTR), fd);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
if (ret == MHD_NO)
abort ();
return ret;
}
static int
testInternalGet ()
{
struct MHD_Daemon *d;
CURL *c;
char buf[2048];
struct CBC cbc;
CURLcode errornum;
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
if (d == NULL)
return 1;
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/");
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
if (oneone)
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
else
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
/* NOTE: use of CONNECTTIMEOUT without also
setting NOSIGNAL results in really weird
crashes on my system!*/
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
if (CURLE_OK != (errornum = curl_easy_perform (c)))
{
fprintf (stderr,
"curl_easy_perform failed: `%s'\n",
curl_easy_strerror (errornum));
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 2;
}
curl_easy_cleanup (c);
MHD_stop_daemon (d);
if (cbc.pos != strlen (TESTSTR))
return 4;
if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
return 8;
return 0;
}
static int
testMultithreadedGet ()
{
struct MHD_Daemon *d;
CURL *c;
char buf[2048];
struct CBC cbc;
CURLcode errornum;
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
if (d == NULL)
return 16;
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/");
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
if (oneone)
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
else
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
/* NOTE: use of CONNECTTIMEOUT without also
setting NOSIGNAL results in really weird
crashes on my system! */
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
if (CURLE_OK != (errornum = curl_easy_perform (c)))
{
fprintf (stderr,
"curl_easy_perform failed: `%s'\n",
curl_easy_strerror (errornum));
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 32;
}
curl_easy_cleanup (c);
MHD_stop_daemon (d);
if (cbc.pos != strlen (TESTSTR))
return 64;
if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
return 128;
return 0;
}
static int
testMultithreadedPoolGet ()
{
struct MHD_Daemon *d;
CURL *c;
char buf[2048];
struct CBC cbc;
CURLcode errornum;
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
1081, NULL, NULL, &ahc_echo, "GET",
MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
if (d == NULL)
return 16;
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/");
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
if (oneone)
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
else
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
/* NOTE: use of CONNECTTIMEOUT without also
setting NOSIGNAL results in really weird
crashes on my system!*/
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
if (CURLE_OK != (errornum = curl_easy_perform (c)))
{
fprintf (stderr,
"curl_easy_perform failed: `%s'\n",
curl_easy_strerror (errornum));
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 32;
}
curl_easy_cleanup (c);
MHD_stop_daemon (d);
if (cbc.pos != strlen (TESTSTR))
return 64;
if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
return 128;
return 0;
}
static int
testExternalGet ()
{
struct MHD_Daemon *d;
CURL *c;
char buf[2048];
struct CBC cbc;
CURLM *multi;
CURLMcode mret;
fd_set rs;
fd_set ws;
fd_set es;
int max;
int running;
struct CURLMsg *msg;
time_t start;
struct timeval tv;
multi = NULL;
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_DEBUG,
1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
if (d == NULL)
return 256;
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/");
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
if (oneone)
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
else
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
/* NOTE: use of CONNECTTIMEOUT without also
setting NOSIGNAL results in really weird
crashes on my system! */
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
multi = curl_multi_init ();
if (multi == NULL)
{
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 512;
}
mret = curl_multi_add_handle (multi, c);
if (mret != CURLM_OK)
{
curl_multi_cleanup (multi);
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 1024;
}
start = time (NULL);
while ((time (NULL) - start < 5) && (multi != NULL))
{
max = 0;
FD_ZERO (&rs);
FD_ZERO (&ws);
FD_ZERO (&es);
curl_multi_perform (multi, &running);
mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
if (mret != CURLM_OK)
{
curl_multi_remove_handle (multi, c);
curl_multi_cleanup (multi);
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 2048;
}
if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
{
curl_multi_remove_handle (multi, c);
curl_multi_cleanup (multi);
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 4096;
}
tv.tv_sec = 0;
tv.tv_usec = 1000;
select (max + 1, &rs, &ws, &es, &tv);
curl_multi_perform (multi, &running);
if (running == 0)
{
msg = curl_multi_info_read (multi, &running);
if (msg == NULL)
break;
if (msg->msg == CURLMSG_DONE)
{
if (msg->data.result != CURLE_OK)
printf ("%s failed at %s:%d: `%s'\n",
"curl_multi_perform",
__FILE__,
__LINE__, curl_easy_strerror (msg->data.result));
curl_multi_remove_handle (multi, c);
curl_multi_cleanup (multi);
curl_easy_cleanup (c);
c = NULL;
multi = NULL;
}
}
MHD_run (d);
}
if (multi != NULL)
{
curl_multi_remove_handle (multi, c);
curl_easy_cleanup (c);
curl_multi_cleanup (multi);
}
MHD_stop_daemon (d);
if (cbc.pos != strlen (TESTSTR))
return 8192;
if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
return 16384;
return 0;
}
static int
testUnknownPortGet ()
{
struct MHD_Daemon *d;
const union MHD_DaemonInfo *di;
CURL *c;
char buf[2048];
struct CBC cbc;
CURLcode errornum;
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
1, NULL, NULL, &ahc_echo, "GET",
MHD_OPTION_SOCK_ADDR, &addr,
MHD_OPTION_END);
if (d == NULL)
return 32768;
di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
if (di == NULL)
return 65536;
if (0 != getsockname(di->listen_fd, &addr, &addr_len))
return 131072;
if (addr.sin_family != AF_INET)
return 26214;
snprintf(buf, sizeof(buf), "http://localhost:%hu/",
ntohs(addr.sin_port));
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, buf);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
if (oneone)
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
else
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
/* NOTE: use of CONNECTTIMEOUT without also
setting NOSIGNAL results in really weird
crashes on my system! */
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
if (CURLE_OK != (errornum = curl_easy_perform (c)))
{
fprintf (stderr,
"curl_easy_perform failed: `%s'\n",
curl_easy_strerror (errornum));
curl_easy_cleanup (c);
MHD_stop_daemon (d);
return 524288;
}
curl_easy_cleanup (c);
MHD_stop_daemon (d);
if (cbc.pos != strlen (TESTSTR))
return 1048576;
if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
return 2097152;
return 0;
}
int
main (int argc, char *const *argv)
{
unsigned int errorCount = 0;
oneone = NULL != strstr (argv[0], "11");
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
return 2;
errorCount += testInternalGet ();
errorCount += testMultithreadedGet ();
errorCount += testMultithreadedPoolGet ();
errorCount += testExternalGet ();
errorCount += testUnknownPortGet ();
if (errorCount != 0)
fprintf (stderr, "Error (code: %u)\n", errorCount);
curl_global_cleanup ();
return errorCount != 0; /* 0 == pass */
}
+18 -18
View File
@@ -1,22 +1,22 @@
/*
This file is part of libmicrohttpd
(C) 2007 Christian Grothoff
libmicrohttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
This file is part of libmicrohttpd
(C) 2007 Christian Grothoff
libmicrohttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file mhds_get_test.c
+18 -26
View File
@@ -1,22 +1,22 @@
/*
This file is part of libmicrohttpd
(C) 2007 Christian Grothoff
libmicrohttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
This file is part of libmicrohttpd
(C) 2007, 2010 Christian Grothoff
libmicrohttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file tls_daemon_options_test.c
@@ -103,7 +103,6 @@ main (int argc, char *const *argv)
fprintf (stderr, "Error: %s\n", strerror (errno));
return -1;
}
#if 0
errorCount +=
test_wrap ("TLS1.0-AES-SHA1",
&test_https_transfer, test_fd, daemon_flags,
@@ -113,8 +112,6 @@ main (int argc, char *const *argv)
MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
MHD_OPTION_HTTPS_PRIORITIES, "NONE:+VERS-TLS1.0:+AES-128-CBC:+SHA1:+RSA:+COMP-NULL",
MHD_OPTION_END);
#endif
#if 0
errorCount +=
test_wrap ("TLS1.0-AES-SHA1",
&test_https_transfer, test_fd, daemon_flags,
@@ -134,8 +131,6 @@ main (int argc, char *const *argv)
MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
MHD_OPTION_HTTPS_PRIORITIES, "NONE:+VERS-SSL3.0:+AES-128-CBC:+SHA1:+RSA:+COMP-NULL",
MHD_OPTION_END);
#endif
#if 0
/* manual inspection of the handshake suggests that CURL will
request TLSv1, we send back "SSL3" and CURL takes it *despite*
@@ -152,7 +147,6 @@ main (int argc, char *const *argv)
MHD_OPTION_CIPHER_ALGORITHM, "SSL3", MHD_OPTION_END);
#endif
#if 1
errorCount +=
test_wrap ("TLS1.0 vs SSL3",
&test_unmatching_ssl_version, test_fd, daemon_flags,
@@ -162,8 +156,6 @@ main (int argc, char *const *argv)
MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
MHD_OPTION_HTTPS_PRIORITIES, "NONE:+VERS-TLS1.0:+AES-256-CBC:+SHA1:+RSA:+COMP-NULL",
MHD_OPTION_END);
#endif
curl_global_cleanup ();
fclose (test_fd);
remove (TEST_FILE_NAME);
+1 -1
View File
@@ -240,7 +240,7 @@
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.4.2"
#define VERSION "0.9.0"
/* This is a Windows system */
/* #undef WINDOWS */