1/* Feel free to use this example code in any way 2 you see fit (Public Domain) */ 3 4#include <sys/types.h> 5#ifndef _WIN32 6#include <sys/select.h> 7#include <sys/socket.h> 8#else 9#include <winsock2.h> 10#endif 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <microhttpd.h> 15 16#define PORT 8888 17#define POSTBUFFERSIZE 512 18#define MAXCLIENTS 2 19 20#define GET 0 21#define POST 1 22 23static unsigned int nr_of_uploading_clients = 0; 24 25struct connection_info_struct 26{ 27 int connectiontype; 28 struct MHD_PostProcessor *postprocessor; 29 FILE *fp; 30 const char *answerstring; 31 int answercode; 32}; 33 34const char *askpage = "<html><body>\n\ 35 Upload a file, please!<br>\n\ 36 There are %u clients uploading at the moment.<br>\n\ 37 <form action=\"/filepost\" method=\"post\" enctype=\"multipart/form-data\">\n\ 38 <input name=\"file\" type=\"file\">\n\ 39 <input type=\"submit\" value=\" Send \"></form>\n\ 40 </body></html>"; 41 42const char *busypage = 43 "<html><body>This server is busy, please try again later.</body></html>"; 44 45const char *completepage = 46 "<html><body>The upload has been completed.</body></html>"; 47 48const char *errorpage = 49 "<html><body>This doesn't seem to be right.</body></html>"; 50const char *servererrorpage = 51 "<html><body>An internal server error has occured.</body></html>"; 52const char *fileexistspage = 53 "<html><body>This file already exists.</body></html>"; 54 55 56static int 57send_page (struct MHD_Connection *connection, const char *page, 58 int status_code) 59{ 60 int ret; 61 struct MHD_Response *response; 62 63 response = 64 MHD_create_response_from_buffer (strlen (page), (void *) page, 65 MHD_RESPMEM_MUST_COPY); 66 if (!response) 67 return MHD_NO; 68 MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html"); 69 ret = MHD_queue_response (connection, status_code, response); 70 MHD_destroy_response (response); 71 72 return ret; 73} 74 75 76static int 77iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key, 78 const char *filename, const char *content_type, 79 const char *transfer_encoding, const char *data, uint64_t off, 80 size_t size) 81{ 82 struct connection_info_struct *con_info = coninfo_cls; 83 FILE *fp; 84 85 con_info->answerstring = servererrorpage; 86 con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR; 87 88 if (0 != strcmp (key, "file")) 89 return MHD_NO; 90 91 if (!con_info->fp) 92 { 93 if (NULL != (fp = fopen (filename, "rb"))) 94 { 95 fclose (fp); 96 con_info->answerstring = fileexistspage; 97 con_info->answercode = MHD_HTTP_FORBIDDEN; 98 return MHD_NO; 99 } 100 101 con_info->fp = fopen (filename, "ab"); 102 if (!con_info->fp) 103 return MHD_NO; 104 } 105 106 if (size > 0) 107 { 108 if (!fwrite (data, size, sizeof (char), con_info->fp)) 109 return MHD_NO; 110 } 111 112 con_info->answerstring = completepage; 113 con_info->answercode = MHD_HTTP_OK; 114 115 return MHD_YES; 116} 117 118 119static void 120request_completed (void *cls, struct MHD_Connection *connection, 121 void **con_cls, enum MHD_RequestTerminationCode toe) 122{ 123 struct connection_info_struct *con_info = *con_cls; 124 125 if (NULL == con_info) 126 return; 127 128 if (con_info->connectiontype == POST) 129 { 130 if (NULL != con_info->postprocessor) 131 { 132 MHD_destroy_post_processor (con_info->postprocessor); 133 nr_of_uploading_clients--; 134 } 135 136 if (con_info->fp) 137 fclose (con_info->fp); 138 } 139 140 free (con_info); 141 *con_cls = NULL; 142} 143 144 145static int 146answer_to_connection (void *cls, struct MHD_Connection *connection, 147 const char *url, const char *method, 148 const char *version, const char *upload_data, 149 size_t *upload_data_size, void **con_cls) 150{ 151 if (NULL == *con_cls) 152 { 153 struct connection_info_struct *con_info; 154 155 if (nr_of_uploading_clients >= MAXCLIENTS) 156 return send_page (connection, busypage, MHD_HTTP_SERVICE_UNAVAILABLE); 157 158 con_info = malloc (sizeof (struct connection_info_struct)); 159 if (NULL == con_info) 160 return MHD_NO; 161 162 con_info->fp = NULL; 163 164 if (0 == strcmp (method, "POST")) 165 { 166 con_info->postprocessor = 167 MHD_create_post_processor (connection, POSTBUFFERSIZE, 168 iterate_post, (void *) con_info); 169 170 if (NULL == con_info->postprocessor) 171 { 172 free (con_info); 173 return MHD_NO; 174 } 175 176 nr_of_uploading_clients++; 177 178 con_info->connectiontype = POST; 179 con_info->answercode = MHD_HTTP_OK; 180 con_info->answerstring = completepage; 181 } 182 else 183 con_info->connectiontype = GET; 184 185 *con_cls = (void *) con_info; 186 187 return MHD_YES; 188 } 189 190 if (0 == strcmp (method, "GET")) 191 { 192 char buffer[1024]; 193 194 snprintf (buffer, sizeof (buffer), askpage, nr_of_uploading_clients); 195 return send_page (connection, buffer, MHD_HTTP_OK); 196 } 197 198 if (0 == strcmp (method, "POST")) 199 { 200 struct connection_info_struct *con_info = *con_cls; 201 202 if (0 != *upload_data_size) 203 { 204 MHD_post_process (con_info->postprocessor, upload_data, 205 *upload_data_size); 206 *upload_data_size = 0; 207 208 return MHD_YES; 209 } 210 else 211 { 212 if (NULL != con_info->fp) 213 { 214 fclose (con_info->fp); 215 con_info->fp = NULL; 216 } 217 /* Now it is safe to open and inspect the file before calling send_page with a response */ 218 return send_page (connection, con_info->answerstring, 219 con_info->answercode); 220 } 221 222 } 223 224 return send_page (connection, errorpage, MHD_HTTP_BAD_REQUEST); 225} 226 227 228int 229main () 230{ 231 struct MHD_Daemon *daemon; 232 233 daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, 234 &answer_to_connection, NULL, 235 MHD_OPTION_NOTIFY_COMPLETED, request_completed, 236 NULL, MHD_OPTION_END); 237 if (NULL == daemon) 238 return 1; 239 (void) getchar (); 240 MHD_stop_daemon (daemon); 241 return 0; 242} 243