~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to sope-appserver/mod_ngobjweb/handler.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2000-2005 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
extern int HEAVY_LOG;
 
27
 
 
28
#if WITH_LOGGING
 
29
static void _logTable(const char *text, apr_table_t *table);
 
30
#endif
 
31
 
 
32
static ngobjweb_dir_config *_getConfig(request_rec *r) {
 
33
  ngobjweb_dir_config *cfg;
 
34
 
 
35
  if (r == NULL) {
 
36
    fprintf(stderr, "%s: missing request !\n", __PRETTY_FUNCTION__);
 
37
    return NULL;
 
38
  }
 
39
  if (r->per_dir_config == NULL) {
 
40
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
41
                 "missing directory config in request ...");
 
42
    return NULL;
 
43
  }
 
44
  
 
45
  cfg = (ngobjweb_dir_config *)
 
46
    ap_get_module_config(r->per_dir_config, &ngobjweb_module);
 
47
  
 
48
  return cfg;
 
49
}
 
50
 
 
51
static void _extractAppName(const char *uri, char *appName, int maxLen) {
 
52
  char *tmp;
 
53
  
 
54
  /* extract name of application */
 
55
  if ((tmp = index(uri + 1, '/'))) {
 
56
    int len;
 
57
    len = (tmp - (uri + 1));
 
58
    strncpy(appName, (uri + 1), len);
 
59
    appName[len] = '\0';
 
60
  }
 
61
  else {
 
62
    strncpy(appName, (uri + 1), maxLen - 1);
 
63
    appName[maxLen - 1] = '\0';
 
64
  }
 
65
  
 
66
  /* cut off .woa extension from application name */
 
67
  if ((tmp = strstr(appName, ".woa")))
 
68
    *tmp = '\0';
 
69
  
 
70
  /* cut off .sky extension from application name */
 
71
  if ((tmp = strstr(appName, ".sky")))
 
72
    *tmp = '\0';
 
73
}
 
74
 
 
75
static void *_readRequestBody(request_rec *r, int *requestContentLength) {
 
76
  const char *clen;
 
77
  int  contentLength;
 
78
  void *ptr;
 
79
  int  readBytes, toBeRead;
 
80
  void *requestBody;
 
81
  
 
82
  clen = apr_table_get(r->headers_in, "content-length");
 
83
  contentLength = clen ? atoi(clen) : 0;
 
84
  *requestContentLength = contentLength;
 
85
  
 
86
  /* no content to read ... */
 
87
  if (contentLength == 0) return NULL;
 
88
  
 
89
  /* read content */
 
90
  
 
91
  if (HEAVY_LOG) {
 
92
    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, 
 
93
                 "going to read %i bytes from browser ...", contentLength);
 
94
  }
 
95
  
 
96
  requestBody = apr_palloc(r->pool, contentLength + 2);
 
97
 
 
98
  ptr = requestBody;
 
99
  for (toBeRead = contentLength; toBeRead > 0;) {
 
100
#ifdef AP_VERSION_1
 
101
    readBytes = ap_bread(r->connection->client, ptr, toBeRead);
 
102
#else
 
103
                ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
 
104
    readBytes = ap_get_client_block(r, ptr, toBeRead);
 
105
#endif
 
106
    toBeRead -= readBytes;
 
107
    ptr += readBytes;
 
108
    if (readBytes == 0) break;
 
109
  }
 
110
  ptr = NULL;
 
111
      
 
112
  if (toBeRead > 0) {
 
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);
 
117
    return NULL;
 
118
  }
 
119
  
 
120
  return requestBody;
 
121
}
 
122
 
 
123
static void
 
124
_copyHeadersToRequest(request_rec *r, apr_table_t *headers, int *contentLength)
 
