"Fossies" - the Fresh Open Source Software Archive 
Member "opengroupware-5.5rc3/SOPE/mod_ngobjweb/handler.c" (5 Dec 2015, 24470 Bytes) of package /linux/privat/opengroupware-5.5rc3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "handler.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.5rc2_vs_5.5rc3.
1 /*
2 Copyright (C) 2000-2008 SKYRIX Software AG
3
4 This file is part of SOPE.
5
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20 */
21
22 #include "common.h"
23
24 #define BUFSIZE 2048
25
26 /* ap_http_method is deprecated in Apache 2.2.x */
27 #if MODULE_MAGIC_NUMBER_MAJOR >= 20051115
28 #define ap_http_method ap_http_scheme
29 #endif
30
31 #ifdef APLOG_USE_MODULE
32 APLOG_USE_MODULE(ngobjweb);
33 #endif
34
35 extern int HEAVY_LOG;
36
37 #if WITH_LOGGING
38 static void _logTable(const char *text, apr_table_t *table);
39 #endif
40
41 static ngobjweb_dir_config *_getConfig(request_rec *r) {
42 ngobjweb_dir_config *cfg;
43
44 if (r == NULL) {
45 fprintf(stderr, "%s: missing request !\n", __PRETTY_FUNCTION__);
46 return NULL;
47 }
48 if (r->per_dir_config == NULL) {
49 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
50 "missing directory config in request ...");
51 return NULL;
52 }
53
54 cfg = (ngobjweb_dir_config *)
55 ap_get_module_config(r->per_dir_config, &ngobjweb_module);
56
57 return cfg;
58 }
59
60 static void _extractAppName(const char *uri, char *appName, int maxLen) {
61 char *tmp;
62
63 /* extract name of application */
64 if ((tmp = index(uri + 1, '/'))) {
65 int len;
66 len = (tmp - (uri + 1));
67 strncpy(appName, (uri + 1), len);
68 appName[len] = '\0';
69 }
70 else {
71 strncpy(appName, (uri + 1), maxLen - 1);
72 appName[maxLen - 1] = '\0';
73 }
74
75 /* cut off .woa extension from application name */
76 if ((tmp = strstr(appName, ".woa")))
77 *tmp = '\0';
78
79 /* cut off .sky extension from application name */
80 if ((tmp = strstr(appName, ".sky")))
81 *tmp = '\0';
82 }
83
84 static void *_readRequestBody(request_rec *r, int *requestContentLength) {
85 const char *clen;
86 int contentLength;
87 void *ptr;
88 int readBytes, toBeRead;
89 void *requestBody;
90
91 clen = apr_table_get(r->headers_in, "content-length");
92 contentLength = clen ? atoi(clen) : 0;
93 *requestContentLength = contentLength;
94
95 /* no content to read ... */
96 if (contentLength == 0) return NULL;
97
98 /* read content */
99
100 if (HEAVY_LOG) {
101 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
102 "going to read %i bytes from browser ...", contentLength);
103 }
104
105 requestBody = apr_palloc(r->pool, contentLength + 2);
106
107 ptr = requestBody;
108 for (toBeRead = contentLength; toBeRead > 0;) {
109 #ifdef AP_VERSION_1
110 readBytes = ap_bread(r->connection->client, ptr, toBeRead);
111 #else
112 ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
113 readBytes = ap_get_client_block(r, ptr, toBeRead);
114 #endif
115 toBeRead -= readBytes;
116 ptr += readBytes;
117 if (readBytes == 0) break;
118 }
119 ptr = NULL;
120
121 if (toBeRead > 0) {
122 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
123 "couldn't read complete HTTP req body from browser "
124 "(read %i of %i bytes)",
125 (contentLength - toBeRead), contentLength);
126 return NULL;
127 }
128
129 return requestBody;
130 }
131
132 static void
133 _copyHeadersToRequest(request_rec *r, apr_table_t *headers, int *contentLength)
134 {
135 const apr_array_header_t *array;
136 apr_table_entry_t *entries;
137 int i;
138 const char *value;
139
140 if (headers == NULL) return;
141
142 value = apr_table_get(headers, "content-type");
143 if (value) r->content_type = value;
144 value = apr_table_get(headers, "content-encoding");
145 if (value) r->content_encoding = value;
146 value = apr_table_get(headers, "content-length");
147 *contentLength = value ? atoi(value) : 0;
148
149 array = apr_table_elts(headers);
150 entries = (apr_table_entry_t *)array->elts;
151
152 for (i = 0; i < array->nelts; i++) {
153 apr_table_entry_t *entry = &(entries[i]);
154
155 apr_table_set(r->headers_out, entry->key, entry->val);
156 }
157 // _logTable("out", r->headers_out);
158 }
159
160 static void _logInstanceAddress(request_rec *r, struct sockaddr *address,
161 size_t addressLen, int domain)
162 {
163 char buf[1024];
164
165 if (!HEAVY_LOG) return;
166
167 apr_snprintf(buf, sizeof(buf), " => address len=%li domain=%i<", (long int) addressLen, domain);
168 switch (domain) {
169 case AF_INET: strcat(buf, "inet"); break;
170 case AF_UNIX: strcat(buf, "unix"); break;
171 default: strcat(buf, "unknown"); break;
172 }
173 strcat(buf, ">");
174
175 if (domain == AF_UNIX) {
176 strcat(buf, " path=\"");
177 strcat(buf, ((struct sockaddr_un *)address)->sun_path);
178 strcat(buf, "\"");
179 }
180 else if (domain == AF_INET) {
181 char *ptr = NULL;
182 int port;
183 char sport[256];
184
185 ptr = inet_ntoa(((struct sockaddr_in *)address)->sin_addr);
186 port = ntohs(((struct sockaddr_in *)address)->sin_port);
187 apr_snprintf(sport, sizeof(sport), "host=\"%s\" port=%i", ptr, port);
188 strcat(buf, sport);
189 }
190
191 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "%s", buf);
192 }
193
194 static int _connectInstance(request_rec *r,
195 int appFd, struct sockaddr *address,
196 size_t addressLen)
197 {
198 int result;
199 int tryCount = 0;
200 char isConnected = 0;
201
202 result = connect(appFd, address, addressLen);
203 if (result >= 0) return result;
204
205 while (tryCount < 3) {
206 char *pdelay = NULL; /* pblock_findval("delay", _paras) */
207 int delay = pdelay ? atoi(pdelay) : 3; // default: 3s
208
209 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
210 "sleeping %is ..", delay);
211 #ifdef AP_VERSION_1
212 apr_sleep(delay); /* should be in seconds for Apache 1? */
213 #else
214 apr_sleep(delay * 1000 * 1000 /* in microseconds now! */);
215 #endif
216
217 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
218 "retry connect ..");
219 result = connect(appFd, address, addressLen);
220
221 if (result >= 0) {
222 isConnected = 1;
223 break;
224 }
225 tryCount++;
226 }
227
228 if (isConnected == 0) {
229 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
230 "connect to application instance failed, tried %i times.",
231 tryCount);
232 close(appFd);
233 return -1;
234 }
235 return result;
236 }
237
238 static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
239 const apr_array_header_t *array;
240 apr_table_entry_t *entries;
241 int i;
242
243 if (r->headers_in == NULL) return 1;
244
245 array = apr_table_elts(r->headers_in);
246 entries = (apr_table_entry_t *)array->elts;
247
248 for (i = 0; i < array->nelts; i++) {
249 apr_table_entry_t *entry = &(entries[i]);
250
251 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
252 entry->key, (void*)entry->val)) {
253 return 0;
254 }
255 }
256 return 1;
257 }
258
259 int ngobjweb_handler(request_rec *r) {
260 struct sockaddr *address = NULL;
261 size_t addressLen;
262 int domain;
263 char appName[256];
264 NGBufferedDescriptor *toApp = NULL;
265 int appFd;
266 int result;
267 int writeError = 0;
268 int contentLength = 0;
269 int statusCode = 500;
270 ngobjweb_dir_config *cfg;
271 const char *uri;
272 unsigned requestContentLength;
273 void *requestBody;
274
275 uri = r->uri;
276 requestContentLength = 0;
277 requestBody = NULL;
278
279 #ifndef AP_VERSION_1
280 if (r->handler == NULL)
281 return DECLINED;
282 if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
283 return DECLINED;
284 #endif
285
286 if (uri == NULL) return DECLINED;
287 if (uri[0] != '/') return DECLINED;
288 if (strstr(uri, "WebServerResources")) return DECLINED;
289
290 /* get directory configuration */
291
292 if ((cfg = _getConfig(r))) {
293 if (cfg->appPrefix) {
294 if (HEAVY_LOG) {
295 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
296 "using prefix '%s'\n", cfg->appPrefix);
297 }
298 uri += strlen(cfg->appPrefix);
299 }
300 }
301 else {
302 return 500;
303 }
304
305 /* find app name in url */
306 _extractAppName(uri, appName, sizeof(appName));
307
308 /* before continuing, read request body */
309
310 requestBody = _readRequestBody(r, &contentLength);
311 requestContentLength = contentLength;
312
313 if ((requestBody == NULL) && (contentLength > 0))
314 /* read failed, error is logged in function */
315 return 500;
316
317 /* ask SNS for server address */
318
319 if (cfg->snsPort) {
320 address = _sendSNSQuery(r,
321 r->the_request,
322 apr_table_get(r->headers_in, "cookie"),
323 &domain, &addressLen,
324 appName,
325 cfg);
326 if (address == NULL) {
327 /* did not find an appropriate application server */
328 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
329 "did not find SOPE instance using SNS.");
330 return DECLINED;
331 }
332 }
333 else if (cfg->appPort) {
334 domain = cfg->appPortDomain;
335
336 if (cfg->appPortDomain == AF_UNIX) {
337 addressLen = sizeof(struct sockaddr_un);
338 address = apr_palloc(r->pool, sizeof(struct sockaddr_un));
339 memset(address, 0, sizeof(struct sockaddr_un));
340
341 ((struct sockaddr_un *)address)->sun_family = AF_UNIX;
342 strncpy(((struct sockaddr_un *)address)->sun_path,
343 cfg->appPort,
344 sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
345 }
346 else {
347 struct sockaddr_in *snsi;
348 char *host, *pos;
349 int port;
350
351 if ((pos = index(cfg->appPort, ':'))) {
352 host = apr_palloc(r->pool, (pos - cfg->appPort) + 3);
353 strncpy(host, cfg->appPort, (pos - cfg->appPort));
354 host[pos - cfg->appPort] = '\0';
355
356 port = atoi(pos + 1);
357 }
358 else {
359 host = "127.0.0.1";
360 port = atoi(cfg->appPort);
361 }
362
363 #if HEAVY_LOG
364 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
365 "appPort: '%s' host: %s port %d, cfg 0x%p",
366 cfg->appPort, host, port, cfg);
367 #endif
368
369 addressLen = sizeof(struct sockaddr_in);
370 address = apr_palloc(r->pool, sizeof(struct sockaddr_in));
371 memset(address, 0, sizeof(struct sockaddr_in));
372 snsi = (struct sockaddr_in *)address;
373
374 snsi->sin_addr.s_addr = apr_inet_addr(host);
375
376 snsi->sin_family = AF_INET;
377 snsi->sin_port = htons((short)(port & 0xFFFF));
378
379 if (snsi->sin_addr.s_addr == -1) {
380 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
381 "could not convert IP address: %s", host);
382 }
383 if (HEAVY_LOG && 0) {
384 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
385 "connect IP address: %s", host);
386 }
387 }
388 }
389 else {
390 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
391 "neither SNS port nor app port are set for request ...");
392 return 500;
393 }
394
395 if (addressLen > 10000) {
396 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
397 "suspect instance port length (%li) ...",
398 (long int) addressLen);
399 return 500;
400 }
401
402 _logInstanceAddress(r, address, addressLen, domain);
403
404 /* setup connection to application server */
405
406 if ((appFd = socket(domain, SOCK_STREAM, 0)) < 0) {
407 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
408 "could not create socket in domain %i.", domain);
409 return DECLINED;
410 }
411
412 if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
413 return 500;
414
415 toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
416 if (toApp == NULL) {
417 close(appFd);
418 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
419 "could not alloc socket buffer for "
420 "application server connection");
421 return 500;
422 }
423
424 /* write request to application server */
425
426 if (HEAVY_LOG) {
427 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
428 "transfer reqline");
429 }
430
431 {
432 char *reqLine;
433 unsigned toGo;
434
435 reqLine = r->the_request;
436 toGo = reqLine ? strlen(reqLine) : 0;
437
438 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
439 "req is %s(len=%i)", reqLine, toGo);
440
441 if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
442 reqLine ? strlen(reqLine) : 0)) {
443 writeError = 1;
444 goto writeErrorHandler;
445 }
446 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
447 writeError = 1;
448 goto writeErrorHandler;
449 }
450 }
451
452 /* transfer headers */
453
454 if (writeError == 0) {
455 if (HEAVY_LOG) {
456 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
457 "transfer hdrs");
458 }
459
460 /* extended adaptor headers */
461 {
462 char tmp[256];
463 const char *value;
464
465 value = r->protocol;
466 value = (value != NULL) ? value : "http";
467 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
468 "x-webobjects-server-protocol",
469 (unsigned char *)value)) {
470 writeError = 1;
471 goto writeErrorHandler;
472 }
473
474 if ((value = r->connection->client_ip) != NULL) {
475 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
476 "x-webobjects-remote-addr",
477 (unsigned char *)value)) {
478 writeError = 1;
479 goto writeErrorHandler;
480 }
481 }
482
483 value = r->connection->remote_host;
484 if (value == NULL) value = r->connection->client_ip;
485 if (value != NULL) {
486 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
487 "x-webobjects-remote-host",
488 (unsigned char *)value)) {
489 writeError = 1;
490 goto writeErrorHandler;
491 }
492 }
493
494 #ifdef AP_VERSION_1
495 if ((value = r->connection->ap_auth_type) != NULL) {
496 #else
497 if ((value = r->ap_auth_type) != NULL) {
498 #endif
499 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
500 "x-webobjects-auth-type",
501 (unsigned char *)value)) {
502 writeError = 1;
503 goto writeErrorHandler;
504 }
505 }
506
507 #ifdef AP_VERSION_1
508 if ((value = r->connection->user) != NULL) {
509 #else
510 if ((value = r->user) != NULL) {
511 #endif
512 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
513 "x-webobjects-remote-user",
514 (unsigned char *)value)) {
515 writeError = 1;
516 goto writeErrorHandler;
517 }
518 }
519
520 if (cfg != NULL) {
521 if (cfg->appPrefix != NULL) {
522 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
523 "x-webobjects-adaptor-prefix",
524 (unsigned char *)cfg->appPrefix)) {
525 writeError = 1;
526 goto writeErrorHandler;
527 }
528 }
529 }
530
531 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
532 "x-webobjects-server-name",
533 (unsigned char *)
534 r->server->server_hostname)) {
535 writeError = 1;
536 goto writeErrorHandler;
537 }
538
539 if (r->server->port != 0) {
540 apr_snprintf(tmp, sizeof(tmp), "%i", r->server->port);
541 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
542 "x-webobjects-server-port",
543 (unsigned char *)tmp)) {
544 writeError = 1;
545 goto writeErrorHandler;
546 }
547 }
548
549 // TODO: this seems to be broken with some Apache's!
550 // see: http://www.mail-archive.com/modssl-users@modssl.org/msg16396.html
551 if (r->server->port != 0) {
552 apr_snprintf(tmp, sizeof(tmp), "%s://%s:%i",
553 ap_http_method(r),
554 r->server->server_hostname,
555 r->server->port);
556 }
557 else {
558 apr_snprintf(tmp, sizeof(tmp), "%s://%s",
559 ap_http_method(r), r->server->server_hostname);
560 }
561 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
562 "x-webobjects-server-url",
563 (unsigned char *)tmp)) {
564 writeError = 1;
565 goto writeErrorHandler;
566 }
567
568 /* SSL environment */
569
570 if (r->subprocess_env != NULL) {
571 apr_table_t *env = r->subprocess_env;
572 const char *s;
573
574 s = apr_table_get(env, "HTTPS");
575 if (s != NULL && strncasecmp(s, "on", 2) == 0) { // SSL is one
576 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
577 "x-webobjects-https-enabled",
578 (unsigned char *)"1")) {
579 writeError = 1;
580 goto writeErrorHandler;
581 }
582 }
583
584 s = apr_table_get(env, "SSL_CLIENT_CERT");
585 if (s != NULL) {
586 const apr_array_header_t *array;
587 apr_table_entry_t *entries;
588 int i;
589
590 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
591 "x-webobjects-clients-cert",
592 (unsigned char *)s)) {
593 writeError = 1;
594 goto writeErrorHandler;
595 }
596
597 /* deliver all SSL_CLIENT_ env-vars as headers */
598 array = apr_table_elts(env);
599 entries = (apr_table_entry_t *)array->elts;
600 for (i = 0; i < array->nelts; i++) {
601 apr_table_entry_t *entry = &(entries[i]);
602
603 if (strncmp(entry->key, "SSL_CLIENT_", 11) != 0)
604 continue;
605 if (strncmp(entry->key, "SSL_CLIENT_CERT", 15) == 0)
606 continue; /* already avail as x-webobjects-clients-cert" */
607
608 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
609 entry->key,
610 (void *)entry->val)) {
611 writeError = 1;
612 goto writeErrorHandler;
613 }
614 }
615 }
616
617 /* keysize, don't know whether mapping is correct? */
618 if ((s = apr_table_get(env, "SSL_CIPHER_ALGKEYSIZE")) != NULL) {
619 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
620 "x-webobjects-https-secret-keysize",
621 (unsigned char *)s)) {
622 writeError = 1;
623 goto writeErrorHandler;
624 }
625 }
626 if ((s = apr_table_get(env, "SSL_CIPHER_USEKEYSIZE")) != NULL) {
627 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
628 "x-webobjects-https-keysize",
629 (unsigned char *)s)) {
630 writeError = 1;
631 goto writeErrorHandler;
632 }
633 }
634 }
635 }
636
637 /* http headers */
638 if (!_writeInHeaders(toApp, r)) {
639 writeError = 1;
640 goto writeErrorHandler;
641 }
642
643 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
644 writeError = 1;
645 goto writeErrorHandler;
646 }
647 if (!NGBufferedDescriptor_flush(toApp))
648 writeError = 1;
649 }
650
651 writeErrorHandler:
652 if (writeError == 1) {
653 if (toApp) {
654 NGBufferedDescriptor_free(toApp);
655 toApp = NULL;
656 }
657
658 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
659 "socket write error during transfer of HTTP header section");
660 return 500;
661 }
662
663 /* transfer request body */
664
665 if (requestContentLength > 0) {
666 if (!NGBufferedDescriptor_safeWrite(toApp,
667 requestBody,
668 requestContentLength)) {
669 if (toApp) {
670 NGBufferedDescriptor_free(toApp);
671 toApp = NULL;
672 }
673 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
674 "couldn't transfer HTTP req body to app server (%i bytes)",
675 contentLength);
676 return 500;
677 }
678 NGBufferedDescriptor_flush(toApp);
679 }
680 else {
681 if (HEAVY_LOG) {
682 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
683 "no content in request to transfer");
684 }
685 }
686
687 /* read response line */
688
689 if (!NGScanResponseLine(toApp, NULL, &statusCode, NULL)) {
690 if (toApp) {
691 NGBufferedDescriptor_free(toApp);
692 toApp = NULL;
693 }
694 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
695 "error during reading of response line ..");
696 return 500;
697 }
698 r->status = statusCode;
699 r->status_line = NULL;
700
701 /* process response headers */
702 {
703 apr_table_t *headers = NULL;
704
705 if (HEAVY_LOG)
706 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "scan headers");
707
708 if ((headers = NGScanHeaders(r->pool, toApp)) == NULL) {
709 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
710 "error during parsing of response headers ..");
711 }
712
713 _copyHeadersToRequest(r, headers, &contentLength);
714 #ifdef AP_VERSION_1
715 ap_send_http_header(r);
716 #endif
717 }
718
719 /* send response content */
720
721 if (!r->header_only) {
722 if (contentLength > 0) {
723 void *buffer = NULL;
724
725 if ((buffer = apr_pcalloc(r->pool, contentLength + 1)) == NULL) {
726 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
727 "could not allocate response buffer (size=%i)",
728 contentLength);
729 }
730
731 // read whole response
732 NGBufferedDescriptor_safeRead(toApp, buffer, contentLength);
733
734 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
735 "send response (size=%i)",
736 contentLength);
737 // send response to client
738 ap_rwrite(buffer, contentLength, r);
739 ap_rflush(r);
740 }
741 else if (contentLength == 0) {
742 // no content length header, read until EOF
743 unsigned char buffer[4096];
744 int result = 0;
745 int writeCount = 0;
746
747 while ((result = NGBufferedDescriptor_read(toApp,
748 buffer,
749 sizeof(buffer))
750 > 0)) {
751 ap_rwrite(buffer, result, r);
752 ap_rflush(r);
753 writeCount += result;
754 }
755
756 if (HEAVY_LOG && (writeCount > 0)) {
757 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
758 "write %i bytes (without content-length header)",
759 writeCount);
760 }
761 }
762 }
763
764 // close connection to app
765 if (toApp) {
766 NGBufferedDescriptor_free(toApp);
767 toApp = NULL;
768 }
769
770 return OK;
771 }
772
773 #if WITH_LOGGING
774 #if 0
775 static void test(void) {
776 fprintf(stderr,
777 "%s: called:\n"
778 " app: %s\n"
779 " uri: %s\n"
780 " pathinfo: %s\n"
781 " method: %s\n"
782 " protocol: %s\n"
783 " 1st: %s\n"
784 " host: %s\n"
785 " type: %s\n"
786 " handler: %s\n",
787 __PRETTY_FUNCTION__,
788 appName,
789 r->uri,
790 r->path_info,
791 r->method,
792 r->protocol,
793 r->the_request,
794 apr_table_get(r->headers_in, "content-length"),
795 r->content_type,
796 r->handler
797 );
798
799 _logTable(" out", r->headers_out);
800 _logTable(" err", r->err_headers_out);
801 _logTable(" env", r->subprocess_env);
802 _logTable(" in", r->headers_in);
803 }
804 #endif
805
806 static void _logTable(const char *text, apr_table_t *table) {
807 const apr_array_header_t *array;
808 apr_table_entry_t *entries;
809 int i;
810
811 if (table == NULL) {
812 fprintf(stderr, "%s: log NULL table.\n", text);
813 return;
814 }
815
816 array = apr_table_elts(table);
817 entries = (apr_table_entry_t *)array->elts;
818
819 if (array->nelts == 0) {
820 fprintf(stderr, "%s: empty\n", text);
821 return;
822 }
823
824 for (i = 0; i < array->nelts; i++) {
825 apr_table_entry_t *entry = &(entries[i]);
826
827 fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);
828 }
829 }
830 #endif