ngx_int_t
ajp_msg_get_string(ajp_msg_t *msg, ngx_str_t *value)
{
    u_char    *start;
    uint16_t   size;
    ngx_int_t  status;
    ngx_buf_t *buf;

    buf = msg->buf;
    status = ajp_msg_get_uint16(msg, &size);

    start = buf->pos;

    if ((status != NGX_OK) || (start + size + 1 > buf->last)) {
        return ajp_log_overflow(msg, "ajp_msg_get_string");
    }

    buf->pos += (size_t)size;
    buf->pos++;   /* a String in AJP is NULL terminated */

    value->data = start;
    value->len = size;

    return NGX_OK;
}
Beispiel #2
0
/* parse the body and return data address and length */
apr_status_t  ajp_parse_data(request_rec  *r, ajp_msg_t *msg,
                             apr_uint16_t *len, char **ptr)
{
    apr_byte_t result;
    apr_status_t rc;
    apr_uint16_t expected_len;

    rc = ajp_msg_get_uint8(msg, &result);
    if (rc != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00996)
               "ajp_parse_data: ajp_msg_get_byte failed");
        return rc;
    }
    if (result != CMD_AJP13_SEND_BODY_CHUNK) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00997)
               "ajp_parse_data: wrong type %s (0x%02x) expecting %s (0x%02x)",
               ajp_type_str(result), result,
               ajp_type_str(CMD_AJP13_SEND_BODY_CHUNK), CMD_AJP13_SEND_BODY_CHUNK);
        return AJP_EBAD_HEADER;
    }
    rc = ajp_msg_get_uint16(msg, len);
    if (rc != APR_SUCCESS) {
        return rc;
    }
    /*
     * msg->len contains the complete length of the message including all
     * headers. So the expected length for a CMD_AJP13_SEND_BODY_CHUNK is
     * msg->len minus the sum of
     * AJP_HEADER_LEN    : The length of the header to every AJP message.
     * AJP_HEADER_SZ_LEN : The header giving the size of the chunk.
     * 1                 : The CMD_AJP13_SEND_BODY_CHUNK indicator byte (0x03).
     * 1                 : The last byte of this message always seems to be
     *                     0x00 and is not part of the chunk.
     */
    expected_len = msg->len - (AJP_HEADER_LEN + AJP_HEADER_SZ_LEN + 1 + 1);
    if (*len != expected_len) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00998)
               "ajp_parse_data: Wrong chunk length. Length of chunk is %i,"
               " expected length is %i.", *len, expected_len);
        return AJP_EBAD_HEADER;
    }
    *ptr = (char *)&(msg->buf[msg->pos]);
    return APR_SUCCESS;
}
Beispiel #3
0
/**
 * Get a String value from AJP Message
 *
 * @param msg       AJP Message to get value from
 * @param rvalue    Pointer where value will be returned
 * @return          APR_SUCCESS or error
 */
apr_status_t ajp_msg_get_string(ajp_msg_t *msg, const char **rvalue)
{
    apr_uint16_t size;
    apr_size_t   start;
    apr_status_t status;

    status = ajp_msg_get_uint16(msg, &size);
    start = msg->pos;

    if ((status != APR_SUCCESS) || (size + start > msg->max_size)) {
        return ajp_log_overflow(msg, "ajp_msg_get_string");
    }

    msg->pos += (apr_size_t)size;
    msg->pos++;                   /* a String in AJP is NULL terminated */

    *rvalue = (const char *)(msg->buf + start);
    return APR_SUCCESS;
}
Beispiel #4
0
/**
 * Get a Byte array from AJP Message
 *
 * @param msg       AJP Message to get value from
 * @param rvalue    Pointer where value will be returned
 * @param rvalueLen Pointer where Byte array len will be returned
 * @return          APR_SUCCESS or error
 */
