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);
205 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
207 result = connect(appFd, address, addressLen);
216 if (isConnected == 0) {
217 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
218 "connect to application instance failed, tried %i times.",
226 static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
227 const apr_array_header_t *array;
228 apr_table_entry_t *entries;
231 if (r->headers_in == NULL) return 1;
233 array = apr_table_elts(r->headers_in);
234 entries = (apr_table_entry_t *)array->elts;
236 for (i = 0; i < array->nelts; i++) {
237 apr_table_entry_t *entry = &(entries[i]);
239 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
240 entry->key, entry->val)) {
247 int ngobjweb_handler(request_rec *r) {
248 struct sockaddr *address = NULL;
252 NGBufferedDescriptor *toApp = NULL;
256 int contentLength = 0;
257 int statusCode = 500;
258 ngobjweb_dir_config *cfg;
260 unsigned requestContentLength;
264 requestContentLength = 0;
268 if (r->handler == NULL)
270 if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
274 if (uri == NULL) return DECLINED;
275 if (uri[0] != '/') return DECLINED;
276 if (strstr(uri, "WebServerResources")) return DECLINED;
278 /* get directory configuration */
280 if ((cfg = _getConfig(r))) {
281 if (cfg->appPrefix) {
283 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
284 "using prefix '%s'\n", cfg->appPrefix);
286 uri += strlen(cfg->appPrefix);
293 /* find app name in url */
294 _extractAppName(uri, appName, sizeof(appName));
296 /* before continuing, read request body */
298 requestBody = _readRequestBody(r, &contentLength);
299 requestContentLength = contentLength;
301 if ((requestBody == NULL) && (contentLength > 0))
302 /* read failed, error is logged in function */
305 /* ask SNS for server address */
308 address = _sendSNSQuery(r,
310 apr_table_get(r->headers_in, "cookie"),
311 &domain, &addressLen,
314 if (address == NULL) {
315 /* did not find an appropriate application server */
316 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
317 "did not find SOPE instance using SNS.");
321 else if (cfg->appPort) {
322 domain = cfg->appPortDomain;
324 if (cfg->appPortDomain == AF_UNIX) {
325 addressLen = sizeof(struct sockaddr_un);
326 address = apr_palloc(r->pool, sizeof(struct sockaddr_un));
327 memset(address, 0, sizeof(struct sockaddr_un));
329 ((struct sockaddr_un *)address)->sun_family = AF_UNIX;
330 strncpy(((struct sockaddr_un *)address)->sun_path,
332 sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
335 struct sockaddr_in *snsi;
340 port = atoi(cfg->appPort);
342 //ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
343 // "appPort: '%s', cfg 0x%08X", cfg->appPort, cfg);
345 addressLen = sizeof(struct sockaddr_in);
346 address = apr_palloc(r->pool, sizeof(struct sockaddr_in));
347 memset(address, 0, sizeof(struct sockaddr_in));
348 snsi = (struct sockaddr_in *)address;
350 snsi->sin_addr.s_addr = apr_inet_addr(host);
352 snsi->sin_family = AF_INET;
353 snsi->sin_port = htons((short)(port & 0xFFFF));
355 if (snsi->sin_addr.s_addr == -1) {
356 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
357 "couldn't convert snsd IP address: %s", host);
359 if (HEAVY_LOG && 0) {
360 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
361 "connect IP address: %s", host);
366 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
367 "neither SNS port nor app port are set for request ...");
371 if (addressLen > 10000) {
372 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
373 "suspect instance port length (%li) ...", (long int) addressLen);
377 _logInstanceAddress(r, address, addressLen, domain);
379 /* setup connection to application server */
381 if ((appFd = socket(domain, SOCK_STREAM, 0)) < 0) {
382 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
383 "could not create socket in domain %i.", domain);
387 if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
390 toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
393 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
394 "could not alloc socket buffer for "
395 "application server connection");
399 /* write request to application server */
402 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer reqline");
408 reqLine = r->the_request;
409 toGo = reqLine ? strlen(reqLine) : 0;
411 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
412 "req is %s(len=%i)", reqLine, toGo);
414 if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
415 reqLine ? strlen(reqLine) : 0)) {
417 goto writeErrorHandler;
419 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
421 goto writeErrorHandler;
425 /* transfer headers */
427 if (writeError == 0) {
429 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer hdrs");
431 /* extended adaptor headers */
437 value = value ? value : "http";
439 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
440 "x-webobjects-server-protocol",
443 goto writeErrorHandler;
447 if ((value = r->connection->remote_ip)) {
448 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
449 "x-webobjects-remote-addr",
452 goto writeErrorHandler;
456 value = r->connection->remote_host;
457 if (value == NULL) value = r->connection->remote_ip;
459 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
460 "x-webobjects-remote-host",
463 goto writeErrorHandler;
468 if ((value = r->connection->ap_auth_type)) {
470 if ((value = r->ap_auth_type)) {
472 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
473 "x-webobjects-auth-type",
476 goto writeErrorHandler;
481 if ((value = r->connection->user)) {
483 if ((value = r->user)) {
485 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
486 "x-webobjects-remote-user",
489 goto writeErrorHandler;
494 if (cfg->appPrefix) {
495 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
496 "x-webobjects-adaptor-prefix", cfg->appPrefix)) {
498 goto writeErrorHandler;
503 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
504 "x-webobjects-server-name",
505 r->server->server_hostname)) {
507 goto writeErrorHandler;
510 apr_snprintf(tmp, sizeof(tmp), "%i", r->server->port);
511 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
512 "x-webobjects-server-port",
515 goto writeErrorHandler;
518 // TODO: this seems to be broken with some Apache's!
519 // see: http://www.mail-archive.com/modssl-users@modssl.org/msg16396.html
520 apr_snprintf(tmp, sizeof(tmp), "%s://%s:%i",
522 r->server->server_hostname,
524 if (!NGBufferedDescriptor_writeHttpHeader(toApp,
525 "x-webobjects-server-url",
528 goto writeErrorHandler;
533 x-webobjects-clients-cert
534 x-webobjects-https-enabled
535 x-webobjects-https-keysize
536 x-webobjects-https-secret-keysize
541 if (!_writeInHeaders(toApp, r)) {
543 goto writeErrorHandler;
546 if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
548 goto writeErrorHandler;
550 if (!NGBufferedDescriptor_flush(toApp))
555 if (writeError == 1) {
556 if (toApp) NGBufferedDescriptor_free(toApp);
558 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
559 "socket write error during transfer of HTTP header section");
563 /* transfer request body */
565 if (requestContentLength > 0) {
566 if (!NGBufferedDescriptor_safeWrite(toApp,
568 requestContentLength)) {
569 if (toApp) NGBufferedDescriptor_free(toApp);
570 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
571 "couldn't transfer HTTP req body to app server (%i bytes)",
575 NGBufferedDescriptor_flush(toApp);
579 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
580 "no content in request to transfer");
584 /* read response line */
586 if (!NGScanResponseLine(toApp, NULL, &statusCode, NULL)) {
587 if (toApp) NGBufferedDescriptor_free(toApp);
588 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
589 "error during reading of response line ..");
592 r->status = statusCode;
593 r->status_line = NULL;
595 /* process response headers */
597 apr_table_t *headers = NULL;
600 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "scan headers");
602 if ((headers = NGScanHeaders(r->pool, toApp)) == NULL) {
603 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
604 "error during parsing of response headers ..");
607 _copyHeadersToRequest(r, headers, &contentLength);
609 ap_send_http_header(r);
613 /* send response content */
615 if (!r->header_only) {
616 if (contentLength > 0) {
619 if ((buffer = apr_pcalloc(r->pool, contentLength + 1)) == NULL) {
620 ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
621 "could not allocate response buffer (size=%i)",
625 // read whole response
626 if (!NGBufferedDescriptor_safeRead(toApp, buffer, contentLength)) {
627 if (toApp) NGBufferedDescriptor_free(toApp);
630 // close connection to app
632 NGBufferedDescriptor_free(toApp);
636 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
637 "send response (size=%i)",
639 // send response to client
640 ap_rwrite(buffer, contentLength, r);
643 else if (contentLength == 0) {
644 // no content length header, read until EOF
645 unsigned char buffer[4096];
650 result = NGBufferedDescriptor_read(toApp, buffer, sizeof(buffer));
652 ap_rwrite(buffer, result, r);
654 writeCount += result;
659 if (HEAVY_LOG && (writeCount > 0)) {
660 ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
661 "write %i bytes (without content-length header)",
671 static void test(void) {
690 apr_table_get(r->headers_in, "content-length"),
695 _logTable(" out", r->headers_out);
696 _logTable(" err", r->err_headers_out);
697 _logTable(" env", r->subprocess_env);
698 _logTable(" in", r->headers_in);
701 static void _logTable(const char *text, apr_table_t *table) {
702 apr_array_header_t *array;
703 apr_table_entry_t *entries;
707 fprintf(stderr, "%s: log NULL table.\n", text);
711 array = apr_table_elts(table);
712 entries = (apr_table_entry_t *)array->elts;
714 if (array->nelts == 0) {
715 fprintf(stderr, "%s: empty\n", text);
719 for (i = 0; i < array->nelts; i++) {
720 apr_table_entry_t *entry = &(entries[i]);
722 fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);