diff options
author | Alessio Vanni <vannilla@firemail.cc> | 2021-10-14 21:22:40 +0200 |
---|---|---|
committer | Alessio Vanni <vannilla@firemail.cc> | 2021-11-21 15:23:26 +0100 |
commit | 48ccb35c9aea178d7103c3f198946c1bcbcc080c (patch) | |
tree | efa23246d4b5a657d2a311a326346483ff1a5e54 /src/gns/gnunet-bcd.c | |
parent | 5cbf93d3c6c7a058d9a7893e2a3583a2b5b30d0e (diff) | |
download | gnunet-48ccb35c9aea178d7103c3f198946c1bcbcc080c.tar.gz gnunet-48ccb35c9aea178d7103c3f198946c1bcbcc080c.zip |
Improve gnunet-bcd and update logo used in generated cards
The HTML forms now use a custom CSS instead of importing Bootstrap 4. This new
CSS is basd on Bootstrap 5 with some minimal differences to make it look a bit
like the older theme.
Bootstrap was removed because these pages don't need its full power and also
because it was difficult for some text editors to handle the one-long-line
minified CSS embedded in the HTML. Since the forms are just a series of label
+ input elements, using a specific set of directives doesn't add any
significant maintenance cost while making editing easiers.
A new form to generate a simplified card was added. This card is desgined to
reduce the leftover whitespace when some optional entries are left blank in
the "full" form, while at the same time giving importance to the QR code
containing the GNS address. Its layout can be improved.
The simplified form can also be used to generate a PNG picture of the QR code,
so that it can be included in other graphical media other than a business
card, for example on a flyer or in the signature of a HTML-based e-mail.
Generally, the gnunet-bcd service should provide a slightly better user
experience, even if it's just to provide different pages for different errors
but with a unified style.
The logo used in the cards has been changed from the previous "gnu in front of
a spiderweb" illustration to the new "gnu-shaped network of peers" image. It
is also now a pure TikZ picture instead of being made using PSTricks, because,
apparently, there is an incompatibility between the two packages in recent
versions which made it impossible to compile the file.
As a consequence of the incompatibility between TikZ and PSTricks, the QR code
is now generated using the 'qrcode' package.
This commit contains some changes to FCFS, but they're just some minor fixes
and are unrelated to the changes to BCD.
Diffstat (limited to 'src/gns/gnunet-bcd.c')
-rw-r--r-- | src/gns/gnunet-bcd.c | 884 |
1 files changed, 513 insertions, 371 deletions
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c index a2e94089c..83efcfba5 100644 --- a/src/gns/gnunet-bcd.c +++ b/src/gns/gnunet-bcd.c | |||
@@ -30,394 +30,522 @@ | |||
30 | #include "gnunet_identity_service.h" | 30 | #include "gnunet_identity_service.h" |
31 | #include "gnunet_mhd_compat.h" | 31 | #include "gnunet_mhd_compat.h" |
32 | 32 | ||
33 | struct StaticResource | ||
34 | { | ||
35 | /** | ||
36 | * Handle to file on disk. | ||
37 | */ | ||
38 | struct GNUNET_DISK_FileHandle *handle; | ||
39 | |||
40 | /** | ||
41 | * Size in bytes of the file. | ||
42 | */ | ||
43 | uint64_t size; | ||
44 | |||
45 | /** | ||
46 | * Cached response object to send to clients. | ||
47 | */ | ||
48 | struct MHD_Response *response; | ||
49 | }; | ||
50 | |||
51 | struct ParameterMap | ||
52 | { | ||
53 | /** | ||
54 | * Name of the parameter from the request. | ||
55 | */ | ||
56 | char *name; | ||
57 | |||
58 | /** | ||
59 | * Name of the definition in the TeX output. | ||
60 | */ | ||
61 | char *definition; | ||
62 | }; | ||
63 | |||
33 | /** | 64 | /** |
34 | * Error page to display if submitted GNS key is invalid. | 65 | * Handle to the HTTP server as provided by libmicrohttpd |
35 | */ | 66 | */ |
36 | #define INVALID_GNSKEY \ | 67 | static struct MHD_Daemon *httpd = NULL; |
37 | "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>" | ||
38 | 68 | ||
39 | /** | 69 | /** |
40 | * Error page to display on 404. | 70 | * Our primary task for the HTTPD. |
41 | */ | 71 | */ |
42 | #define NOT_FOUND \ | 72 | static struct GNUNET_SCHEDULER_Task *httpd_task = NULL; |
43 | "<html><head><title>Error</title><body>404 not found</body></html>" | ||
44 | 73 | ||
45 | /** | 74 | /** |
46 | * Handle to the HTTP server as provided by libmicrohttpd | 75 | * Index file resource (simple result). |
47 | */ | 76 | */ |
48 | static struct MHD_Daemon *daemon_handle; | 77 | static struct StaticResource *index_simple = NULL; |
49 | 78 | ||
50 | /** | 79 | /** |
51 | * Our configuration. | 80 | * Index file resource (full result). |
52 | */ | 81 | */ |
53 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 82 | static struct StaticResource *index_full = NULL; |
54 | 83 | ||
55 | /** | 84 | /** |
56 | * Our primary task for the HTTPD. | 85 | * Error: invalid gns key. |
57 | */ | 86 | */ |
58 | static struct GNUNET_SCHEDULER_Task *http_task; | 87 | static struct StaticResource *key_error = NULL; |
59 | 88 | ||
60 | /** | 89 | /** |
61 | * Our main website. | 90 | * Error: 404 |
62 | */ | 91 | */ |
63 | static struct MHD_Response *main_response; | 92 | static struct StaticResource *notfound_error = NULL; |
64 | 93 | ||
65 | /** | 94 | /** |
66 | * Error: invalid gns key. | 95 | * Errors after receiving the form data. |
67 | */ | 96 | */ |
68 | static struct MHD_Response *invalid_gnskey_response; | 97 | static struct StaticResource *internal_error = NULL; |
69 | 98 | ||
70 | /** | 99 | /** |
71 | * Error: 404 | 100 | * Other errors. |
72 | */ | 101 | */ |
73 | static struct MHD_Response *not_found_response; | 102 | static struct StaticResource *forbidden_error = NULL; |
74 | 103 | ||
75 | /** | 104 | /** |
76 | * Absolute name of the 'gns-bcd.tex' file. | 105 | * Full path to the TeX template file (simple result) |
77 | */ | 106 | */ |
78 | static char *resfile; | 107 | static char *tex_file_simple = NULL; |
79 | 108 | ||
80 | /** | 109 | /** |
81 | * Port number. | 110 | * Full path to the TeX template file (full result) |
82 | */ | 111 | */ |
83 | static uint16_t port = 8888; | 112 | static char *tex_file_full = NULL; |
84 | 113 | ||
114 | /** | ||
115 | * Full path to the TeX template file (PNG result) | ||
116 | */ | ||
117 | static char *tex_file_png = NULL; | ||
85 | 118 | ||
86 | struct Entry | 119 | /** |
87 | { | 120 | * Used as a sort of singleton to send exactly one 100 CONTINUE per request. |
88 | const char *formname; | 121 | */ |
89 | const char *texname; | 122 | static int continue_100 = 100; |
123 | |||
124 | /** | ||
125 | * Map of names with TeX definitions, used during PDF generation. | ||
126 | */ | ||
127 | static const struct ParameterMap pmap[] = { | ||
128 | {"prefix", "prefix"}, | ||
129 | {"name", "name"}, | ||
130 | {"suffix", "suffix"}, | ||
131 | {"street", "street"}, | ||
132 | {"city", "city"}, | ||
133 | {"phone", "phone"}, | ||
134 | {"fax", "fax"}, | ||
135 | {"email", "email"}, | ||
136 | {"homepage", "homepage"}, | ||
137 | {"org", "organization"}, | ||
138 | {"department", "department"}, | ||
139 | {"subdepartment", "subdepartment"}, | ||
140 | {"jobtitle", "jobtitle"}, | ||
141 | {NULL, NULL}, | ||
90 | }; | 142 | }; |
91 | 143 | ||
144 | /** | ||
145 | * Port number. | ||
146 | */ | ||
147 | static uint16_t port = 8888; | ||
92 | 148 | ||
93 | /** | 149 | /** |
94 | * Main request handler. | 150 | * Task ran at shutdown to clean up everything. |
151 | * | ||
152 | * @param cls unused | ||
95 | */ | 153 | */ |
96 | static MHD_RESULT | 154 | static void |
97 | access_handler_callback (void *cls, | 155 | do_shutdown (void *cls) |
98 | struct MHD_Connection *connection, | ||
99 | const char *url, | ||
100 | const char *method, | ||
101 | const char *version, | ||
102 | const char *upload_data, | ||
103 | size_t *upload_data_size, | ||
104 | void **con_cls) | ||
105 | { | 156 | { |
106 | static int dummy; | 157 | /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so |
107 | static const struct Entry map[] = { { "prefix", "prefix" }, | 158 | calling `GNUNET_DISK_file_close' would generate a spurious warning message |
108 | { "name", "name" }, | 159 | in the log. Since that function does nothing but close the descriptor and |
109 | { "suffix", "suffix" }, | 160 | free the allocated memory, After destroying the response all that's left to |
110 | { "street", "street" }, | 161 | do is call `GNUNET_free'. */ |
111 | { "city", "city" }, | 162 | if (NULL != index_simple) |
112 | { "phone", "phone" }, | ||
113 | { "fax", "fax" }, | ||
114 | { "email", "email" }, | ||
115 | { "homepage", "homepage" }, | ||
116 | { "orga", "orga" }, | ||
117 | { "departmenti18n", "departmentde" }, | ||
118 | { "departmenten", "departmenten" }, | ||
119 | { "subdepartmenti18n", | ||
120 | "subdepartmentde" }, | ||
121 | { "subdepartmenten", "subdepartmenten" }, | ||
122 | { "jobtitlei18n", "jobtitlegerman" }, | ||
123 | { "jobtitleen", "jobtitleenglish" }, | ||
124 | { "subdepartmenten", "subdepartmenten" }, | ||
125 | { NULL, NULL } }; | ||
126 | |||
127 | (void) cls; | ||
128 | (void) version; | ||
129 | (void) upload_data; | ||
130 | (void) upload_data_size; | ||
131 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
132 | { | 163 | { |
133 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 164 | MHD_destroy_response (index_simple->response); |
134 | _ ("Refusing `%s' request to HTTP server\n"), | 165 | GNUNET_free (index_simple->handle); |
135 | method); | 166 | GNUNET_free (index_simple); |
136 | return MHD_NO; | ||
137 | } | 167 | } |
138 | if (NULL == *con_cls) | 168 | if (NULL != index_full) |
139 | { | 169 | { |
140 | (*con_cls) = &dummy; | 170 | MHD_destroy_response (index_full->response); |
141 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n"); | 171 | GNUNET_free (index_full->handle); |
142 | return MHD_YES; /* send 100 continue */ | 172 | GNUNET_free (index_full); |
143 | } | 173 | } |
144 | if (0 == strcasecmp (url, "/")) | 174 | if (NULL != key_error) |
145 | return MHD_queue_response (connection, MHD_HTTP_OK, main_response); | ||
146 | if (0 == strcasecmp (url, "/submit.pdf")) | ||
147 | { | 175 | { |
148 | unsigned int i; | 176 | MHD_destroy_response (key_error->response); |
149 | char *p; | 177 | GNUNET_free (key_error->handle); |
150 | char *tmp; | 178 | GNUNET_free (key_error); |
151 | char *deffile; | 179 | } |
152 | struct GNUNET_IDENTITY_PublicKey pub; | 180 | if (NULL != notfound_error) |
153 | size_t slen; | 181 | { |
154 | FILE *f; | 182 | MHD_destroy_response (notfound_error->response); |
155 | struct stat st; | 183 | GNUNET_free (notfound_error->handle); |
156 | struct MHD_Response *response; | 184 | GNUNET_free (notfound_error); |
157 | int fd; | 185 | } |
158 | MHD_RESULT ret; | 186 | if (NULL != internal_error) |
159 | 187 | { | |
160 | const char *gpg_fp = MHD_lookup_connection_value (connection, | 188 | MHD_destroy_response (internal_error->response); |
161 | MHD_GET_ARGUMENT_KIND, | 189 | GNUNET_free (internal_error->handle); |
162 | "gpgfingerprint"); | 190 | GNUNET_free (internal_error); |
163 | const char *gns_nick = MHD_lookup_connection_value (connection, | 191 | } |
164 | MHD_GET_ARGUMENT_KIND, | 192 | if (NULL != forbidden_error) |
165 | "gnsnick"); | 193 | { |
166 | const char *gnskey = | 194 | MHD_destroy_response (forbidden_error->response); |
167 | MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "gnskey"); | 195 | GNUNET_free (forbidden_error->handle); |
168 | if ((NULL == gnskey) || | 196 | GNUNET_free (forbidden_error); |
169 | (GNUNET_OK != | ||
170 | GNUNET_IDENTITY_public_key_from_string (gnskey, | ||
171 | &pub))) | ||
172 | { | ||
173 | return MHD_queue_response (connection, | ||
174 | MHD_HTTP_OK, | ||
175 | invalid_gnskey_response); | ||
176 | } | ||
177 | tmp = GNUNET_DISK_mkdtemp (gnskey); | ||
178 | if (NULL == tmp) | ||
179 | { | ||
180 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey); | ||
181 | return MHD_NO; | ||
182 | } | ||
183 | GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "def.tex"); | ||
184 | f = fopen (deffile, "w"); | ||
185 | if (NULL == f) | ||
186 | { | ||
187 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile); | ||
188 | GNUNET_free (deffile); | ||
189 | GNUNET_DISK_directory_remove (tmp); | ||
190 | GNUNET_free (tmp); | ||
191 | return MHD_NO; | ||
192 | } | ||
193 | for (i = 0; NULL != map[i].formname; i++) | ||
194 | { | ||
195 | const char *val = MHD_lookup_connection_value (connection, | ||
196 | MHD_GET_ARGUMENT_KIND, | ||
197 | map[i].formname); | ||
198 | if (NULL != val) | ||
199 | fprintf (f, "\\def\\%s{%s}\n", map[i].texname, val); | ||
200 | else | ||
201 | fprintf (f, "\\def\\%s{}\n", map[i].texname); | ||
202 | } | ||
203 | if (NULL != gpg_fp) | ||
204 | { | ||
205 | char *gpg1; | ||
206 | char *gpg2; | ||
207 | |||
208 | slen = strlen (gpg_fp); | ||
209 | gpg1 = GNUNET_strndup (gpg_fp, slen / 2); | ||
210 | gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]); | ||
211 | fprintf (f, "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", gpg1, gpg2); | ||
212 | GNUNET_free (gpg2); | ||
213 | GNUNET_free (gpg1); | ||
214 | } | ||
215 | fprintf (f, | ||
216 | "\\def\\gns{%s/%s}\n", | ||
217 | gnskey, | ||
218 | (NULL == gns_nick) ? "" : gns_nick); | ||
219 | fclose (f); | ||
220 | GNUNET_asprintf ( | ||
221 | &p, | ||
222 | "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null", | ||
223 | tmp, | ||
224 | resfile); | ||
225 | GNUNET_free (deffile); | ||
226 | ret = system (p); | ||
227 | if (WIFSIGNALED (ret) || (0 != WEXITSTATUS (ret))) | ||
228 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", p); | ||
229 | GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf"); | ||
230 | fd = open (deffile, O_RDONLY); | ||
231 | if (-1 == fd) | ||
232 | { | ||
233 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile); | ||
234 | GNUNET_free (deffile); | ||
235 | GNUNET_free (p); | ||
236 | GNUNET_DISK_directory_remove (tmp); | ||
237 | GNUNET_free (tmp); | ||
238 | return MHD_NO; | ||
239 | } | ||
240 | GNUNET_break (0 == stat (deffile, &st)); | ||
241 | if (NULL == | ||
242 | (response = MHD_create_response_from_fd ((size_t) st.st_size, fd))) | ||
243 | { | ||
244 | GNUNET_break (0); | ||
245 | GNUNET_break (0 == close (fd)); | ||
246 | GNUNET_free (deffile); | ||
247 | GNUNET_free (p); | ||
248 | GNUNET_DISK_directory_remove (tmp); | ||
249 | GNUNET_free (tmp); | ||
250 | return MHD_NO; | ||
251 | } | ||
252 | (void) MHD_add_response_header (response, | ||
253 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
254 | "application/pdf"); | ||
255 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
256 | MHD_destroy_response (response); | ||
257 | GNUNET_free (deffile); | ||
258 | GNUNET_free (p); | ||
259 | GNUNET_DISK_directory_remove (tmp); | ||
260 | GNUNET_free (tmp); | ||
261 | return ret; | ||
262 | } | 197 | } |
263 | return MHD_queue_response (connection, | ||
264 | MHD_HTTP_NOT_FOUND, | ||
265 | not_found_response); | ||
266 | } | ||
267 | |||
268 | |||
269 | /** | ||
270 | * Function that queries MHD's select sets and | ||
271 | * starts the task waiting for them. | ||
272 | */ | ||
273 | static struct GNUNET_SCHEDULER_Task * | ||
274 | prepare_daemon (struct MHD_Daemon *daemon_handle); | ||
275 | 198 | ||
199 | if (NULL != httpd_task) | ||
200 | { | ||
201 | GNUNET_SCHEDULER_cancel (httpd_task); | ||
202 | } | ||
203 | if (NULL != httpd) | ||
204 | { | ||
205 | MHD_stop_daemon (httpd); | ||
206 | } | ||
207 | } | ||
276 | 208 | ||
277 | /** | 209 | /** |
278 | * Call MHD to process pending requests and then go back | 210 | * Called when the HTTP server has some pending operations. |
279 | * and schedule the next run. | 211 | * |
212 | * @param cls unused | ||
280 | */ | 213 | */ |
281 | static void | 214 | static void |
282 | run_daemon (void *cls) | 215 | do_httpd (void *cls); |
283 | { | ||
284 | struct MHD_Daemon *daemon_handle = cls; | ||
285 | |||
286 | http_task = NULL; | ||
287 | GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); | ||
288 | http_task = prepare_daemon (daemon_handle); | ||
289 | } | ||
290 | |||
291 | 216 | ||
292 | /** | 217 | /** |
293 | * Function that queries MHD's select sets and | 218 | * Schedule a task to run MHD. |
294 | * starts the task waiting for them. | ||
295 | */ | 219 | */ |
296 | static struct GNUNET_SCHEDULER_Task * | 220 | static void |
297 | prepare_daemon (struct MHD_Daemon *daemon_handle) | 221 | run_httpd (void) |
298 | { | 222 | { |
299 | struct GNUNET_SCHEDULER_Task *ret; | ||
300 | fd_set rs; | 223 | fd_set rs; |
301 | fd_set ws; | 224 | fd_set ws; |
302 | fd_set es; | 225 | fd_set es; |
303 | struct GNUNET_NETWORK_FDSet *wrs; | 226 | |
304 | struct GNUNET_NETWORK_FDSet *wws; | 227 | struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create (); |
305 | int max; | 228 | struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create (); |
306 | MHD_UNSIGNED_LONG_LONG timeout; | 229 | struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create (); |
307 | int haveto; | ||
308 | struct GNUNET_TIME_Relative tv; | ||
309 | 230 | ||
310 | FD_ZERO (&rs); | 231 | FD_ZERO (&rs); |
311 | FD_ZERO (&ws); | 232 | FD_ZERO (&ws); |
312 | FD_ZERO (&es); | 233 | FD_ZERO (&es); |
313 | wrs = GNUNET_NETWORK_fdset_create (); | 234 | |
314 | wws = GNUNET_NETWORK_fdset_create (); | 235 | int max = -1; |
315 | max = -1; | 236 | GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); |
316 | GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); | 237 | |
317 | haveto = MHD_get_timeout (daemon_handle, &timeout); | 238 | unsigned MHD_LONG_LONG timeout = 0; |
318 | if (haveto == MHD_YES) | 239 | struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL; |
319 | tv.rel_value_us = (uint64_t) timeout * 1000LL; | 240 | if (MHD_YES == MHD_get_timeout (httpd, &timeout)) |
320 | else | 241 | { |
321 | tv = GNUNET_TIME_UNIT_FOREVER_REL; | 242 | gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, |
322 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | 243 | timeout); |
323 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | 244 | } |
324 | ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, | 245 | |
325 | tv, | 246 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); |
326 | wrs, | 247 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); |
327 | wws, | 248 | GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1); |
328 | &run_daemon, | 249 | |
329 | daemon_handle); | 250 | httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, |
330 | GNUNET_NETWORK_fdset_destroy (wrs); | 251 | gtime, |
331 | GNUNET_NETWORK_fdset_destroy (wws); | 252 | grs, |
332 | return ret; | 253 | gws, |
254 | &do_httpd, | ||
255 | NULL); | ||
256 | GNUNET_NETWORK_fdset_destroy (grs); | ||
257 | GNUNET_NETWORK_fdset_destroy (gws); | ||
258 | GNUNET_NETWORK_fdset_destroy (ges); | ||
333 | } | 259 | } |
334 | 260 | ||
261 | /** | ||
262 | * Called when the HTTP server has some pending operations. | ||
263 | * | ||
264 | * @param cls unused | ||
265 | */ | ||
266 | static void | ||
267 | do_httpd (void *cls) | ||
268 | { | ||
269 | httpd_task = NULL; | ||
270 | MHD_run (httpd); | ||
271 | run_httpd (); | ||
272 | } | ||
335 | 273 | ||
336 | /** | 274 | /** |
337 | * Start server offering our hostlist. | 275 | * Send a response back to a connected client. |
338 | * | 276 | * |
339 | * @return #GNUNET_OK on success | 277 | * @param cls unused |
278 | * @param connection the connection with the client | ||
279 | * @param url the requested address | ||
280 | * @param method the HTTP method used | ||
281 | * @param version the protocol version (including the "HTTP/" part) | ||
282 | * @param upload_data data sent with a POST request | ||
283 | * @param upload_data_size length in bytes of the POST data | ||
284 | * @param ptr used to pass data between request handling phases | ||
285 | * @return MHD_NO on error | ||
340 | */ | 286 | */ |
341 | static int | 287 | static MHD_RESULT |
342 | server_start () | 288 | create_response (void *cls, |
289 | struct MHD_Connection *connection, | ||
290 | const char *url, | ||
291 | const char *method, | ||
292 | const char *version, | ||
293 | const char *upload_data, | ||
294 | size_t *upload_data_size, | ||
295 | void **ptr) | ||
343 | { | 296 | { |
344 | if (0 == port) | 297 | (void) cls; |
298 | (void) version; | ||
299 | (void) upload_data; | ||
300 | (void) upload_data_size; | ||
301 | |||
302 | bool isget = (0 == strcmp (method, MHD_HTTP_METHOD_GET)); | ||
303 | bool ishead = (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)); | ||
304 | |||
305 | if (!isget && !ishead) | ||
345 | { | 306 | { |
346 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 307 | return MHD_queue_response (connection, |
347 | _ ("Invalid port number %u. Exiting.\n"), | 308 | MHD_HTTP_NOT_IMPLEMENTED, |
348 | port); | 309 | forbidden_error->response); |
349 | return GNUNET_SYSERR; | ||
350 | } | 310 | } |
351 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 311 | |
352 | _ ("Businesscard HTTP server starts on %u\n"), | 312 | if (ishead) |
353 | port); | ||
354 | daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG, | ||
355 | port, | ||
356 | NULL /* accept_policy_callback */, | ||
357 | NULL, | ||
358 | &access_handler_callback, | ||
359 | NULL, | ||
360 | MHD_OPTION_CONNECTION_LIMIT, | ||
361 | (unsigned int) 512, | ||
362 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, | ||
363 | (unsigned int) 2, | ||
364 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
365 | (unsigned int) 60, | ||
366 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
367 | (size_t) (16 * 1024), | ||
368 | MHD_OPTION_END); | ||
369 | if (NULL == daemon_handle) | ||
370 | { | 313 | { |
371 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 314 | /* Dedicated branch in case we want to provide a different result for some |
372 | _ ("Could not start businesscard HTTP server on port %u\n"), | 315 | reason (e.g. a non-web browser application using the web UI) */ |
373 | (unsigned int) port); | 316 | return MHD_queue_response (connection, |
374 | return GNUNET_SYSERR; | 317 | MHD_HTTP_OK, |
318 | index_simple->response); | ||
375 | } | 319 | } |
376 | http_task = prepare_daemon (daemon_handle); | ||
377 | return GNUNET_OK; | ||
378 | } | ||
379 | 320 | ||
321 | /* Send a 100 CONTINUE response to tell clients that the result of the | ||
322 | request might take some time */ | ||
323 | if (NULL == *ptr) | ||
324 | { | ||
325 | *ptr = &continue_100; | ||
326 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE\n"); | ||
327 | return MHD_YES; | ||
328 | } | ||
380 | 329 | ||
381 | /** | 330 | if (0 == strcmp ("/", url)) |
382 | * Stop HTTP server. | 331 | { |
383 | */ | 332 | return MHD_queue_response (connection, |
384 | static void | 333 | MHD_HTTP_OK, |
385 | server_stop (void *cls) | 334 | index_simple->response); |
386 | { | 335 | } |
387 | (void) cls; | 336 | |
388 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n"); | 337 | if (0 == strcmp ("/full", url)) |
389 | if (NULL != http_task) | 338 | { |
339 | return MHD_queue_response (connection, | ||
340 | MHD_HTTP_OK, | ||
341 | index_full->response); | ||
342 | } | ||
343 | |||
344 | bool isfull = (0 == strcmp ("/submit/full", url)); | ||
345 | bool issimple = (0 == strcmp ("/submit/simple", url)); | ||
346 | |||
347 | if (!isfull && !issimple) | ||
348 | { | ||
349 | return MHD_queue_response (connection, | ||
350 | MHD_HTTP_NOT_FOUND, | ||
351 | notfound_error->response); | ||
352 | } | ||
353 | |||
354 | const char *gpgfp = MHD_lookup_connection_value (connection, | ||
355 | MHD_GET_ARGUMENT_KIND, | ||
356 | "gpgfingerprint"); | ||
357 | const char *gnsnick = MHD_lookup_connection_value (connection, | ||
358 | MHD_GET_ARGUMENT_KIND, | ||
359 | "gnsnick"); | ||
360 | const char *gnskey = MHD_lookup_connection_value (connection, | ||
361 | MHD_GET_ARGUMENT_KIND, | ||
362 | "gnskey"); | ||
363 | const char *qrpng = MHD_lookup_connection_value (connection, | ||
364 | MHD_GET_ARGUMENT_KIND, | ||
365 | "gnspng"); | ||
366 | |||
367 | struct GNUNET_IDENTITY_PublicKey pk; | ||
368 | if (NULL == gnskey | ||
369 | || GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (gnskey, &pk)) | ||
370 | { | ||
371 | return MHD_queue_response (connection, | ||
372 | MHD_HTTP_BAD_REQUEST, | ||
373 | key_error->response); | ||
374 | } | ||
375 | |||
376 | char *tmpd = GNUNET_DISK_mkdtemp (gnskey); | ||
377 | if (NULL == tmpd) | ||
378 | { | ||
379 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey); | ||
380 | return MHD_queue_response (connection, | ||
381 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
382 | internal_error->response); | ||
383 | } | ||
384 | |||
385 | char *defpath = NULL; | ||
386 | GNUNET_asprintf (&defpath, "%s%s%s", tmpd, DIR_SEPARATOR_STR, "def.tex"); | ||
387 | |||
388 | FILE *deffile = fopen (defpath, "w"); | ||
389 | if (NULL == deffile) | ||
390 | { | 390 | { |
391 | GNUNET_SCHEDULER_cancel (http_task); | 391 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath); |
392 | http_task = NULL; | 392 | GNUNET_free (defpath); |
393 | GNUNET_DISK_directory_remove (tmpd); | ||
394 | GNUNET_free (tmpd); | ||
395 | return MHD_queue_response (connection, | ||
396 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
397 | internal_error->response); | ||
393 | } | 398 | } |
394 | if (NULL != daemon_handle) | 399 | |
400 | GNUNET_free (defpath); | ||
401 | |||
402 | for (size_t i=0; NULL!=pmap[i].name; ++i) | ||
395 | { | 403 | { |
396 | MHD_stop_daemon (daemon_handle); | 404 | const char *value = MHD_lookup_connection_value (connection, |
397 | daemon_handle = NULL; | 405 | MHD_GET_ARGUMENT_KIND, |
406 | pmap[i].name); | ||
407 | fprintf (deffile, | ||
408 | "\\def\\%s{%s}\n", | ||
409 | pmap[i].definition, | ||
410 | (NULL == value) ? "" : value); | ||
398 | } | 411 | } |
399 | if (NULL != main_response) | 412 | |
413 | if (NULL != gpgfp) | ||
400 | { | 414 | { |
401 | MHD_destroy_response (main_response); | 415 | size_t len = strlen (gpgfp); |
402 | main_response = NULL; | 416 | char *line1 = GNUNET_strndup (gpgfp, len/2); |
417 | char *line2 = GNUNET_strdup (&gpgfp[len/2]); | ||
418 | fprintf (deffile, | ||
419 | "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", | ||
420 | line1, | ||
421 | line2); | ||
403 | } | 422 | } |
404 | if (NULL != invalid_gnskey_response) | 423 | |
424 | fprintf (deffile, | ||
425 | "\\def\\gns{%s/%s}\n", | ||
426 | gnskey, | ||
427 | (NULL == gnsnick) ? "" : gnsnick); | ||
428 | |||
429 | fclose (deffile); | ||
430 | |||
431 | char *command = NULL; | ||
432 | GNUNET_asprintf (&command, | ||
433 | "cd %s; cp %s gns-bcd.tex; " | ||
434 | "pdflatex %s gns-bcd.tex >/dev/null 2>&1", | ||
435 | tmpd, | ||
436 | (isfull) ? tex_file_full : | ||
437 | ((NULL == qrpng) ? tex_file_simple : tex_file_png), | ||
438 | (NULL == qrpng) ? "" : "-shell-escape"); | ||
439 | |||
440 | int ret = system (command); | ||
441 | |||
442 | GNUNET_free (command); | ||
443 | |||
444 | if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret)) | ||
405 | { | 445 | { |
406 | MHD_destroy_response (invalid_gnskey_response); | 446 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", command); |
407 | invalid_gnskey_response = NULL; | ||
408 | } | 447 | } |
409 | if (NULL != not_found_response) | 448 | |
449 | GNUNET_asprintf (&defpath, | ||
450 | "%s%s%s", | ||
451 | tmpd, | ||
452 | DIR_SEPARATOR_STR, | ||
453 | (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png"); | ||
454 | |||
455 | int pdf = open (defpath, O_RDONLY); | ||
456 | if (-1 == pdf) | ||
410 | { | 457 | { |
411 | MHD_destroy_response (not_found_response); | 458 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath); |
412 | not_found_response = NULL; | 459 | GNUNET_free (defpath); |
460 | GNUNET_DISK_directory_remove (tmpd); | ||
461 | GNUNET_free (tmpd); | ||
462 | return MHD_queue_response (connection, | ||
463 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
464 | internal_error->response); | ||
413 | } | 465 | } |
414 | if (NULL != resfile) | 466 | |
467 | struct stat statret; | ||
468 | GNUNET_break (0 == stat (defpath, &statret)); | ||
469 | |||
470 | GNUNET_free (defpath); | ||
471 | |||
472 | struct MHD_Response *pdfrs = | ||
473 | MHD_create_response_from_fd ((size_t) statret.st_size, pdf); | ||
474 | if (NULL == pdfrs) | ||
415 | { | 475 | { |
416 | GNUNET_free (resfile); | 476 | GNUNET_break (0); |
417 | resfile = NULL; | 477 | GNUNET_break (0 == close (pdf)); |
478 | GNUNET_DISK_directory_remove (tmpd); | ||
479 | GNUNET_free (tmpd); | ||
480 | return MHD_queue_response (connection, | ||
481 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
482 | internal_error->response); | ||
418 | } | 483 | } |
484 | |||
485 | MHD_add_response_header (pdfrs, | ||
486 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
487 | (NULL == qrpng) ? "application/pdf" : "image/png"); | ||
488 | MHD_add_response_header (pdfrs, | ||
489 | MHD_HTTP_HEADER_CONTENT_DISPOSITION, | ||
490 | (NULL == qrpng) ? | ||
491 | "attachment; filename=\"gns-business-card.pdf\"" : | ||
492 | "attachment; filename=\"gns-qr-code.png\""); | ||
493 | MHD_RESULT r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs); | ||
494 | |||
495 | MHD_destroy_response (pdfrs); | ||
496 | GNUNET_DISK_directory_remove (tmpd); | ||
497 | GNUNET_free (tmpd); | ||
498 | |||
499 | return r; | ||
419 | } | 500 | } |
420 | 501 | ||
502 | /** | ||
503 | * Open a file on disk and generate a response for it. | ||
504 | * | ||
505 | * @param name name of the file to open | ||
506 | * @param basedir directory where the file is located | ||
507 | * @return NULL on error | ||
508 | */ | ||
509 | static struct StaticResource * | ||
510 | open_static_resource (const char *name, const char *basedir) | ||
511 | { | ||
512 | char *fullname = NULL; | ||
513 | GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name); | ||
514 | |||
515 | struct GNUNET_DISK_FileHandle *f = | ||
516 | GNUNET_DISK_file_open (fullname, | ||
517 | GNUNET_DISK_OPEN_READ, | ||
518 | GNUNET_DISK_PERM_NONE); | ||
519 | |||
520 | GNUNET_free (fullname); | ||
521 | |||
522 | if (NULL == f) | ||
523 | { | ||
524 | return NULL; | ||
525 | } | ||
526 | |||
527 | off_t size = 0; | ||
528 | if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size)) | ||
529 | { | ||
530 | GNUNET_DISK_file_close (f); | ||
531 | return NULL; | ||
532 | } | ||
533 | |||
534 | struct MHD_Response *response = MHD_create_response_from_fd64 (size, f->fd); | ||
535 | |||
536 | if (NULL == response) | ||
537 | { | ||
538 | GNUNET_DISK_file_close (f); | ||
539 | return NULL; | ||
540 | } | ||
541 | |||
542 | struct StaticResource *res = GNUNET_new (struct StaticResource); | ||
543 | res->handle = f; | ||
544 | res->size = (uint64_t) size; | ||
545 | res->response = response; | ||
546 | |||
547 | return res; | ||
548 | } | ||
421 | 549 | ||
422 | /** | 550 | /** |
423 | * Main function that will be run. | 551 | * Main function that will be run. |
@@ -433,63 +561,84 @@ run (void *cls, | |||
433 | const char *cfgfile, | 561 | const char *cfgfile, |
434 | const struct GNUNET_CONFIGURATION_Handle *c) | 562 | const struct GNUNET_CONFIGURATION_Handle *c) |
435 | { | 563 | { |
436 | struct stat st; | ||
437 | char *dir; | ||
438 | char *fn; | ||
439 | int fd; | ||
440 | |||
441 | (void) cls; | 564 | (void) cls; |
442 | (void) args; | 565 | (void) args; |
443 | (void) cfgfile; | 566 | (void) cfgfile; |
444 | cfg = c; | 567 | |
445 | dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); | 568 | if (0 == port) |
446 | GNUNET_assert (NULL != dir); | ||
447 | GNUNET_asprintf (&fn, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.html"); | ||
448 | GNUNET_asprintf (&resfile, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.tex"); | ||
449 | GNUNET_free (dir); | ||
450 | fd = open (fn, O_RDONLY); | ||
451 | if (-1 == fd) | ||
452 | { | 569 | { |
453 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); | 570 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
454 | GNUNET_free (fn); | 571 | _ ("Invalid port number %u\n"), |
572 | port); | ||
573 | GNUNET_SCHEDULER_shutdown (); | ||
455 | return; | 574 | return; |
456 | } | 575 | } |
457 | if (0 != stat (fn, &st)) | 576 | |
577 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
578 | |||
579 | char *datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); | ||
580 | GNUNET_assert (NULL != datadir); | ||
581 | |||
582 | GNUNET_asprintf (&tex_file_full, | ||
583 | "%s%s%s", | ||
584 | datadir, | ||
585 | DIR_SEPARATOR_STR, | ||
586 | "gns-bcd.tex"); | ||
587 | GNUNET_asprintf (&tex_file_simple, | ||
588 | "%s%s%s", | ||
589 | datadir, | ||
590 | DIR_SEPARATOR_STR, | ||
591 | "gns-bcd-simple.tex"); | ||
592 | GNUNET_asprintf(&tex_file_png, | ||
593 | "%s%s%s", | ||
594 | datadir, | ||
595 | DIR_SEPARATOR_STR, | ||
596 | "gns-bcd-png.tex"); | ||
597 | |||
598 | index_simple = open_static_resource ("gns-bcd-simple.html", datadir); | ||
599 | index_full = open_static_resource ("gns-bcd.html", datadir); | ||
600 | key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir); | ||
601 | notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir); | ||
602 | internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir); | ||
603 | forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir); | ||
604 | |||
605 | GNUNET_free (datadir); | ||
606 | |||
607 | if ((NULL == index_simple) || (NULL == index_full) | ||
608 | || (NULL == key_error) || (NULL == notfound_error) | ||
609 | || (NULL == internal_error) || (NULL == forbidden_error)) | ||
458 | { | 610 | { |
459 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); | 611 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
460 | GNUNET_free (fn); | 612 | _ ("Unable to set up the daemon\n")); |
461 | GNUNET_break (0 == close (fd)); | 613 | GNUNET_SCHEDULER_shutdown (); |
462 | return; | 614 | return; |
463 | } | 615 | } |
464 | GNUNET_free (fn); | 616 | |
465 | if (NULL == | 617 | int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME; |
466 | (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd))) | 618 | do |
467 | { | 619 | { |
468 | GNUNET_break (0); | 620 | httpd = MHD_start_daemon (flags, |
469 | GNUNET_break (0 == close (fd)); | 621 | port, |
622 | NULL, NULL, | ||
623 | &create_response, NULL, | ||
624 | MHD_OPTION_CONNECTION_LIMIT, 512, | ||
625 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2, | ||
626 | MHD_OPTION_CONNECTION_TIMEOUT, 60, | ||
627 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024, | ||
628 | MHD_OPTION_END); | ||
629 | flags = MHD_USE_DEBUG; | ||
630 | } while (NULL == httpd && flags != MHD_USE_DEBUG); | ||
631 | |||
632 | if (NULL == httpd) | ||
633 | { | ||
634 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
635 | _ ("Failed to start HTTP server\n")); | ||
636 | GNUNET_SCHEDULER_shutdown (); | ||
470 | return; | 637 | return; |
471 | } | 638 | } |
472 | (void) MHD_add_response_header (main_response, | ||
473 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
474 | "text/html"); | ||
475 | invalid_gnskey_response = | ||
476 | MHD_create_response_from_buffer (strlen (INVALID_GNSKEY), | ||
477 | INVALID_GNSKEY, | ||
478 | MHD_RESPMEM_PERSISTENT); | ||
479 | (void) MHD_add_response_header (invalid_gnskey_response, | ||
480 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
481 | "text/html"); | ||
482 | not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND), | ||
483 | NOT_FOUND, | ||
484 | MHD_RESPMEM_PERSISTENT); | ||
485 | (void) MHD_add_response_header (not_found_response, | ||
486 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
487 | "text/html"); | ||
488 | if (GNUNET_OK != server_start ()) | ||
489 | return; | ||
490 | GNUNET_SCHEDULER_add_shutdown (&server_stop, NULL); | ||
491 | } | ||
492 | 639 | ||
640 | run_httpd (); | ||
641 | } | ||
493 | 642 | ||
494 | /** | 643 | /** |
495 | * The main function for gnunet-gns. | 644 | * The main function for gnunet-gns. |
@@ -502,32 +651,25 @@ int | |||
502 | main (int argc, char *const *argv) | 651 | main (int argc, char *const *argv) |
503 | { | 652 | { |
504 | struct GNUNET_GETOPT_CommandLineOption options[] = { | 653 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
505 | GNUNET_GETOPT_option_uint16 ('p', | 654 | GNUNET_GETOPT_option_uint16 ( |
506 | "port", | 655 | 'p', |
507 | "PORT", | 656 | "port", |
508 | gettext_noop ( | 657 | "PORT", |
509 | "Run HTTP serve on port PORT (default is 8888)"), | 658 | gettext_noop ("Run HTTP server on port PORT (default is 8888)"), |
510 | &port), | 659 | &port), |
511 | GNUNET_GETOPT_OPTION_END | 660 | GNUNET_GETOPT_OPTION_END, |
512 | }; | 661 | }; |
513 | int ret; | ||
514 | |||
515 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
516 | return 2; | ||
517 | GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL); | ||
518 | ret = (GNUNET_OK == | ||
519 | GNUNET_PROGRAM_run (argc, | ||
520 | argv, | ||
521 | "gnunet-bcd", | ||
522 | _ ("GNUnet HTTP server to create business cards"), | ||
523 | options, | ||
524 | &run, | ||
525 | NULL)) | ||
526 | ? 0 | ||
527 | : 1; | ||
528 | GNUNET_free_nz ((void *) argv); | ||
529 | return ret; | ||
530 | } | ||
531 | 662 | ||
663 | return ((GNUNET_OK == | ||
664 | GNUNET_PROGRAM_run (argc, | ||
665 | argv, | ||
666 | "gnunet-bcd", | ||
667 | _ ("GNUnet HTTP server to create business cards"), | ||
668 | options, | ||
669 | &run, | ||
670 | NULL)) | ||
671 | ? 0 | ||
672 | : 1); | ||
673 | } | ||
532 | 674 | ||
533 | /* end of gnunet-bcd.c */ | 675 | /* end of gnunet-bcd.c */ |