static ngx_int_t ngx_http_ajp_create_request(ngx_http_request_t *r) { ajp_msg_t *msg; ngx_chain_t *cl; ngx_http_ajp_ctx_t *a; 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; } msg = ajp_msg_reuse(&a->msg); if (NGX_OK != ajp_msg_create_buffer(r->pool, alcf->ajp_header_packet_buffer_size_conf, msg)) { return NGX_ERROR; } if (NGX_OK != ajp_marshal_into_msgb(msg, r, alcf)) { return NGX_ERROR; } ajp_msg_end(msg); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = msg->buf; cl->buf->flush = 1; a->state = ngx_http_ajp_st_forward_request_sent; if (alcf->upstream.pass_request_body) { a->body = r->upstream->request_bufs; r->upstream->request_bufs = cl; cl->next = ajp_data_msg_send_body(r, alcf->max_ajp_data_packet_size_conf, &a->body); if (a->body) { a->state = ngx_http_ajp_st_request_body_data_sending; } else { a->state = ngx_http_ajp_st_request_send_all_done; } } else { a->state = ngx_http_ajp_st_request_send_all_done; r->upstream->request_bufs = cl; cl->next = NULL; } return NGX_OK; }
/* * Read the ajp message and return the type of the message. */ apr_status_t ajp_read_header(apr_socket_t *sock, request_rec *r, apr_size_t buffsize, ajp_msg_t **msg) { apr_byte_t result; apr_status_t rc; if (*msg) { rc = ajp_msg_reuse(*msg); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00990) "ajp_read_header: ajp_msg_reuse failed"); return rc; } } else { rc = ajp_msg_create(r->pool, buffsize, msg); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00991) "ajp_read_header: ajp_msg_create failed"); return rc; } } ajp_msg_reset(*msg); rc = ajp_ilink_receive(sock, *msg); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00992) "ajp_read_header: ajp_ilink_receive failed"); return rc; } ajp_msg_log(r, *msg, "ajp_read_header: ajp_ilink_receive packet dump"); rc = ajp_msg_peek_uint8(*msg, &result); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00993) "ajp_read_header: ajp_msg_peek_uint8 failed"); return rc; } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "ajp_read_header: ajp_ilink_received %s (0x%02x)", ajp_type_str(result), result); return APR_SUCCESS; }
static ngx_int_t ngx_http_ajp_reinit_request(ngx_http_request_t *r) { ngx_http_ajp_ctx_t *a; 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; } a->state = ngx_http_ajp_st_init_state; a->pstate = ngx_http_ajp_pst_init_state; a->length = 0; a->extra_zero_byte = 0; ajp_msg_reuse(&a->msg); a->body = NULL; return NGX_OK; }
ngx_chain_t * ajp_data_msg_send_body(ngx_http_request_t *r, size_t max_size, ngx_chain_t **body) { size_t size; ngx_buf_t *b_in, *b_out; ajp_msg_t *msg; ngx_chain_t *out, *cl, *in; ngx_http_ajp_ctx_t *a; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); if (*body == NULL || a == NULL) { return NULL; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ajp_data_msg_send_body"); msg = ajp_msg_reuse(&a->msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NULL; } out = cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NULL; } cl->buf = msg->buf; max_size -= AJP_HEADER_SZ; size = 0; in = *body; b_out = NULL; while (in) { b_in = in->buf; b_out = ngx_alloc_buf(r->pool); if (b_out == NULL) { return NULL; } ngx_memcpy(b_out, b_in, sizeof(ngx_buf_t)); if (b_in->in_file) { if ((size_t)(b_in->file_last - b_in->file_pos) <= (max_size - size)) { b_out->file_pos = b_in->file_pos; b_out->file_last = b_in->file_pos = b_in->file_last; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } else if ((size_t)(b_in->file_last - b_in->file_pos) > (max_size - size)) { b_out->file_pos = b_in->file_pos; b_in->file_pos += max_size - size; b_out->file_last = b_in->file_pos; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } } else { if ((size_t)(b_in->last - b_in->pos) <= (max_size - size)) { b_out->pos = b_in->pos; b_out->last = b_in->pos = b_in->last; size += b_out->last - b_out->pos; } else if ((size_t)(b_in->last - b_in->pos) > (max_size - size)) { b_out->pos = b_in->pos; b_in->pos += max_size - size; b_out->last = b_in->pos; size += b_out->last - b_out->pos; } } cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NULL; } cl = cl->next; cl->buf = b_out; if (size >= max_size) { break; } else { in = in->next; } } *body = in; cl->next = NULL; ajp_data_msg_end(msg, size); return out; }
static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_int_t rc; ngx_chain_t *cl; ajp_msg_t *msg, local_msg; ngx_connection_t *c; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; c = u->peer.connection; 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->state > ngx_http_ajp_st_request_body_data_sending) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx_http_upstream_send_request_body: bad state(%d)", a->state); } cl = ajp_data_msg_send_body(r, alcf->max_ajp_data_packet_size_conf, &a->body); if (u->output.in == NULL && u->output.busy == NULL) { if (cl == NULL) { /* If there is no more data in the body (i.e. the servlet * container is trying to read past the end of the body), * the server will send back an "empty" packet, which is * a body packet with a payload length of 0. * (0x12,0x34,0x00,0x00) */ msg = ajp_msg_reuse(&local_msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NGX_ERROR; } ajp_data_msg_end(msg, 0); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = msg->buf; cl->next = NULL; } } if (a->body) { a->state = ngx_http_ajp_st_request_body_data_sending; } else { a->state = ngx_http_ajp_st_request_send_all_done; } c->log->action = "sending request body again to upstream"; rc = ngx_output_chain(&u->output, cl); if (rc == NGX_ERROR) { return NGX_ERROR; } if (c->write->timer_set) { ngx_del_timer(c->write); } if (rc == NGX_AGAIN) { ngx_add_timer(c->write, u->conf->send_timeout); if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_send_request_body_handler; return NGX_AGAIN; } /* rc == NGX_OK */ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_tcp_push_n " failed"); return NGX_ERROR; } c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } ngx_add_timer(c->read, u->conf->read_timeout); if (ngx_handle_write_event(c->write, 0) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_dummy_handler; return NGX_OK; }
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; }