aboutsummaryrefslogtreecommitdiff
path: root/lib/libmicrohttpd/doc/chapters/largerpost.inc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libmicrohttpd/doc/chapters/largerpost.inc')
-rw-r--r--lib/libmicrohttpd/doc/chapters/largerpost.inc299
1 files changed, 0 insertions, 299 deletions
diff --git a/lib/libmicrohttpd/doc/chapters/largerpost.inc b/lib/libmicrohttpd/doc/chapters/largerpost.inc
deleted file mode 100644
index 2cf8c3c030..0000000000
--- a/lib/libmicrohttpd/doc/chapters/largerpost.inc
+++ /dev/null
@@ -1,299 +0,0 @@
-The previous chapter introduced a way to upload data to the server, but the developed example program
-has some shortcomings, such as not being able to handle larger chunks of data. In this chapter, we
-are going to discuss a more advanced server program that allows clients to upload a file in order to
-have it stored on the server's filesystem. The server shall also watch and limit the number of
-clients concurrently uploading, responding with a proper busy message if necessary.
-
-
-@heading Prepared answers
-We choose to operate the server with the @code{SELECT_INTERNALLY} method. This makes it easier to
-synchronize the global states at the cost of possible delays for other connections if the processing
-of a request is too slow. One of these variables that needs to be shared for all connections is the
-total number of clients that are uploading.
-
-@verbatim
-#define MAXCLIENTS 2
-static unsigned char 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>";
-@end verbatim
-@noindent
-
-Otherwise, the server will send a @emph{form} that informs the user of the current number of uploading clients,
-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\
- <input name=\"file\" type=\"file\">\n\
- <input type=\"submit\" value=\" Send \"></form>\n\
- </body></html>";
-@end verbatim
-@noindent
-
-If the upload has succeeded, the server will respond with a message saying so.
-@verbatim
-const char* completepage = "<html><body>The upload has been completed.</body></html>";
-@end verbatim
-@noindent
-
-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>";
-@end verbatim
-@noindent
-
-It would be tolerable to send all these responses undifferentiated with a @code{200 HTTP_OK}
-status code but in order to improve the @code{HTTP} conformance of our server a bit, we extend the
-@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)
-{
- int ret;
- struct MHD_Response *response;
-
-
- 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);
- MHD_destroy_response (response);
-
- return ret;
-}
-@end verbatim
-@noindent
-
-Note how we ask @emph{MHD} to make its own copy of the message data. The reason behind this will
-become clear later.
-
-
-@heading Connection cycle
-The decision whether the server is busy or not is made right at the beginning of the connection. To
-do that at this stage is especially important for @emph{POST} requests because if no response is
-queued at this point, and @code{MHD_YES} returned, @emph{MHD} will not sent any queued messages until
-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)
-{
- if (NULL == *con_cls)
- {
- struct connection_info_struct *con_info;
-
- if (nr_of_uploading_clients >= MAXCLIENTS)
- return send_page(connection, busypage, MHD_HTTP_SERVICE_UNAVAILABLE);
-@end verbatim
-@noindent
-
-If the server is not busy, the @code{connection_info} structure is initialized as usual, with
-the addition of a filepointer for each connection.
-
-@verbatim
- con_info = malloc (sizeof (struct connection_info_struct));
- if (NULL == con_info) return MHD_NO;
- con_info->fp = 0;
-
- if (0 == strcmp (method, "POST"))
- {
- ...
- }
- else con_info->connectiontype = GET;
-
- *con_cls = (void*) con_info;
-
- return MHD_YES;
- }
-@end verbatim
-@noindent
-
-For @emph{POST} requests, the postprocessor is created and we register a new uploading client. From
-this point on, there are many possible places for errors to occur that make it necessary to interrupt
-the uploading process. We need a means of having the proper response message ready at all times.
-Therefore, the @code{connection_info} structure is extended to hold the most current response
-message so that whenever a response is sent, the client will get the most informative message. Here,
-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);
-
- if (NULL == con_info->postprocessor)
- {
- free (con_info);
- return MHD_NO;
- }
-
- nr_of_uploading_clients++;
-
- con_info->connectiontype = POST;
- con_info->answercode = MHD_HTTP_OK;
- con_info->answerstring = completepage;
- }
- else con_info->connectiontype = GET;
-@end verbatim
-@noindent
-
-If the connection handler is called for the second time, @emph{GET} requests will be answered with
-the @emph{form}. We can keep the buffer under function scope, because we asked @emph{MHD} to make its
-own copy of it for as long as it is needed.
-@verbatim
- if (0 == strcmp (method, "GET"))
- {
- int ret;
- char buffer[1024] = {0};
-
- sprintf (buffer, askpage, nr_of_uploading_clients);
- return send_page (connection, buffer, MHD_HTTP_OK);
- }
-@end verbatim
-@noindent
-
-
-The rest of the @code{answer_to_connection} function is very similar to the @code{simplepost.c}
-example, except the more flexible content of the responses. The @emph{POST} data is processed until
-there is none left and the execution falls through to return an error page if the connection
-constituted no expected request method.
-@verbatim
- if (0 == strcmp (method, "POST"))
- {
- struct connection_info_struct *con_info = *con_cls;
-
- if (0 != *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);
- }
-
- return send_page(connection, errorpage, MHD_HTTP_BAD_REQUEST);
-}
-@end verbatim
-@noindent
-
-
-@heading Storing to data
-Unlike the @code{simplepost.c} example, here it is to be expected that post iterator will be called
-several times now. This means that for any given connection (there might be several concurrent of them)
-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)
-{
- struct connection_info_struct *con_info = (struct connection_info_struct*) coninfo_cls;
-@end verbatim
-@noindent
-
-Because the following actions depend heavily on correct file processing, which might be error prone,
-we default to reporting internal errors in case anything will go wrong.
-
-@verbatim
-con_info->answerstring = servererrorpage;
-con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
-@end verbatim
-@noindent
-
-In the "askpage" @emph{form}, we told the client to label its post data with the "file" key. Anything else
-would be an error.
-
-@verbatim
- if (0 != strcmp (key, "file")) return MHD_NO;
-@end verbatim
-@noindent
-
-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.
-@verbatim
- if (!con_info->fp)
- {
- if (NULL != (fp = fopen (filename, "rb")) )
- {
- fclose (fp);
- con_info->answerstring = fileexistspage;
- con_info->answercode = MHD_HTTP_FORBIDDEN;
- return MHD_NO;
- }
-
- con_info->fp = fopen (filename, "ab");
- if (!con_info->fp) return MHD_NO;
- }
-@end verbatim
-@noindent
-
-
-Occasionally, the iterator function will be called even when there are 0 new bytes to process. The
-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;
- }
-@end verbatim
-@noindent
-
-If this point has been reached, everything worked well for this iteration and the response can
-be set to success again. If the upload has finished, this iterator function will not be called again.
-@verbatim
- con_info->answerstring = completepage;
- con_info->answercode = MHD_HTTP_OK;
-
- return MHD_YES;
-}
-@end verbatim
-@noindent
-
-
-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,
- enum MHD_RequestTerminationCode toe)
-{
- struct connection_info_struct *con_info = (struct connection_info_struct*) *con_cls;
-
- if (NULL == con_info) return;
-
- if (con_info->connectiontype == POST)
- {
- if (NULL != con_info->postprocessor)
- {
- MHD_destroy_post_processor (con_info->postprocessor);
- nr_of_uploading_clients--;
- }
-
- if (con_info->fp) fclose (con_info->fp);
- }
-
- free (con_info);
- *con_cls = NULL;
-}
-@end verbatim
-@noindent
-
-
-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.