125
{
 
126
  const apr_array_header_t *array;
 
127
  apr_table_entry_t  *entries;
 
128
  int          i;
 
129
  const char   *value;
 
130
  
 
131
  if (headers == NULL) return;
 
132
  
 
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;
 
139
  
 
140
  array   = apr_table_elts(headers);
 
141
  entries = (apr_table_entry_t *)array->elts;
 
142
 
 
143
  for (i = 0; i < array->nelts; i++) {
 
144
    apr_table_entry_t *entry = &(entries[i]);
 
145
 
 
146
    apr_table_set(r->headers_out, entry->key, entry->val);
 
147
  }
 
148
  // _logTable("out", r->headers_out);
 
149
}
 
150
 
 
151
static void _logInstanceAddress(request_rec *r, struct sockaddr *address,
 
152
                                size_t addressLen, int domain)
 
153
{
 
154
  char buf[1024];
 
155
  
 
156
  if (!HEAVY_LOG) return;
 
157
  
 
158
  apr_snprintf(buf, sizeof(buf), "  => address len=%li domain=%i<", (long int) addressLen, domain);
 
159
  switch (domain) {
 
160
    case AF_INET: strcat(buf, "inet"); break;
 
161
    case AF_UNIX: strcat(buf, "unix"); break;
 
162
    default: strcat(buf, "unknown"); break;
 
163
  }
 
164
  strcat(buf, ">");
 
165
  
 
166
  if (domain == AF_UNIX) {
 
167
    strcat(buf, " path=\"");
 
168
    strcat(buf, ((struct sockaddr_un *)address)->sun_path);
 
169
    strcat(buf, "\"");
 
170
  }
 
171
  else if (domain == AF_INET) {
 
172
    char         *ptr = NULL;
 
173
    int  port;
 
174
    char sport[256];
 
175
    
 
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);
 
179
    strcat(buf, sport);
 
180
  }
 
181
  
 
182
  ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, buf);
 
183
}
 
184
 
 
185
static int _connectInstance(request_rec *r,
 
186
                            int appFd, struct sockaddr *address,
 
187
                            size_t addressLen)
 
188
{
 
189
  int  result;
 
190
  int  tryCount = 0;
 
191
  char isConnected = 0;
 
192
  
 
193
  result = connect(appFd, address, addressLen);
 
194
  if (result >= 0) return result;
 
195
  
 
196
  while (tryCount < 3) {
 
197
    char *pdelay = NULL; /* pblock_findval("delay", _paras) */
 
198
    int delay    = pdelay ? atoi(pdelay) : 3; // default: 3s
 
199
 
 
200
    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
201
                 "sleeping %is ..", delay);
 
202
#ifdef AP_VERSION_1
 
203
    apr_sleep(delay); /* should be in seconds for Apache 1? */
 
204
#else
 
205
    apr_sleep(delay * 1000 * 1000 /* in microseconds now! */);
 
206
#endif
 
207
    
 
208
    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
209
                 "retry connect ..");
 
210
    result = connect(appFd, address, addressLen);
 
211
    
 
212
    if (result >= 0) {
 
213
      isConnected = 1;
 
214
      break;
 
215
    }
 
216
    tryCount++;
 
217
  }
 
218
  
 
219
  if (isConnected == 0) {
 
220
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
221
                 "connect to application instance failed, tried %i times.",
 
222
                 tryCount);
 
223
    close(appFd);
 
224
    return -1;
 
225
  }
 
226
  return result;
 
227
}
 
228
 
 
229
static int _writeInHeaders(NGBufferedDescriptor *toApp, request_rec *r) {
 
230
  const apr_array_header_t *array;
 
231
  apr_table_entry_t  *entries;
 
232
  int          i;
 
233
  
 
234
  if (r->headers_in == NULL) return 1;
 
235
 
 
236
  array   = apr_table_elts(r->headers_in);
 
237
  entries = (apr_table_entry_t *)array->elts;
 
238
 
 
239
  for (i = 0; i < array->nelts; i++) {
 
240
    apr_table_entry_t *entry = &(entries[i]);
 
241
        
 
242
    if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
243
                                              entry->key, entry->val)) {
 
244
      return 0;
 
245
    }
 
