mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
ready for 0.9.0
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 "../".
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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 = \
|
||||
|
||||
@@ -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, ©Buffer);
|
||||
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, ©Buffer);
|
||||
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, ©Buffer);
|
||||
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, ©Buffer);
|
||||
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, ©Buffer);
|
||||
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 */
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user