]> granicus.if.org Git - apache/blob - modules/proxy/mod_proxy_ajp.c
Netwarep proxy makefiles
[apache] / modules / proxy / mod_proxy_ajp.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* AJP routines for Apache proxy */
18
19 #include "mod_proxy.h"
20 #include "ajp.h"
21
22 module AP_MODULE_DECLARE_DATA proxy_ajp_module;
23
24 /*
25  * Canonicalise http-like URLs.
26  * scheme is the scheme for the URL
27  * url is the URL starting with the first '/'
28  * def_port is the default port for this scheme.
29  */
30 static int proxy_ajp_canon(request_rec *r, char *url)
31 {
32     char *host, *path, sport[7];
33     char *search = NULL;
34     const char *err;
35     apr_port_t port, def_port;
36
37     /* ap_port_of_scheme() */
38     if (ap_casecmpstrn(url, "ajp:", 4) == 0) {
39         url += 4;
40     }
41     else {
42         return DECLINED;
43     }
44
45     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url);
46
47     /*
48      * do syntactic check.
49      * We break the URL into host, port, path, search
50      */
51     port = def_port = ap_proxy_port_of_scheme("ajp");
52
53     err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
54     if (err) {
55         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00867) "error parsing URL %s: %s",
56                       url, err);
57         return HTTP_BAD_REQUEST;
58     }
59
60     /*
61      * now parse path/search args, according to rfc1738:
62      * process the path. With proxy-nocanon set (by
63      * mod_proxy) we use the raw, unparsed uri
64      */
65     if (apr_table_get(r->notes, "proxy-nocanon")) {
66         path = url;   /* this is the raw path */
67     }
68     else {
69         path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
70                                  r->proxyreq);
71         search = r->args;
72     }
73     if (path == NULL)
74         return HTTP_BAD_REQUEST;
75
76     if (port != def_port)
77          apr_snprintf(sport, sizeof(sport), ":%d", port);
78     else
79          sport[0] = '\0';
80
81     if (ap_strchr_c(host, ':')) {
82         /* if literal IPv6 address */
83         host = apr_pstrcat(r->pool, "[", host, "]", NULL);
84     }
85     r->filename = apr_pstrcat(r->pool, "proxy:ajp://", host, sport,
86                               "/", path, (search) ? "?" : "",
87                               (search) ? search : "", NULL);
88     return OK;
89 }
90
91 #define METHOD_NON_IDEMPOTENT       0
92 #define METHOD_IDEMPOTENT           1
93 #define METHOD_IDEMPOTENT_WITH_ARGS 2
94
95 static int is_idempotent(request_rec *r)
96 {
97     /*
98      * RFC2616 (9.1.2): GET, HEAD, PUT, DELETE, OPTIONS, TRACE are considered
99      * idempotent. Hint: HEAD requests use M_GET as method number as well.
100      */
101     switch (r->method_number) {
102         case M_GET:
103         case M_DELETE:
104         case M_PUT:
105         case M_OPTIONS:
106         case M_TRACE:
107             /*
108              * If the request has arguments it might have side-effects and thus
109              * it might be undesirable to resend it to a backend again
110              * automatically.
111              */
112             if (r->args) {
113                 return METHOD_IDEMPOTENT_WITH_ARGS;
114             }
115             return METHOD_IDEMPOTENT;
116         /* Everything else is not considered idempotent. */
117         default:
118             return METHOD_NON_IDEMPOTENT;
119     }
120 }
121
122 static apr_off_t get_content_length(request_rec * r)
123 {
124     apr_off_t len = 0;
125
126     if (r->main == NULL) {
127         const char *clp = apr_table_get(r->headers_in, "Content-Length");
128
129         if (clp) {
130             char *errp;
131             if (apr_strtoff(&len, clp, &errp, 10) || *errp || len < 0) {
132                 len = 0; /* parse error */
133             }
134         }
135     }
136
137     return len;
138 }
139
140 /*
141  * XXX: AJP Auto Flushing
142  *
143  * When processing CMD_AJP13_SEND_BODY_CHUNK AJP messages we will do a poll
144  * with FLUSH_WAIT miliseconds timeout to determine if more data is currently
145  * available at the backend. If there is no more data available, we flush
146  * the data to the client by adding a flush bucket to the brigade we pass
147  * up the filter chain.
148  * This is only a bandaid to fix the AJP/1.3 protocol shortcoming of not
149  * sending (actually not having defined) a flush message, when the data
150  * should be flushed to the client. As soon as this protocol shortcoming is
151  * fixed this code should be removed.
152  *
153  * For further discussion see PR37100.
154  * http://issues.apache.org/bugzilla/show_bug.cgi?id=37100
155  */
156
157 /*
158  * process the request and write the response.
159  */
160 static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
161                                 proxy_conn_rec *conn,
162                                 conn_rec *origin,
163                                 proxy_dir_conf *conf,
164                                 apr_uri_t *uri,
165                                 char *url, char *server_portstr)
166 {
167     apr_status_t status;
168     int result;
169     apr_bucket *e;
170     apr_bucket_brigade *input_brigade;
171     apr_bucket_brigade *output_brigade;
172     ajp_msg_t *msg;
173     apr_size_t bufsiz = 0;
174     char *buff;
175     char *send_body_chunk_buff;
176     apr_uint16_t size;
177     apr_byte_t conn_reuse = 0;
178     const char *tenc;
179     int havebody = 1;
180     int client_failed = 0;
181     int backend_failed = 0;
182     apr_off_t bb_len;
183     int data_sent = 0;
184     int request_ended = 0;
185     int headers_sent = 0;
186     int rv = OK;
187     apr_int32_t conn_poll_fd;
188     apr_pollfd_t *conn_poll;
189     proxy_server_conf *psf =
190     ap_get_module_config(r->server->module_config, &proxy_module);
191     apr_size_t maxsize = AJP_MSG_BUFFER_SZ;
192     int send_body = 0;
193     apr_off_t content_length = 0;
194     int original_status = r->status;
195     const char *original_status_line = r->status_line;
196
197     if (psf->io_buffer_size_set)
198        maxsize = psf->io_buffer_size;
199     if (maxsize > AJP_MAX_BUFFER_SZ)
200        maxsize = AJP_MAX_BUFFER_SZ;
201     else if (maxsize < AJP_MSG_BUFFER_SZ)
202        maxsize = AJP_MSG_BUFFER_SZ;
203     maxsize = APR_ALIGN(maxsize, 1024);
204
205     /*
206      * Send the AJP request to the remote server
207      */
208
209     /* send request headers */
210     status = ajp_send_header(conn->sock, r, maxsize, uri);
211     if (status != APR_SUCCESS) {
212         conn->close = 1;
213         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868)
214                       "request failed to %pI (%s)",
215                       conn->worker->cp->addr,
216                       conn->worker->s->hostname);
217         if (status == AJP_EOVERFLOW)
218             return HTTP_BAD_REQUEST;
219         else {
220             /*
221              * This is only non fatal when the method is idempotent. In this
222              * case we can dare to retry it with a different worker if we are
223              * a balancer member.
224              */
225             if (is_idempotent(r) == METHOD_IDEMPOTENT) {
226                 return HTTP_SERVICE_UNAVAILABLE;
227             }
228             return HTTP_INTERNAL_SERVER_ERROR;
229         }
230     }
231
232     /* allocate an AJP message to store the data of the buckets */
233     bufsiz = maxsize;
234     status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);
235     if (status != APR_SUCCESS) {
236         /* We had a failure: Close connection to backend */
237         conn->close = 1;
238         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00869)
239                       "ajp_alloc_data_msg failed");
240         return HTTP_INTERNAL_SERVER_ERROR;
241     }
242
243     /* read the first bloc of data */
244     input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
245     tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
246     if (tenc && (ap_casecmpstr(tenc, "chunked") == 0)) {
247         /* The AJP protocol does not want body data yet */
248         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked");
249     } else {
250         /* Get client provided Content-Length header */
251         content_length = get_content_length(r);
252         status = ap_get_brigade(r->input_filters, input_brigade,
253                                 AP_MODE_READBYTES, APR_BLOCK_READ,
254                                 maxsize - AJP_HEADER_SZ);
255
256         if (status != APR_SUCCESS) {
257             /* We had a failure: Close connection to backend */
258             conn->close = 1;
259             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00871)
260                           "ap_get_brigade failed");
261             apr_brigade_destroy(input_brigade);
262             return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
263         }
264
265         /* have something */
266         if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
267             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00872) "APR_BUCKET_IS_EOS");
268         }
269
270         /* Try to send something */
271         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00873)
272                       "data to read (max %" APR_SIZE_T_FMT
273                       " at %" APR_SIZE_T_FMT ")", bufsiz, msg->pos);
274
275         status = apr_brigade_flatten(input_brigade, buff, &bufsiz);
276         if (status != APR_SUCCESS) {
277             /* We had a failure: Close connection to backend */
278             conn->close = 1;
279             apr_brigade_destroy(input_brigade);
280             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00874)
281                           "apr_brigade_flatten");
282             return HTTP_INTERNAL_SERVER_ERROR;
283         }
284         apr_brigade_cleanup(input_brigade);
285
286         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00875)
287                       "got %" APR_SIZE_T_FMT " bytes of data", bufsiz);
288         if (bufsiz > 0) {
289             status = ajp_send_data_msg(conn->sock, msg, bufsiz);
290             ajp_msg_log(r, msg, "First ajp_send_data_msg: ajp_ilink_send packet dump");
291             if (status != APR_SUCCESS) {
292                 /* We had a failure: Close connection to backend */
293                 conn->close = 1;
294                 apr_brigade_destroy(input_brigade);
295                 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00876)
296                               "send failed to %pI (%s)",
297                               conn->worker->cp->addr,
298                               conn->worker->s->hostname);
299                 /*
300                  * It is fatal when we failed to send a (part) of the request
301                  * body.
302                  */
303                 return HTTP_INTERNAL_SERVER_ERROR;
304             }
305             conn->worker->s->transferred += bufsiz;
306             send_body = 1;
307         }
308         else if (content_length > 0) {
309             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00877)
310                           "read zero bytes, expecting"
311                           " %" APR_OFF_T_FMT " bytes",
312                           content_length);
313             /*
314              * We can only get here if the client closed the connection
315              * to us without sending the body.
316              * Now the connection is in the wrong state on the backend.
317              * Sending an empty data msg doesn't help either as it does
318              * not move this connection to the correct state on the backend
319              * for later resusage by the next request again.
320              * Close it to clean things up.
321              */
322             conn->close = 1;
323             return HTTP_BAD_REQUEST;
324         }
325     }
326
327     /* read the response */
328     conn->data = NULL;
329     status = ajp_read_header(conn->sock, r, maxsize,
330                              (ajp_msg_t **)&(conn->data));
331     if (status != APR_SUCCESS) {
332         /* We had a failure: Close connection to backend */
333         conn->close = 1;
334         apr_brigade_destroy(input_brigade);
335         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00878)
336                       "read response failed from %pI (%s)",
337                       conn->worker->cp->addr,
338                       conn->worker->s->hostname);
339
340         /* If we had a successful cping/cpong and then a timeout
341          * we assume it is a request that cause a back-end timeout,
342          * but doesn't affect the whole worker.
343          */
344         if (APR_STATUS_IS_TIMEUP(status) &&
345             conn->worker->s->ping_timeout_set &&
346             conn->worker->s->ping_timeout >= 0) {
347             return HTTP_GATEWAY_TIME_OUT;
348         }
349
350         /*
351          * This is only non fatal when we have not sent (parts) of a possible
352          * request body so far (we do not store it and thus cannot send it
353          * again) and the method is idempotent. In this case we can dare to
354          * retry it with a different worker if we are a balancer member.
355          */
356         if (!send_body && (is_idempotent(r) == METHOD_IDEMPOTENT)) {
357             return HTTP_SERVICE_UNAVAILABLE;
358         }
359         return HTTP_INTERNAL_SERVER_ERROR;
360     }
361     /* parse the reponse */
362     result = ajp_parse_type(r, conn->data);
363     output_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
364
365     /*
366      * Prepare apr_pollfd_t struct for possible later check if there is currently
367      * data available from the backend (do not flush response to client)
368      * or not (flush response to client)
369      */
370     conn_poll = apr_pcalloc(p, sizeof(apr_pollfd_t));
371     conn_poll->reqevents = APR_POLLIN;
372     conn_poll->desc_type = APR_POLL_SOCKET;
373     conn_poll->desc.s = conn->sock;
374
375     bufsiz = maxsize;
376     for (;;) {
377         switch (result) {
378             case CMD_AJP13_GET_BODY_CHUNK:
379                 if (havebody) {
380                     if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
381                         /* This is the end */
382                         bufsiz = 0;
383                         havebody = 0;
384                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00879)
385                                       "APR_BUCKET_IS_EOS");
386                     } else {
387                         status = ap_get_brigade(r->input_filters, input_brigade,
388                                                 AP_MODE_READBYTES,
389                                                 APR_BLOCK_READ,
390                                                 maxsize - AJP_HEADER_SZ);
391                         if (status != APR_SUCCESS) {
392                             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00880)
393                                           "ap_get_brigade failed");
394                             if (APR_STATUS_IS_TIMEUP(status)) {
395                                 rv = HTTP_REQUEST_TIME_OUT;
396                             }
397                             else if (status == AP_FILTER_ERROR) {
398                                 rv = AP_FILTER_ERROR;
399                             }
400                             client_failed = 1;
401                             break;
402                         }
403                         bufsiz = maxsize;
404                         status = apr_brigade_flatten(input_brigade, buff,
405                                                      &bufsiz);
406                         apr_brigade_cleanup(input_brigade);
407                         if (status != APR_SUCCESS) {
408                             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00881)
409                                          "apr_brigade_flatten failed");
410                             rv = HTTP_INTERNAL_SERVER_ERROR;
411                             client_failed = 1;
412                             break;
413                         }
414                     }
415
416                     ajp_msg_reset(msg);
417                     /* will go in ajp_send_data_msg */
418                     status = ajp_send_data_msg(conn->sock, msg, bufsiz);
419                     ajp_msg_log(r, msg, "ajp_send_data_msg after CMD_AJP13_GET_BODY_CHUNK: ajp_ilink_send packet dump");
420                     if (status != APR_SUCCESS) {
421                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00882)
422                                       "ajp_send_data_msg failed");
423                         backend_failed = 1;
424                         break;
425                     }
426                     conn->worker->s->transferred += bufsiz;
427                 } else {
428                     /*
429                      * something is wrong TC asks for more body but we are
430                      * already at the end of the body data
431                      */
432                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00883)
433                                   "ap_proxy_ajp_request error read after end");
434                     backend_failed = 1;
435                 }
436                 break;
437             case CMD_AJP13_SEND_HEADERS:
438                 if (headers_sent) {
439                     /* Do not send anything to the client.
440                      * Backend already send us the headers.
441                      */
442                     backend_failed = 1;
443                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00884)
444                                   "Backend sent headers twice.");
445                     break;
446                 }
447                 /* AJP13_SEND_HEADERS: process them */
448                 status = ajp_parse_header(r, conf, conn->data);
449                 if (status != APR_SUCCESS) {
450                     backend_failed = 1;
451                 }
452                 else if ((r->status == 401) && conf->error_override) {
453                     const char *buf;
454                     const char *wa = "WWW-Authenticate";
455                     if ((buf = apr_table_get(r->headers_out, wa))) {
456                         apr_table_set(r->err_headers_out, wa, buf);
457                     } else {
458                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00885)
459                                       "ap_proxy_ajp_request: origin server "
460                                       "sent 401 without WWW-Authenticate header");
461                     }
462                 }
463                 headers_sent = 1;
464                 break;
465             case CMD_AJP13_SEND_BODY_CHUNK:
466                 /* AJP13_SEND_BODY_CHUNK: piece of data */
467                 status = ajp_parse_data(r, conn->data, &size, &send_body_chunk_buff);
468                 if (status == APR_SUCCESS) {
469                     /* If we are overriding the errors, we can't put the content
470                      * of the page into the brigade.
471                      */
472                     if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
473                         /* AJP13_SEND_BODY_CHUNK with zero length
474                          * is explicit flush message
475                          */
476                         if (size == 0) {
477                             if (headers_sent) {
478                                 e = apr_bucket_flush_create(r->connection->bucket_alloc);
479                                 APR_BRIGADE_INSERT_TAIL(output_brigade, e);
480                             }
481                             else {
482                                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00886)
483                                               "Ignoring flush message "
484                                               "received before headers");
485                             }
486                         }
487                         else {
488                             apr_status_t rv;
489
490                             /* Handle the case where the error document is itself reverse
491                              * proxied and was successful. We must maintain any previous
492                              * error status so that an underlying error (eg HTTP_NOT_FOUND)
493                              * doesn't become an HTTP_OK.
494                              */
495                             if (conf->error_override && !ap_is_HTTP_ERROR(r->status)
496                                     && ap_is_HTTP_ERROR(original_status)) {
497                                 r->status = original_status;
498                                 r->status_line = original_status_line;
499                             }
500
501                             e = apr_bucket_transient_create(send_body_chunk_buff, size,
502                                                         r->connection->bucket_alloc);
503                             APR_BRIGADE_INSERT_TAIL(output_brigade, e);
504
505                             if ((conn->worker->s->flush_packets == flush_on) ||
506                                 ((conn->worker->s->flush_packets == flush_auto) &&
507                                 ((rv = apr_poll(conn_poll, 1, &conn_poll_fd,
508                                                  conn->worker->s->flush_wait))
509                                                  != APR_SUCCESS) &&
510                                   APR_STATUS_IS_TIMEUP(rv))) {
511                                 e = apr_bucket_flush_create(r->connection->bucket_alloc);
512                                 APR_BRIGADE_INSERT_TAIL(output_brigade, e);
513                             }
514                             apr_brigade_length(output_brigade, 0, &bb_len);
515                             if (bb_len != -1)
516                                 conn->worker->s->read += bb_len;
517                         }
518                         if (headers_sent) {
519                             if (ap_pass_brigade(r->output_filters,
520                                                 output_brigade) != APR_SUCCESS) {
521                                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00887)
522                                               "error processing body.%s",
523                                               r->connection->aborted ?
524                                               " Client aborted connection." : "");
525                                 client_failed = 1;
526                             }
527                             data_sent = 1;
528                             apr_brigade_cleanup(output_brigade);
529                         }
530                     }
531                 }
532                 else {
533                     backend_failed = 1;
534                 }
535                 break;
536             case CMD_AJP13_END_RESPONSE:
537                 /* If we are overriding the errors, we must not send anything to
538                  * the client, especially as the brigade already contains headers.
539                  * So do nothing here, and it will be cleaned up below.
540                  */
541                 status = ajp_parse_reuse(r, conn->data, &conn_reuse);
542                 if (status != APR_SUCCESS) {
543                     backend_failed = 1;
544                 }
545                 if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
546                     e = apr_bucket_eos_create(r->connection->bucket_alloc);
547                     APR_BRIGADE_INSERT_TAIL(output_brigade, e);
548                     if (ap_pass_brigade(r->output_filters,
549                                         output_brigade) != APR_SUCCESS) {
550                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00888)
551                                       "error processing end");
552                         client_failed = 1;
553                     }
554                     /* XXX: what about flush here? See mod_jk */
555                     data_sent = 1;
556                 }
557                 request_ended = 1;
558                 break;
559             default:
560                 backend_failed = 1;
561                 break;
562         }
563
564         /*
565          * If connection has been aborted by client: Stop working.
566          * Pretend we are done (data_sent) to avoid further processing.
567          */
568         if (r->connection->aborted) {
569             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02821)
570                           "client connection aborted");
571             /* no response yet (or ever), set status for access log */
572             if (!headers_sent) {
573                 r->status = HTTP_BAD_REQUEST;
574             }
575             client_failed = 1;
576             /* return DONE */
577             data_sent = 1;
578             break;
579         }
580
581         /*
582          * We either have finished successfully or we failed.
583          * So bail out
584          */
585         if ((result == CMD_AJP13_END_RESPONSE)
586                 || backend_failed || client_failed)
587             break;
588
589         /* read the response */
590         status = ajp_read_header(conn->sock, r, maxsize,
591                                  (ajp_msg_t **)&(conn->data));
592         if (status != APR_SUCCESS) {
593             backend_failed = 1;
594             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00889)
595                           "ajp_read_header failed");
596             break;
597         }
598         result = ajp_parse_type(r, conn->data);
599     }
600     apr_brigade_destroy(input_brigade);
601
602     /*
603      * Clear output_brigade to remove possible buckets that remained there
604      * after an error.
605      */
606     apr_brigade_cleanup(output_brigade);
607
608     if (backend_failed || client_failed) {
609         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00890)
610                       "Processing of request failed backend: %i, client: %i",
611                       backend_failed, client_failed);
612         /* We had a failure: Close connection to backend */
613         conn->close = 1;
614         if (data_sent) {
615             /* Return DONE to avoid error messages being added to the stream */
616             rv = DONE;
617         }
618     }
619     else if (!request_ended) {
620         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00891)
621                       "Processing of request didn't terminate cleanly");
622         /* We had a failure: Close connection to backend */
623         conn->close = 1;
624         backend_failed = 1;
625         if (data_sent) {
626             /* Return DONE to avoid error messages being added to the stream */
627             rv = DONE;
628         }
629     }
630     else if (!conn_reuse) {
631         /* Our backend signalled connection close */
632         conn->close = 1;
633     }
634     else {
635         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00892)
636                       "got response from %pI (%s)",
637                       conn->worker->cp->addr,
638                       conn->worker->s->hostname);
639
640         if (conf->error_override && ap_is_HTTP_ERROR(r->status)) {
641             /* clear r->status for override error, otherwise ErrorDocument
642              * thinks that this is a recursive error, and doesn't find the
643              * custom error page
644              */
645             rv = r->status;
646             r->status = HTTP_OK;
647             /*
648              * prevent proxy_handler() from treating this as an
649              * internal error.
650              */
651             apr_table_setn(r->notes, "proxy-error-override", "1");
652         }
653         else {
654             rv = OK;
655         }
656     }
657
658     if (backend_failed) {
659         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00893)
660                       "dialog to %pI (%s) failed",
661                       conn->worker->cp->addr,
662                       conn->worker->s->hostname);
663         /*
664          * If we already send data, signal a broken backend connection
665          * upwards in the chain.
666          */
667         if (data_sent) {
668             ap_proxy_backend_broke(r, output_brigade);
669         } else if (!send_body && (is_idempotent(r) == METHOD_IDEMPOTENT)) {
670             /*
671              * This is only non fatal when we have not send (parts) of a possible
672              * request body so far (we do not store it and thus cannot send it
673              * again) and the method is idempotent. In this case we can dare to
674              * retry it with a different worker if we are a balancer member.
675              */
676             rv = HTTP_SERVICE_UNAVAILABLE;
677         } else {
678             /* If we had a successful cping/cpong and then a timeout
679              * we assume it is a request that cause a back-end timeout,
680              * but doesn't affect the whole worker.
681              */
682             if (APR_STATUS_IS_TIMEUP(status) &&
683                 conn->worker->s->ping_timeout_set &&
684                 conn->worker->s->ping_timeout >= 0) {
685                 apr_table_setn(r->notes, "proxy_timedout", "1");
686                 rv = HTTP_GATEWAY_TIME_OUT;
687             }
688             else {
689                 rv = HTTP_INTERNAL_SERVER_ERROR;
690             }
691         }
692     }
693     else if (client_failed) {
694         int level = (r->connection->aborted) ? APLOG_DEBUG : APLOG_ERR;
695         ap_log_rerror(APLOG_MARK, level, status, r, APLOGNO(02822)
696                       "dialog with client %pI failed",
697                       r->connection->client_addr);
698         if (rv == OK) {
699             rv = HTTP_BAD_REQUEST;
700         }
701     }
702
703     /*
704      * Ensure that we sent an EOS bucket thru the filter chain, if we already
705      * have sent some data. Maybe ap_proxy_backend_broke was called and added
706      * one to the brigade already (no longer making it empty). So we should
707      * not do this in this case.
708      */
709     if (data_sent && !r->eos_sent && !r->connection->aborted
710             && APR_BRIGADE_EMPTY(output_brigade)) {
711         e = apr_bucket_eos_create(r->connection->bucket_alloc);
712         APR_BRIGADE_INSERT_TAIL(output_brigade, e);
713     }
714
715     /* If we have added something to the brigade above, send it */
716     if (!APR_BRIGADE_EMPTY(output_brigade)
717         && ap_pass_brigade(r->output_filters, output_brigade) != APR_SUCCESS) {
718         rv = AP_FILTER_ERROR;
719     }
720
721     apr_brigade_destroy(output_brigade);
722
723     if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
724         conn->close = 1;
725     }
726
727     return rv;
728 }
729
730 /*
731  * This handles ajp:// URLs
732  */
733 static int proxy_ajp_handler(request_rec *r, proxy_worker *worker,
734                              proxy_server_conf *conf,
735                              char *url, const char *proxyname,
736                              apr_port_t proxyport)
737 {
738     int status;
739     char server_portstr[32];
740     conn_rec *origin = NULL;
741     proxy_conn_rec *backend = NULL;
742     const char *scheme = "AJP";
743     int retry;
744     proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
745                                                  &proxy_module);
746     apr_pool_t *p = r->pool;
747     apr_uri_t *uri;
748
749     if (ap_casecmpstrn(url, "ajp:", 4) != 0) {
750         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00894) "declining URL %s", url);
751         return DECLINED;
752     }
753
754     uri = apr_palloc(p, sizeof(*uri));
755     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00895) "serving URL %s", url);
756
757     /* create space for state information */
758     status = ap_proxy_acquire_connection(scheme, &backend, worker,
759                                          r->server);
760     if (status != OK) {
761         if (backend) {
762             backend->close = 1;
763             ap_proxy_release_connection(scheme, backend, r->server);
764         }
765         return status;
766     }
767
768     backend->is_ssl = 0;
769     backend->close = 0;
770
771     retry = 0;
772     while (retry < 2) {
773         char *locurl = url;
774         /* Step One: Determine Who To Connect To */
775         status = ap_proxy_determine_connection(p, r, conf, worker, backend,
776                                                uri, &locurl, proxyname, proxyport,
777                                                server_portstr,
778                                                sizeof(server_portstr));
779
780         if (status != OK)
781             break;
782
783         /* Step Two: Make the Connection */
784         if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
785             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00896)
786                           "failed to make connection to backend: %s",
787                           backend->hostname);
788             status = HTTP_SERVICE_UNAVAILABLE;
789             break;
790         }
791
792         /* Handle CPING/CPONG */
793         if (worker->s->ping_timeout_set) {
794             if (worker->s->ping_timeout < 0) {
795                 if (!ap_proxy_is_socket_connected(backend->sock)) {
796                     backend->close = 1;
797                     ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02534)
798                                   "socket check failed to %pI (%s)",
799                                   worker->cp->addr, worker->s->hostname);
800                     status = HTTP_SERVICE_UNAVAILABLE;
801                     retry++;
802                     continue;
803                 }
804             }
805             else {
806                 status = ajp_handle_cping_cpong(backend->sock, r,
807                                                 worker->s->ping_timeout);
808                 /*
809                  * In case the CPING / CPONG failed for the first time we might be
810                  * just out of luck and got a faulty backend connection, but the
811                  * backend might be healthy nevertheless. So ensure that the backend
812                  * TCP connection gets closed and try it once again.
813                  */
814                 if (status != APR_SUCCESS) {
815                     backend->close = 1;
816                     ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897)
817                                   "cping/cpong failed to %pI (%s)",
818                                   worker->cp->addr, worker->s->hostname);
819                     status = HTTP_SERVICE_UNAVAILABLE;
820                     retry++;
821                     continue;
822                 }
823             }
824         }
825         /* Step Three: Process the Request */
826         status = ap_proxy_ajp_request(p, r, backend, origin, dconf, uri, locurl,
827                                       server_portstr);
828         break;
829     }
830
831     /* Do not close the socket */
832     ap_proxy_release_connection(scheme, backend, r->server);
833     return status;
834 }
835
836 static void ap_proxy_http_register_hook(apr_pool_t *p)
837 {
838     proxy_hook_scheme_handler(proxy_ajp_handler, NULL, NULL, APR_HOOK_FIRST);
839     proxy_hook_canon_handler(proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST);
840 }
841
842 AP_DECLARE_MODULE(proxy_ajp) = {
843     STANDARD20_MODULE_STUFF,
844     NULL,                       /* create per-directory config structure */
845     NULL,                       /* merge per-directory config structures */
846     NULL,                       /* create per-server config structure */
847     NULL,                       /* merge per-server config structures */
848     NULL,                       /* command apr_table_t */
849     ap_proxy_http_register_hook /* register hooks */
850 };
851