246
  }
 
247
  return 1;
 
248
}
 
249
 
 
250
int ngobjweb_handler(request_rec *r) {
 
251
  struct    sockaddr   *address = NULL;
 
252
  size_t               addressLen;
 
253
  int                  domain;
 
254
  char                 appName[256];
 
255
  NGBufferedDescriptor *toApp = NULL;
 
256
  int                  appFd;
 
257
  int                  result;
 
258
  int                  writeError    = 0;
 
259
  int                  contentLength = 0;
 
260
  int                  statusCode    = 500;
 
261
  ngobjweb_dir_config  *cfg;
 
262
  const char           *uri;
 
263
  unsigned             requestContentLength;
 
264
  void                 *requestBody;
 
265
  
 
266
  uri = r->uri;
 
267
  requestContentLength = 0;
 
268
  requestBody = NULL;
 
269
  
 
270
#ifndef AP_VERSION_1
 
271
  if (r->handler == NULL)
 
272
    return DECLINED;
 
273
  if (strcmp(r->handler, "ngobjweb-adaptor") != 0)
 
274
    return DECLINED;
 
275
#endif
 
276
 
 
277
  if (uri == NULL)   return DECLINED;
 
278
  if (uri[0] != '/') return DECLINED;
 
279
  if (strstr(uri, "WebServerResources")) return DECLINED;
 
280
 
 
281
  /* get directory configuration */
 
282
  
 
283
  if ((cfg = _getConfig(r))) {
 
284
    if (cfg->appPrefix) {
 
285
      if (HEAVY_LOG) {
 
286
        ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
287
                     "using prefix '%s'\n", cfg->appPrefix);
 
288
      }
 
289
      uri += strlen(cfg->appPrefix);
 
290
    }
 
291
  }
 
292
  else {
 
293
    return 500;
 
294
  }
 
295
 
 
296
  /* find app name in url */
 
297
  _extractAppName(uri, appName, sizeof(appName));
 
298
  
 
299
  /* before continuing, read request body */
 
300
  
 
301
  requestBody = _readRequestBody(r, &contentLength);
 
302
  requestContentLength = contentLength;
 
303
  
 
304
  if ((requestBody == NULL) && (contentLength > 0))
 
305
    /* read failed, error is logged in function */
 
306
    return 500;
 
307
  
 
308
  /* ask SNS for server address */
 
309
 
 
310
  if (cfg->snsPort) {
 
311
    address = _sendSNSQuery(r,
 
312
                            r->the_request,
 
313
                            apr_table_get(r->headers_in, "cookie"),
 
314
                            &domain, &addressLen,
 
315
                            appName,
 
316
                            cfg);
 
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.");
 
321
      return DECLINED;
 
322
    }
 
323
  }
 
324
  else if (cfg->appPort) {
 
325
    domain = cfg->appPortDomain;
 
326
    
 
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)); 
 
331
         
 
332
      ((struct sockaddr_un *)address)->sun_family = AF_UNIX; 
 
333
      strncpy(((struct sockaddr_un *)address)->sun_path, 
 
334
              cfg->appPort, 
 
335
              sizeof(((struct sockaddr_un *)address)->sun_path) - 1);
 
336
    }
 
337
    else {
 
338
      struct sockaddr_in *snsi;
 
339
      char *host;
 
340
      int  port;
 
341
      
 
342
      host = "127.0.0.1";
 
343
      port = atoi(cfg->appPort);
 
344
 
 
345
      //ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
346
      //             "appPort: '%s', cfg 0x%08X", cfg->appPort, cfg);
 
347
      
 
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; 
 
352
         
 
353
      snsi->sin_addr.s_addr = apr_inet_addr(host); 
 
354
      
 
355
      snsi->sin_family = AF_INET; 
 
356
      snsi->sin_port   = htons((short)(port & 0xFFFF)); 
 
357
      
 
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); 
 
