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
23 static unsigned int nr_of_uploading_clients = 0;
24
25 struct connection_info_struct
26 {
27 int connectiontype;
28 struct MHD_PostProcessor *postprocessor;
29 FILE *fp;
30 const char *answerstring;
31 int answercode;
32 };
33
34 const 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
42 const char *busypage =
43 "<html><body>This server is busy, please try again later.</body></html>";
44
45 const char *completepage =
46 "<html><body>The upload has been completed.</body></html>";
47
48 const char *errorpage =
49 "<html><body>This doesn't seem to be right.</body></html>";
50 const char *servererrorpage =
51 "<html><body>An internal server error has occured.</body></html>";
52 const char *fileexistspage =
53 "<html><body>This file already exists.</body></html>";
54
55
56 static int
send_page(struct MHD_Connection * connection,const char * page,int status_code)57 send_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
76 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)77 iterate_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
119 static void
request_completed(void * cls,struct MHD_Connection * connection,void ** con_cls,enum MHD_RequestTerminationCode toe)120 request_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
145 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)146 answer_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
228 int
main()229 main ()
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