2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
10 #include "AccessLogEntry.h"
11 #include "fqdncache.h"
12 #include "HttpReply.h"
13 #include "HttpRequest.h"
15 #include "proxyp/Header.h"
16 #include "SquidConfig.h"
17 #include "ssl/support.h"
20 AccessLogEntry::getLogClientIp(char *buf
, size_t bufsz
) const
24 #if FOLLOW_X_FORWARDED_FOR
25 if (Config
.onoff
.log_uses_indirect_client
&& request
)
26 log_ip
= request
->indirect_client_addr
;
30 log_ip
= tcpClient
->remote
;
34 // internally generated requests (and some ICAP) lack client IP
35 if (log_ip
.isNoAddr()) {
36 strncpy(buf
, "-", bufsz
);
40 // Apply so-called 'privacy masking' to IPv4 clients
41 // - localhost IP is always shown in full
42 // - IPv4 clients masked with client_netmask
43 // - IPv6 clients use 'privacy addressing' instead.
45 log_ip
.applyClientMask(Config
.Addrs
.client_netmask
);
47 log_ip
.toStr(buf
, bufsz
);
51 AccessLogEntry::getLogClientFqdn(char * const buf
, const size_t bufSize
) const
53 // TODO: Use indirect client and tcpClient like getLogClientIp() does.
54 const auto &client
= cache
.caddr
;
56 // internally generated (and ICAP OPTIONS) requests lack client IP
57 if (client
.isAnyAddr())
60 // If we are here, Squid was configured to use %>A or equivalent.
61 // Improve our chances of getting FQDN by resolving client IPs ASAP.
62 Dns::ResolveClientAddressesAsap
= true; // may already be true
64 // Too late for ours, but FQDN_LOOKUP_IF_MISS might help the next caller.
65 if (const auto fqdn
= fqdncache_gethostbyaddr(client
, FQDN_LOOKUP_IF_MISS
))
66 return fqdn
; // TODO: Return a safe SBuf from fqdncache_gethostbyaddr().
68 return client
.toStr(buf
, bufSize
);
72 AccessLogEntry::getLogMethod() const
74 static const SBuf
dash("-");
77 method
.append(icp_opcode_str
[icp
.opcode
]);
79 method
.append(htcp
.opcode
);
81 method
= http
.method
.image();
88 AccessLogEntry::syncNotes(HttpRequest
*req
)
90 // XXX: auth code only has access to HttpRequest being authenticated
91 // so we must handle the case where HttpRequest is set without ALE being set.
96 assert(notes
== req
->notes());
100 AccessLogEntry::getClientIdent() const
103 return tcpClient
->rfc931
;
105 if (cache
.rfc931
&& *cache
.rfc931
)
112 AccessLogEntry::getExtUser() const
114 if (request
&& request
->extacl_user
.size())
115 return request
->extacl_user
.termedBuf();
117 if (cache
.extuser
&& *cache
.extuser
)
118 return cache
.extuser
;
123 AccessLogEntry::AccessLogEntry() {}
125 AccessLogEntry::~AccessLogEntry()
127 safe_free(headers
.request
);
130 safe_free(adapt
.last_meta
);
133 safe_free(headers
.adapted_request
);
134 HTTPMSGUNLOCK(adapted_request
);
136 safe_free(lastAclName
);
138 HTTPMSGUNLOCK(request
);
140 HTTPMSGUNLOCK(icap
.reply
);
141 HTTPMSGUNLOCK(icap
.request
);
146 AccessLogEntry::codeContextGist() const
149 if (const auto &mx
= request
->masterXaction
)
150 return mx
->id
.detach();
152 // TODO: Carefully merge ALE and MasterXaction.
153 return ScopedId("ALE w/o master");
157 AccessLogEntry::detailCodeContext(std::ostream
&os
) const
159 // TODO: Consider printing all instead of the first most important detail.
162 if (const auto &mx
= request
->masterXaction
)
163 return os
<< Debug::Extra
<< "current master transaction: " << mx
->id
;
166 // provide helpful details since we cannot identify the transaction exactly
169 return os
<< Debug::Extra
<< "current from-client connection: " << tcpClient
;
170 else if (!cache
.caddr
.isNoAddr())
171 return os
<< Debug::Extra
<< "current client: " << cache
.caddr
;
173 const auto optionalMethod
= [this,&os
]() {
175 os
<< getLogMethod() << ' ';
178 if (const auto uri
= effectiveVirginUrl())
179 return os
<< Debug::Extra
<< "current client request: " << optionalMethod() << *uri
;
180 else if (!url
.isEmpty())
181 return os
<< Debug::Extra
<< "current request: " << optionalMethod() << url
;
182 else if (hasLogMethod())
183 return os
<< Debug::Extra
<< "current request method: " << getLogMethod();
189 AccessLogEntry::effectiveVirginUrl() const
191 const SBuf
*effectiveUrl
= request
? &request
->effectiveRequestUri() : &virginUrlForMissingRequest_
;
192 if (effectiveUrl
&& !effectiveUrl
->isEmpty())
194 // We can not use ALE::url here because it may contain a request URI after
195 // adaptation/redirection. When the request is missing, a non-empty ALE::url
196 // means that we missed a setVirginUrlForMissingRequest() call somewhere.
201 AccessLogEntry::error() const
203 // the order ensures that the first-imported error is returned
204 if (error_
) // updateError() was called before importing the request
206 if (request
&& request
->error
) // request was imported before updateError()
207 return &request
->error
;
208 return nullptr; // we imported no errors and no requests
212 AccessLogEntry::updateError(const Error
&err
)
214 // the order ensures that error() returns the first-imported error
216 request
->error
.update(err
);
222 AccessLogEntry::packReplyHeaders(MemBuf
&mb
) const
225 reply
->packHeadersUsingFastPacker(mb
);