361
      } 
 
362
      if (HEAVY_LOG && 0) { 
 
363
        ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
364
                     "connect IP address: %s", host); 
 
365
      } 
 
366
    }
 
367
  }
 
368
  else {
 
369
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
370
                 "neither SNS port nor app port are set for request ...");
 
371
    return 500;
 
372
  }
 
373
 
 
374
  if (addressLen > 10000) {
 
375
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
376
                 "suspect instance port length (%li) ...", (long int) addressLen);
 
377
    return 500;
 
378
  }
 
379
  
 
380
  _logInstanceAddress(r, address, addressLen, domain);
 
381
  
 
382
  /* setup connection to application server */
 
383
  
 
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);
 
387
    return DECLINED;
 
388
  }
 
389
 
 
390
  if ((result = _connectInstance(r, appFd, address, addressLen)) < 0)
 
391
    return 500;
 
392
  
 
393
  toApp = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(appFd, 512);
 
394
  if (toApp == NULL) {
 
395
    close(appFd);
 
396
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
397
                 "could not alloc socket buffer for "
 
398
                 "application server connection");
 
399
    return 500;
 
400
  }
 
401
  
 
402
  /* write request to application server */
 
403
  
 
404
  if (HEAVY_LOG)
 
405
    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer reqline");
 
406
 
 
407
  {
 
408
    char *reqLine;
 
409
    unsigned toGo;
 
410
 
 
411
    reqLine = r->the_request;
 
412
    toGo = reqLine ? strlen(reqLine) : 0;
 
413
    
 
414
    ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
415
                 "req is %s(len=%i)", reqLine, toGo);
 
416
 
 
417
    if (!NGBufferedDescriptor_safeWrite(toApp, reqLine,
 
418
                                        reqLine ? strlen(reqLine) : 0)) {
 
419
      writeError = 1;
 
420
      goto writeErrorHandler;
 
421
    }
 
422
    if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
 
423
      writeError = 1;
 
424
      goto writeErrorHandler;
 
425
    }
 
426
  }
 
427
 
 
428
  /* transfer headers */
 
429
  
 
430
  if (writeError == 0) {
 
431
    if (HEAVY_LOG)
 
432
      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "transfer hdrs");
 
433
    
 
434
    /* extended adaptor headers */
 
435
    {
 
436
      char tmp[256];
 
437
      const char *value;
 
438
      
 
439
      value = r->protocol;
 
440
      value = value ? value : "http";
 
441
      if (value) {
 
442
        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
443
                                                  "x-webobjects-server-protocol",
 
444
                                                  value)) {
 
445
          writeError = 1;
 
446
          goto writeErrorHandler;
 
447
        }
 
448
      }
 
449
 
 
450
      if ((value = r->connection->remote_ip)) {
 
451
        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
452
                                                  "x-webobjects-remote-addr",
 
453
                                                  value)) {
 
454
          writeError = 1;
 
455
          goto writeErrorHandler;
 
456
        }
 
457
      }
 
458
      
 
459
      value = r->connection->remote_host;
 
460
      if (value == NULL) value = r->connection->remote_ip;
 
461
      if (value) {
 
462
        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
463
                                                  "x-webobjects-remote-host",
 
464
                                                  value)) {
 
465
          writeError = 1;
 
466
          goto writeErrorHandler;
 
467
        }
 
468
      }
 
469
 
 
470
#ifdef AP_VERSION_1
 
471
      if ((value = r->connection->ap_auth_type)) {
 
472
#else
 
473
      if ((value = r->ap_auth_type)) {
 
474
#endif
 
475
        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
476
                                                  "x-webobjects-auth-type",
 
477
                                                  value)) {
 
478
          writeError = 1;
 
479
          goto writeErrorHandler;
 
480
        }
 
