Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file

PreTransactionLogData populates LogData for requests that fail before
HttpSM creation.
NonHttpSmLogData populates LogData for access-log entries that cannot be
backed by an HttpSM.

@section license License

Expand Down Expand Up @@ -30,23 +30,32 @@

#include <string>

/** Populate LogData for requests that never created an HttpSM.
/** Owns access-log data for entries that cannot be backed by an @c HttpSM.
*
* Malformed HTTP/2 or HTTP/3 request headers can be rejected while the
* connection is still decoding and validating the stream, before the request
* progresses far enough to create an HttpSM. This class carries the
* copied request and session metadata needed to emit a best-effort
* transaction log entry for those failures.
* Normal transaction access logging is expected to use data extracted from a
* live @c HttpSM. This type is for exceptional client-facing failures that need
* transaction-log visibility but occur before an @c HttpSM exists, such as
* malformed HTTP/2 or HTTP/3 request headers rejected during protocol
* validation. It may also be used for connection-level failures, such as TLS
* handshake errors, when operators need those events in the access log.
*
* This class owns its milestones, addresses, and strings because the
* originating stream is about to be destroyed.
* Because the protocol stream or connection state may be destroyed immediately
* after the failure is handled, this object owns the copied headers,
* addresses, milestones, protocol strings, and outcome fields needed by
* @c LogAccess. Fields that require an @c HttpSM, origin transaction, cache
* lookup, or server response are intentionally left unset and marshal through
* the normal default values.
*
* This path should remain narrow. If an @c HttpSM exists, prefer the standard
* @c HttpSM-backed logging path so normal transactions do not pay for extra
* copying or exceptional state.
*/
class PreTransactionLogData
class NonHttpSmLogData
{
public:
PreTransactionLogData() = default;
NonHttpSmLogData() = default;

~PreTransactionLogData()
~NonHttpSmLogData()
{
if (owned_client_request.valid()) {
owned_client_request.destroy();
Expand Down
9 changes: 5 additions & 4 deletions include/proxy/ProxyTransaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,19 @@ class ProxyTransaction : public VConnection

void mark_as_tunnel_endpoint() override;

/** Emit a best-effort access log entry for a request that failed before
* HttpSM creation.
/** Emit a best-effort access log entry for a request without an HttpSM.
*
* Call this when a malformed request is rejected at the protocol layer
* (e.g. during HTTP/2 or HTTP/3 header decoding) and no HttpSM was
* created. The method populates a PreTransactionLogData from the
* created. The method populates a NonHttpSmLogData from the
* session and the partially decoded request, then invokes Log::access.
* If an HttpSM exists, callers should use the normal transaction logging
* path instead.
*
* @param[in] request The decoded (possibly partial) request header.
* @param[in] protocol_str Protocol string for the log entry (e.g. "http/2").
*/
void log_pre_transaction_access(HTTPHdr const *request, const char *protocol_str);
void log_non_http_sm_access(HTTPHdr const *request, const char *protocol_str);

/// Variables
//
Expand Down
2 changes: 1 addition & 1 deletion include/proxy/logging/Log.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
@section example Example usage of the API

@code
// Populate a TransactionLogData, then:
// Populate a TransactionLogData source, then:
LogAccess entry(data);
int ret = Log::access(&entry);
@endcode
Expand Down
4 changes: 2 additions & 2 deletions include/proxy/logging/LogAccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ class LogAccess
* The caller retains ownership of @a data, which must outlive the
* synchronous Log::access() call that marshals this entry.
*
* @param[in] data Populated TransactionLogData for a completed or
* pre-transaction entry.
* @param[in] data Populated TransactionLogData for an HttpSM-backed or
* non-HttpSM entry.
*/
explicit LogAccess(TransactionLogData &data);

Expand Down
18 changes: 9 additions & 9 deletions include/proxy/logging/TransactionLogData.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@
#include <string_view>

class HttpSM;
class PreTransactionLogData;
class NonHttpSmLogData;

/** Provide access-log data from either a completed HttpSM or pre-transaction storage.
/** Provide access-log data from either a completed HttpSM or non-HttpSM storage.
*
* The common completed-transaction path reads directly from @c HttpSM. The
* rare pre-transaction path reads from @c PreTransactionLogData, which owns
* copied request/session state for malformed requests rejected before HttpSM
* creation.
* rare non-HttpSM path reads from @c NonHttpSmLogData, which owns copied
* request/session state for exceptional access-log entries that cannot be
* backed by an @c HttpSM.
*/
class TransactionLogData
{
public:
explicit TransactionLogData(HttpSM *sm);
explicit TransactionLogData(PreTransactionLogData const &pre_data);
explicit TransactionLogData(NonHttpSmLogData const &non_http_sm_data);

void *http_sm_for_plugins() const;

Expand Down Expand Up @@ -185,7 +185,7 @@ class TransactionLogData
// ===== Server response Transfer-Encoding =====
std::string_view get_server_response_transfer_encoding() const;

// ===== Fallback fields for pre-transaction logging =====
// ===== Fallback fields for non-HttpSM logging =====
std::string_view get_method() const;
std::string_view get_scheme() const;
std::string_view get_client_protocol_str() const;
Expand All @@ -194,8 +194,8 @@ class TransactionLogData
TransactionLogData &operator=(const TransactionLogData &) = delete;

private:
HttpSM *m_http_sm = nullptr;
PreTransactionLogData const *m_pre_data = nullptr;
HttpSM *m_http_sm = nullptr;
NonHttpSmLogData const *m_non_http_sm_data = nullptr;

// Cached values for fields that require computation or string formatting.
mutable char m_client_rx_error_code[10] = {'-', '\0'};
Expand Down
6 changes: 3 additions & 3 deletions src/proxy/ProxyTransaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#include "proxy/http/HttpSM.h"
#include "proxy/Plugin.h"
#include "proxy/PreTransactionLogData.h"
#include "proxy/NonHttpSmLogData.h"
#include "proxy/logging/LogAccess.h"
#include "proxy/logging/TransactionLogData.h"
#include "proxy/logging/Log.h"
Expand Down Expand Up @@ -343,7 +343,7 @@ get_pseudo_header_value(HTTPHdr const &hdr, std::string_view name)
} // end anonymous namespace

void
ProxyTransaction::log_pre_transaction_access(HTTPHdr const *request, const char *protocol_str)
ProxyTransaction::log_non_http_sm_access(HTTPHdr const *request, const char *protocol_str)
{
if (get_sm() != nullptr) {
return;
Expand All @@ -358,7 +358,7 @@ ProxyTransaction::log_pre_transaction_access(HTTPHdr const *request, const char
return;
}

PreTransactionLogData data;
NonHttpSmLogData data;

data.owned_client_request.create(HTTPType::REQUEST, request->version_get());
data.owned_client_request.copy(request);
Expand Down
4 changes: 2 additions & 2 deletions src/proxy/http2/Http2ConnectionState.cc
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ Http2ConnectionState::rcv_headers_frame(const Http2Frame &frame)
"recv headers enhance your calm");
} else {
if (!stream->trailing_header_is_possible() && !stream->is_outbound_connection()) {
stream->log_pre_transaction_access(stream->get_receive_header(), "http/2");
stream->log_non_http_sm_access(stream->get_receive_header(), "http/2");
}
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
"recv headers malformed request");
Expand Down Expand Up @@ -1112,7 +1112,7 @@ Http2ConnectionState::rcv_continuation_frame(const Http2Frame &frame)
"continuation enhance your calm");
} else {
if (!stream->trailing_header_is_possible() && !stream->is_outbound_connection()) {
stream->log_pre_transaction_access(stream->get_receive_header(), "http/2");
stream->log_non_http_sm_access(stream->get_receive_header(), "http/2");
}
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
"continuation malformed request");
Expand Down
4 changes: 2 additions & 2 deletions src/proxy/http3/Http3HeaderVIOAdaptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,15 @@ Http3HeaderVIOAdaptor::_on_qpack_decode_complete()
NON_TRAILER)) {
Dbg(dbg_ctl_http3, "Header is invalid");
if (this->_txn != nullptr) {
this->_txn->log_pre_transaction_access(&this->_header, "http/3");
this->_txn->log_non_http_sm_access(&this->_header, "http/3");
}
return -1;
}
int res = this->_hvc.convert(this->_header, 3, 1);
if (res != 0) {
Dbg(dbg_ctl_http3, "ParseResult::ERROR");
if (this->_txn != nullptr) {
this->_txn->log_pre_transaction_access(&this->_header, "http/3");
this->_txn->log_non_http_sm_access(&this->_header, "http/3");
}
return -1;
}
Expand Down
Loading