mod_proxy_ajp.c revision 62c48ce0fc62af721a6ee30a74cfc664c9714583
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
842ae4bd224140319ae7feec1872b93dfd491143fielding * applicable.
842ae4bd224140319ae7feec1872b93dfd491143fielding * Licensed under the Apache License, Version 2.0 (the "License");
842ae4bd224140319ae7feec1872b93dfd491143fielding * you may not use this file except in compliance with the License.
842ae4bd224140319ae7feec1872b93dfd491143fielding * You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* AJP routines for Apache proxy */
7764153915ff9a646f32cbd6e39c26f3609829abtrawick * Canonicalise http-like URLs.
2dcfdce30a4dabc6a194c367c9ef5e53d37df638jwoolley * scheme is the scheme for the URL
6865813dee5d3c1ebf12dd810368171792a0190atrawick * url is the URL starting with the first '/'
024cd9589e52cf11ce765dfddb5b5f0c6e421a48gstein * def_port is the default port for this scheme.
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int proxy_ajp_canon(request_rec *r, char *url)
d4f1d9c1ff112a8ab9bee31f196973761329b236rbb const char *err;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* ap_port_of_scheme() */
ea1fb61cbff78b1e1e8d01acc5df0fb495d979c8fielding * do syntactic check.
ea1fb61cbff78b1e1e8d01acc5df0fb495d979c8fielding * We break the URL into host, port, path, search
ea1fb61cbff78b1e1e8d01acc5df0fb495d979c8fielding err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "error parsing URL %s: %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * now parse path/search args, according to rfc1738
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * N.B. if this isn't a true proxy request, then the URL _path_
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * has already been decoded. True proxy requests have
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * r->uri == r->unparsed_uri, and no others have that property.
a93bec588d3829a236a6dc1dca8d51c4eca98d23sf /* process path */
a93bec588d3829a236a6dc1dca8d51c4eca98d23sf path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if literal IPv6 address */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_pstrcat(r->pool, "proxy:ajp://", host, sport,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * XXX: Flushing bandaid
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * When processing CMD_AJP13_SEND_BODY_CHUNK AJP messages we will do a poll
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * with FLUSH_WAIT miliseconds timeout to determine if more data is currently
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * available at the backend. If there is no more data available, we flush
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * the data to the client by adding a flush bucket to the brigade we pass
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * up the filter chain.
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * This is only a bandaid to fix the AJP/1.3 protocol shortcoming of not
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * sending (actually not having defined) a flush message, when the data
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * should be flushed to the client. As soon as this protocol shortcoming is
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * fixed this code should be removed.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * For further discussion see PR37100.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * http://issues.apache.org/bugzilla/show_bug.cgi?id=37100
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Wait 10000 microseconds to find out if more data is currently
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * available at the backend. Just an arbitrary choose.
f95db61e2d8538db83aeef9ce7f9bfef11828ec2sf * process the request and write the response.
f95db61e2d8538db83aeef9ce7f9bfef11828ec2sfstatic int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh const char *tenc;
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * Send the AJP request to the remote server
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* send request headers */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: AJP: request failed to %pI (%s)",
4d12805e6c18253040223ea637acd6b3b3c18f60jorton /* allocate an AJP message to store the data of the buckets */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* We had a failure: Close connection to backend */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: ajp_alloc_data_msg failed");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* read the first bloc of data */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* The AJP protocol does not want body data yet */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: request is chunked");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding status = ap_get_brigade(r->input_filters, input_brigade,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
ce4dc40a4e87991087488f70d96d3447d7557294sf "proxy: ap_get_brigade failed");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* have something */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
ea1fb61cbff78b1e1e8d01acc5df0fb495d979c8fielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: APR_BUCKET_IS_EOS");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Try to send something */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
4d12805e6c18253040223ea637acd6b3b3c18f60jorton status = apr_brigade_flatten(input_brigade, buff, &bufsiz);
3511969853863eeb6e80018afe63831e5bf81447rpluem /* We had a failure: Close connection to backend */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: apr_brigade_flatten");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: got %" APR_SIZE_T_FMT " bytes of data", bufsiz);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding status = ajp_send_data_msg(conn->sock, msg, bufsiz);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* We had a failure: Close connection to backend */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
e8f95a682820a599fe41b22977010636be5c2717jim "proxy: send failed to %pI (%s)",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* read the response */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* We had a failure: Close connection to backend */
ea1fb61cbff78b1e1e8d01acc5df0fb495d979c8fielding ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "proxy: read response failed from %pI (%s)",
ce4dc40a4e87991087488f70d96d3447d7557294sf /* parse the reponse */
ce4dc40a4e87991087488f70d96d3447d7557294sf output_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
ce4dc40a4e87991087488f70d96d3447d7557294sf * Prepare apr_pollfd_t struct for later check if there is currently
ce4dc40a4e87991087488f70d96d3447d7557294sf * data available from the backend (do not flush response to client)
ce4dc40a4e87991087488f70d96d3447d7557294sf * or not (flush response to client)
ce4dc40a4e87991087488f70d96d3447d7557294sf switch (result) {
ce4dc40a4e87991087488f70d96d3447d7557294sf if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
ce4dc40a4e87991087488f70d96d3447d7557294sf /* This is the end */
ce4dc40a4e87991087488f70d96d3447d7557294sf "proxy: APR_BUCKET_IS_EOS");
ce4dc40a4e87991087488f70d96d3447d7557294sf "ap_get_brigade failed");
ce4dc40a4e87991087488f70d96d3447d7557294sf "apr_brigade_flatten failed");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* will go in ajp_send_data_msg */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding status = ajp_send_data_msg(conn->sock, msg, bufsiz);
8079d062f963eccadaa8f584df5c5aa33be09525rbb ap_log_error(APLOG_MARK, APLOG_DEBUG, status, r->server,
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe "ajp_send_data_msg failed");
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asf * something is wrong TC asks for more body but we are
8079d062f963eccadaa8f584df5c5aa33be09525rbb * already at the end of the body data
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "ap_proxy_ajp_request error read after end");
isok = 0;
#ifdef FLUSHING_BANDAID
== APR_TIMEUP) {
isok = 0;
isok = 0;
case CMD_AJP13_END_RESPONSE:
isok = 0;
isok = 0;
if (!isok)
isok = 0;
return HTTP_SERVICE_UNAVAILABLE;
return OK;
return HTTP_SERVICE_UNAVAILABLE;
int status;
&proxy_module);
return DECLINED;
if (!backend) {
r->server);
if (backend) {
return status;
sizeof(server_portstr));
goto cleanup;
goto cleanup;
return status;