481
      }
 
482
      
 
483
#ifdef AP_VERSION_1
 
484
      if ((value = r->connection->user)) {
 
485
#else
 
486
      if ((value = r->user)) {
 
487
#endif
 
488
        if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
489
                                                  "x-webobjects-remote-user",
 
490
                                                  value)) {
 
491
          writeError = 1;
 
492
          goto writeErrorHandler;
 
493
        }
 
494
      }
 
495
 
 
496
      if (cfg != NULL) {
 
497
        if (cfg->appPrefix != NULL) {
 
498
          if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
499
                "x-webobjects-adaptor-prefix", cfg->appPrefix)) {
 
500
            writeError = 1;
 
501
            goto writeErrorHandler;
 
502
          }
 
503
        }
 
504
      }
 
505
 
 
506
      if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
507
                                                "x-webobjects-server-name",
 
508
                                                r->server->server_hostname)) {
 
509
        writeError = 1;
 
510
        goto writeErrorHandler;
 
511
      }
 
512
 
 
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",
 
517
                                                  tmp)) {
 
518
          writeError = 1;
 
519
          goto writeErrorHandler;
 
520
        }
 
521
      }
 
522
 
 
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",
 
527
                     ap_http_method(r),
 
528
                     r->server->server_hostname,
 
529
                     r->server->port);
 
530
      }
 
531
      else {
 
532
        apr_snprintf(tmp, sizeof(tmp), "%s://%s",
 
533
                     ap_http_method(r), r->server->server_hostname);
 
534
      }
 
535
      if (!NGBufferedDescriptor_writeHttpHeader(toApp,
 
536
                                                "x-webobjects-server-url",
 
537
                                                tmp)) {
 
538
        writeError = 1;
 
539
        goto writeErrorHandler;
 
540
      }
 
541
 
 
542
      /*
 
543
        SSL stuff:
 
544
        x-webobjects-clients-cert
 
545
        x-webobjects-https-enabled
 
546
        x-webobjects-https-keysize
 
547
        x-webobjects-https-secret-keysize
 
548
      */
 
549
    }
 
550
    
 
551
    /* http headers */
 
552
    if (!_writeInHeaders(toApp, r)) {
 
553
      writeError = 1;
 
554
      goto writeErrorHandler;
 
555
    }
 
556
    
 
557
    if (!NGBufferedDescriptor_safeWrite(toApp, "\r\n", 2)) {
 
558
      writeError = 1;
 
559
      goto writeErrorHandler;
 
560
    }
 
561
    if (!NGBufferedDescriptor_flush(toApp))
 
562
      writeError = 1;
 
563
  }
 
564
 
 
565
 writeErrorHandler:
 
566
  if (writeError == 1) {
 
567
    if (toApp) NGBufferedDescriptor_free(toApp);
 
568
    
 
569
    ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, r->server,
 
570
                 "socket write error during transfer of HTTP header section");
 
571
    return 500;
 
572
  }
 
573
  
 
574
  /* transfer request body */
 
575
  
 
576
  if (requestContentLength > 0) {
 
577
    if (!NGBufferedDescriptor_safeWrite(toApp,
 
578
                                        requestBody,
 
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)",
 
583
                   contentLength);
 
584
      return 500;
 
585
    }
 
586
    NGBufferedDescriptor_flush(toApp);
 
587
  }
 
588
  else {
 
589
    if (HEAVY_LOG) {
 
590
      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
591
                   "no content in request to transfer");
 
592
    }
 
593
  }
 
594
  
 
595
  /* read response line */
 
596
  
 
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 ..");
 
601
    return 500;
 
602
  }
 
603
  r->status      = statusCode;
 
604
  r->status_line = NULL;
 
605
 
 
606
  /* process response headers */
 
607
  {
 
608
    apr_table_t *headers = NULL;
 
609
    
 
610
    if (HEAVY_LOG)
 
611
      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server, "scan headers");
 
