📄 jk_ajp_common.c
字号:
if (!jk_is_socket_connected(ae->sd)) { jk_log(l, JK_LOG_DEBUG, "(%s) socket %d is not connected any more (errno=%d)", ae->worker->name, ae->sd, errno); jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; err = 1; } if (ae->worker->prepost_timeout > 0 && !err) { /* handle cping/cpong if prepost_timeout is set * If the socket is disconnected no need to handle * the cping/cpong */ if (ajp_handle_cping_cpong(ae, ae->worker->prepost_timeout, l) == JK_FALSE) { /* XXX: Is there any reason to try other * connections to the node if one of them fails * the cping/cpong heartbeat? * Tomcat can be either too busy or simply dead, so * there is a chance that all oter connections would * fail as well. */ err = 2; } } /* If we got an error or can't send data, then try to get a pooled * connection and try again. If we are succesful, break out of this * loop. */ if (err || ((rc = ajp_connection_tcp_send_message(ae, op->request, l)) != JK_TRUE)) { if (rc != JK_FATAL_ERROR) { if (err == 1) { jk_log(l, JK_LOG_DEBUG, "(%s) failed sending request. " "Will try another pooled connection", ae->worker->name); } else { jk_log(l, JK_LOG_INFO, "(%s) error sending request. " "Will try another pooled connection", ae->worker->name); } ajp_next_connection(ae, l); } else { op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) error sending request. Unrecoverable operation", ae->worker->name); jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; JK_TRACE_EXIT(l); return JK_FALSE; } } else break; } /* * If we failed to reuse a connection, try to reconnect. */ if (!IS_VALID_SOCKET(ae->sd)) { if (err == 1) { /* If err is set, the tomcat is disconnected */ jk_log(l, JK_LOG_INFO, "(%s) all endpoints are disconnected", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } else if (err) { /* If err is set, the tomcat is dead */ jk_log(l, JK_LOG_INFO, "(%s) all endpoints are dead", ae->worker->name); /* TODO: What is the purpose of the following log message? * IMO it is very confusing and does not reflect the * real reason (CPING/CPONG failed) of the error. * Further more user might deliberately set the * connectionTimeout and this is normal operational * message in that case. */ jk_log(l, JK_LOG_INFO, "(%s) increase the backend idle connection " "timeout or the connection_pool_minsize", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } /* Connect to the backend. * This can be either uninitalized connection or a reconnect. */ if (ajp_connect_to_endpoint(ae, l) == JK_TRUE) { /* * After we are connected, each error that we are going to * have is probably unrecoverable */ if (ajp_connection_tcp_send_message(ae, op->request, l) != JK_TRUE) { /* Close the socket if unable to send request */ jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; jk_log(l, JK_LOG_INFO, "(%s) error sending request on a fresh connection (errno=%d)", ae->worker->name, ae->last_errno); JK_TRACE_EXIT(l); return JK_FALSE; } } else { /* Close the socket if unable to connect */ jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; jk_log(l, JK_LOG_INFO, "(%s) error connecting to the backend server (errno=%d)", ae->worker->name, ae->last_errno); JK_TRACE_EXIT(l); return JK_FALSE; } } /* * From now on an error means that we have an internal server error * or Tomcat crashed. In any case we cannot recover this. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) request body to send %" JK_UINT64_T_FMT " - request body to resend %d", ae->worker->name, ae->left_bytes_to_send, op->reply->len - AJP_HEADER_LEN); /* * POST recovery job is done here and will work when data to * POST are less than 8k, since it's the maximum size of op-post buffer. * We send here the first part of data which was sent previously to the * remote Tomcat */ /* Did we have something to resend (ie the op-post has been feeded previously */ postlen = op->post->len; if (postlen > AJP_HEADER_LEN) { if (ajp_connection_tcp_send_message(ae, op->post, l) != JK_TRUE) { /* Close the socket if unable to send request */ jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; jk_log(l, JK_LOG_ERROR, "(%s) failed resending request body (%d)", ae->worker->name, postlen); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Resent the request body (%d)", postlen); } } else if (s->reco_status == RECO_FILLED) { /* Recovery in LB MODE */ postlen = s->reco_buf->len; if (postlen > AJP_HEADER_LEN) { if (ajp_connection_tcp_send_message(ae, s->reco_buf, l) != JK_TRUE) { /* Close the socket if unable to send request */ jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; jk_log(l, JK_LOG_ERROR, "(%s) failed resending request body (lb mode) (%d)", ae->worker->name, postlen); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Resent the request body (lb mode) (%d)", postlen); } } else { /* We never sent any POST data and we check if we have to send at * least one block of data (max 8k). These data will be kept in reply * for resend if the remote Tomcat is down, a fact we will learn only * doing a read (not yet) */ /* || s->is_chunked - this can't be done here. The original protocol sends the first chunk of post data ( based on Content-Length ), and that's what the java side expects. Sending this data for chunked would break other ajp13 servers. Note that chunking will continue to work - using the normal read. */ if (ae->left_bytes_to_send > 0) { int len = AJP13_MAX_SEND_BODY_SZ; if (ae->left_bytes_to_send < (jk_uint64_t)AJP13_MAX_SEND_BODY_SZ) { len = (int)ae->left_bytes_to_send; } if ((len = ajp_read_into_msg_buff(ae, s, op->post, len, l)) < 0) { /* the browser stop sending data, no need to recover */ op->recoverable = JK_FALSE; JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } /* If a RECOVERY buffer is available in LB mode, fill it */ if (s->reco_status == RECO_INITED) { jk_b_copy(op->post, s->reco_buf); s->reco_status = RECO_FILLED; } s->content_read = (jk_uint64_t)len; if (ajp_connection_tcp_send_message(ae, op->post, l) != JK_TRUE) { /* Close the socket if unable to send request */ jk_shutdown_socket(ae->sd); ae->sd = JK_INVALID_SOCKET; jk_log(l, JK_LOG_ERROR, "(%s) error sending request body", ae->worker->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } } } JK_TRACE_EXIT(l); return (JK_TRUE);}static int is_http_status_fail(ajp_worker_t *w, int status){ unsigned int i; int soft_status = -1 * status; for (i = 0; i < w->http_status_fail_num; i++) { if (w->http_status_fail[i] == status) return 1; else if (w->http_status_fail[i] == soft_status) return -1; } return 0;}/* * What to do with incoming data (dispatcher) */static int ajp_process_callback(jk_msg_buf_t *msg, jk_msg_buf_t *pmsg, ajp_endpoint_t * ae, jk_ws_service_t *r, jk_logger_t *l){ int code = (int)jk_b_get_byte(msg); JK_TRACE_ENTER(l); switch (code) { case JK_AJP13_SEND_HEADERS: { int rc; jk_res_data_t res; if (!ajp_unmarshal_response(msg, &res, ae, l)) { jk_log(l, JK_LOG_ERROR, "ajp_unmarshal_response failed"); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } r->http_response_status = res.status; rc = is_http_status_fail(ae->worker, res.status); if (rc > 0) { JK_TRACE_EXIT(l); return JK_STATUS_FATAL_ERROR; } else if (rc < 0) { JK_TRACE_EXIT(l); return JK_STATUS_ERROR; } r->start_response(r, res.status, res.msg, (const char *const *)res.header_names, (const char *const *)res.header_values, res.num_headers); if (r->flush && r->flush_header) r->flush(r); } return JK_AJP13_SEND_HEADERS; case JK_AJP13_SEND_BODY_CHUNK: { unsigned int len = (unsigned int)jk_b_get_int(msg); /* * Do a sanity check on len to prevent write reading beyond buffer * boundaries and thus revealing possible sensitive memory * contents to the client. * len cannot be larger than msg->len - 3 because the ajp message * contains the magic byte for JK_AJP13_SEND_BODY_CHUNK (1 byte) * and the length of the chunk (2 bytes). The remaining part of * the message is the chunk. */ if (len > (unsigned int)(msg->len - 3)) { jk_log(l, JK_LOG_ERROR, "Chunk length too large. Length of AJP message is %i," " chunk length is %i.", msg->len, len); JK_TRACE_EXIT(l); return JK_INTERNAL_ERROR; } if (len == 0) { /* AJP13_SEND_BODY_CHUNK with length 0 is * explicit flush packet message. */ if (r->flush) r->flush(r); } else { if (!r->write(r, msg->buf + msg->pos, len)) { jk_log(l, JK_LOG_INFO, "Writing to client aborted or client network problems"); JK_TRACE_EXIT(l); return JK_CLIENT_WR_ERROR; } if (r->flush && r->flush_packets) r->flush(r); } } break; case JK_AJP13_GET_BODY_CHUNK: { int len = (int)jk_b_get_int(msg); if (len < 0) { len = 0; } if (len > AJP13_MAX_SEND_BODY_SZ) { len = AJP13_MAX_SEND_BODY_SZ; } if ((jk_uint64_t)len > ae->left_bytes_to_send) { len = (int)ae->left_bytes_to_send; } /* the right place to add file storage for upload */ if ((len = ajp_read_into_msg_buff(ae, r, pmsg, len, l)) >= 0) { r->content_read += (jk_uint64_t)len; JK_TRACE_EXIT(l); return JK_AJP13_HAS_RESPONSE; } jk_log(l, JK_LOG_INFO, "Reding from client aborted or client network problems"); JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } break; case JK_AJP13_END_RESPONSE: ae->reuse = (int)jk_b_get_byte(msg); if (!ae->reuse) { /* * AJP13 protocol reuse flag set to false. * Tomcat will close its side of the connection. */ jk_log(l, JK_LOG_WARNING, "AJP13 protocol: Reuse is set to false"); } else if (r->disable_reuse) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is disabled"); } ae->reuse = JK_FALSE; } else { /* Reuse in all cases */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is OK"); } ae->reuse = JK_TRUE; } /* Flush after the last write */ if (r->flush && !r->flush_packets) r->flush(r); JK_TRACE_EXIT(l); return JK_AJP13_END_RESPONSE; break; default: jk_log(l, JK_LOG_ERROR, "Unknown AJP protocol code: %02X", code); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } JK_TRACE_EXIT(l); return JK_AJP13_NO_RESPONSE;}/* * get replies from Tomcat via Ajp13/Ajp14 * We will know only at read time if the remote host closed * the connection (half-closed state - FIN-WAIT2). In that case * we must close our side of the socket and abort emission.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -