/** * nginx handler to feed request body (if any) to IronBee * * @param[in] r the nginx request object * @return NGX_DECLINED for normal operation * @return NGX_DONE if body is not yet available (processing will resume * on new data) * @return Error status if set by IronBee on sight of request data. */ ngx_int_t ngxib_handler(ngx_http_request_t *r) { ngx_chain_t *link; ngxib_req_ctx *ctx; ngx_int_t rv = NGX_DECLINED; ngx_http_request_body_t *rb; /* Don't process internal requests */ if (r->internal) return rv; ctx = ngx_http_get_module_ctx(r, ngx_ironbee_module); if (ctx->body_done) return rv; /* We already completed handling of no-body requests * when we looked at headers */ if (!ngxib_has_request_body(r, ctx)) return rv; ngx_regex_malloc_init(r->pool); /* We can now read the body. * This may come asynchronously in many chunks, so we need * to check for AGAIN and return DONE if waiting. * We pass it a handler to go round again while waiting. * * TODO: figure out how to pass data to ironbee asynchronously */ rv = ngx_http_read_client_request_body(r, ngxib_post_handler); if (rv == NGX_AGAIN) { ctx->body_wait = 1; cleanup_return NGX_DONE; } /* We now have the request body. Feed it to ironbee */ rb = r->request_body; if (!rb) { ib_log_error_tx(ctx->tx, "Failed to read request body."); cleanup_return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (!rb->bufs) { /* I think this shouldn't happen */ /* But rethink if this turns up in logs when all is fine */ ib_log_error_tx(ctx->tx, "Probable error reading request body."); } if (rb->temp_file && (rb->temp_file->file.fd != NGX_INVALID_FILE)) { /* Reader has put request body in temp file */ off_t count = 0; u_char buf[BUFSIZE]; size_t buf_len; ib_log_debug_tx(ctx->tx, "Reading request body in temp file."); while (buf_len = ngx_read_file(&rb->temp_file->file, buf, BUFSIZE, count), buf_len > 0) { ib_log_debug_tx(ctx->tx, "Feeding %zd bytes request data to ironbee.", buf_len); ib_state_notify_request_body_data(ctx->tx->ib, ctx->tx, (const char*)buf, buf_len); count += buf_len; } if ((int)buf_len == NGX_ERROR) { ib_log_error_tx(ctx->tx, "Failed to read request body in temp file."); } } for (link = rb->bufs; link != NULL; link = link->next) { size_t len = (link->buf->last - link->buf->pos); ib_log_debug_tx(ctx->tx, "Feeding %zd bytes request data to ironbee.", len); if (len > 0) { ib_state_notify_request_body_data(ctx->tx->ib, ctx->tx, (const char*)link->buf->pos, len); } } ctx->body_done = 1; ib_state_notify_request_finished(ctx->tx->ib, ctx->tx); /* If IronBee signaled an error, we can return it */ if (STATUS_IS_ERROR(ctx->status)) { rv = ctx->status; ctx->internal_errordoc = 1; ib_log_error_tx(ctx->tx, "IronBee set %d reading request body.", (int)rv); } cleanup_return rv; }
/** * nginx handler to feed request body (if any) to Ironbee * * @param[in] r the nginx request object * @return NGX_DECLINED for normal operation * @return NGX_DONE if body is not yet available (processing will restart * on new data) * @return Error status if set by Ironbee on sight of request data. */ ngx_int_t ngxib_handler(ngx_http_request_t *r) { ngx_log_t *prev_log; ib_txdata_t itxdata; ngx_chain_t *link; ngxib_req_ctx *ctx; ngx_int_t rv = NGX_DECLINED; ngx_http_request_body_t *rb; /* Don't process internal requests */ if (r->internal) return rv; ctx = ngx_http_get_module_ctx(r, ngx_ironbee_module); if (ctx->body_done) return rv; if (!has_request_body(r, ctx)) return rv; prev_log = ngxib_log(r->connection->log); ngx_regex_malloc_init(r->pool); /* We can now read the body. * This may come asynchronously in many chunks, so we need * to check for AGAIN and return DONE if waiting. * We pass it a handler to go round again while waiting. * * TODO: figure out how to pass data to ironbee asynchronously */ rv = ngx_http_read_client_request_body(r, ngxib_post_handler); if (rv == NGX_AGAIN) { ctx->body_wait = 1; cleanup_return(prev_log) NGX_DONE; } /* We now have the request body. Feed it to ironbee */ rb = r->request_body; if (!rb) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Error reading request body"); cleanup_return(prev_log) NGX_HTTP_INTERNAL_SERVER_ERROR; } if (!rb->bufs) { /* I think this shouldn't happen */ /* But rethink if this turns up in logs when all is fine */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Probable error reading request body"); } if (rb->temp_file && (rb->temp_file->file.fd != NGX_INVALID_FILE)) { /* Reader has put request body in temp file */ off_t count = 0; u_char buf[BUFSIZE]; ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Reading request body in temp file"); while (itxdata.dlen = ngx_read_file(&rb->temp_file->file, buf, BUFSIZE, count), (int)itxdata.dlen > 0) { itxdata.data = buf; ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Feeding %d bytes request data to ironbee", itxdata.dlen); ib_state_notify_request_body_data(ngxib_engine(), ctx->tx, &itxdata); count += itxdata.dlen; } if ((int)itxdata.dlen == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Error reading request body in temp file"); } } for (link = rb->bufs; link != NULL; link = link->next) { itxdata.data = link->buf->pos; itxdata.dlen = (link->buf->last - link->buf->pos); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Feeding %d bytes request data to ironbee", itxdata.dlen); if (itxdata.dlen > 0) { ib_state_notify_request_body_data(ngxib_engine(), ctx->tx, &itxdata); } } ctx->body_done = 1; ib_state_notify_request_finished(ngxib_engine(), ctx->tx); /* If Ironbee signalled an error, we can return it */ if (STATUS_IS_ERROR(ctx->status)) { rv = ctx->status; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Ironbee set %d reading request body", rv); } cleanup_return(prev_log) rv; }