612
 
 
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 ..");
 
616
    }
 
617
    
 
618
    _copyHeadersToRequest(r, headers, &contentLength);
 
619
#ifdef AP_VERSION_1
 
620
    ap_send_http_header(r);
 
621
#endif
 
622
  }
 
623
  
 
624
  /* send response content */
 
625
  
 
626
  if (!r->header_only) {
 
627
    if (contentLength > 0) {
 
628
      void *buffer = NULL;
 
629
      
 
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)",
 
633
                     contentLength);
 
634
      }
 
635
 
 
636
      // read whole response
 
637
      if (!NGBufferedDescriptor_safeRead(toApp, buffer, contentLength)) {
 
638
        if (toApp) NGBufferedDescriptor_free(toApp);
 
639
      }
 
640
 
 
641
      // close connection to app
 
642
      if (toApp) {
 
643
        NGBufferedDescriptor_free(toApp);
 
644
        toApp = NULL;
 
645
      }
 
646
 
 
647
      ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, r->server,
 
648
                   "send response (size=%i)",
 
649
                   contentLength);
 
650
      // send response to client
 
651
      ap_rwrite(buffer, contentLength, r);
 
652
      ap_rflush(r);
 
653
    }
 
654
    else if (contentLength == 0) {
 
655
      // no content length header, read until EOF
 
656
      unsigned char buffer[4096];
 
657
      int result = 0;
 
658
      int writeCount = 0;
 
659
 
 
660
      do {
 
661
        result = NGBufferedDescriptor_read(toApp, buffer, sizeof(buffer));
 
662
        if (result > 0) {
 
663
          ap_rwrite(buffer, result, r);
 
664
          ap_rflush(r);
 
665
          writeCount += result;
 
666
        }
 
667
      }
 
668
      while (result > 0);
 
669
 
 
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)",
 
673
                     writeCount);
 
674
      }
 
675
    }
 
676
  }
 
677
  
 
678
  return OK;
 
679
}
 
680
 
 
681
#if WITH_LOGGING
 
682
static void test(void) {
 
683
  fprintf(stderr,
 
684
          "%s: called:\n"
 
685
          "  app:      %s\n"
 
686
          "  uri:      %s\n"
 
687
          "  pathinfo: %s\n"
 
688
          "  method:   %s\n"
 
689
          "  protocol: %s\n"
 
690
          "  1st:      %s\n"
 
691
          "  host:     %s\n"
 
692
          "  type:     %s\n"
 
693
          "  handler:  %s\n",
 
694
          __PRETTY_FUNCTION__,
 
695
          appName,
 
696
          r->uri,
 
697
          r->path_info,
 
698
          r->method,
 
699
          r->protocol,
 
700
          r->the_request,
 
701
          apr_table_get(r->headers_in, "content-length"),
 
702
          r->content_type,
 
703
          r->handler
 
704
          );
 
705
 
 
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);
 
710
}
 
711
 
 
712
static void _logTable(const char *text, apr_table_t *table) {
 
713
  apr_array_header_t *array;
 
714
  apr_table_entry_t  *entries;
 
715
  int          i;
 
716
 
 
717
  if (table == NULL) {
 
718
    fprintf(stderr, "%s: log NULL table.\n", text);
 
719
    return;
 
720
  }
 
721
 
 
722
  array   = apr_table_elts(table);
 
723
  entries = (apr_table_entry_t *)array->elts;
 
724
 
 
725
  if (array->nelts == 0) {
 
726
    fprintf(stderr, "%s: empty\n", text);
 
727
    return;
 
728
  }
 
729
 
 
730
  for (i = 0; i < array->nelts; i++) {
 
731
    apr_table_entry_t *entry = &(entries[i]);
 
732
    
 
733
    fprintf(stderr, "%s: %s: %s\n", text, entry->key, entry->val);
 
734
  }
 
735
}
 
736
#endif