ib_parsed_name_value_pair_list_wrapper_t* make_pnv_list( Transaction transaction, Iterator begin, Iterator end ) { ib_parsed_name_value_pair_list_wrapper_t* ib_pnv_list; throw_if_error( ib_parsed_name_value_pair_list_wrapper_create( &ib_pnv_list, transaction.ib() ) ); BOOST_FOREACH( ParsedNameValue pnv, std::make_pair(begin, end) ) { // This will reconstruct the bytestrings but not copy the data. // The C API is currently asymmetric: named values are consumed as // structures but added to list as members. IronBee++ hides that // asymmetry. throw_if_error( ib_parsed_name_value_pair_list_add( ib_pnv_list, pnv.name().const_data(), pnv.name().length(), pnv.value().const_data(), pnv.value().length() ) ); }
/** * nginx post-read-request handler to feed request line and headers to Ironbee. * * @param[in] r The nginx request object. * @return Declined (ignoreme) or error status. */ static ngx_int_t ironbee_post_read_request(ngx_http_request_t *r) { ngx_log_t *prev_log; ngxib_req_ctx *ctx; ib_conn_t *iconn; ib_parsed_req_line_t *rline; ib_parsed_header_wrapper_t *ibhdrs; ib_status_t rc; ngx_list_part_t *part; ngx_table_elt_t *hdr; unsigned int i; /* Don't process internal requests */ if (r->internal) return NGX_DECLINED; prev_log = ngxib_log(r->connection->log); ngx_regex_malloc_init(r->pool); ctx = ngx_pcalloc(r->pool, sizeof(ngxib_req_ctx)); ctx->r = r; ngx_http_set_ctx(r, ctx, ngx_ironbee_module); iconn = ngxib_conn_get(ctx, ironbee); ib_tx_create(&ctx->tx, iconn, ctx); /* Notify Ironbee of request line and headers */ rc = ib_parsed_req_line_create(ctx->tx, &rline, (const char*)r->request_line.data, r->request_line.len, (const char*)r->method_name.data, r->method_name.len, (const char*)r->unparsed_uri.data, r->unparsed_uri.len, (const char*)r->http_protocol.data, r->http_protocol.len); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; ib_state_notify_request_started(ironbee, ctx->tx, rline); rc = ib_parsed_name_value_pair_list_wrapper_create(&ibhdrs, ctx->tx); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; for (part = &r->headers_in.headers.part; part != NULL; part = part->next) { hdr = part->elts; for (i = 0; i < part->nelts; ++i) { ib_parsed_name_value_pair_list_add(ibhdrs, (const char*)hdr->key.data, hdr->key.len, (const char*)hdr->value.data, hdr->value.len); ++hdr; } } rc = ib_state_notify_request_header_data(ironbee, ctx->tx, ibhdrs); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; rc = ib_state_notify_request_header_finished(ironbee, ctx->tx); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; if (!ngxib_has_request_body(r, ctx)) { rc = ib_state_notify_request_finished(ironbee, ctx->tx); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; } ctx->hdrs_in = 1; if (STATUS_IS_ERROR(ctx->status)) { ctx->internal_errordoc = 1; cleanup_return(prev_log) ctx->status; } cleanup_return(prev_log) NGX_DECLINED; }
/** * A header filter to intercept response line and headers and feed to Ironbee. * * @param[in] r The nginx request object. * @return status propagated from next filter, or Error */ static ngx_int_t ironbee_headers_out(ngx_http_request_t *r) { ngx_log_t *prev_log; ngxib_req_ctx *ctx; ib_parsed_resp_line_t *rline; ib_parsed_header_wrapper_t *ibhdrs; ib_status_t rc; ngx_list_part_t *part; ngx_table_elt_t *hdr; unsigned int i; char proto[12]; char *status; const char *reason; int status_len, reason_len; /* FIXME: needs more logic here to catch error pages */ if (r->internal) return ngx_http_next_header_filter(r); ctx = ngx_http_get_module_ctx(r, ngx_ironbee_module); assert((ctx != NULL) && (ctx->tx != NULL)); prev_log = ngxib_log(r->connection->log); ngx_regex_malloc_init(r->pool); /* Notify Ironbee of request line and headers */ sprintf(proto, "HTTP/%d.%d", r->http_major, r->http_minor); if (r->headers_out.status_line.len) { status = (char*)r->headers_out.status_line.data; status_len = strcspn(status, " \t"); for (reason = status+status_len; isspace(*reason); ++reason); reason_len = r->headers_out.status_line.len - (reason-status); } else if (r->headers_out.status >= 100 && r->headers_out.status < 600) { status = ngx_palloc(r->pool, 4); /* cast to int, because ngx_int_t requires different format args * on different platforms. We're already limited to 3-digit numbers. */ sprintf(status, "%d", (int)r->headers_out.status); status_len = 3; reason = ""; reason_len = 0; } else { ib_log_error_tx(ctx->tx, "Ironbee: bogus response status %d", (int)r->headers_out.status); cleanup_return(prev_log) NGX_ERROR; } rc = ib_parsed_resp_line_create(ctx->tx, &rline, NULL, 0, proto, strlen(proto), status, status_len, reason, reason_len); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; ib_state_notify_response_started(ironbee, ctx->tx, rline); rc = ib_parsed_name_value_pair_list_wrapper_create(&ibhdrs, ctx->tx); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; for (part = &r->headers_out.headers.part; part != NULL; part = part->next) { hdr = part->elts; for (i = 0; i < part->nelts; ++i) { ib_parsed_name_value_pair_list_add(ibhdrs, (const char*)hdr->key.data, hdr->key.len, (const char*)hdr->value.data, hdr->value.len); ++hdr; } } /* Ironbee currently crashes if called here with no headers, * even perfectly correctly on a 204/304 response. */ if (ibhdrs->size > 0) { rc = ib_state_notify_response_header_data(ironbee, ctx->tx, ibhdrs); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; } rc = ib_state_notify_response_header_finished(ironbee, ctx->tx); if (rc != IB_OK) cleanup_return(prev_log) NGX_ERROR; ctx->hdrs_out = 1; cleanup_return(prev_log) ngx_http_next_header_filter(r); }