/* Check the reuse flag in CMD_AJP13_END_RESPONSE */ apr_status_t ajp_parse_reuse(request_rec *r, ajp_msg_t *msg, apr_byte_t *reuse) { apr_byte_t result; apr_status_t rc; rc = ajp_msg_get_uint8(msg, &result); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00999) "ajp_parse_reuse: ajp_msg_get_byte failed"); return rc; } if (result != CMD_AJP13_END_RESPONSE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01000) "ajp_parse_reuse: wrong type %s (0x%02x) expecting %s (0x%02x)", ajp_type_str(result), result, ajp_type_str(CMD_AJP13_END_RESPONSE), CMD_AJP13_END_RESPONSE); return AJP_EBAD_HEADER; } return ajp_msg_get_uint8(msg, reuse); }
/* 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; }
/* parse the header */ apr_status_t ajp_parse_header(request_rec *r, proxy_dir_conf *conf, ajp_msg_t *msg) { apr_byte_t result; apr_status_t rc; rc = ajp_msg_get_uint8(msg, &result); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00994) "ajp_parse_headers: ajp_msg_get_byte failed"); return rc; } if (result != CMD_AJP13_SEND_HEADERS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00995) "ajp_parse_headers: wrong type %s (0x%02x) expecting %s (0x%02x)", ajp_type_str(result), result, ajp_type_str(CMD_AJP13_SEND_HEADERS), CMD_AJP13_SEND_HEADERS); return AJP_EBAD_HEADER; } return ajp_unmarshal_response(msg, r, conf); }
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; }