Transaction handler: writes headers to the log file using AIO
| 396 | |
| 397 | // Transaction handler: writes headers to the log file using AIO |
| 398 | int |
| 399 | TransactionData::global_transaction_handler(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata) |
| 400 | { |
| 401 | TSHttpTxn txnp = static_cast<TSHttpTxn>(edata); |
| 402 | |
| 403 | // Retrieve SessionData |
| 404 | TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp); |
| 405 | SessionData *ssnData = static_cast<SessionData *>(TSUserArgGet(ssnp, SessionData::get_session_arg_index())); |
| 406 | |
| 407 | // If no valid ssnData, continue transaction as if nothing happened. This transaction |
| 408 | // must be filtered out by our filter criteria. |
| 409 | if (!ssnData) { |
| 410 | Dbg(dbg_ctl, "session_txn_handler(): No ssnData found. Abort."); |
| 411 | TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); |
| 412 | return TS_SUCCESS; |
| 413 | } |
| 414 | |
| 415 | switch (event) { |
| 416 | case TS_EVENT_HTTP_TXN_START: { |
| 417 | // We will piece together JSON content accumulated across several hooks of |
| 418 | // the transaction. The catch is that hooks across transactions in a |
| 419 | // session may fire interleaved in HTTP/2. Thus, in order to get |
| 420 | // non-garbled JSON content, we accumulate the data for an entire |
| 421 | // transaction and write that atomically once the transaction is completed. |
| 422 | TransactionData *txnData = new TransactionData(txnp, ssnData->get_http_version_in_client_stack()); |
| 423 | TSUserArgSet(txnp, transaction_arg_index, txnData); |
| 424 | // Get UUID |
| 425 | char uuid[TS_CRUUID_STRING_LEN + 1]; |
| 426 | TSAssert(TS_SUCCESS == TSClientRequestUuidGet(txnp, uuid)); |
| 427 | std::string_view uuid_view{uuid, strnlen(uuid, TS_CRUUID_STRING_LEN)}; |
| 428 | |
| 429 | // Generate per transaction json records |
| 430 | txnData->_txn_json += "{"; |
| 431 | // "connection-time":(number) |
| 432 | TSHRTime start_time; |
| 433 | TSHttpTxnMilestoneGet(txnp, TS_MILESTONE_UA_BEGIN, &start_time); |
| 434 | txnData->_txn_json += "\"connection-time\":" + std::to_string(start_time); |
| 435 | |
| 436 | // "uuid":(string) |
| 437 | // The uuid is a header field for each message in the transaction. Use the |
| 438 | // "all" node to apply to each message. |
| 439 | std::string_view name = "uuid"; |
| 440 | txnData->_txn_json += R"(,"all":{"headers":{"fields":[)" + json_entry_array(name, uuid_view); |
| 441 | txnData->_txn_json += "]}}"; |
| 442 | break; |
| 443 | } |
| 444 | |
| 445 | case TS_EVENT_HTTP_READ_REQUEST_HDR: { |
| 446 | TransactionData *txnData = static_cast<TransactionData *>(TSUserArgGet(txnp, transaction_arg_index)); |
| 447 | if (!txnData) { |
| 448 | TSError("[%s] No transaction data found for the header hook we registered for.", traffic_dump::debug_tag); |
| 449 | break; |
| 450 | } |
| 451 | // This hook is registered globally, not at TS_EVENT_HTTP_SSN_START in |
| 452 | // global_session_handler(). As such, this handler will be called with every |
| 453 | // transaction. However, we infer that we are dumping this transaction |
| 454 | // because there is a ssnData associated with it. |
| 455 |
nothing calls this directly
no test coverage detected