Mercurial > urweb
comparison src/c/request.c @ 856:86ec89baee01
cgi protocol
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 23 Jun 2009 17:59:23 -0400 |
parents | 158d980889ac |
children | 305bc0a431de |
comparison
equal
deleted
inserted
replaced
855:28e42b22424d | 856:86ec89baee01 |
---|---|
15 | 15 |
16 #include "urweb.h" | 16 #include "urweb.h" |
17 | 17 |
18 #define MAX_RETRIES 5 | 18 #define MAX_RETRIES 5 |
19 | 19 |
20 static int try_rollback(uw_context ctx) { | 20 static int try_rollback(uw_context ctx, void *logger_data, uw_logger log_error) { |
21 int r = uw_rollback(ctx); | 21 int r = uw_rollback(ctx); |
22 | 22 |
23 if (r) { | 23 if (r) { |
24 printf("Error running SQL ROLLBACK\n"); | 24 log_error(logger_data, "Error running SQL ROLLBACK\n"); |
25 uw_reset(ctx); | 25 uw_reset(ctx); |
26 uw_write(ctx, "HTTP/1.1 500 Internal Server Error\n\r"); | 26 uw_write(ctx, "HTTP/1.1 500 Internal Server Error\n\r"); |
27 uw_write(ctx, "Content-type: text/plain\r\n\r\n"); | 27 uw_write(ctx, "Content-type: text/plain\r\n\r\n"); |
28 uw_write(ctx, "Error running SQL ROLLBACK\n"); | 28 uw_write(ctx, "Error running SQL ROLLBACK\n"); |
29 } | 29 } |
30 | 30 |
31 return r; | 31 return r; |
32 } | 32 } |
33 | 33 |
34 uw_context uw_request_new_context() { | 34 uw_context uw_request_new_context(void *logger_data, uw_logger log_error, uw_logger log_debug) { |
35 uw_context ctx = uw_init(); | 35 uw_context ctx = uw_init(); |
36 int retries_left = MAX_RETRIES; | 36 int retries_left = MAX_RETRIES; |
37 | 37 |
38 while (1) { | 38 while (1) { |
39 failure_kind fk = uw_begin_init(ctx); | 39 failure_kind fk = uw_begin_init(ctx); |
40 | 40 |
41 if (fk == SUCCESS) { | 41 if (fk == SUCCESS) { |
42 printf("Database connection initialized.\n"); | 42 log_debug(logger_data, "Database connection initialized.\n"); |
43 break; | 43 break; |
44 } else if (fk == BOUNDED_RETRY) { | 44 } else if (fk == BOUNDED_RETRY) { |
45 if (retries_left) { | 45 if (retries_left) { |
46 printf("Initialization error triggers bounded retry: %s\n", uw_error_message(ctx)); | 46 log_debug(logger_data, "Initialization error triggers bounded retry: %s\n", uw_error_message(ctx)); |
47 --retries_left; | 47 --retries_left; |
48 } else { | 48 } else { |
49 printf("Fatal initialization error (out of retries): %s\n", uw_error_message(ctx)); | 49 log_error(logger_data, "Fatal initialization error (out of retries): %s\n", uw_error_message(ctx)); |
50 uw_free(ctx); | 50 uw_free(ctx); |
51 return NULL; | 51 return NULL; |
52 } | 52 } |
53 } else if (fk == UNLIMITED_RETRY) | 53 } else if (fk == UNLIMITED_RETRY) |
54 printf("Initialization error triggers unlimited retry: %s\n", uw_error_message(ctx)); | 54 log_debug(logger_data, "Initialization error triggers unlimited retry: %s\n", uw_error_message(ctx)); |
55 else if (fk == FATAL) { | 55 else if (fk == FATAL) { |
56 printf("Fatal initialization error: %s\n", uw_error_message(ctx)); | 56 log_error(logger_data, "Fatal initialization error: %s\n", uw_error_message(ctx)); |
57 uw_free(ctx); | 57 uw_free(ctx); |
58 return NULL; | 58 return NULL; |
59 } else { | 59 } else { |
60 printf("Unknown uw_begin_init return code!\n"); | 60 log_error(logger_data, "Unknown uw_begin_init return code!\n"); |
61 uw_free(ctx); | 61 uw_free(ctx); |
62 return NULL; | 62 return NULL; |
63 } | 63 } |
64 } | 64 } |
65 | 65 |
76 int uw_hash_blocksize = HASH_BLOCKSIZE; | 76 int uw_hash_blocksize = HASH_BLOCKSIZE; |
77 | 77 |
78 static int password[PASSSIZE]; | 78 static int password[PASSSIZE]; |
79 static unsigned char private_key[KEYSIZE]; | 79 static unsigned char private_key[KEYSIZE]; |
80 | 80 |
81 static void init_crypto() { | 81 static void init_crypto(void *logger_data, uw_logger log_error) { |
82 KEYGEN kg = {{HASH_ALGORITHM, HASH_ALGORITHM}}; | 82 KEYGEN kg = {{HASH_ALGORITHM, HASH_ALGORITHM}}; |
83 int i; | 83 int i; |
84 | 84 |
85 assert(mhash_get_block_size(HASH_ALGORITHM) == HASH_BLOCKSIZE); | 85 assert(mhash_get_block_size(HASH_ALGORITHM) == HASH_BLOCKSIZE); |
86 | 86 |
88 password[i] = rand(); | 88 password[i] = rand(); |
89 | 89 |
90 if (mhash_keygen_ext(KEYGEN_ALGORITHM, kg, | 90 if (mhash_keygen_ext(KEYGEN_ALGORITHM, kg, |
91 private_key, sizeof(private_key), | 91 private_key, sizeof(private_key), |
92 (unsigned char*)password, sizeof(password)) < 0) { | 92 (unsigned char*)password, sizeof(password)) < 0) { |
93 printf("Key generation failed\n"); | 93 log_error(logger_data, "Key generation failed\n"); |
94 exit(1); | 94 exit(1); |
95 } | 95 } |
96 } | 96 } |
97 | 97 |
98 void uw_request_init() { | 98 void uw_request_init(void *logger_data, uw_logger log_error, uw_logger log_debug) { |
99 uw_context ctx; | 99 uw_context ctx; |
100 failure_kind fk; | 100 failure_kind fk; |
101 | 101 |
102 uw_global_init(); | 102 uw_global_init(); |
103 | 103 |
104 ctx = uw_request_new_context(); | 104 ctx = uw_request_new_context(logger_data, log_error, log_debug); |
105 | 105 |
106 if (!ctx) | 106 if (!ctx) |
107 exit(1); | 107 exit(1); |
108 | 108 |
109 for (fk = uw_initialize(ctx); fk == UNLIMITED_RETRY; fk = uw_initialize(ctx)) { | 109 for (fk = uw_initialize(ctx); fk == UNLIMITED_RETRY; fk = uw_initialize(ctx)) { |
110 printf("Unlimited retry during init: %s\n", uw_error_message(ctx)); | 110 log_debug(logger_data, "Unlimited retry during init: %s\n", uw_error_message(ctx)); |
111 uw_db_rollback(ctx); | 111 uw_db_rollback(ctx); |
112 uw_reset(ctx); | 112 uw_reset(ctx); |
113 } | 113 } |
114 | 114 |
115 if (fk != SUCCESS) { | 115 if (fk != SUCCESS) { |
116 printf("Failed to initialize database! %s\n", uw_error_message(ctx)); | 116 log_error(logger_data, "Failed to initialize database! %s\n", uw_error_message(ctx)); |
117 uw_db_rollback(ctx); | 117 uw_db_rollback(ctx); |
118 exit(1); | 118 exit(1); |
119 } | 119 } |
120 | 120 |
121 uw_free(ctx); | 121 uw_free(ctx); |
122 | 122 |
123 init_crypto(); | 123 init_crypto(logger_data, log_error); |
124 } | 124 } |
125 | 125 |
126 void uw_sign(const char *in, char *out) { | 126 void uw_sign(const char *in, char *out) { |
127 MHASH td; | 127 MHASH td; |
128 | 128 |
129 td = mhash_hmac_init(HASH_ALGORITHM, private_key, sizeof(private_key), | 129 td = mhash_hmac_init(HASH_ALGORITHM, private_key, sizeof(private_key), |
130 mhash_get_hash_pblock(HASH_ALGORITHM)); | 130 mhash_get_hash_pblock(HASH_ALGORITHM)); |
131 | 131 |
132 mhash(td, in, strlen(in)); | 132 mhash(td, in, strlen(in)); |
133 if (mhash_hmac_deinit(td, out) < 0) | 133 if (mhash_hmac_deinit(td, out) < 0) |
134 printf("Signing failed"); | 134 fprintf(stderr, "Signing failed\n"); |
135 } | 135 } |
136 | 136 |
137 typedef struct uw_rc { | 137 typedef struct uw_rc { |
138 size_t path_copy_size; | 138 size_t path_copy_size; |
139 char *path_copy; | 139 char *path_copy; |
152 } | 152 } |
153 | 153 |
154 request_result uw_request(uw_request_context rc, uw_context ctx, | 154 request_result uw_request(uw_request_context rc, uw_context ctx, |
155 char *method, char *path, char *query_string, | 155 char *method, char *path, char *query_string, |
156 char *body, size_t body_len, | 156 char *body, size_t body_len, |
157 void (*on_success)(uw_context), void (*on_failure)(uw_context), | |
158 void *logger_data, uw_logger log_error, uw_logger log_debug, | |
157 int sock) { | 159 int sock) { |
158 int retries_left = MAX_RETRIES; | 160 int retries_left = MAX_RETRIES; |
159 char *s; | 161 char *s; |
160 failure_kind fk; | 162 failure_kind fk; |
161 int is_post = 0, do_normal_send = 1; | 163 int is_post = 0, do_normal_send = 1; |
164 char *inputs; | 166 char *inputs; |
165 | 167 |
166 if (!strcmp(method, "POST")) { | 168 if (!strcmp(method, "POST")) { |
167 char *clen_s = uw_Basis_requestHeader(ctx, "Content-length"); | 169 char *clen_s = uw_Basis_requestHeader(ctx, "Content-length"); |
168 if (!clen_s) { | 170 if (!clen_s) { |
169 fprintf(stderr, "No Content-length with POST\n"); | 171 log_error(logger_data, "No Content-length with POST\n"); |
170 return FAILED; | 172 return FAILED; |
171 } | 173 } |
172 int clen = atoi(clen_s); | 174 int clen = atoi(clen_s); |
173 if (clen < 0) { | 175 if (clen < 0) { |
174 fprintf(stderr, "Negative Content-length with POST\n"); | 176 log_error(logger_data, "Negative Content-length with POST\n"); |
175 return FAILED; | 177 return FAILED; |
176 } | 178 } |
177 | 179 |
178 if (body_len < clen) { | 180 if (body_len < clen) { |
179 fprintf(stderr, "Request doesn't contain all POST data (according to Content-Length)\n"); | 181 log_error(logger_data, "Request doesn't contain all POST data (according to Content-Length)\n"); |
180 return FAILED; | 182 return FAILED; |
181 } | 183 } |
182 | 184 |
183 is_post = 1; | 185 is_post = 1; |
184 | 186 |
185 clen_s = uw_Basis_requestHeader(ctx, "Content-type"); | 187 clen_s = uw_Basis_requestHeader(ctx, "Content-type"); |
186 if (clen_s && !strncasecmp(clen_s, "multipart/form-data", 19)) { | 188 if (clen_s && !strncasecmp(clen_s, "multipart/form-data", 19)) { |
187 if (strncasecmp(clen_s + 19, "; boundary=", 11)) { | 189 if (strncasecmp(clen_s + 19, "; boundary=", 11)) { |
188 fprintf(stderr, "Bad multipart boundary spec"); | 190 log_error(logger_data, "Bad multipart boundary spec"); |
189 return FAILED; | 191 return FAILED; |
190 } | 192 } |
191 | 193 |
192 boundary = clen_s + 28; | 194 boundary = clen_s + 28; |
193 boundary[0] = '-'; | 195 boundary[0] = '-'; |
194 boundary[1] = '-'; | 196 boundary[1] = '-'; |
195 boundary_len = strlen(boundary); | 197 boundary_len = strlen(boundary); |
196 } | 198 } |
197 } else if (strcmp(method, "GET")) { | 199 } else if (strcmp(method, "GET")) { |
198 fprintf(stderr, "Not ready for non-GET/POST command: %s\n", method); | 200 log_error(logger_data, "Not ready for non-GET/POST command: %s\n", method); |
199 return FAILED; | 201 return FAILED; |
200 } | 202 } |
201 | 203 |
202 if (!strcmp(path, "/.msgs")) { | 204 if (!strcmp(path, "/.msgs")) { |
203 char *id = uw_Basis_requestHeader(ctx, "UrWeb-Client"); | 205 char *id = uw_Basis_requestHeader(ctx, "UrWeb-Client"); |
204 char *pass = uw_Basis_requestHeader(ctx, "UrWeb-Pass"); | 206 char *pass = uw_Basis_requestHeader(ctx, "UrWeb-Pass"); |
205 | 207 |
206 if (sock < 0) { | 208 if (sock < 0) { |
207 fprintf(stderr, ".msgs requested, but not socket supplied\n"); | 209 log_error(logger_data, ".msgs requested, but not socket supplied\n"); |
208 return FAILED; | 210 return FAILED; |
209 } | 211 } |
210 | 212 |
211 if (id && pass) { | 213 if (id && pass) { |
212 unsigned idn = atoi(id); | 214 unsigned idn = atoi(id); |
213 uw_client_connect(idn, atoi(pass), sock); | 215 uw_client_connect(idn, atoi(pass), sock); |
214 fprintf(stderr, "Processed request for messages by client %u\n\n", idn); | 216 log_error(logger_data, "Processed request for messages by client %u\n\n", idn); |
215 return KEEP_OPEN; | 217 return KEEP_OPEN; |
216 } | 218 } |
217 else { | 219 else { |
218 fprintf(stderr, "Missing fields in .msgs request: %s, %s\n\n", id, pass); | 220 log_error(logger_data, "Missing fields in .msgs request: %s, %s\n\n", id, pass); |
219 return FAILED; | 221 return FAILED; |
220 } | 222 } |
221 } | 223 } |
222 | 224 |
223 if (boundary) { | 225 if (boundary) { |
224 char *part = body, *after_sub_headers, *header, *after_header; | 226 char *part = body, *after_sub_headers, *header, *after_header; |
225 size_t part_len; | 227 size_t part_len; |
226 | 228 |
227 part = strstr(part, boundary); | 229 part = strstr(part, boundary); |
228 if (!part) { | 230 if (!part) { |
229 fprintf(stderr, "Missing first multipart boundary\n"); | 231 log_error(logger_data, "Missing first multipart boundary\n"); |
230 return FAILED; | 232 return FAILED; |
231 } | 233 } |
232 part += boundary_len; | 234 part += boundary_len; |
233 | 235 |
234 while (1) { | 236 while (1) { |
236 | 238 |
237 if (part[0] == '-' && part[1] == '-') | 239 if (part[0] == '-' && part[1] == '-') |
238 break; | 240 break; |
239 | 241 |
240 if (*part != '\r') { | 242 if (*part != '\r') { |
241 fprintf(stderr, "No \\r after multipart boundary\n"); | 243 log_error(logger_data, "No \\r after multipart boundary\n"); |
242 return FAILED; | 244 return FAILED; |
243 } | 245 } |
244 ++part; | 246 ++part; |
245 if (*part != '\n') { | 247 if (*part != '\n') { |
246 fprintf(stderr, "No \\n after multipart boundary\n"); | 248 log_error(logger_data, "No \\n after multipart boundary\n"); |
247 return FAILED; | 249 return FAILED; |
248 } | 250 } |
249 ++part; | 251 ++part; |
250 | 252 |
251 if (!(after_sub_headers = strstr(part, "\r\n\r\n"))) { | 253 if (!(after_sub_headers = strstr(part, "\r\n\r\n"))) { |
252 fprintf(stderr, "Missing end of headers after multipart boundary\n"); | 254 log_error(logger_data, "Missing end of headers after multipart boundary\n"); |
253 return FAILED; | 255 return FAILED; |
254 } | 256 } |
255 after_sub_headers[2] = 0; | 257 after_sub_headers[2] = 0; |
256 after_sub_headers += 4; | 258 after_sub_headers += 4; |
257 | 259 |
258 for (header = part; after_header = strstr(header, "\r\n"); header = after_header + 2) { | 260 for (header = part; after_header = strstr(header, "\r\n"); header = after_header + 2) { |
259 char *colon, *after_colon; | 261 char *colon, *after_colon; |
260 | 262 |
261 *after_header = 0; | 263 *after_header = 0; |
262 if (!(colon = strchr(header, ':'))) { | 264 if (!(colon = strchr(header, ':'))) { |
263 fprintf(stderr, "Missing colon in multipart sub-header\n"); | 265 log_error(logger_data, "Missing colon in multipart sub-header\n"); |
264 return FAILED; | 266 return FAILED; |
265 } | 267 } |
266 *colon++ = 0; | 268 *colon++ = 0; |
267 if (*colon++ != ' ') { | 269 if (*colon++ != ' ') { |
268 fprintf(stderr, "No space after colon in multipart sub-header\n"); | 270 log_error(logger_data, "No space after colon in multipart sub-header\n"); |
269 return FAILED; | 271 return FAILED; |
270 } | 272 } |
271 | 273 |
272 if (!strcasecmp(header, "Content-Disposition")) { | 274 if (!strcasecmp(header, "Content-Disposition")) { |
273 if (strncmp(colon, "form-data; ", 11)) { | 275 if (strncmp(colon, "form-data; ", 11)) { |
274 fprintf(stderr, "Multipart data is not \"form-data\"\n"); | 276 log_error(logger_data, "Multipart data is not \"form-data\"\n"); |
275 return FAILED; | 277 return FAILED; |
276 } | 278 } |
277 | 279 |
278 for (colon += 11; after_colon = strchr(colon, '='); colon = after_colon) { | 280 for (colon += 11; after_colon = strchr(colon, '='); colon = after_colon) { |
279 char *data; | 281 char *data; |
280 after_colon[0] = 0; | 282 after_colon[0] = 0; |
281 if (after_colon[1] != '"') { | 283 if (after_colon[1] != '"') { |
282 fprintf(stderr, "Disposition setting is missing initial quote\n"); | 284 log_error(logger_data, "Disposition setting is missing initial quote\n"); |
283 return FAILED; | 285 return FAILED; |
284 } | 286 } |
285 data = after_colon+2; | 287 data = after_colon+2; |
286 if (!(after_colon = strchr(data, '"'))) { | 288 if (!(after_colon = strchr(data, '"'))) { |
287 fprintf(stderr, "Disposition setting is missing final quote\n"); | 289 log_error(logger_data, "Disposition setting is missing final quote\n"); |
288 return FAILED; | 290 return FAILED; |
289 } | 291 } |
290 after_colon[0] = 0; | 292 after_colon[0] = 0; |
291 ++after_colon; | 293 ++after_colon; |
292 if (after_colon[0] == ';' && after_colon[1] == ' ') | 294 if (after_colon[0] == ';' && after_colon[1] == ' ') |
302 } | 304 } |
303 } | 305 } |
304 | 306 |
305 part = memmem(after_sub_headers, body + body_len - after_sub_headers, boundary, boundary_len); | 307 part = memmem(after_sub_headers, body + body_len - after_sub_headers, boundary, boundary_len); |
306 if (!part) { | 308 if (!part) { |
307 fprintf(stderr, "Missing boundary after multipart payload\n"); | 309 log_error(logger_data, "Missing boundary after multipart payload\n"); |
308 return FAILED; | 310 return FAILED; |
309 } | 311 } |
310 part[-2] = 0; | 312 part[-2] = 0; |
311 part_len = part - after_sub_headers - 2; | 313 part_len = part - after_sub_headers - 2; |
312 part[0] = 0; | 314 part[0] = 0; |
314 | 316 |
315 if (filename) { | 317 if (filename) { |
316 uw_Basis_file f = {filename, type, {part_len, after_sub_headers}}; | 318 uw_Basis_file f = {filename, type, {part_len, after_sub_headers}}; |
317 | 319 |
318 if (uw_set_file_input(ctx, name, f)) { | 320 if (uw_set_file_input(ctx, name, f)) { |
319 fprintf(stderr, "%s\n", uw_error_message(ctx)); | 321 log_error(logger_data, "%s\n", uw_error_message(ctx)); |
320 return FAILED; | 322 return FAILED; |
321 } | 323 } |
322 } else if (uw_set_input(ctx, name, after_sub_headers)) { | 324 } else if (uw_set_input(ctx, name, after_sub_headers)) { |
323 fprintf(stderr, "%s\n", uw_error_message(ctx)); | 325 log_error(logger_data, "%s\n", uw_error_message(ctx)); |
324 return FAILED; | 326 return FAILED; |
325 } | 327 } |
326 } | 328 } |
327 } | 329 } |
328 else { | 330 else { |
339 inputs = strchr(name, 0); | 341 inputs = strchr(name, 0); |
340 | 342 |
341 if (value = strchr(name, '=')) { | 343 if (value = strchr(name, '=')) { |
342 *value++ = 0; | 344 *value++ = 0; |
343 if (uw_set_input(ctx, name, value)) { | 345 if (uw_set_input(ctx, name, value)) { |
344 fprintf(stderr, "%s\n", uw_error_message(ctx)); | 346 log_error(logger_data, "%s\n", uw_error_message(ctx)); |
345 return FAILED; | 347 return FAILED; |
346 } | 348 } |
347 } | 349 } |
348 else if (uw_set_input(ctx, name, "")) { | 350 else if (uw_set_input(ctx, name, "")) { |
349 fprintf(stderr, "%s\n", uw_error_message(ctx)); | 351 log_error(logger_data, "%s\n", uw_error_message(ctx)); |
350 return FAILED; | 352 return FAILED; |
351 } | 353 } |
352 } | 354 } |
353 } | 355 } |
354 } | 356 } |
355 | 357 |
356 printf("Serving URI %s....\n", path); | 358 log_debug(logger_data, "Serving URI %s....\n", path); |
357 | 359 |
358 while (1) { | 360 while (1) { |
359 size_t path_len = strlen(path); | 361 size_t path_len = strlen(path); |
360 | 362 |
361 uw_write_header(ctx, "HTTP/1.1 200 OK\r\n"); | 363 on_success(ctx); |
362 | 364 |
363 if (path_len + 1 > rc->path_copy_size) { | 365 if (path_len + 1 > rc->path_copy_size) { |
364 rc->path_copy_size = path_len + 1; | 366 rc->path_copy_size = path_len + 1; |
365 rc->path_copy = realloc(rc->path_copy, rc->path_copy_size); | 367 rc->path_copy = realloc(rc->path_copy, rc->path_copy_size); |
366 } | 368 } |
369 if (fk == SUCCESS || fk == RETURN_BLOB) { | 371 if (fk == SUCCESS || fk == RETURN_BLOB) { |
370 uw_commit(ctx); | 372 uw_commit(ctx); |
371 return SERVED; | 373 return SERVED; |
372 } else if (fk == BOUNDED_RETRY) { | 374 } else if (fk == BOUNDED_RETRY) { |
373 if (retries_left) { | 375 if (retries_left) { |
374 printf("Error triggers bounded retry: %s\n", uw_error_message(ctx)); | 376 log_debug(logger_data, "Error triggers bounded retry: %s\n", uw_error_message(ctx)); |
375 --retries_left; | 377 --retries_left; |
376 } | 378 } |
377 else { | 379 else { |
378 printf("Fatal error (out of retries): %s\n", uw_error_message(ctx)); | 380 log_error(logger_data, "Fatal error (out of retries): %s\n", uw_error_message(ctx)); |
379 | 381 |
380 try_rollback(ctx); | 382 try_rollback(ctx, logger_data, log_error); |
381 | 383 |
382 uw_reset_keep_error_message(ctx); | 384 uw_reset_keep_error_message(ctx); |
383 uw_write_header(ctx, "HTTP/1.1 500 Internal Server Error\n\r"); | 385 on_failure(ctx); |
384 uw_write_header(ctx, "Content-type: text/plain\r\n"); | 386 uw_write_header(ctx, "Content-type: text/plain\r\n"); |
385 uw_write(ctx, "Fatal error (out of retries): "); | 387 uw_write(ctx, "Fatal error (out of retries): "); |
386 uw_write(ctx, uw_error_message(ctx)); | 388 uw_write(ctx, uw_error_message(ctx)); |
387 uw_write(ctx, "\n"); | 389 uw_write(ctx, "\n"); |
388 | 390 |
389 return FAILED; | 391 return FAILED; |
390 } | 392 } |
391 } else if (fk == UNLIMITED_RETRY) | 393 } else if (fk == UNLIMITED_RETRY) |
392 printf("Error triggers unlimited retry: %s\n", uw_error_message(ctx)); | 394 log_debug(logger_data, "Error triggers unlimited retry: %s\n", uw_error_message(ctx)); |
393 else if (fk == FATAL) { | 395 else if (fk == FATAL) { |
394 printf("Fatal error: %s\n", uw_error_message(ctx)); | 396 log_error(logger_data, "Fatal error: %s\n", uw_error_message(ctx)); |
395 | 397 |
396 try_rollback(ctx); | 398 try_rollback(ctx, logger_data, log_error); |
397 | 399 |
398 uw_reset_keep_error_message(ctx); | 400 uw_reset_keep_error_message(ctx); |
399 uw_write_header(ctx, "HTTP/1.1 500 Internal Server Error\r\n"); | 401 on_failure(ctx); |
400 uw_write_header(ctx, "Content-type: text/html\r\n"); | 402 uw_write_header(ctx, "Content-type: text/html\r\n"); |
401 uw_write(ctx, "<html><head><title>Fatal Error</title></head><body>"); | 403 uw_write(ctx, "<html><head><title>Fatal Error</title></head><body>"); |
402 uw_write(ctx, "Fatal error: "); | 404 uw_write(ctx, "Fatal error: "); |
403 uw_write(ctx, uw_error_message(ctx)); | 405 uw_write(ctx, uw_error_message(ctx)); |
404 uw_write(ctx, "\n</body></html>"); | 406 uw_write(ctx, "\n</body></html>"); |
405 | 407 |
406 return FAILED; | 408 return FAILED; |
407 } else { | 409 } else { |
408 printf("Unknown uw_handle return code!\n"); | 410 log_error(logger_data, "Unknown uw_handle return code!\n"); |
409 | 411 |
410 try_rollback(ctx); | 412 try_rollback(ctx, logger_data, log_error); |
411 | 413 |
412 uw_reset_keep_request(ctx); | 414 uw_reset_keep_request(ctx); |
413 uw_write_header(ctx, "HTTP/1.1 500 Internal Server Error\n\r"); | 415 on_failure(ctx); |
414 uw_write_header(ctx, "Content-type: text/plain\r\n"); | 416 uw_write_header(ctx, "Content-type: text/plain\r\n"); |
415 uw_write(ctx, "Unknown uw_handle return code!\n"); | 417 uw_write(ctx, "Unknown uw_handle return code!\n"); |
416 | 418 |
417 return FAILED; | 419 return FAILED; |
418 } | 420 } |
419 | 421 |
420 if (try_rollback(ctx)) | 422 if (try_rollback(ctx, logger_data, log_error)) |
421 return FAILED; | 423 return FAILED; |
422 | 424 |
423 uw_reset_keep_request(ctx); | 425 uw_reset_keep_request(ctx); |
424 } | 426 } |
425 } | 427 } |
426 | 428 |
429 typedef struct { | |
430 void *logger_data; | |
431 uw_logger log_error, log_debug; | |
432 } loggers; | |
433 | |
427 void *client_pruner(void *data) { | 434 void *client_pruner(void *data) { |
428 uw_context ctx = uw_request_new_context(); | 435 loggers *ls = (loggers *)data; |
436 uw_context ctx = uw_request_new_context(ls->logger_data, ls->log_error, ls->log_debug); | |
429 | 437 |
430 if (!ctx) | 438 if (!ctx) |
431 exit(1); | 439 exit(1); |
432 | 440 |
433 while (1) { | 441 while (1) { |