"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