]> granicus.if.org Git - apache/blob - modules/proxy/mod_proxy_ajp.c
Fix spelling in comments and text files.
[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_cstr_casecmpn(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 milliseconds 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     const char *secret = NULL;
197
198     if (psf->io_buffer_size_set)
199        maxsize = psf->io_buffer_size;
200     if (maxsize > AJP_MAX_BUFFER_SZ)
201        maxsize = AJP_MAX_BUFFER_SZ;
202     else if (maxsize < AJP_MSG_BUFFER_SZ)
203        maxsize = AJP_MSG_BUFFER_SZ;
204     maxsize = APR_ALIGN(maxsize, 1024);
205
206     if (*conn->worker->s->secret)
207         secret = conn->worker->s->secret;
208
209     /*
210      * Send the AJP request to the remote server
211      */
212
213     /* send request headers */
214     status = ajp_send_header(conn->sock, r, maxsize, uri, secret);
215     if (status != APR_SUCCESS) {
216         conn->close = 1;
217         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868)
218                       "request failed to %pI (%s)",
219                       conn->worker->cp->addr,
220                       conn->worker->s->hostname);
221         if (status == AJP_EOVERFLOW)
222             return HTTP_BAD_REQUEST;
223         else {
224             /*
225              * This is only non fatal when the method is idempotent. In this
226              * case we can dare to retry it with a different worker if we are
227              * a balancer member.
228              */
229             if (is_idempotent(r) == METHOD_IDEMPOTENT) {
230                 return HTTP_SERVICE_UNAVAILABLE;
231             }
232             return HTTP_INTERNAL_SERVER_ERROR;
233         }
234     }
235
236     /* allocate an AJP message to store the data of the buckets */
237     bufsiz = maxsize;
238     status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);
239     if (status != APR_SUCCESS) {
240         /* We had a failure: Close connection to backend */
241         conn->close = 1;
242         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00869)
243                       "ajp_alloc_data_msg failed");
244         return HTTP_INTERNAL_SERVER_ERROR;
245     }
246
247     /* read the first bloc of data */
248     input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
249     tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
250     if (tenc && (ap_cstr_casecmp(tenc, "chunked") == 0)) {
251         /* The AJP protocol does not want body data yet */
252         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked");
253     } else {
254         /* Get client provided Content-Length header */
255         content_length = get_content_length(r);
256         status = ap_get_brigade(r->input_filters, input_brigade,
257                                 AP_MODE_READBYTES, APR_BLOCK_READ,
258                                 maxsize - AJP_HEADER_SZ);
259
260         if (status != APR_SUCCESS) {
261             /* We had a failure: Close connection to backend */
262             conn->close = 1;
263             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00871)
264                           "ap_get_brigade failed");
265             apr_brigade_destroy(input_brigade);
266             return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
267         }
268
269         /* have something */
270         if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
271             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00872) "APR_BUCKET_IS_EOS");
272         }
273
274         /* Try to send something */
275         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00873)
276                       "data to read (max %" APR_SIZE_T_FMT
277                       " at %" APR_SIZE_T_FMT ")", bufsiz, msg->pos);
278
279         status = apr_brigade_flatten(input_brigade, buff, &bufsiz);
280         if (status != APR_SUCCESS) {
281             /* We had a failure: Close connection to backend */
282             conn->close = 1;
283             apr_brigade_destroy(input_brigade);
284             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00874)
285                           "apr_brigade_flatten");
286             return HTTP_INTERNAL_SERVER_ERROR;
287         }
288         apr_brigade_cleanup(input_brigade);
289
290         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00875)
291                       "got %" APR_SIZE_T_FMT " bytes of data", bufsiz);
292         if (bufsiz > 0) {
293             status = ajp_send_data_msg(conn->sock, msg, bufsiz);
294             ajp_msg_log(r, msg, "First ajp_send_data_msg: ajp_ilink_send packet dump");
295             if (status != APR_SUCCESS) {
296                 /* We had a failure: Close connection to backend */
297                 conn->close = 1;
298                 apr_brigade_destroy(input_brigade);
299                 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00876)
300                               "send failed to %pI (%s)",
301                               conn->worker->cp->addr,
302                               conn->worker->s->hostname);
303                 /*
304                  * It is fatal when we failed to send a (part) of the request
305                  * body.
306                  */
307                 return HTTP_INTERNAL_SERVER_ERROR;
308             }
309             conn->worker->s->transferred += bufsiz;
310             send_body = 1;
311         }
312         else if (content_length > 0) {
313             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00877)
314                           "read zero bytes, expecting"
315                           " %" APR_OFF_T_FMT " bytes",
316                           content_length);
317             /*
318              * We can only get here if the client closed the connection
319              * to us without sending the body.
320              * Now the connection is in the wrong state on the backend.
321              * Sending an empty data msg doesn't help either as it does
322              * not move this connection to the correct state on the backend
323              * for later resusage by the next request again.
324              * Close it to clean things up.
325              */
326             conn->close = 1;
327             return HTTP_BAD_REQUEST;
328         }
329     }
330
331     /* read the response */
332     conn->data = NULL;
333     status = ajp_read_header(conn->sock, r, maxsize,
334                              (ajp_msg_t **)&(conn->data));
335     if (status != APR_SUCCESS) {
336         /* We had a failure: Close connection to backend */
337         conn->close = 1;
338         apr_brigade_destroy(input_brigade);
339         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00878)
340                       "read response failed from %pI (%s)",
341                       conn->worker->cp->addr,
342                       conn->worker->s->hostname);
343
344         /* If we had a successful cping/cpong and then a timeout
345          * we assume it is a request that cause a back-end timeout,
346          * but doesn't affect the whole worker.
347          */
348         if (APR_STATUS_IS_TIMEUP(status) &&
349                 conn->worker->s->ping_timeout_set) {
350             return HTTP_GATEWAY_TIME_OUT;
351         }
352
353         /*
354          * This is only non fatal when we have not sent (parts) of a possible
355          * request body so far (we do not store it and thus cannot send it
356          * again) and the method is idempotent. In this case we can dare to
357          * retry it with a different worker if we are a balancer member.
358          */
359         if (!send_body && (is_idempotent(r) == METHOD_IDEMPOTENT)) {
360             return HTTP_SERVICE_UNAVAILABLE;
361         }
362         return HTTP_INTERNAL_SERVER_ERROR;
363     }
364     /* parse the response */
365     result = ajp_parse_type(r, conn->data);
366     output_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
367
368     /*
369      * Prepare apr_pollfd_t struct for possible later check if there is currently
370      * data available from the backend (do not flush response to client)
371      * or not (flush response to client)
372      */
373     conn_poll = apr_pcalloc(p, sizeof(apr_pollfd_t));
374     conn_poll->reqevents = APR_POLLIN;
375     conn_poll->desc_type = APR_POLL_SOCKET;
376     conn_poll->desc.s = conn->sock;
377
378     bufsiz = maxsize;
379     for (;;) {
380         switch (result) {
381             case CMD_AJP13_GET_BODY_CHUNK:
382                 if (havebody) {
383                     if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
384                         /* This is the end */
385                         bufsiz = 0;
386                         havebody = 0;
387                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00879)
388                                       "APR_BUCKET_IS_EOS");
389                     } else {
390                         status = ap_get_brigade(r->input_filters, input_brigade,
391                                                 AP_MODE_READBYTES,
392                                                 APR_BLOCK_READ,
393                                                 maxsize - AJP_HEADER_SZ);
394                         if (status != APR_SUCCESS) {
395                             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00880)
396                                           "ap_get_brigade failed");
397                             if (APR_STATUS_IS_TIMEUP(status)) {
398                                 rv = HTTP_REQUEST_TIME_OUT;
399                             }
400                             else if (status == AP_FILTER_ERROR) {
401                                 rv = AP_FILTER_ERROR;
402                             }
403                             client_failed = 1;
404                             break;
405                         }
406                         bufsiz = maxsize;
407                         status = apr_brigade_flatten(input_brigade, buff,
408                                                      &bufsiz);
409                         apr_brigade_cleanup(input_brigade);
410                         if (status != APR_SUCCESS) {
411                             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00881)
412                                          "apr_brigade_flatten failed");
413                             rv = HTTP_INTERNAL_SERVER_ERROR;
414                             client_failed = 1;
415                             break;
416                         }
417                     }
418
419                     ajp_msg_reset(msg);
420                     /* will go in ajp_send_data_msg */
421                     status = ajp_send_data_msg(conn->sock, msg, bufsiz);
422                     ajp_msg_log(r, msg, "ajp_send_data_msg after CMD_AJP13_GET_BODY_CHUNK: ajp_ilink_send packet dump");
423                     if (status != APR_SUCCESS) {
424                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00882)
425                                       "ajp_send_data_msg failed");
426                         backend_failed = 1;
427                         break;
428                     }
429                     conn->worker->s->transferred += bufsiz;
430                 } else {
431                     /*
432                      * something is wrong TC asks for more body but we are
433                      * already at the end of the body data
434                      */
435                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00883)
436                                   "ap_proxy_ajp_request error read after end");
437                     backend_failed = 1;
438                 }
439                 break;
440             case CMD_AJP13_SEND_HEADERS:
441                 if (headers_sent) {
442                     /* Do not send anything to the client.
443                      * Backend already send us the headers.
444                      */
445                     backend_failed = 1;
446                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00884)
447                                   "Backend sent headers twice.");
448                     break;
449                 }
450                 /* AJP13_SEND_HEADERS: process them */
451                 status = ajp_parse_header(r, conf, conn->data);
452                 if (status != APR_SUCCESS) {
453                     backend_failed = 1;
454                 }
455                 else if ((r->status == 401) && conf->error_override) {
456                     const char *buf;
457                     const char *wa = "WWW-Authenticate";
458                     if ((buf = apr_table_get(r->headers_out, wa))) {
459                         apr_table_set(r->err_headers_out, wa, buf);
460                     } else {
461                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00885)
462                                       "ap_proxy_ajp_request: origin server "
463                                       "sent 401 without WWW-Authenticate header");
464                     }
465                 }
466                 headers_sent = 1;
467                 break;
468             case CMD_AJP13_SEND_BODY_CHUNK:
469                 /* AJP13_SEND_BODY_CHUNK: piece of data */
470                 status = ajp_parse_data(r, conn->data, &size, &send_body_chunk_buff);
471                 if (status == APR_SUCCESS) {
472                     /* If we are overriding the errors, we can't put the content
473                      * of the page into the brigade.
474                      */
475                     if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
476                         /* AJP13_SEND_BODY_CHUNK with zero length
477                          * is explicit flush message
478                          */
479                         if (size == 0) {
480                             if (headers_sent) {
481                                 e = apr_bucket_flush_create(r->connection->bucket_alloc);
482                                 APR_BRIGADE_INSERT_TAIL(output_brigade, e);
483                             }
484                             else {
485                                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00886)
486                                               "Ignoring flush message "
487                                               "received before headers");
488                             }
489                         }
490                         else {
491                             apr_status_t rv;
492
493                             /* Handle the case where the error document is itself reverse
494                              * proxied and was successful. We must maintain any previous
495                              * error status so that an underlying error (eg HTTP_NOT_FOUND)
496                              * doesn't become an HTTP_OK.
497                              */
498                             if (conf->error_override && !ap_is_HTTP_ERROR(r->status)
499                                     && ap_is_HTTP_ERROR(original_status)) {
500                                 r->status = original_status;
501                                 r->status_line = original_status_line;
502                             }
503
504                             e = apr_bucket_transient_create(send_body_chunk_buff, size,
505                                                         r->connection->bucket_alloc);
506                             APR_BRIGADE_INSERT_TAIL(output_brigade, e);
507
508                             if ((conn->worker->s->flush_packets == flush_on) ||
509                                 ((conn->worker->s->flush_packets == flush_auto) &&
510                                 ((rv = apr_poll(conn_poll, 1, &conn_poll_fd,
511                                                  conn->worker->s->flush_wait))
512                                                  != APR_SUCCESS) &&
513                                   APR_STATUS_IS_TIMEUP(rv))) {
514                                 e = apr_bucket_flush_create(r->connection->bucket_alloc);
515                                 APR_BRIGADE_INSERT_TAIL(output_brigade, e);
516                             }
517                             apr_brigade_length(output_brigade, 0, &bb_len);
518                             if (bb_len != -1)
519                                 conn->worker->s->read += bb_len;
520                         }
521                         if (headers_sent) {
522                             if (ap_pass_brigade(r->output_filters,
523                                                 output_brigade) != APR_SUCCESS) {
524                                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00887)
525                                               "error processing body.%s",
526                                               r->connection->aborted ?
527                                               " Client aborted connection." : "");
528                                 client_failed = 1;
529                             }
530                             data_sent = 1;
531                             apr_brigade_cleanup(output_brigade);
532                         }
533                     }
534                 }
535                 else {
536                     backend_failed = 1;
537                 }
538                 break;
539             case CMD_AJP13_END_RESPONSE:
540                 /* If we are overriding the errors, we must not send anything to
541                  * the client, especially as the brigade already contains headers.
542                  * So do nothing here, and it will be cleaned up below.
543                  */
544                 status = ajp_parse_reuse(r, conn->data, &conn_reuse);
545                 if (status != APR_SUCCESS) {
546                     backend_failed = 1;
547                 }
548                 if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
549                     e = apr_bucket_eos_create(r->connection->bucket_alloc);
550                     APR_BRIGADE_INSERT_TAIL(output_brigade, e);
551                     if (ap_pass_brigade(r->output_filters,
552                                         output_brigade) != APR_SUCCESS) {
553                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00888)
554                                       "error processing end");
555                         client_failed = 1;
556                     }
557                     /* XXX: what about flush here? See mod_jk */
558                     data_sent = 1;
559                 }
560                 request_ended = 1;
561                 break;
562             default:
563                 backend_failed = 1;
564                 break;
565         }
566
567         /*
568          * If connection has been aborted by client: Stop working.
569          * Pretend we are done (data_sent) to avoid further processing.
570          */
571         if (r->connection->aborted) {
572             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02821)
573                           "client connection aborted");
574             /* no response yet (or ever), set status for access log */
575             if (!headers_sent) {
576                 r->status = HTTP_BAD_REQUEST;
577             }
578             client_failed = 1;
579             /* return DONE */
580             data_sent = 1;
581             break;
582         }
583
584         /*
585          * We either have finished successfully or we failed.
586          * So bail out
587          */
588         if ((result == CMD_AJP13_END_RESPONSE)
589                 || backend_failed || client_failed)
590             break;
591
592         /* read the response */
593         status = ajp_read_header(conn->sock, r, maxsize,
594                                  (ajp_msg_t **)&(conn->data));
595         if (status != APR_SUCCESS) {
596             backend_failed = 1;
597             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00889)
598                           "ajp_read_header failed");
599             break;
600         }
601         result = ajp_parse_type(r, conn->data);
602     }
603     apr_brigade_destroy(input_brigade);
604
605     /*
606      * Clear output_brigade to remove possible buckets that remained there
607      * after an error.
608      */
609     apr_brigade_cleanup(output_brigade);
610
611     if (backend_failed || client_failed) {
612         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00890)
613                       "Processing of request failed backend: %i, client: %i",
614                       backend_failed, client_failed);
615         /* We had a failure: Close connection to backend */
616         conn->close = 1;
617         if (data_sent) {
618             /* Return DONE to avoid error messages being added to the stream */
619             rv = DONE;
620         }
621     }
622     else if (!request_ended) {
623         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00891)
624                       "Processing of request didn't terminate cleanly");
625         /* We had a failure: Close connection to backend */
626         conn->close = 1;
627         backend_failed = 1;
628         if (data_sent) {
629             /* Return DONE to avoid error messages being added to the stream */
630             rv = DONE;
631         }
632     }
633     else if (!conn_reuse) {
634         /* Our backend signalled connection close */
635         conn->close = 1;
636     }
637     else {
638         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00892)
639                       "got response from %pI (%s)",
640                       conn->worker->cp->addr,
641                       conn->worker->s->hostname);
642
643         if (conf->error_override && ap_is_HTTP_ERROR(r->status)) {
644             /* clear r->status for override error, otherwise ErrorDocument
645              * thinks that this is a recursive error, and doesn't find the
646              * custom error page
647              */
648             rv = r->status;
649             r->status = HTTP_OK;
650             /*
651              * prevent proxy_handler() from treating this as an
652              * internal error.
653              */
654             apr_table_setn(r->notes, "proxy-error-override", "1");
655         }
656         else {
657             rv = OK;
658         }
659     }
660
661     if (backend_failed) {
662         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00893)
663                       "dialog to %pI (%s) failed",
664                       conn->worker->cp->addr,
665                       conn->worker->s->hostname);
666         /*
667          * If we already send data, signal a broken backend connection
668          * upwards in the chain.
669          */
670         if (data_sent) {
671             ap_proxy_backend_broke(r, output_brigade);
672         } else if (!send_body && (is_idempotent(r) == METHOD_IDEMPOTENT)) {
673             /*
674              * This is only non fatal when we have not send (parts) of a possible
675              * request body so far (we do not store it and thus cannot send it
676              * again) and the method is idempotent. In this case we can dare to
677              * retry it with a different worker if we are a balancer member.
678              */
679             rv = HTTP_SERVICE_UNAVAILABLE;
680         } else {
681             /* If we had a successful cping/cpong and then a timeout
682              * we assume it is a request that cause a back-end timeout,
683              * but doesn't affect the whole worker.
684              */
685             if (APR_STATUS_IS_TIMEUP(status) &&
686                     conn->worker->s->ping_timeout_set) {
687                 apr_table_setn(r->notes, "proxy_timedout", "1");
688                 rv = HTTP_GATEWAY_TIME_OUT;
689             }
690             else {
691                 rv = HTTP_INTERNAL_SERVER_ERROR;
692             }
693         }
694     }
695     else if (client_failed) {
696         int level = (r->connection->aborted) ? APLOG_DEBUG : APLOG_ERR;
697         ap_log_rerror(APLOG_MARK, level, status, r, APLOGNO(02822)
698                       "dialog with client %pI failed",
699                       r->connection->client_addr);
700         if (rv == OK) {
701             rv = HTTP_BAD_REQUEST;
702         }
703     }
704
705     /*
706      * Ensure that we sent an EOS bucket thru the filter chain, if we already
707      * have sent some data. Maybe ap_proxy_backend_broke was called and added
708      * one to the brigade already (no longer making it empty). So we should
709      * not do this in this case.
710      */
711     if (data_sent && !r->eos_sent && !r->connection->aborted
712             && APR_BRIGADE_EMPTY(output_brigade)) {
713         e = apr_bucket_eos_create(r->connection->bucket_alloc);
714         APR_BRIGADE_INSERT_TAIL(output_brigade, e);
715     }
716
717     /* If we have added something to the brigade above, send it */
718     if (!APR_BRIGADE_EMPTY(output_brigade)
719         && ap_pass_brigade(r->output_filters, output_brigade) != APR_SUCCESS) {
720         rv = AP_FILTER_ERROR;
721     }
722
723     apr_brigade_destroy(output_brigade);
724
725     if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
726         conn->close = 1;
727     }
728
729     return rv;
730 }
731
732 /*
733  * This handles ajp:// URLs
734  */
735 static int proxy_ajp_handler(request_rec *r, proxy_worker *worker,
736                              proxy_server_conf *conf,
737                              char *url, const char *proxyname,
738                              apr_port_t proxyport)
739 {
740     int status;
741     char server_portstr[32];
742     conn_rec *origin = NULL;
743     proxy_conn_rec *backend = NULL;
744     const char *scheme = "AJP";
745     int retry;
746     proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
747                                                  &proxy_module);
748     apr_pool_t *p = r->pool;
749     apr_uri_t *uri;
750
751     if (ap_cstr_casecmpn(url, "ajp:", 4) != 0) {
752         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00894) "declining URL %s", url);
753         return DECLINED;
754     }
755
756     uri = apr_palloc(p, sizeof(*uri));
757     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00895) "serving URL %s", url);
758
759     /* create space for state information */
760     status = ap_proxy_acquire_connection(scheme, &backend, worker,
761                                          r->server);
762     if (status != OK) {
763         if (backend) {
764             backend->close = 1;
765             ap_proxy_release_connection(scheme, backend, r->server);
766         }
767         return status;
768     }
769
770     backend->is_ssl = 0;
771     backend->close = 0;
772
773     retry = 0;
774     while (retry < 2) {
775         char *locurl = url;
776         /* Step One: Determine Who To Connect To */
777         status = ap_proxy_determine_connection(p, r, conf, worker, backend,
778                                                uri, &locurl, proxyname, proxyport,
779                                                server_portstr,
780                                                sizeof(server_portstr));
781
782         if (status != OK)
783             break;
784
785         /* Step Two: Make the Connection */
786         if (ap_proxy_check_backend(scheme, backend, r->server, 1) &&
787                 ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
788             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00896)
789                           "failed to make connection to backend: %s",
790                           backend->hostname);
791             status = HTTP_SERVICE_UNAVAILABLE;
792             break;
793         }
794
795         /* Handle CPING/CPONG */
796         if (worker->s->ping_timeout_set) {
797             status = ajp_handle_cping_cpong(backend->sock, r,
798                                             worker->s->ping_timeout);
799             /*
800              * In case the CPING / CPONG failed for the first time we might be
801              * just out of luck and got a faulty backend connection, but the
802              * backend might be healthy nevertheless. So ensure that the backend
803              * TCP connection gets closed and try it once again.
804              */
805             if (status != APR_SUCCESS) {
806                 backend->close = 1;
807                 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897)
808                               "cping/cpong failed to %pI (%s)",
809                               worker->cp->addr, worker->s->hostname);
810                 status = HTTP_SERVICE_UNAVAILABLE;
811                 retry++;
812                 continue;
813             }
814         }
815         /* Step Three: Process the Request */
816         status = ap_proxy_ajp_request(p, r, backend, origin, dconf, uri, locurl,
817                                       server_portstr);
818         break;
819     }
820
821     /* Do not close the socket */
822     ap_proxy_release_connection(scheme, backend, r->server);
823     return status;
824 }
825
826 static void ap_proxy_http_register_hook(apr_pool_t *p)
827 {
828     proxy_hook_scheme_handler(proxy_ajp_handler, NULL, NULL, APR_HOOK_FIRST);
829     proxy_hook_canon_handler(proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST);
830 }
831
832 AP_DECLARE_MODULE(proxy_ajp) = {
833     STANDARD20_MODULE_STUFF,
834     NULL,                       /* create per-directory config structure */
835     NULL,                       /* merge per-directory config structures */
836     NULL,                       /* create per-server config structure */
837     NULL,                       /* merge per-server config structures */
838     NULL,                       /* command apr_table_t */
839     ap_proxy_http_register_hook /* register hooks */
840 };
841