2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo 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
11 OGo 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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
30 static void _logTable(const char *text, apr_table_t *table);
33 static ngobjweb_dir_config *_getConfig(request_rec *r) {
34 ngobjweb_dir_config *cfg;
37 fprintf(stderr, "%s: missing request !\n", __PRETTY_FUNCTION__);
40 if (r->per_dir_config == NULL) {
41 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
42 "missing directory config in request ...");
46 cfg = (ngobjweb_dir_config *)
47 ap_get_module_config(r->per_dir_config, &ngobjweb_module);
52 static void _extractAppName(const char *uri, char *appName, int maxLen) {
55 /* extract name of application */
56 if ((tmp = index(uri + 1, '/'))) {
58 len = (tmp - (uri + 1));
59 strncpy(appName, (uri + 1), len);
63 strncpy(appName, (uri + 1), maxLen - 1);
64 appName[maxLen - 1] = '\0';
67 /* cut off .woa extension from application name */
68 if ((tmp = strstr(appName, ".woa")))
71 /* cut off .sky extension from application name */
72 if ((tmp = strstr(appName, ".sky")))
76 static void *_readRequestBody(request_rec *r, int *requestContentLength) {
80 int readBytes, toBeRead;
83 clen = apr_table_get(r->headers_in, "content-length");
84 contentLength = clen ? atoi(clen) : 0;
85 *requestContentLength = contentLength;
87 /* no content to read ... */
88 if (contentLength == 0) return NULL;
93 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
94 "going to read %i bytes from browser ...", contentLength);
97 requestBody = apr_palloc(r->pool, contentLength + 2);
100 for (toBeRead = contentLength; toBeRead > 0;) {
102 readBytes = ap_bread(r->connection->client, ptr, toBeRead);
104 ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
105 readBytes = ap_get_client_block(r, ptr, toBeRead);
107 toBeRead -= readBytes;
109 if (readBytes == 0) break;
114 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
115 "couldn't read complete HTTP req body from browser "
116 "(read %i of %i bytes)",
117 (contentLength - toBeRead), contentLength);
125 _copyHeadersToRequest(request_rec *r, apr_table_t *headers, int *contentLength)
127 const apr_array_header_t *array;
128 apr_table_entry_t *entries;
132 if (headers == NULL) return;
134 value = apr_table_get(headers, "content-type");
135 if (value) r->content_type = value;
136 value = apr_table_get(headers, "content-encoding");
137 if (value) r->content_encoding = value;
138 value = apr_table_get(headers, "content-length");
139 *contentLength = value ? atoi(value) : 0;
141 array = apr_table_elts(headers);
142 entries = (apr_table_entry_t *)array->elts;
144 for (i = 0; i < array->nelts; i++) {
145 apr_table_entry_t *entry = &(entries[i]);
147 apr_table_set(r->headers_out, entry->key, entry->val);
149 // _logTable("out", r->headers_out);
152 static void _logInstanceAddress(request_rec *r, struct sockaddr *address,
153 size_t addressLen, int domain)
157 if (!HEAVY_LOG) return;
159 apr_snprintf(buf, sizeof(buf), " => address len=%li domain=%i<", (long int) addressLen, domain);
161 case AF_INET: strcat(buf, "inet"); break;
162 case AF_UNIX: strcat(buf, "unix"); break;
163 default: strcat(buf, "unknown"); break;
167 if (domain == AF_UNIX) {
168 strcat(buf, " path=\"");
169 strcat(buf, ((struct sockaddr_un *)address)->sun_path);
172 else if (domain == AF_INET) {
177 ptr = inet_ntoa(((struct sockaddr_in *)address)->sin_addr);
178 port = ntohs(((struct sockaddr_in *)address)->sin_port);
179 apr_snprintf(sport, sizeof(sport), "host=\"%s\" port=%i", ptr, port);
183 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, buf);
186 static int _connectInstance(request_rec *r,
187 int appFd, struct sockaddr *address,
192 char isConnected = 0;
194 result = connect(appFd, address, addressLen);
195 if (result >= 0) return result;
197 while (tryCount < 3) {
198 char *pdelay = NULL; /* pblock_findval("delay", _paras) */
199 int delay = pdelay ? atoi(pdelay) : 3; // default: 3s
201 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
202 "sleeping %is ..", delay);
204 apr_sleep(delay); /* should be in seconds for Apache 1? */
206 apr_sleep(delay * 1000 * 1000 /* in microseconds now! */);
209 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
211 result = connect(appFd, address, addressLen);
220 if (isConnected == 0) {
221 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
222 "connect to application instance failed, tried %i times.",
230 static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
231 const apr_array_header_t *array;
232 apr_table_entry_t *entries;
235 if (r->headers_in == NULL) return 1;
237 array = apr_table_elts(r->headers_in);
238 entries = (apr_table_entry_t *)array->elts;
240 for (i = 0; i < array->nelts; i++) {
241 apr_table_entry_t *entry = &(entries[i]);
243 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
244 entry->key, entry->val)) {
251 int ngobjweb_handler(request_rec *r) {
252 struct sockaddr *address = NULL;
256 NGBufferedDescriptor *toApp = NULL;
260 int contentLength = 0;
261 int statusCode = 500;
262 ngobjweb_dir_config *cfg;
264 unsigned requestContentLength;
268 requestContentLength = 0;
272 if (r->handler == NULL)
274 if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
278 if (uri == NULL) return DECLINED;
279 if (uri[0] != '/') return DECLINED;
280 if (strstr(uri, "WebServerResources")) return DECLINED;
282 /* get directory configuration */
284 if ((cfg = _getConfig(r))) {
285 if (cfg->appPrefix) {
287 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
288 "using prefix '%s'\n", cfg->appPrefix);
290 uri += strlen(cfg->appPrefix);
297 /* find app name in url */
298 _extractAppName(uri, appName, sizeof(appName));
300 /* before continuing, read request body */
302 requestBody = _readRequestBody(r, &contentLength);
303 requestContentLength = contentLength;
305 if ((requestBody == NULL) && (contentLength > 0))
306 /* read failed, error is logged in function */
309 /* ask SNS for server address */
312 address = _sendSNSQuery(r,
314 apr_table_get(r->headers_in, "cookie"),
315 &domain, &addressLen,
318 if (address == NULL) {
319 /* did not find an appropriate application server */
320 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
321 "did not find SOPE instance using SNS.");
325 else if (cfg->appPort) {
326 domain = cfg->appPortDomain;
328 if (cfg->appPortDomain == AF_UNIX) {
329 addressLen = sizeof(struct sockaddr_un);
330 address = apr_palloc(r->pool, sizeof(struct sockaddr_un));
331 memset(address, 0, sizeof(struct sockaddr_un));
333 ((struct sockaddr_un *)address)->sun_family = AF_UNIX;
334 strncpy(((struct sockaddr_un *)address)->sun_path,
336 sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
339 struct sockaddr_in *snsi;
344 port = atoi(cfg->appPort);
346 //ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
347 // "appPort: '%s', cfg 0x%08X", cfg->appPort, cfg);
349 addressLen = sizeof(struct sockaddr_in);
350 address = apr_palloc(r->pool, sizeof(struct sockaddr_in));
351 memset(address, 0, sizeof(struct sockaddr_in));
352 snsi = (struct sockaddr_in *)address;
354 snsi->sin_addr.s_addr = apr_inet_addr(host);
356 snsi->sin_family = AF_INET;
357 snsi->sin_port = htons((short)(port & 0xFFFF));
359 if (snsi->sin_addr.s_addr == -1) {
360 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
361 "couldn't convert snsd IP address: %s", host);
363 if (HEAVY_LOG && 0) {
364 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
365 "connect IP address: %s", host);
370 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
371 "neither SNS port nor app port are set for request ...");
375 if (addressLen > 10000) {
376 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
377 "suspect instance port length (%li) ...", (long int) addressLen);
381 _logInstanceAddress(r, address, addressLen, domain);
383 /* setup connection to application server */
385 if ((appFd = socket(domain, SOCK_STREAM, 0)) < 0) {
386 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
387 "could not create socket in domain %i.", domain);
391 if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
394 toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
397 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
398 "could not alloc socket buffer for "
399 "application server connection");
403 /* write request to application server */
406 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer reqline");
412 reqLine = r->the_request;
413 toGo = reqLine ? strlen(reqLine) : 0;
415 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
416 "req is %s(len=%i)", reqLine, toGo);
418 if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
419 reqLine ? strlen(reqLine) : 0)) {
421 goto writeErrorHandler;
423 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
425 goto writeErrorHandler;
429 /* transfer headers */
431 if (writeError == 0) {
433 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer hdrs");
435 /* extended adaptor headers */
441 value = value ? value : "http";
443 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
444 "x-webobjects-server-protocol",
447 goto writeErrorHandler;
451 if ((value = r->connection->remote_ip)) {
452 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
453 "x-webobjects-remote-addr",
456 goto writeErrorHandler;
460 value = r->connection->remote_host;
461 if (value == NULL) value = r->connection->remote_ip;
463 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
464 "x-webobjects-remote-host",
467 goto writeErrorHandler;
472 if ((value = r->connection->ap_auth_type)) {
474 if ((value = r->ap_auth_type)) {
476 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
477 "x-webobjects-auth-type",
480 goto writeErrorHandler;
485 if ((value = r->connection->user)) {
487 if ((value = r->user)) {
489 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
490 "x-webobjects-remote-user",
493 goto writeErrorHandler;
498 if (cfg->appPrefix) {
499 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
500 "x-webobjects-adaptor-prefix", cfg->appPrefix)) {
502 goto writeErrorHandler;
507 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
508 "x-webobjects-server-name",
509 r->server->server_hostname)) {
511 goto writeErrorHandler;
514 apr_snprintf(tmp, sizeof(tmp), "%i", r->server->port);
515 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
516 "x-webobjects-server-port",
519 goto writeErrorHandler;
522 // TODO: this seems to be broken with some Apache's!
523 // see: http://www.mail-archive.com/modssl-users@modssl.org/msg16396.html
524 apr_snprintf(tmp, sizeof(tmp), "%s://%s:%i",
526 r->server->server_hostname,
528 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
529 "x-webobjects-server-url",
532 goto writeErrorHandler;
537 x-webobjects-clients-cert
538 x-webobjects-https-enabled
539 x-webobjects-https-keysize
540 x-webobjects-https-secret-keysize
545 if (!_writeInHeaders(toApp, r)) {
547 goto writeErrorHandler;
550 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
552 goto writeErrorHandler;
554 if (!NGBufferedDescriptor_flush(toApp))
559 if (writeError == 1) {
560 if (toApp) NGBufferedDescriptor_free(toApp);
562 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
563 "socket write error during transfer of HTTP header section");
567 /* transfer request body */
569 if (requestContentLength > 0) {
570 if (!NGBufferedDescriptor_safeWrite(toApp,
572 requestContentLength)) {
573 if (toApp) NGBufferedDescriptor_free(toApp);
574 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
575 "couldn't transfer HTTP req body to app server (%i bytes)",
579 NGBufferedDescriptor_flush(toApp);
583 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
584 "no content in request to transfer");
588 /* read response line */
590 if (!NGScanResponseLine(toApp, NULL, &statusCode, NULL)) {
591 if (toApp) NGBufferedDescriptor_free(toApp);
592 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
593 "error during reading of response line ..");
596 r->status = statusCode;
597 r->status_line = NULL;
599 /* process response headers */
601 apr_table_t *headers = NULL;
604 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "scan headers");
606 if ((headers = NGScanHeaders(r->pool, toApp)) == NULL) {
607 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
608 "error during parsing of response headers ..");
611 _copyHeadersToRequest(r, headers, &contentLength);
613 ap_send_http_header(r);
617 /* send response content */
619 if (!r->header_only) {
620 if (contentLength > 0) {
623 if ((buffer = apr_pcalloc(r->pool, contentLength + 1)) == NULL) {
624 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
625 "could not allocate response buffer (size=%i)",
629 // read whole response
630 if (!NGBufferedDescriptor_safeRead(toApp, buffer, contentLength)) {
631 if (toApp) NGBufferedDescriptor_free(toApp);
634 // close connection to app
636 NGBufferedDescriptor_free(toApp);
640 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
641 "send response (size=%i)",
643 // send response to client
644 ap_rwrite(buffer, contentLength, r);
647 else if (contentLength == 0) {
648 // no content length header, read until EOF
649 unsigned char buffer[4096];
654 result = NGBufferedDescriptor_read(toApp, buffer, sizeof(buffer));
656 ap_rwrite(buffer, result, r);
658 writeCount += result;
663 if (HEAVY_LOG && (writeCount > 0)) {
664 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
665 "write %i bytes (without content-length header)",
675 static void test(void) {
694 apr_table_get(r->headers_in, "content-length"),
699 _logTable(" out", r->headers_out);
700 _logTable(" err", r->err_headers_out);
701 _logTable(" env", r->subprocess_env);
702 _logTable(" in", r->headers_in);
705 static void _logTable(const char *text, apr_table_t *table) {
706 apr_array_header_t *array;
707 apr_table_entry_t *entries;
711 fprintf(stderr, "%s: log NULL table.\n", text);
715 array = apr_table_elts(table);
716 entries = (apr_table_entry_t *)array->elts;
718 if (array->nelts == 0) {
719 fprintf(stderr, "%s: empty\n", text);
723 for (i = 0; i < array->nelts; i++) {
724 apr_table_entry_t *entry = &(entries[i]);
726 fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);