apr_status_t ajp_msg_get_bytes(ajp_msg_t *msg, apr_byte_t **rvalue,
                               apr_size_t *rvalue_len)
{
    apr_uint16_t size;
    apr_size_t   start;
    apr_status_t status;

    status = ajp_msg_get_uint16(msg, &size);
    /* save the current position */
    start = msg->pos;

    if ((status != APR_SUCCESS) || (size + start > msg->max_size)) {
        return ajp_log_overflow(msg, "ajp_msg_get_bytes");
    }
    msg->pos += (apr_size_t)size;   /* only bytes, no trailer */

    *rvalue     = msg->buf + start;
    *rvalue_len = size;

    return APR_SUCCESS;
}
static ngx_int_t
ngx_http_ajp_process_header(ngx_http_request_t *r)
{
    u_char                   *pos, *last, type, reuse;
    uint16_t                  length;
    ngx_int_t                 rc;
    ngx_buf_t                *buf;
    ajp_msg_t                *msg;
    ngx_http_ajp_ctx_t       *a;
    ngx_http_upstream_t      *u;
    ngx_http_ajp_loc_conf_t  *alcf;

    a = ngx_http_get_module_ctx(r, ngx_http_ajp_module);
    alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module);

    if (a == NULL || alcf == NULL) {
        return NGX_ERROR;
    }

    ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                  "ngx_http_ajp_process_header: state(%d)", a->state);

    u = r->upstream;

    msg = ajp_msg_reuse(&a->msg);
    buf = msg->buf = &u->buffer;

    while (buf->pos < buf->last) {

        ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                      "ngx_http_ajp_process_header: parse response, "
                      "pos:%p, last:%p", buf->pos, buf->last);

        /* save the position for returning NGX_AGAIN */
        pos = buf->pos;
        last = buf->last;

        if (ngx_buf_size(msg->buf) < AJP_HEADER_LEN + 1) {
            return ngx_http_ajp_move_buffer(r, buf, pos, last);
        }

        rc = ajp_msg_parse_begin(msg);
        if (rc != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "ngx_http_ajp_process_header: bad header\n"
                          "%s", ajp_msg_dump(r->pool, msg, "bad header"));

            return NGX_ERROR;
        }

        rc = ajp_msg_get_uint8(msg, (u_char *)&type);
        if (rc != NGX_OK) {
            return NGX_ERROR;
        }

        switch (type) {
            case CMD_AJP13_GET_BODY_CHUNK:

                rc = ajp_msg_get_uint16(msg, &length);
                if (rc == AJP_EOVERFLOW) {
                    return ngx_http_ajp_move_buffer(r, buf, pos, last);
                }

                rc = ngx_http_upstream_send_request_body(r, u);
                if (rc != NGX_OK) {
                    return rc;
                }

                break;

            case CMD_AJP13_SEND_HEADERS:

                rc = ajp_unmarshal_response(msg, r, alcf);

                if (rc == NGX_OK) {
                    a->state = ngx_http_ajp_st_response_parse_headers_done;
                    return NGX_OK;

                } else if (rc == AJP_EOVERFLOW) {
                    a->state = ngx_http_ajp_st_response_recv_headers;

                    /* reinit the headers_int list, the memory may be stale */
                    ngx_list_reinit(&u->headers_in.headers);

                    /* It's an uncomplete AJP packet, move back to the header
                     * of packet, and parse the header again in next call
                     */
                    return ngx_http_ajp_move_buffer(r, buf, pos, last);

                } else {
                    return  NGX_ERROR;
                }

                break;

            case CMD_AJP13_SEND_BODY_CHUNK:

                buf->pos = pos;
                a->state = ngx_http_ajp_st_response_body_data_sending;

                /* input_filter function will process these data */
                return NGX_OK;

            case CMD_AJP13_END_RESPONSE:

                rc = ajp_msg_get_uint8(msg, &reuse);
                if (rc == AJP_EOVERFLOW) {
                    return ngx_http_ajp_move_buffer(r, buf, pos, last);
                }

                ngx_http_ajp_end_response(r, reuse);

                buf->last_buf = 1;
                return NGX_OK;

            default:

                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "ngx_http_ajp_process_header: "
                              "bad_packet_type(%d)\n%s",
                              type, ajp_msg_dump(r->pool, msg, "bad type"));

                return  NGX_ERROR;
        }
    }

    return NGX_AGAIN;
}
Beispiel #6
0
static apr_status_t ajp_unmarshal_response(ajp_msg_t *msg,
                                           request_rec *r,
                                           proxy_dir_conf *dconf)
{
    apr_uint16_t status;
    apr_status_t rc;
    const char *ptr;
    apr_uint16_t  num_headers;
    int i;

    rc = ajp_msg_get_uint16(msg, &status);

    if (rc != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00983)
                "ajp_unmarshal_response: Null status");
        return rc;
    }
    r->status = status;

    rc = ajp_msg_get_string(msg, &ptr);
    if (rc == APR_SUCCESS) {
#if APR_CHARSET_EBCDIC /* copy only if we have to */
        ptr = apr_pstrdup(r->pool, ptr);
        ap_xlate_proto_from_ascii(ptr, strlen(ptr));
#endif
        r->status_line =  apr_psprintf(r->pool, "%d %s", status, ptr);
    } else {
        r->status_line = NULL;
    }

    ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r,
           "ajp_unmarshal_response: status = %d", status);

    rc = ajp_msg_get_uint16(msg, &num_headers);
    if (rc == APR_SUCCESS) {
        apr_table_t *save_table;

        /* First, tuck away all already existing cookies */
        /*
         * Could optimize here, but just in case we want to
         * also save other headers, keep this logic.
         */
        save_table = apr_table_make(r->pool, num_headers + 2);
        apr_table_do(addit_dammit, save_table, r->headers_out,
                     "Set-Cookie", NULL);
        r->headers_out = save_table;
    } else {
        r->headers_out = NULL;
        num_headers = 0;
    }

    ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r,
           "ajp_unmarshal_response: Number of headers is = %d",
           num_headers);

    for(i = 0 ; i < (int) num_headers ; i++) {
        apr_uint16_t name;
        const char *stringname;
        const char *value;
        rc  = ajp_msg_peek_uint16(msg, &name);
        if (rc != APR_SUCCESS) {
            return rc;
        }

        if ((name & 0XFF00) == 0XA000) {
            ajp_msg_get_uint16(msg, &name);
            stringname = long_res_header_for_sc(name);
            if (stringname == NULL) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00984)
                       "ajp_unmarshal_response: "
                       "No such sc (%08x)",
                       name);
                return AJP_EBAD_HEADER;
            }
        } else {
            name = 0;
            rc = ajp_msg_get_string(msg, &stringname);
            if (rc != APR_SUCCESS) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00985)
                       "ajp_unmarshal_response: "
                       "Null header name");
                return rc;
            }
            ap_xlate_proto_from_ascii(stringname, strlen(stringname));
        }

        rc = ajp_msg_get_string(msg, &value);
        if (rc != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00986)
                   "ajp_unmarshal_response: "
                   "Null header value");
            return rc;
        }

        /* Set-Cookie need additional processing */
        if (!strcasecmp(stringname, "Set-Cookie")) {
            value = ap_proxy_cookie_reverse_map(r, dconf, value);
        }
        /* Location, Content-Location, URI and Destination need additional
         * processing */
        else if (!strcasecmp(stringname, "Location")
                 || !strcasecmp(stringname, "Content-Location")
                 || !strcasecmp(stringname, "URI")
                 || !strcasecmp(stringname, "Destination"))
        {
          value = ap_proxy_location_reverse_map(r, dconf, value);
        }

        ap_xlate_proto_from_ascii(value, strlen(value));
        ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r,
               "ajp_unmarshal_response: Header[%d] [%s] = [%s]",
                       i, stringname, value);

        apr_table_add(r->headers_out, stringname, value);

        /* Content-type needs an additional handling */
        if (strcasecmp(stringname, "Content-Type") == 0) {
             /* add corresponding filter */
            ap_set_content_type(r, apr_pstrdup(r->pool, value));
            ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r,
               "ajp_unmarshal_response: ap_set_content_type to '%s'", value);
        }
    }

    return APR_SUCCESS;
}
/*
   AJPV13_RESPONSE/AJPV14_RESPONSE:=
   response_prefix (2)
   status          (short)
   status_msg      (short)
   num_headers     (short)
   num_headers*(res_header_name header_value)
 *body_chunk
 terminator      boolean <! -- recycle connection or not  -->

req_header_name :=
sc_req_header_name | (string)

res_header_name :=
sc_res_header_name | (string)

header_value :=
(string)

body_chunk :=
length  (short)
body    length*(var binary)

 */
