⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jk_ajp_common.c

📁 精通tomcat书籍原代码,希望大家共同学习
💻 C
📖 第 1 页 / 共 5 页
字号:

        /* 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) {
                jk_log(l, JK_LOG_INFO,
                       "Error sending request. Will try another pooled connection");
                ajp_next_connection(ae, l);
            }
            else {
                op->recoverable = JK_FALSE;
                jk_log(l, JK_LOG_INFO,
                       "Error sending request. Unrecoverable operation");
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
        else
            break;
    }

    /*
     * If we failed to reuse a connection, try to reconnect.
     */
    if (ae->sd < 0) {

        if (err) {
            /* XXX: If err is set, the tomcat is either dead or disconnected */
            jk_log(l, JK_LOG_INFO,
                   "All endpoints are disconnected or dead");
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }
        /* no need to handle cping/cpong here since it should be at connection time */

        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) {
                jk_log(l, JK_LOG_INFO,
                       "Error sending request on a fresh connection");
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
        else {
            /* Close the socket if unable to connect */
            jk_close_socket(ae->sd);
            ae->sd = -1;
            jk_log(l, JK_LOG_INFO,
                   "Error connecting to the Tomcat process.");
            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,
               "request body to send %d - request body to resend %d",
               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) {
            jk_log(l, JK_LOG_ERROR, "Error resending request body (%d)",
                   postlen);
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }
        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) {
                jk_log(l, JK_LOG_ERROR,
                       "Error resending request body (lb mode) (%d)",
                       postlen);
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
        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 = ae->left_bytes_to_send;
            if (len > AJP13_MAX_SEND_BODY_SZ) {
                len = AJP13_MAX_SEND_BODY_SZ;
            }
            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 len;
            }

            /* 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 = len;
            if (ajp_connection_tcp_send_message(ae, op->post, l) != JK_TRUE) {
                jk_log(l, JK_LOG_ERROR, "Error sending request body");
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
    }
    JK_TRACE_EXIT(l);
    return (JK_TRUE);
}

/*
 * 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:
        {
            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->start_response(r, res.status, res.msg,
                              (const char *const *)res.header_names,
                              (const char *const *)res.header_values,
                              res.num_headers);
        }
        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 (!r->write(r, msg->buf + msg->pos, len)) {
                jk_log(l, JK_LOG_INFO,
                       "Connection aborted or network problems");
                JK_TRACE_EXIT(l);
                return JK_CLIENT_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 ((unsigned int)len > ae->left_bytes_to_send) {
                len = 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 += len;
                JK_TRACE_EXIT(l);
                return JK_AJP13_HAS_RESPONSE;
            }

            jk_log(l, JK_LOG_INFO,
                   "Connection aborted or network problems");

            JK_TRACE_EXIT(l);
            return JK_CLIENT_ERROR;
        }
        break;

    case JK_AJP13_END_RESPONSE:
        ae->reuse = (int)jk_b_get_byte(msg);
        if (!ae->reuse) {
            /*
                * Strange protocol error.
                */
            jk_log(l, JK_LOG_INFO, " Protocol error: Reuse is set to false");
        }
        /* Flush after the last write */
        if (r->flush && !r->flush_packets)
            r->flush(r);

        /* Reuse in all cases */
        ae->reuse = JK_TRUE;
        JK_TRACE_EXIT(l);
        return JK_AJP13_END_RESPONSE;
        break;

    default:
        jk_log(l, JK_LOG_ERROR,
               "Invalid code: %d", 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.
 * We will need another connection to send the request
 * There is need of refactoring here since we mix
 * reply reception (tomcat -> apache) and request send (apache -> tomcat)
 * and everything using the same buffer (repmsg)
 * ajp13/ajp14 is async but handling read/send this way prevent nice recovery
 * In fact if tomcat link is broken during upload (browser -> apache -> tomcat)
 * we'll loose data and we'll have to abort the whole request.
 */
static int ajp_get_reply(jk_endpoint_t *e,
                         jk_ws_service_t *s,
                         jk_logger_t *l,
                         ajp_endpoint_t * p, ajp_operation_t * op)
{
    /* Don't get header from tomcat yet */
    int headeratclient = JK_FALSE;

    JK_TRACE_ENTER(l);

    /* Start read all reply message */
    while (1) {
        int rc = 0;

        /* If we set a reply timeout, check it something is available */
        if (p->worker->reply_timeout != 0) {
            if (ajp_is_input_event(p, p->worker->reply_timeout, l) ==
                JK_FALSE) {
                jk_log(l, JK_LOG_ERROR,
                       "Timeout with waiting reply from tomcat. "
                       "Tomcat is down, stopped or network problems.");
                if (headeratclient == JK_FALSE) {
                    if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
                        op->recoverable = JK_FALSE;
                }
                else {
                    if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
                        op->recoverable = JK_FALSE;
                }

                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }

        if (!ajp_connection_tcp_get_message(p, op->reply, l)) {
            /* we just can't recover, unset recover flag */
            if (headeratclient == JK_FALSE) {
                jk_log(l, JK_LOG_ERROR,
                       "Tomcat is down or refused connection. "
                       "No response has been sent to the client (yet)");
                /*
                 * communication with tomcat has been interrupted BEFORE
                 * headers have been sent to the client.
                 * DISCUSSION: As we suppose that tomcat has already started
                 * to process the query we think it's unrecoverable (and we
                 * should not retry or switch to another tomcat in the
                 * cluster).
                 */

                /*
                 * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCGETREQUEST
                 */
                if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
                    op->recoverable = JK_FALSE;
                /*
                 * we want to display the webservers error page, therefore
                 * we return JK_FALSE
                 */
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
            else {
                jk_log(l, JK_LOG_ERROR,
                       "Tomcat is down or network problems. "
                       "Part of the response has already been sent to the client");

                /* communication with tomcat has been interrupted AFTER
                 * headers have been sent to the client.
                 * headers (and maybe parts of the body) have already been
                 * sent, therefore the response is "complete" in a sense
                 * that nobody should append any data, especially no 500 error
                 * page of the webserver!
                 *
                 * BUT if you retrun JK_TRUE you have a 200 (OK) code in your
                 * in your apache access.log instead of a 500 (Error).
                 * Therefore return FALSE/FALSE
                 * return JK_TRUE;
                 */

                /*
                 * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCSENDHEADER
                 */
                if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
                    op->recoverable = JK_FALSE;

                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }

        rc = ajp_process_callback(op->reply, op->post, p, s, l);

        /* no more data to be sent, fine we have finish here */
        if (JK_AJP13_END_RESPONSE == rc) {
            JK_TRACE_EXIT(l);
            return JK_TRUE;
        }
        else if (JK_AJP13_SEND_HEADERS == rc) {
            headeratclient = JK_TRUE;
        }
        else if (JK_AJP13_HAS_RESPONSE == rc) {
            /*
             * in upload-mode there is no second chance since
             * we may have allready sent part of the uploaded data
             * to Tomcat.
             * In this case if Tomcat connection is broken we must
             * abort request and indicate error.
             * A possible work-around could be to store the uploaded
             * data to file and replay for it
             */
            op->recoverable = JK_FALSE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -