sync code (#43)

Co-authored-by: Ned Wright <nedwright@proton.me>
This commit is contained in:
Daniel-Eisenberg 2025-08-10 13:23:10 +03:00 committed by GitHub
parent 6154961b0b
commit a5db1bbbc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 402 additions and 157 deletions

View File

@ -14,7 +14,7 @@ static HttpHeaderData *
get_http_header(HttpHeaders *http_headers, const char *header_name) { get_http_header(HttpHeaders *http_headers, const char *header_name) {
size_t i; size_t i;
for (i = 0; i < http_headers->headers_count; ++i) { for (i = 0; i < http_headers->headers_count; ++i) {
if (strcmp((char*)http_headers->data[i].key.data, header_name) == 0) { if (strcasecmp((char*)http_headers->data[i].key.data, header_name) == 0) {
return &http_headers->data[i]; return &http_headers->data[i];
} }
} }
@ -42,11 +42,11 @@ set_response_content_encoding(
return; return;
} }
if (strcmp((char*)content_encoding->value.data, "gzip") == 0) { if (strcasecmp((char*)content_encoding->value.data, "gzip") == 0) {
session_data_p->response_data.compression_type = GZIP; session_data_p->response_data.compression_type = GZIP;
} else if (strcmp((char*)content_encoding->value.data, "deflate") == 0) { } else if (strcasecmp((char*)content_encoding->value.data, "deflate") == 0) {
session_data_p->response_data.compression_type = ZLIB; session_data_p->response_data.compression_type = ZLIB;
} else if (strcmp((char*)content_encoding->value.data, "identity") == 0) { } else if (strcasecmp((char*)content_encoding->value.data, "identity") == 0) {
session_data_p->response_data.compression_type = NO_COMPRESSION; session_data_p->response_data.compression_type = NO_COMPRESSION;
} else { } else {
write_dbg( write_dbg(

View File

@ -385,7 +385,7 @@ set_docker_id(NanoAttachment *attachment)
} }
if (!uid_read) { if (!uid_read) {
const char *env_var_name = "OPENAPPSEC_UID"; // Replace with your environment variable name const char *env_var_name = "CLOUDGUARD_UID"; // Replace with your environment variable name
const char *env_value = getenv(env_var_name); const char *env_value = getenv(env_var_name);
if (env_value) { if (env_value) {

View File

@ -153,6 +153,47 @@ set_buffer_data(ngx_buf_t *buffer, const ngx_str_t *data)
buffer->end = buffer->last; buffer->end = buffer->last;
} }
///
/// @brief Removes empty chunks from the specified NGINX chain.
/// @param[in,out] chain Pointer to the start of the chain to modify.
/// @param[in] pool NGINX pool used for allocating and freeing chain links.
/// @returns ngx_int_t
/// - #NGX_OK
/// - #NGX_ERROR
///
static ngx_int_t
ngx_chain_remove_empty_chunks(ngx_chain_t **chain, ngx_pool_t *pool)
{
ngx_chain_t *prev = NULL;
ngx_chain_t *curr = *chain;
size_t chunk_num = 0;
while (curr != NULL) {
size_t size = curr->buf->last - curr->buf->pos;
if (size == 0) {
write_dbg(DBG_LEVEL_WARNING, "Removing empty chunk from the chain, chunk number: %d", chunk_num);
if (prev == NULL) {
*chain = curr->next;
} else {
prev->next = curr->next;
}
ngx_chain_t *tmp = curr;
curr = curr->next;
ngx_free_chain(pool, tmp);
continue;
}
prev = curr;
curr = curr->next;
chunk_num++;
}
if (chunk_num == 0) {
write_dbg(DBG_LEVEL_WARNING, "Empty chain after removing empty chunks");
return NGX_ERROR;
}
return NGX_OK;
}
/// ///
/// @brief Decompresses or compresses the provided data. /// @brief Decompresses or compresses the provided data.
/// @param[in] should_compress Checks if buffer is used for compression or decompression. /// @param[in] should_compress Checks if buffer is used for compression or decompression.
@ -432,11 +473,17 @@ compress_chain(
ngx_pool_t *pool ngx_pool_t *pool
) )
{ {
ngx_int_t compression_result;
ngx_cp_http_compression_params params; ngx_cp_http_compression_params params;
params.compression_type = compression_type; params.compression_type = compression_type;
params.is_last_part = is_last_part; params.is_last_part = is_last_part;
return compression_chain_filter(1, compression_stream, NULL, body, original_body_contents, pool, &params); compression_result = compression_chain_filter(1, compression_stream, NULL, body, original_body_contents, pool, &params);
// remove empty chunks from the chain to prevent getting nginx alert: "zero size buf in writer" down the line
if (compression_result == NGX_OK) {
compression_result = ngx_chain_remove_empty_chunks(body, pool);
}
return compression_result;
} }
/// ///
@ -534,6 +581,14 @@ compress_body(
return NGX_ERROR; return NGX_ERROR;
} }
if (compression_type == BROTLI) {
// Brotli compression is not supported.
// This if statement serves a case that the compression type is set to BROTLI
// For now, we should not reach inside this function with a compression type of BROTLI.
write_dbg(DBG_LEVEL_WARNING, "Brotli compression is not supported");
return NGX_ERROR;
}
body_type = chunk_type == REQUEST_BODY ? "request" : "response"; body_type = chunk_type == REQUEST_BODY ? "request" : "response";
write_dbg( write_dbg(
DBG_LEVEL_TRACE, DBG_LEVEL_TRACE,

View File

@ -73,6 +73,7 @@ decompress_body(
/// @param[in] compression_type Compression type. /// @param[in] compression_type Compression type.
/// - #GZIP /// - #GZIP
/// - #ZLIB /// - #ZLIB
/// - #BROTLI
/// - #NO_COMPRESSION - Serves as a sanity check in case this function is called /// - #NO_COMPRESSION - Serves as a sanity check in case this function is called
/// on a compression type of data that isn't defined and will return NGX_ERROR. /// on a compression type of data that isn't defined and will return NGX_ERROR.
/// @param[in] chunk_type Body chunk type: /// @param[in] chunk_type Body chunk type:

View File

@ -205,11 +205,11 @@ ngx_add_event_id_to_header(ngx_http_request_t *request)
} }
ngx_int_t ngx_int_t
ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request) ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request, int is_response_phase)
{ {
static u_char text_html[] = {'t', 'e', 'x', 't', '/', 'h', 't', 'm', 'l'}; static u_char text_html[] = {'t', 'e', 'x', 't', '/', 'h', 't', 'm', 'l'};
static size_t size_of_text_html = sizeof(text_html); static size_t size_of_text_html = sizeof(text_html);
ngx_int_t http_res_code, rc; ngx_int_t http_res_code, rc = NGX_OK;
ngx_table_elt_t *location_header; ngx_table_elt_t *location_header;
ngx_chain_t out_chain[7]; // http://lxr.nginx.org/source/src/http/ngx_http_special_response.c#0772 ngx_chain_t out_chain[7]; // http://lxr.nginx.org/source/src/http/ngx_http_special_response.c#0772
int send_response_custom_body = 1; int send_response_custom_body = 1;
@ -235,6 +235,12 @@ ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request)
goto CUSTOM_RES_OUT; goto CUSTOM_RES_OUT;
} }
if (is_response_phase) {
write_dbg(DBG_LEVEL_DEBUG, "Closing connection in response phase");
rc = NGX_HTTP_CLOSE;
goto CUSTOM_RES_OUT;
}
if (get_response_code() == NGX_HTTP_TEMPORARY_REDIRECT) { if (get_response_code() == NGX_HTTP_TEMPORARY_REDIRECT) {
// Handling redirect web response. // Handling redirect web response.
write_dbg( write_dbg(
@ -791,7 +797,7 @@ ngx_http_cp_body_modifier(
if (curr_modification == NULL) return NGX_OK; if (curr_modification == NULL) return NGX_OK;
if (curr_modification->modification.orig_buff_index != cur_body_chunk) continue; if (curr_modification->modification.orig_buff_index != cur_body_chunk) continue;
cur_chunk_size = body_chain->buf->last - body_chain->buf->pos; cur_chunk_size = chain_iter->buf->last - chain_iter->buf->pos;
if (cur_chunk_size == 0) { if (cur_chunk_size == 0) {
write_dbg(DBG_LEVEL_TRACE, "No need to modify body chunk of size 0. Chunk index: %d", cur_body_chunk); write_dbg(DBG_LEVEL_TRACE, "No need to modify body chunk of size 0. Chunk index: %d", cur_body_chunk);
continue; continue;

View File

@ -81,7 +81,7 @@ ngx_http_cp_file_response_sender(
/// - #NGX_OK /// - #NGX_OK
/// - #NGX_ERROR /// - #NGX_ERROR
/// ///
ngx_int_t ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request); ngx_int_t ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request, int is_response_phase);
/// ///
/// @brief Modifies headers with the provided modifiers. /// @brief Modifies headers with the provided modifiers.

View File

@ -165,6 +165,7 @@ end_req_header_handler(
return ngx_http_cp_reply_receiver( return ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
modifications, modifications,
@ -189,7 +190,7 @@ ngx_http_cp_req_header_handler_thread(void *_ctx)
ngx_uint_t num_messages_sent = 0; ngx_uint_t num_messages_sent = 0;
ngx_int_t send_header_result; ngx_int_t send_header_result;
send_meta_data_result = ngx_http_cp_meta_data_sender(request, session_data_p->session_id, &num_messages_sent); send_meta_data_result = ngx_http_cp_meta_data_sender(request, session_data_p->session_id, &num_messages_sent, &ctx->waf_tag);
if (send_meta_data_result == inspection_irrelevant) { if (send_meta_data_result == inspection_irrelevant) {
// Ignoring irrelevant requests. // Ignoring irrelevant requests.
session_data_p->verdict = TRAFFIC_VERDICT_IRRELEVANT; session_data_p->verdict = TRAFFIC_VERDICT_IRRELEVANT;
@ -223,8 +224,7 @@ ngx_http_cp_req_header_handler_thread(void *_ctx)
&(request->headers_in.headers.part), &(request->headers_in.headers.part),
REQUEST_HEADER, REQUEST_HEADER,
session_data_p->session_id, session_data_p->session_id,
&num_messages_sent, &num_messages_sent
&ctx->waf_tag
); );
if (send_header_result != NGX_OK) { if (send_header_result != NGX_OK) {
write_dbg( write_dbg(
@ -281,6 +281,7 @@ ngx_http_cp_req_body_filter_thread(void *_ctx)
ctx->res = ngx_http_cp_reply_receiver( ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
&ctx->modifications, &ctx->modifications,
@ -322,6 +323,7 @@ ngx_http_cp_req_end_transaction_thread(void *_ctx)
ctx->res = ngx_http_cp_reply_receiver( ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
&ctx->modifications, &ctx->modifications,
@ -407,14 +409,14 @@ ngx_http_cp_res_header_filter_thread(void *_ctx)
} }
session_data_p->response_data.new_compression_type = session_data_p->response_data.original_compression_type; session_data_p->response_data.new_compression_type = session_data_p->response_data.original_compression_type;
if (session_data_p->response_data.inspect_all_response_headers) {
// Sends response headers to the nano service. // Sends response headers to the nano service.
num_messages_sent = 0; num_messages_sent = 0;
send_header_result = ngx_http_cp_header_sender( send_header_result = ngx_http_cp_header_sender(
&request->headers_out.headers.part, &request->headers_out.headers.part,
RESPONSE_HEADER, RESPONSE_HEADER,
session_data_p->session_id, session_data_p->session_id,
&num_messages_sent, &num_messages_sent
&ctx->waf_tag
); );
if (send_header_result != NGX_OK) { if (send_header_result != NGX_OK) {
write_dbg( write_dbg(
@ -430,11 +432,13 @@ ngx_http_cp_res_header_filter_thread(void *_ctx)
} }
session_data_p->remaining_messages_to_reply += num_messages_sent; session_data_p->remaining_messages_to_reply += num_messages_sent;
}
// Fetch nano services' results. // Fetch nano services' results.
ctx->res = ngx_http_cp_reply_receiver( ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
&ctx->modifications, &ctx->modifications,
@ -455,7 +459,13 @@ ngx_http_cp_res_body_filter_thread(void *_ctx)
ngx_uint_t num_messages_sent = 0; ngx_uint_t num_messages_sent = 0;
ngx_int_t is_last_response_part = 0; ngx_int_t is_last_response_part = 0;
// Send response body data to the nano service. write_dbg(
DBG_LEVEL_DEBUG,
"Starting response body filter thread for session ID: %d, current verdict: %d",
session_data_p->session_id,
session_data_p->verdict
);
send_body_result = ngx_http_cp_body_sender( send_body_result = ngx_http_cp_body_sender(
ctx->chain, ctx->chain,
RESPONSE_BODY, RESPONSE_BODY,
@ -464,6 +474,16 @@ ngx_http_cp_res_body_filter_thread(void *_ctx)
&num_messages_sent, &num_messages_sent,
&ctx->chain &ctx->chain
); );
write_dbg(
DBG_LEVEL_DEBUG,
"Body sender result: %d, num_messages_sent: %d, is_last_response_part: %d for session ID: %d",
send_body_result,
num_messages_sent,
is_last_response_part,
session_data_p->session_id
);
if (send_body_result != NGX_OK) { if (send_body_result != NGX_OK) {
write_dbg( write_dbg(
DBG_LEVEL_WARNING, DBG_LEVEL_WARNING,
@ -478,9 +498,48 @@ ngx_http_cp_res_body_filter_thread(void *_ctx)
} }
session_data_p->remaining_messages_to_reply += num_messages_sent; session_data_p->remaining_messages_to_reply += num_messages_sent;
ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply,
&session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id,
request,
&ctx->modifications,
RESPONSE_BODY,
session_data_p->processed_res_body_size
);
write_dbg(
DBG_LEVEL_DEBUG,
"Reply receiver returned: %d, got verdict: %d, remaining messages: %d for session ID: %d",
ctx->res,
session_data_p->verdict,
session_data_p->remaining_messages_to_reply,
session_data_p->session_id
);
if (session_data_p->verdict == TRAFFIC_VERDICT_WAIT) {
if (!ngx_http_cp_hold_verdict(ctx)) {
session_data_p->verdict = fail_mode_hold_verdict == NGX_OK ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP;
updateMetricField(HOLD_THREAD_TIMEOUT, 1);
handle_inspection_failure(inspection_failure_weight, fail_mode_verdict, session_data_p);
if (fail_mode_verdict == NGX_OK) {
THREAD_CTX_RETURN_NEXT_FILTER();
}
THREAD_CTX_RETURN(NGX_HTTP_FORBIDDEN);
}
}
num_messages_sent = 0; num_messages_sent = 0;
if (is_last_response_part) { if (is_last_response_part) {
// Signals the nano service that the transaction reached the end. // Signals the nano service that the transaction reached the end.
write_dbg(
DBG_LEVEL_DEBUG,
"This is the last response part, sending RESPONSE_END signal for session ID: %d",
session_data_p->session_id
);
if (ngx_http_cp_end_transaction_sender(RESPONSE_END, session_data_p->session_id, &num_messages_sent) != NGX_OK) { if (ngx_http_cp_end_transaction_sender(RESPONSE_END, session_data_p->session_id, &num_messages_sent) != NGX_OK) {
write_dbg( write_dbg(
DBG_LEVEL_WARNING, DBG_LEVEL_WARNING,
@ -493,19 +552,51 @@ ngx_http_cp_res_body_filter_thread(void *_ctx)
} }
THREAD_CTX_RETURN(NGX_HTTP_FORBIDDEN); THREAD_CTX_RETURN(NGX_HTTP_FORBIDDEN);
} }
session_data_p->remaining_messages_to_reply++;
if (
session_data_p->verdict == TRAFFIC_VERDICT_ACCEPT ||
session_data_p->verdict == TRAFFIC_VERDICT_DROP
) {
write_dbg(
DBG_LEVEL_DEBUG,
"Will not wait for verdict after RESPONSE_END as we already have verdict %d for session ID %d",
session_data_p->session_id,
session_data_p->verdict
);
return NULL;
} }
// Fetch nano services' results. session_data_p->remaining_messages_to_reply += num_messages_sent;
ctx->res = ngx_http_cp_reply_receiver( ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
&ctx->modifications, &ctx->modifications,
RESPONSE_BODY, RESPONSE_END,
session_data_p->processed_res_body_size session_data_p->processed_res_body_size
); );
write_dbg(
DBG_LEVEL_DEBUG,
"Received verdict %d after RESPONSE_END for session ID %d, will proceed normally",
session_data_p->verdict,
session_data_p->session_id
);
if (session_data_p->verdict == TRAFFIC_VERDICT_WAIT) {
if (!ngx_http_cp_hold_verdict(ctx)) {
session_data_p->verdict = fail_mode_hold_verdict == NGX_OK ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP;
updateMetricField(HOLD_THREAD_TIMEOUT, 1);
handle_inspection_failure(inspection_failure_weight, fail_mode_verdict, session_data_p);
if (fail_mode_verdict == NGX_OK) {
THREAD_CTX_RETURN_NEXT_FILTER();
}
THREAD_CTX_RETURN(NGX_HTTP_FORBIDDEN);
}
}
}
return NULL; return NULL;
} }
@ -537,6 +628,7 @@ ngx_http_cp_hold_verdict_thread(void *_ctx)
ctx->res = ngx_http_cp_reply_receiver( ctx->res = ngx_http_cp_reply_receiver(
&session_data_p->remaining_messages_to_reply, &session_data_p->remaining_messages_to_reply,
&session_data_p->verdict, &session_data_p->verdict,
&session_data_p->response_data.inspect_all_response_headers,
session_data_p->session_id, session_data_p->session_id,
request, request,
&ctx->modifications, &ctx->modifications,

View File

@ -78,6 +78,7 @@ init_cp_session_data(ngx_http_request_t *request)
session_data->response_data.response_data_status = NGX_OK; session_data->response_data.response_data_status = NGX_OK;
session_data->response_data.original_compressed_body = NULL; session_data->response_data.original_compressed_body = NULL;
session_data->response_data.request_pool = NULL; session_data->response_data.request_pool = NULL;
session_data->response_data.inspect_all_response_headers = 1;
if (!metric_timeout.tv_sec) { if (!metric_timeout.tv_sec) {
metric_timeout = get_timeout_val_sec(METRIC_TIMEOUT_VAL); metric_timeout = get_timeout_val_sec(METRIC_TIMEOUT_VAL);
} }
@ -86,6 +87,7 @@ init_cp_session_data(ngx_http_request_t *request)
session_data->res_proccesing_time = 0; session_data->res_proccesing_time = 0;
session_data->processed_req_body_size = 0; session_data->processed_req_body_size = 0;
session_data->processed_res_body_size = 0; session_data->processed_res_body_size = 0;
session_data->is_res_body_inspected = 0;
ngx_http_set_ctx(request, session_data, ngx_http_cp_attachment_module); ngx_http_set_ctx(request, session_data, ngx_http_cp_attachment_module);
@ -334,7 +336,7 @@ ngx_http_cp_finalize_request_headers_hook(
if (final_res == NGX_HTTP_FORBIDDEN) { if (final_res == NGX_HTTP_FORBIDDEN) {
handle_inspection_success(session_data_p); handle_inspection_success(session_data_p);
return ngx_http_cp_finalize_rejected_request(request); return ngx_http_cp_finalize_rejected_request(request, 0);
} }
if (final_res != NGX_OK) { if (final_res != NGX_OK) {
@ -715,6 +717,15 @@ ngx_http_cp_req_body_filter(ngx_http_request_t *request, ngx_chain_t *request_bo
return fail_mode_verdict == NGX_OK ? ngx_http_next_request_body_filter(request, request_body_chain) : NGX_HTTP_FORBIDDEN; return fail_mode_verdict == NGX_OK ? ngx_http_next_request_body_filter(request, request_body_chain) : NGX_HTTP_FORBIDDEN;
} }
if (session_data_p->verdict == TRAFFIC_VERDICT_WAIT) {
write_dbg(DBG_LEVEL_DEBUG, "spawn ngx_http_cp_hold_verdict");
res = ngx_http_cp_hold_verdict(&ctx);
if (!res) {
write_dbg(DBG_LEVEL_DEBUG, "ngx_http_cp_hold_verdict failed");
updateMetricField(HOLD_THREAD_TIMEOUT, 1);
}
}
write_dbg( write_dbg(
DBG_LEVEL_DEBUG, DBG_LEVEL_DEBUG,
"finished ngx_http_cp_req_end_transaction_thread successfully. return=%d next_filter=%d res=%d", "finished ngx_http_cp_req_end_transaction_thread successfully. return=%d next_filter=%d res=%d",
@ -754,7 +765,7 @@ ngx_http_cp_req_body_filter(ngx_http_request_t *request, ngx_chain_t *request_bo
if (final_res == NGX_HTTP_FORBIDDEN) { if (final_res == NGX_HTTP_FORBIDDEN) {
handle_inspection_success(session_data_p); handle_inspection_success(session_data_p);
return ngx_http_cp_finalize_rejected_request(request); return ngx_http_cp_finalize_rejected_request(request, 0);
} }
if (final_res != NGX_OK) { if (final_res != NGX_OK) {
@ -934,7 +945,7 @@ ngx_http_cp_res_header_filter(ngx_http_request_t *request)
if (final_res == NGX_HTTP_FORBIDDEN) { if (final_res == NGX_HTTP_FORBIDDEN) {
handle_inspection_success(session_data_p); handle_inspection_success(session_data_p);
return ngx_http_cp_finalize_rejected_request(request); return ngx_http_cp_finalize_rejected_request(request, 0);
} }
if (final_res != NGX_OK) { if (final_res != NGX_OK) {
@ -1005,23 +1016,48 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
if (session_data_p->response_data.response_data_status != NGX_OK) { if (session_data_p->response_data.response_data_status != NGX_OK) {
write_dbg(DBG_LEVEL_WARNING, "skipping session with corrupted compression"); write_dbg(DBG_LEVEL_WARNING, "skipping session with corrupted compression");
updateMetricField(CORRUPTED_ZIP_SKIPPED_SESSION_COUNT, 1); updateMetricField(CORRUPTED_ZIP_SKIPPED_SESSION_COUNT, 1);
if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) request->keepalive = 0; if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) {
request->keepalive = 0;
}
if (session_data_p->verdict == TRAFFIC_VERDICT_DROP && session_data_p->is_res_body_inspected) {
write_dbg(
DBG_LEVEL_DEBUG,
"Session with corrupted compression has DROP verdict, returning HTTP_FORBIDDEN. Session ID: %d",
session_data_p->session_id
);
return NGX_HTTP_FORBIDDEN;
}
return ngx_http_next_response_body_filter(request, body_chain); return ngx_http_next_response_body_filter(request, body_chain);
} }
if ( if (
session_data_p->verdict != TRAFFIC_VERDICT_INSPECT && session_data_p->verdict != TRAFFIC_VERDICT_INSPECT &&
session_data_p->verdict != TRAFFIC_VERDICT_WAIT &&
( (
session_data_p->verdict != TRAFFIC_VERDICT_ACCEPT || session_data_p->verdict != TRAFFIC_VERDICT_ACCEPT ||
session_data_p->response_data.new_compression_type == NO_COMPRESSION || session_data_p->response_data.new_compression_type == NO_COMPRESSION ||
session_data_p->response_data.new_compression_type == BROTLI ||
session_data_p->response_data.num_body_chunk == 0 session_data_p->response_data.num_body_chunk == 0
) )
) { ) {
write_dbg(DBG_LEVEL_TRACE, "skipping already inspected session"); write_dbg(DBG_LEVEL_TRACE, "skipping already inspected session");
if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) request->keepalive = 0; if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) {
request->keepalive = 0;
}
if (session_data_p->verdict == TRAFFIC_VERDICT_DROP && session_data_p->is_res_body_inspected) {
write_dbg(
DBG_LEVEL_DEBUG,
"Session has DROP verdict, returning HTTP_FORBIDDEN instead of streaming. Session ID: %d",
session_data_p->session_id
);
return NGX_HTTP_FORBIDDEN;
}
return ngx_http_next_response_body_filter(request, body_chain); return ngx_http_next_response_body_filter(request, body_chain);
} }
session_data_p->is_res_body_inspected = 1;
session_data_p->response_data.num_body_chunk++; session_data_p->response_data.num_body_chunk++;
if (body_chain == NULL) { if (body_chain == NULL) {
@ -1033,7 +1069,7 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
return ngx_http_next_response_body_filter(request, body_chain); return ngx_http_next_response_body_filter(request, body_chain);
} }
if (body_chain->buf->pos != NULL && session_data_p->response_data.new_compression_type != NO_COMPRESSION) { if (body_chain->buf->pos != NULL && session_data_p->response_data.new_compression_type != NO_COMPRESSION && session_data_p->response_data.new_compression_type != BROTLI) {
write_dbg(DBG_LEVEL_TRACE, "Decompressing response body"); write_dbg(DBG_LEVEL_TRACE, "Decompressing response body");
if (init_cp_session_original_body(session_data_p, request->pool) == NGX_OK) { if (init_cp_session_original_body(session_data_p, request->pool) == NGX_OK) {
if (session_data_p->response_data.decompression_stream == NULL) { if (session_data_p->response_data.decompression_stream == NULL) {
@ -1208,7 +1244,7 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
if (final_res == NGX_HTTP_FORBIDDEN) { if (final_res == NGX_HTTP_FORBIDDEN) {
handle_inspection_success(session_data_p); handle_inspection_success(session_data_p);
return ngx_http_cp_finalize_rejected_request(request); return ngx_http_cp_finalize_rejected_request(request, 1);
} }
if (final_res != NGX_OK) { if (final_res != NGX_OK) {
@ -1224,7 +1260,7 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
return NGX_HTTP_FORBIDDEN; return NGX_HTTP_FORBIDDEN;
} }
if (ctx.modifications) { if (ctx.modifications && session_data_p->response_data.new_compression_type != BROTLI) {
write_dbg(DBG_LEVEL_TRACE, "Handling response body modification"); write_dbg(DBG_LEVEL_TRACE, "Handling response body modification");
if (ngx_http_cp_body_modifier(body_chain, ctx.modifications, request->pool) != NGX_OK) { if (ngx_http_cp_body_modifier(body_chain, ctx.modifications, request->pool) != NGX_OK) {
write_dbg(DBG_LEVEL_WARNING, "Failed to modify response body"); write_dbg(DBG_LEVEL_WARNING, "Failed to modify response body");
@ -1237,6 +1273,16 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
} }
} }
if (ctx.modifications && session_data_p->response_data.new_compression_type == BROTLI) {
ngx_http_cp_modification_list *mod = ctx.modifications;
while (mod != NULL) {
ngx_http_cp_modification_list *next_mod = mod->next;
ngx_pfree(request->pool, mod);
mod = next_mod;
}
ctx.modifications = NULL;
}
if ( if (
session_data_p->verdict == TRAFFIC_VERDICT_ACCEPT && session_data_p->verdict == TRAFFIC_VERDICT_ACCEPT &&
session_data_p->response_data.num_body_chunk == 1 && session_data_p->response_data.num_body_chunk == 1 &&
@ -1249,7 +1295,7 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
return ngx_http_next_response_body_filter(request, body_chain); return ngx_http_next_response_body_filter(request, body_chain);
} }
if (session_data_p->response_data.new_compression_type != NO_COMPRESSION) { if (session_data_p->response_data.new_compression_type != NO_COMPRESSION && session_data_p->response_data.new_compression_type != BROTLI) {
if (session_data_p->response_data.compression_stream == NULL) { if (session_data_p->response_data.compression_stream == NULL) {
session_data_p->response_data.compression_stream = initCompressionStream(); session_data_p->response_data.compression_stream = initCompressionStream();
} }
@ -1275,5 +1321,23 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain
print_buffer_chain(body_chain, "outgoing", 32, DBG_LEVEL_TRACE); print_buffer_chain(body_chain, "outgoing", 32, DBG_LEVEL_TRACE);
// Check final verdict before streaming data to client
// This prevents malicious data from reaching client when verdict is DROP
if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) {
write_dbg(
DBG_LEVEL_DEBUG,
"Final verdict is DROP, blocking stream to client. Session ID: %d",
session_data_p->session_id
);
return NGX_HTTP_FORBIDDEN;
}
write_dbg(
DBG_LEVEL_DEBUG,
"Final verdict is %d, streaming to client. Session ID: %d",
session_data_p->verdict,
session_data_p->session_id
);
return ngx_http_next_response_body_filter(request, body_chain); return ngx_http_next_response_body_filter(request, body_chain);
} }

View File

@ -45,6 +45,7 @@ typedef struct ngx_http_cp_session_data {
double res_proccesing_time; ///< Holds session's response processing time. double res_proccesing_time; ///< Holds session's response processing time.
uint64_t processed_req_body_size; ///< Holds session's request body's size. uint64_t processed_req_body_size; ///< Holds session's request body's size.
uint64_t processed_res_body_size; ///< Holds session's response body's size'. uint64_t processed_res_body_size; ///< Holds session's response body's size'.
ngx_int_t is_res_body_inspected; ///< Holds if the response body was inspected
} ngx_http_cp_session_data; } ngx_http_cp_session_data;
/// ///

View File

@ -19,24 +19,31 @@
static const char *gzip_encoding_string = "gzip"; static const char *gzip_encoding_string = "gzip";
static const char *zlib_encoding_string = "deflate"; static const char *zlib_encoding_string = "deflate";
static const char *brotli_encoding_string = "br";
static const char *identity_encoding_string = "identity"; static const char *identity_encoding_string = "identity";
ngx_int_t ngx_int_t
parse_content_encoding(CompressionType *response_encoding, const ngx_str_t *content_encoding_header_value) parse_content_encoding(CompressionType *response_encoding, const ngx_str_t *content_encoding_header_value)
{ {
if (ngx_strcmp(content_encoding_header_value->data, gzip_encoding_string) == 0) { if (ngx_strcasecmp(content_encoding_header_value->data, (u_char*)gzip_encoding_string) == 0) {
/// Sets GZIP encoding. /// Sets GZIP encoding.
*response_encoding = GZIP; *response_encoding = GZIP;
return NGX_OK; return NGX_OK;
} }
if (ngx_strcmp(content_encoding_header_value->data, zlib_encoding_string) == 0) { if (ngx_strcasecmp(content_encoding_header_value->data, (u_char*)zlib_encoding_string) == 0) {
/// Sets GZIP encoding. /// Sets GZIP encoding.
*response_encoding = ZLIB; *response_encoding = ZLIB;
return NGX_OK; return NGX_OK;
} }
if (ngx_strcmp(content_encoding_header_value->data, identity_encoding_string) == 0) { if (ngx_strcasecmp(content_encoding_header_value->data, (u_char*)brotli_encoding_string) == 0) {
/// Sets Brotli encoding.
*response_encoding = BROTLI;
return NGX_OK;
}
if (ngx_strcasecmp(content_encoding_header_value->data, (u_char*)identity_encoding_string) == 0) {
/// Sets NO_COMPRESSION encoding. /// Sets NO_COMPRESSION encoding.
*response_encoding = NO_COMPRESSION; *response_encoding = NO_COMPRESSION;
return NGX_OK; return NGX_OK;

View File

@ -30,6 +30,11 @@ typedef struct {
/// - #NGX_ERROR /// - #NGX_ERROR
ngx_int_t response_data_status; ngx_int_t response_data_status;
/// This flag determines whether all response headers should be sent to a service for inspection.
/// - If set to 1, all response headers will be sent.
/// - If set to 0, only the Content-Length, response code, and encoding checks for the response body will be sent.
ngx_int_t inspect_all_response_headers;
/// Original compression type, can hold the following values: /// Original compression type, can hold the following values:
/// - #GZIP /// - #GZIP
/// - #ZLIB /// - #ZLIB
@ -58,6 +63,7 @@ typedef struct {
/// @param[in, out] response_encoding Returns value of one of the supported encoding: /// @param[in, out] response_encoding Returns value of one of the supported encoding:
/// - #GZIP /// - #GZIP
/// - #ZLIB /// - #ZLIB
/// - #BROTLI
/// - #NO_COMPRESSION /// - #NO_COMPRESSION
/// @param[in, out] content_encoding_header_value Encoded value. /// @param[in, out] content_encoding_header_value Encoded value.
/// @return ngx_int_t /// @return ngx_int_t
@ -75,6 +81,7 @@ parse_content_encoding(
/// @param[in, out] content_encoding Returns variable of one of the supported encoding: /// @param[in, out] content_encoding Returns variable of one of the supported encoding:
/// - #GZIP /// - #GZIP
/// - #ZLIB /// - #ZLIB
/// - #BROTLI
/// - #NO_COMPRESSION /// - #NO_COMPRESSION
/// @param[in, out] content_encoding_header NGINX table Encoding header. /// @param[in, out] content_encoding_header NGINX table Encoding header.
/// @return ngx_int_t /// @return ngx_int_t

View File

@ -21,6 +21,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <limits.h>
#include "ngx_cp_utils.h" #include "ngx_cp_utils.h"
#include "ngx_cp_initializer.h" #include "ngx_cp_initializer.h"
@ -452,6 +453,7 @@ ngx_int_t
ngx_http_cp_reply_receiver( ngx_http_cp_reply_receiver(
ngx_int_t *expected_replies, ngx_int_t *expected_replies,
ngx_http_cp_verdict_e *verdict, ngx_http_cp_verdict_e *verdict,
ngx_int_t *inspect_all_response_headers,
uint32_t cur_session_id, uint32_t cur_session_id,
ngx_http_request_t *request, ngx_http_request_t *request,
ngx_http_cp_modification_list **modification_list, ngx_http_cp_modification_list **modification_list,
@ -492,7 +494,7 @@ ngx_http_cp_reply_receiver(
return NGX_ERROR; return NGX_ERROR;
} }
if (reply_p->verdict != TRAFFIC_VERDICT_RECONF) { if (reply_p->verdict != TRAFFIC_VERDICT_RECONF && reply_p->verdict != LIMIT_RESPONSE_HEADERS) {
// Handling reconfiguration verdict. // Handling reconfiguration verdict.
if (reply_p->session_id != cur_session_id) { if (reply_p->session_id != cur_session_id) {
write_dbg(DBG_LEVEL_DEBUG, "Ignoring verdict to an already handled request %d", reply_p->session_id); write_dbg(DBG_LEVEL_DEBUG, "Ignoring verdict to an already handled request %d", reply_p->session_id);
@ -600,6 +602,12 @@ ngx_http_cp_reply_receiver(
updateMetricField(HOLD_VERDICTS_COUNT, 1); updateMetricField(HOLD_VERDICTS_COUNT, 1);
break; break;
} }
case LIMIT_RESPONSE_HEADERS: {
write_dbg(DBG_LEVEL_DEBUG, "Verdict ignore response headers received from the nano service");
*inspect_all_response_headers = 0;
break;
}
} }
free_data_from_service(); free_data_from_service();
@ -662,7 +670,7 @@ convert_sock_addr_to_string(const struct sockaddr *sa, char *ip_addr)
} }
ngx_int_t ngx_int_t
ngx_http_cp_meta_data_sender(ngx_http_request_t *request, uint32_t cur_request_id, ngx_uint_t *num_messages_sent) ngx_http_cp_meta_data_sender(ngx_http_request_t *request, uint32_t cur_request_id, ngx_uint_t *num_messages_sent, ngx_str_t *waf_tag)
{ {
char client_ip[INET6_ADDRSTRLEN]; char client_ip[INET6_ADDRSTRLEN];
char listening_ip[INET6_ADDRSTRLEN]; char listening_ip[INET6_ADDRSTRLEN];
@ -788,6 +796,16 @@ ngx_http_cp_meta_data_sender(ngx_http_request_t *request, uint32_t cur_request_i
set_fragment_elem(fragments, fragments_sizes, &parsed_uri.len, sizeof(uint16_t), PARSED_URI_SIZE + 2); set_fragment_elem(fragments, fragments_sizes, &parsed_uri.len, sizeof(uint16_t), PARSED_URI_SIZE + 2);
set_fragment_elem(fragments, fragments_sizes, parsed_uri.data, parsed_uri.len, PARSED_URI_DATA + 2); set_fragment_elem(fragments, fragments_sizes, parsed_uri.data, parsed_uri.len, PARSED_URI_DATA + 2);
// Add WAF tag data if provided
if (waf_tag != NULL && waf_tag->len > 0) {
set_fragment_elem(fragments, fragments_sizes, &waf_tag->len, sizeof(uint16_t), WAF_TAG_SIZE + 2);
set_fragment_elem(fragments, fragments_sizes, waf_tag->data, waf_tag->len, WAF_TAG_DATA + 2);
} else {
uint16_t zero = 0;
set_fragment_elem(fragments, fragments_sizes, &zero, sizeof(uint16_t), WAF_TAG_SIZE + 2);
set_fragment_elem(fragments, fragments_sizes, "", 0, WAF_TAG_DATA + 2);
}
// Sends all the data to the nano service. // Sends all the data to the nano service.
res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, META_DATA_COUNT + 2, cur_request_id, NULL, fail_open_timeout, min_retries_for_verdict); res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, META_DATA_COUNT + 2, cur_request_id, NULL, fail_open_timeout, min_retries_for_verdict);
if (res != NGX_OK) { if (res != NGX_OK) {
@ -1008,8 +1026,7 @@ ngx_http_cp_header_sender(
ngx_list_part_t *headers_list, ngx_list_part_t *headers_list,
ngx_http_chunk_type_e header_type, ngx_http_chunk_type_e header_type,
uint32_t cur_request_id, uint32_t cur_request_id,
ngx_uint_t *num_messages_sent, ngx_uint_t *num_messages_sent
ngx_str_t *waf_tag
) )
{ {
ngx_uint_t header_idx = 0; ngx_uint_t header_idx = 0;
@ -1025,7 +1042,6 @@ ngx_http_cp_header_sender(
const ngx_uint_t max_bulk_size = 10; const ngx_uint_t max_bulk_size = 10;
char *fragments[HEADER_DATA_COUNT * max_bulk_size + 4]; char *fragments[HEADER_DATA_COUNT * max_bulk_size + 4];
uint16_t fragments_sizes[HEADER_DATA_COUNT * max_bulk_size + 4]; uint16_t fragments_sizes[HEADER_DATA_COUNT * max_bulk_size + 4];
ngx_flag_t waf_tag_found = 0;
write_dbg( write_dbg(
DBG_LEVEL_TRACE, DBG_LEVEL_TRACE,
@ -1036,38 +1052,6 @@ ngx_http_cp_header_sender(
// Sets fragments identifier to the provided body type. // Sets fragments identifier to the provided body type.
set_fragments_identifiers(fragments, fragments_sizes, (uint16_t *)&header_type, &cur_request_id); set_fragments_identifiers(fragments, fragments_sizes, (uint16_t *)&header_type, &cur_request_id);
// If waf_tag is provided and valid, check for existing x-waf-tag headers
if (waf_tag != NULL && waf_tag->len > 0) {
for (headers_iter = headers_list; headers_iter; headers_iter = headers_iter->next) {
headers_to_inspect = headers_iter->elts;
for (header_idx = 0; header_idx < headers_iter->nelts; ++header_idx) {
header = headers_to_inspect + header_idx;
if (header->key.len == 9 && ngx_strncasecmp(header->key.data, (u_char *)"x-waf-tag", 9) == 0) {
// Found existing x-waf-tag header, override its value
// header->value = *waf_tag;
waf_tag_found = 1;
write_dbg(DBG_LEVEL_DEBUG, "Overriding existing x-waf-tag header with value: %.*s", waf_tag->len, waf_tag->data);
break;
}
}
if (waf_tag_found) break;
}
// If no existing x-waf-tag header found, add a new one
if (!waf_tag_found) {
ngx_table_elt_t waf_header;
waf_header.hash = 1;
ngx_str_set(&waf_header.key, "x-waf-tag");
waf_header.value = *waf_tag;
waf_header.lowcase_key = NULL; // Not needed for sending to agent
add_header_to_bulk(fragments, fragments_sizes, &waf_header, idx_in_bulk);
idx_in_bulk++;
part_count++;
write_dbg(DBG_LEVEL_DEBUG, "Adding new x-waf-tag header with value: %.*s", waf_tag->len, waf_tag->data);
}
}
for (headers_iter = headers_list; headers_iter ; headers_iter = headers_iter->next) { for (headers_iter = headers_list; headers_iter ; headers_iter = headers_iter->next) {
// Going over the header list. // Going over the header list.
for (header_idx = 0 ; header_idx < headers_iter->nelts ; ++header_idx) { for (header_idx = 0 ; header_idx < headers_iter->nelts ; ++header_idx) {
@ -1085,16 +1069,7 @@ ngx_http_cp_header_sender(
is_last_part = (headers_iter->next == NULL && header_idx + 1 == headers_iter->nelts) ? 1 : 0; is_last_part = (headers_iter->next == NULL && header_idx + 1 == headers_iter->nelts) ? 1 : 0;
// Create a header bulk to send. // Create a header bulk to send.
if (waf_tag_found && header->key.len == 9 && ngx_strncasecmp(header->key.data, (u_char *)"x-waf-tag", 9) == 0) {
ngx_table_elt_t waf_header;
waf_header.hash = 1;
ngx_str_set(&waf_header.key, "x-waf-tag");
waf_header.value = *waf_tag;
waf_header.lowcase_key = NULL;
add_header_to_bulk(fragments, fragments_sizes, &waf_header, idx_in_bulk);
} else {
add_header_to_bulk(fragments, fragments_sizes, header, idx_in_bulk); add_header_to_bulk(fragments, fragments_sizes, header, idx_in_bulk);
}
idx_in_bulk++; idx_in_bulk++;
part_count++; part_count++;
@ -1152,16 +1127,20 @@ ngx_http_cp_body_sender(
ngx_int_t res = NGX_ERROR; ngx_int_t res = NGX_ERROR;
uint8_t is_last_chunk; uint8_t is_last_chunk;
uint8_t part_count; uint8_t part_count;
size_t buf_size;
ngx_int_t tout_retries = min_retries_for_verdict; ngx_int_t tout_retries = min_retries_for_verdict;
char *fragments[num_body_chunk_fragments]; char *fragments[num_body_chunk_fragments];
uint16_t fragments_sizes[num_body_chunk_fragments]; uint16_t fragments_sizes[num_body_chunk_fragments];
int was_waiting = 0; int was_waiting = 0;
int max_chunks_to_process = (body_type == RESPONSE_BODY) ? 1 : INT_MAX;
int chunks_processed = 0;
write_dbg( write_dbg(
DBG_LEVEL_TRACE, DBG_LEVEL_DEBUG,
"Sending %s body chunk from session id %d for inspection", "Started %s body sender for session ID %d, max_chunks_to_process: %d",
body_type == REQUEST_BODY ? "request" : "response", body_type == REQUEST_BODY ? "request" : "response",
session_data->session_id session_data->session_id,
max_chunks_to_process
); );
// Sets fragments identifier to the provided body type. // Sets fragments identifier to the provided body type.
@ -1169,13 +1148,24 @@ ngx_http_cp_body_sender(
num_parts_sent = 0; num_parts_sent = 0;
part_count = 0; part_count = 0;
for (chain_iter = input; chain_iter; chain_iter = chain_iter->next) {
for (chain_iter = input; chain_iter && chunks_processed < max_chunks_to_process; chain_iter = chain_iter->next) {
// For each NGINX buffer, fragment the buffer and then send the fragments to the nano service. // For each NGINX buffer, fragment the buffer and then send the fragments to the nano service.
buf = chain_iter->buf; buf = chain_iter->buf;
is_last_chunk = buf->last_buf ? 1 : 0; is_last_chunk = buf->last_buf ? 1 : 0;
write_dbg(DBG_LEVEL_TRACE, "Sending last_buf: %d, part_count: %d", buf->last_buf ? 1: 0, part_count); buf_size = buf->last - buf->pos;
if (buf->last - buf->pos > 0 || is_last_chunk) { write_dbg(
DBG_LEVEL_DEBUG,
"Processing %s body chunk %d of size: %d, last_chunk: %d for session ID: %d",
body_type == REQUEST_BODY ? "request" : "response",
part_count,
buf_size,
is_last_chunk,
session_data->session_id
);
if (buf_size > 0 || is_last_chunk) {
// Setting the fragments, including in the case of the last chunk. // Setting the fragments, including in the case of the last chunk.
set_fragment_elem(fragments, fragments_sizes, &is_last_chunk, sizeof(is_last_chunk), 2); set_fragment_elem(fragments, fragments_sizes, &is_last_chunk, sizeof(is_last_chunk), 2);
set_fragment_elem(fragments, fragments_sizes, &part_count, sizeof(part_count), 3); set_fragment_elem(fragments, fragments_sizes, &part_count, sizeof(part_count), 3);
@ -1191,16 +1181,32 @@ ngx_http_cp_body_sender(
tout_retries = max_retries_for_verdict; tout_retries = max_retries_for_verdict;
} }
// Sending the data to the nano service. // Sending the data to the nano service.
res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, num_body_chunk_fragments, session_data->session_id, res = ngx_http_cp_send_data_to_service(
&was_waiting, fail_open_timeout, tout_retries); fragments,
fragments_sizes,
num_body_chunk_fragments,
session_data->session_id,
&was_waiting,
fail_open_timeout,
tout_retries
);
if (res != NGX_OK) { if (res != NGX_OK) {
// Failed to send the fragments to the nano service. // Failed to send the fragments to the nano service.
return NGX_ERROR; return NGX_ERROR;
} }
write_dbg(
DBG_LEVEL_DEBUG,
"Successfully sent %s body chunk %d to service for session ID: %d",
body_type == REQUEST_BODY ? "request" : "response",
part_count,
session_data->session_id
);
num_parts_sent++; num_parts_sent++;
is_empty_chain = 0; is_empty_chain = 0;
chunks_processed++;
} }
part_count++; part_count++;
@ -1239,3 +1245,4 @@ ngx_http_cp_metric_data_sender()
reset_metric_data(); reset_metric_data();
return res; return res;
} }

View File

@ -58,6 +58,7 @@ ngx_int_t
ngx_http_cp_reply_receiver( ngx_http_cp_reply_receiver(
ngx_int_t *expected_replies, ngx_int_t *expected_replies,
ngx_http_cp_verdict_e *verdict, ngx_http_cp_verdict_e *verdict,
ngx_int_t *inspect_all_response_headers,
uint32_t cur_session_id, uint32_t cur_session_id,
ngx_http_request_t *request, ngx_http_request_t *request,
ngx_http_cp_modification_list **modification_list, ngx_http_cp_modification_list **modification_list,
@ -70,6 +71,7 @@ ngx_http_cp_reply_receiver(
/// @param[in, out] request NGINX request. /// @param[in, out] request NGINX request.
/// @param[in] cur_request_id Request session's Id. /// @param[in] cur_request_id Request session's Id.
/// @param[in, out] num_messages_sent Number of messages sent will be saved onto this parameter. /// @param[in, out] num_messages_sent Number of messages sent will be saved onto this parameter.
/// @param[in] waf_tag WAF tag to be sent.
/// @returns ngx_int_t /// @returns ngx_int_t
/// - #NGX_OK /// - #NGX_OK
/// - #NGX_ERROR /// - #NGX_ERROR
@ -78,7 +80,8 @@ ngx_int_t
ngx_http_cp_meta_data_sender( ngx_http_cp_meta_data_sender(
ngx_http_request_t *request, ngx_http_request_t *request,
uint32_t cur_request_id, uint32_t cur_request_id,
ngx_uint_t *num_messages_sent ngx_uint_t *num_messages_sent,
ngx_str_t *waf_tag
); );
/// ///
@ -138,7 +141,6 @@ ngx_http_cp_content_length_sender(
/// - #RESPONSE_HEADER /// - #RESPONSE_HEADER
/// @param[in] cur_request_id Request session's Id. /// @param[in] cur_request_id Request session's Id.
/// @param[in, out] num_messages_sent Number of messages sent will be saved onto this parameter. /// @param[in, out] num_messages_sent Number of messages sent will be saved onto this parameter.
/// @param[in, out] waf_tag WAF tag to be sent.
/// @returns ngx_int_t /// @returns ngx_int_t
/// - #NGX_OK /// - #NGX_OK
/// - #NGX_ERROR /// - #NGX_ERROR
@ -148,8 +150,7 @@ ngx_http_cp_header_sender(
ngx_list_part_t *headers, ngx_list_part_t *headers,
ngx_http_chunk_type_e header_type, ngx_http_chunk_type_e header_type,
uint32_t cur_request_id, uint32_t cur_request_id,
ngx_uint_t *num_messages_sent, ngx_uint_t *num_messages_sent
ngx_str_t *waf_tag
); );
/// ///

View File

@ -45,7 +45,8 @@ typedef enum CompressionType
{ {
NO_COMPRESSION, NO_COMPRESSION,
GZIP, GZIP,
ZLIB ZLIB,
BROTLI
} CompressionType; } CompressionType;
typedef struct CompressionResult typedef struct CompressionResult

View File

@ -146,7 +146,8 @@ typedef enum ngx_http_cp_verdict
TRAFFIC_VERDICT_INJECT, TRAFFIC_VERDICT_INJECT,
TRAFFIC_VERDICT_IRRELEVANT, TRAFFIC_VERDICT_IRRELEVANT,
TRAFFIC_VERDICT_RECONF, TRAFFIC_VERDICT_RECONF,
TRAFFIC_VERDICT_WAIT TRAFFIC_VERDICT_WAIT,
LIMIT_RESPONSE_HEADERS
} ngx_http_cp_verdict_e; } ngx_http_cp_verdict_e;
#ifdef __cplusplus #ifdef __cplusplus
@ -190,6 +191,8 @@ typedef enum ngx_http_meta_data
PARSED_HOST_DATA, PARSED_HOST_DATA,
PARSED_URI_SIZE, PARSED_URI_SIZE,
PARSED_URI_DATA, PARSED_URI_DATA,
WAF_TAG_SIZE,
WAF_TAG_DATA,
META_DATA_COUNT META_DATA_COUNT
} ngx_http_meta_data_e; } ngx_http_meta_data_e;