ngx_int_t 
ajp_unmarshal_response(ajp_msg_t *msg,
        ngx_http_request_t *r, ngx_http_ajp_loc_conf_t *alcf)
{
    int                             i;
    u_char                          line[1024], *last;
    uint16_t                        status;
    uint16_t                        name;
    uint16_t                        num_headers;
    ngx_int_t                       rc;
    ngx_str_t                       str;
    ngx_log_t                      *log;
    ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;

    log = r->connection->log; 

    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

    u = r->upstream;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "ajp_unmarshal_response");

    rc = ajp_msg_get_uint16(msg, &status);
    if (rc != NGX_OK) {
        return rc;
    }
    u->headers_in.status_n = status;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
            "ajp_unmarshal_response: status = %d", status);

    rc = ajp_msg_get_string(msg, &str);
    if (rc == NGX_OK) {
        if (str.len > 0) {
            last = ngx_snprintf(line, 1024, "%d %V", status, &str);

            str.data = line;
            str.len = last - line;

            u->headers_in.status_line.data = ngx_pstrdup(r->pool, &str);
            u->headers_in.status_line.len = str.len;
        }
        else {
            u->headers_in.status_line.data = NULL;
            u->headers_in.status_line.len = 0;
        }
    }
    else {
        return rc;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
            "ajp_unmarshal_response: status_line = \"%V\"", 
            &u->headers_in.status_line);

    if (u->state) {
        u->state->status = u->headers_in.status_n;
    }

    num_headers = 0;
    rc = ajp_msg_get_uint16(msg, &num_headers);
    if (rc != NGX_OK) {
        return rc;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
            "ajp_unmarshal_response: Number of headers is = %d", num_headers);

    for(i = 0 ; i < (int) num_headers ; i++) {

        rc  = ajp_msg_peek_uint16(msg, &name);
        if (rc != NGX_OK) {
            return rc;
        }

        /* a header line has been parsed successfully */

        h = ngx_list_push(&u->headers_in.headers);
        if (h == NULL) {
            return NGX_ERROR;
        }

        if ((name & 0XFF00) == 0XA000) {
            ajp_msg_get_uint16(msg, &name);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http ajp known header: %08Xd", name);

            rc = get_res_header_for_sc(name, h);
            if (rc != NGX_OK) {
                ngx_log_error(NGX_LOG_ERR, log, 0,
                        "ajp_unmarshal_response: No such sc (%08Xd)", name);
                return NGX_ERROR;
            }

        } else {
            name = 0;
            rc = ajp_msg_get_string(msg, &str);
            if (rc != NGX_OK) {
                if (rc != AJP_EOVERFLOW) {
                    ngx_log_error(NGX_LOG_ERR, log, 0,
                            "ajp_unmarshal_response: Null header name");
                }
                return rc;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http ajp unknown header: %V", &str);

            rc = get_res_unknown_header_by_str(&str, h, r->pool);
            if (rc != NGX_OK) {
                return rc;
            }
        }

        rc = ajp_msg_get_string(msg, &h->value);
        if (rc != NGX_OK) {
            if (rc != AJP_EOVERFLOW) {
                ngx_log_error(NGX_LOG_ERR, log, 0,
                        "ajp_unmarshal_response: Null header value");
            }
            return rc;
        }

        hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                h->lowcase_key, h->key.len);

        if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, log, 0,
                    "ajp_unmarshal_response: hh->handler error: \"%V: %V\"", 
                    &h->key, &h->value);

            return NGX_ERROR;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
                "http ajp header: \"%V: %V\"", &h->key, &h->value);
    }

    return NGX_OK;
}