2
Copyright (C) 2000-2005 SKYRIX Software AG
4
This file is part of SOPE.
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
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.
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
29
static void _logTable(const char *text, apr_table_t *table);
32
static ngobjweb_dir_config *_getConfig(request_rec *r) {
33
ngobjweb_dir_config *cfg;
36
fprintf(stderr, "%s: missing request !\n", __PRETTY_FUNCTION__);
39
if (r->per_dir_config == NULL) {
40
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
41
"missing directory config in request ...");
45
cfg = (ngobjweb_dir_config *)
46
ap_get_module_config(r->per_dir_config, &ngobjweb_module);
51
static void _extractAppName(const char *uri, char *appName, int maxLen) {
54
/* extract name of application */
55
if ((tmp = index(uri + 1, '/'))) {
57
len = (tmp - (uri + 1));
58
strncpy(appName, (uri + 1), len);
62
strncpy(appName, (uri + 1), maxLen - 1);
63
appName[maxLen - 1] = '\0';
66
/* cut off .woa extension from application name */
67
if ((tmp = strstr(appName, ".woa")))
70
/* cut off .sky extension from application name */
71
if ((tmp = strstr(appName, ".sky")))
75
static void *_readRequestBody(request_rec *r, int *requestContentLength) {
79
int readBytes, toBeRead;
82
clen = apr_table_get(r->headers_in, "content-length");
83
contentLength = clen ? atoi(clen) : 0;
84
*requestContentLength = contentLength;
86
/* no content to read ... */
87
if (contentLength == 0) return NULL;
92
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
93
"going to read %i bytes from browser ...", contentLength);
96
requestBody = apr_palloc(r->pool, contentLength + 2);
99
for (toBeRead = contentLength; toBeRead > 0;) {
101
readBytes = ap_bread(r->connection->client, ptr, toBeRead);
103
ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
104
readBytes = ap_get_client_block(r, ptr, toBeRead);
106
toBeRead -= readBytes;
108
if (readBytes == 0) break;
113
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
114
"couldn't read complete HTTP req body from browser "
115
"(read %i of %i bytes)",
116
(contentLength - toBeRead), contentLength);
124
_copyHeadersToRequest(request_rec *r, apr_table_t *headers, int *contentLength)
126
const apr_array_header_t *array;
127
apr_table_entry_t *entries;
131
if (headers == NULL) return;
133
value = apr_table_get(headers, "content-type");
134
if (value) r->content_type = value;
135
value = apr_table_get(headers, "content-encoding");
136
if (value) r->content_encoding = value;
137
value = apr_table_get(headers, "content-length");
138
*contentLength = value ? atoi(value) : 0;
140
array = apr_table_elts(headers);
141
entries = (apr_table_entry_t *)array->elts;
143
for (i = 0; i < array->nelts; i++) {
144
apr_table_entry_t *entry = &(entries[i]);
146
apr_table_set(r->headers_out, entry->key, entry->val);
148
// _logTable("out", r->headers_out);
151
static void _logInstanceAddress(request_rec *r, struct sockaddr *address,
152
size_t addressLen, int domain)
156
if (!HEAVY_LOG) return;
158
apr_snprintf(buf, sizeof(buf), " => address len=%li domain=%i<", (long int) addressLen, domain);
160
case AF_INET: strcat(buf, "inet"); break;
161
case AF_UNIX: strcat(buf, "unix"); break;
162
default: strcat(buf, "unknown"); break;
166
if (domain == AF_UNIX) {
167
strcat(buf, " path=\"");
168
strcat(buf, ((struct sockaddr_un *)address)->sun_path);
171
else if (domain == AF_INET) {
176
ptr = inet_ntoa(((struct sockaddr_in *)address)->sin_addr);
177
port = ntohs(((struct sockaddr_in *)address)->sin_port);
178
apr_snprintf(sport, sizeof(sport), "host=\"%s\" port=%i", ptr, port);
182
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, buf);
185
static int _connectInstance(request_rec *r,
186
int appFd, struct sockaddr *address,
191
char isConnected = 0;
193
result = connect(appFd, address, addressLen);
194
if (result >= 0) return result;
196
while (tryCount < 3) {
197
char *pdelay = NULL; /* pblock_findval("delay", _paras) */
198
int delay = pdelay ? atoi(pdelay) : 3; // default: 3s
200
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
201
"sleeping %is ..", delay);
203
apr_sleep(delay); /* should be in seconds for Apache 1? */
205
apr_sleep(delay * 1000 * 1000 /* in microseconds now! */);
208
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
210
result = connect(appFd, address, addressLen);
219
if (isConnected == 0) {
220
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
221
"connect to application instance failed, tried %i times.",
229
static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
230
const apr_array_header_t *array;
231
apr_table_entry_t *entries;
234
if (r->headers_in == NULL) return 1;
236
array = apr_table_elts(r->headers_in);
237
entries = (apr_table_entry_t *)array->elts;
239
for (i = 0; i < array->nelts; i++) {
240
apr_table_entry_t *entry = &(entries[i]);
242
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
243
entry->key, entry->val)) {
250
int ngobjweb_handler(request_rec *r) {
251
struct sockaddr *address = NULL;
255
NGBufferedDescriptor *toApp = NULL;
259
int contentLength = 0;
260
int statusCode = 500;
261
ngobjweb_dir_config *cfg;
263
unsigned requestContentLength;
267
requestContentLength = 0;
271
if (r->handler == NULL)
273
if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
277
if (uri == NULL) return DECLINED;
278
if (uri[0] != '/') return DECLINED;
279
if (strstr(uri, "WebServerResources")) return DECLINED;
281
/* get directory configuration */
283
if ((cfg = _getConfig(r))) {
284
if (cfg->appPrefix) {
286
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
287
"using prefix '%s'\n", cfg->appPrefix);
289
uri += strlen(cfg->appPrefix);
296
/* find app name in url */
297
_extractAppName(uri, appName, sizeof(appName));
299
/* before continuing, read request body */
301
requestBody = _readRequestBody(r, &contentLength);
302
requestContentLength = contentLength;
304
if ((requestBody == NULL) && (contentLength > 0))
305
/* read failed, error is logged in function */
308
/* ask SNS for server address */
311
address = _sendSNSQuery(r,
313
apr_table_get(r->headers_in, "cookie"),
314
&domain, &addressLen,
317
if (address == NULL) {
318
/* did not find an appropriate application server */
319
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
320
"did not find SOPE instance using SNS.");
324
else if (cfg->appPort) {
325
domain = cfg->appPortDomain;
327
if (cfg->appPortDomain == AF_UNIX) {
328
addressLen = sizeof(struct sockaddr_un);
329
address = apr_palloc(r->pool, sizeof(struct sockaddr_un));
330
memset(address, 0, sizeof(struct sockaddr_un));
332
((struct sockaddr_un *)address)->sun_family = AF_UNIX;
333
strncpy(((struct sockaddr_un *)address)->sun_path,
335
sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
338
struct sockaddr_in *snsi;
343
port = atoi(cfg->appPort);
345
//ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
346
// "appPort: '%s', cfg 0x%08X", cfg->appPort, cfg);
348
addressLen = sizeof(struct sockaddr_in);
349
address = apr_palloc(r->pool, sizeof(struct sockaddr_in));
350
memset(address, 0, sizeof(struct sockaddr_in));
351
snsi = (struct sockaddr_in *)address;
353
snsi->sin_addr.s_addr = apr_inet_addr(host);
355
snsi->sin_family = AF_INET;
356
snsi->sin_port = htons((short)(port & 0xFFFF));
358
if (snsi->sin_addr.s_addr == -1) {
359
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
360
"couldn't convert snsd IP address: %s", host);
362
if (HEAVY_LOG && 0) {
363
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
364
"connect IP address: %s", host);
369
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
370
"neither SNS port nor app port are set for request ...");
374
if (addressLen > 10000) {
375
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
376
"suspect instance port length (%li) ...", (long int) addressLen);
380
_logInstanceAddress(r, address, addressLen, domain);
382
/* setup connection to application server */
384
if ((appFd = socket(domain, SOCK_STREAM, 0)) < 0) {
385
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
386
"could not create socket in domain %i.", domain);
390
if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
393
toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
396
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
397
"could not alloc socket buffer for "
398
"application server connection");
402
/* write request to application server */
405
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer reqline");
411
reqLine = r->the_request;
412
toGo = reqLine ? strlen(reqLine) : 0;
414
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
415
"req is %s(len=%i)", reqLine, toGo);
417
if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
418
reqLine ? strlen(reqLine) : 0)) {
420
goto writeErrorHandler;
422
if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
424
goto writeErrorHandler;
428
/* transfer headers */
430
if (writeError == 0) {
432
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer hdrs");
434
/* extended adaptor headers */
440
value = value ? value : "http";
442
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
443
"x-webobjects-server-protocol",
446
goto writeErrorHandler;
450
if ((value = r->connection->remote_ip)) {
451
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
452
"x-webobjects-remote-addr",
455
goto writeErrorHandler;
459
value = r->connection->remote_host;
460
if (value == NULL) value = r->connection->remote_ip;
462
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
463
"x-webobjects-remote-host",
466
goto writeErrorHandler;
471
if ((value = r->connection->ap_auth_type)) {
473
if ((value = r->ap_auth_type)) {
475
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
476
"x-webobjects-auth-type",
479
goto writeErrorHandler;
484
if ((value = r->connection->user)) {
486
if ((value = r->user)) {
488
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
489
"x-webobjects-remote-user",
492
goto writeErrorHandler;
497
if (cfg->appPrefix != NULL) {
498
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
499
"x-webobjects-adaptor-prefix", cfg->appPrefix)) {
501
goto writeErrorHandler;
506
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
507
"x-webobjects-server-name",
508
r->server->server_hostname)) {
510
goto writeErrorHandler;
513
if (r->server->port != 0) {
514
apr_snprintf(tmp, sizeof(tmp), "%i", r->server->port);
515
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
516
"x-webobjects-server-port",
519
goto writeErrorHandler;
523
// TODO: this seems to be broken with some Apache's!
524
// see: http://www.mail-archive.com/modssl-users@modssl.org/msg16396.html
525
if (r->server->port != 0) {
526
apr_snprintf(tmp, sizeof(tmp), "%s://%s:%i",
528
r->server->server_hostname,
532
apr_snprintf(tmp, sizeof(tmp), "%s://%s",
533
ap_http_method(r), r->server->server_hostname);
535
if (!NGBufferedDescriptor_writeHttpHeader(toApp,
536
"x-webobjects-server-url",
539
goto writeErrorHandler;
544
x-webobjects-clients-cert
545
x-webobjects-https-enabled
546
x-webobjects-https-keysize
547
x-webobjects-https-secret-keysize
552
if (!_writeInHeaders(toApp, r)) {
554
goto writeErrorHandler;
557
if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
559
goto writeErrorHandler;
561
if (!NGBufferedDescriptor_flush(toApp))
566
if (writeError == 1) {
567
if (toApp) NGBufferedDescriptor_free(toApp);
569
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
570
"socket write error during transfer of HTTP header section");
574
/* transfer request body */
576
if (requestContentLength > 0) {
577
if (!NGBufferedDescriptor_safeWrite(toApp,
579
requestContentLength)) {
580
if (toApp) NGBufferedDescriptor_free(toApp);
581
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
582
"couldn't transfer HTTP req body to app server (%i bytes)",
586
NGBufferedDescriptor_flush(toApp);
590
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
591
"no content in request to transfer");
595
/* read response line */
597
if (!NGScanResponseLine(toApp, NULL, &statusCode, NULL)) {
598
if (toApp) NGBufferedDescriptor_free(toApp);
599
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
600
"error during reading of response line ..");
603
r->status = statusCode;
604
r->status_line = NULL;
606
/* process response headers */
608
apr_table_t *headers = NULL;
611
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "scan headers");
613
if ((headers = NGScanHeaders(r->pool, toApp)) == NULL) {
614
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
615
"error during parsing of response headers ..");
618
_copyHeadersToRequest(r, headers, &contentLength);
620
ap_send_http_header(r);
624
/* send response content */
626
if (!r->header_only) {
627
if (contentLength > 0) {
630
if ((buffer = apr_pcalloc(r->pool, contentLength + 1)) == NULL) {
631
ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
632
"could not allocate response buffer (size=%i)",
636
// read whole response
637
if (!NGBufferedDescriptor_safeRead(toApp, buffer, contentLength)) {
638
if (toApp) NGBufferedDescriptor_free(toApp);
641
// close connection to app
643
NGBufferedDescriptor_free(toApp);
647
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
648
"send response (size=%i)",
650
// send response to client
651
ap_rwrite(buffer, contentLength, r);
654
else if (contentLength == 0) {
655
// no content length header, read until EOF
656
unsigned char buffer[4096];
661
result = NGBufferedDescriptor_read(toApp, buffer, sizeof(buffer));
663
ap_rwrite(buffer, result, r);
665
writeCount += result;
670
if (HEAVY_LOG && (writeCount > 0)) {
671
ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
672
"write %i bytes (without content-length header)",
682
static void test(void) {
701
apr_table_get(r->headers_in, "content-length"),
706
_logTable(" out", r->headers_out);
707
_logTable(" err", r->err_headers_out);
708
_logTable(" env", r->subprocess_env);
709
_logTable(" in", r->headers_in);
712
static void _logTable(const char *text, apr_table_t *table) {
713
apr_array_header_t *array;
714
apr_table_entry_t *entries;
718
fprintf(stderr, "%s: log NULL table.\n", text);
722
array = apr_table_elts(table);
723
entries = (apr_table_entry_t *)array->elts;
725
if (array->nelts == 0) {
726
fprintf(stderr, "%s: empty\n", text);
730
for (i = 0; i < array->nelts; i++) {
731
apr_table_entry_t *entry = &(entries[i]);
733
fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);