]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
bbc27441 AJ |
3 | * |
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. | |
7 | */ | |
8 | ||
f7f3304a | 9 | #include "squid.h" |
d4204018 | 10 | #include "AccessLogEntry.h" |
582c2af2 | 11 | #include "HttpReply.h" |
d4204018 | 12 | #include "HttpRequest.h" |
49f57088 | 13 | #include "MemBuf.h" |
36c774f7 | 14 | #include "proxyp/Header.h" |
4d5904f7 | 15 | #include "SquidConfig.h" |
f3d7d090 AJ |
16 | #include "ssl/support.h" |
17 | ||
d4204018 AJ |
18 | void |
19 | AccessLogEntry::getLogClientIp(char *buf, size_t bufsz) const | |
20 | { | |
998ef291 AJ |
21 | Ip::Address log_ip; |
22 | ||
d4204018 AJ |
23 | #if FOLLOW_X_FORWARDED_FOR |
24 | if (Config.onoff.log_uses_indirect_client && request) | |
998ef291 | 25 | log_ip = request->indirect_client_addr; |
d4204018 AJ |
26 | else |
27 | #endif | |
705c36c6 | 28 | if (tcpClient) |
998ef291 | 29 | log_ip = tcpClient->remote; |
705c36c6 | 30 | else |
998ef291 AJ |
31 | log_ip = cache.caddr; |
32 | ||
705c36c6 AJ |
33 | // internally generated requests (and some ICAP) lack client IP |
34 | if (log_ip.isNoAddr()) { | |
35 | strncpy(buf, "-", bufsz); | |
36 | return; | |
37 | } | |
38 | ||
998ef291 AJ |
39 | // Apply so-called 'privacy masking' to IPv4 clients |
40 | // - localhost IP is always shown in full | |
41 | // - IPv4 clients masked with client_netmask | |
42 | // - IPv6 clients use 'privacy addressing' instead. | |
43 | ||
36c774f7 | 44 | log_ip.applyClientMask(Config.Addrs.client_netmask); |
998ef291 AJ |
45 | |
46 | log_ip.toStr(buf, bufsz); | |
d4204018 | 47 | } |
41ebd397 | 48 | |
58b148e1 AJ |
49 | SBuf |
50 | AccessLogEntry::getLogMethod() const | |
51 | { | |
ec2c4acf | 52 | static const SBuf dash("-"); |
58b148e1 AJ |
53 | SBuf method; |
54 | if (icp.opcode) | |
55 | method.append(icp_opcode_str[icp.opcode]); | |
56 | else if (htcp.opcode) | |
57 | method.append(htcp.opcode); | |
ec2c4acf | 58 | else if (http.method) |
58b148e1 | 59 | method = http.method.image(); |
ec2c4acf AR |
60 | else |
61 | method = dash; | |
58b148e1 AJ |
62 | return method; |
63 | } | |
64 | ||
75d47340 CT |
65 | void |
66 | AccessLogEntry::syncNotes(HttpRequest *req) | |
67 | { | |
68 | // XXX: auth code only has access to HttpRequest being authenticated | |
69 | // so we must handle the case where HttpRequest is set without ALE being set. | |
70 | assert(req); | |
71 | if (!notes) | |
72 | notes = req->notes(); | |
73 | else | |
74 | assert(notes == req->notes()); | |
75 | } | |
76 | ||
e3bf07f5 AJ |
77 | const char * |
78 | AccessLogEntry::getClientIdent() const | |
79 | { | |
80 | if (tcpClient) | |
81 | return tcpClient->rfc931; | |
82 | ||
83 | if (cache.rfc931 && *cache.rfc931) | |
84 | return cache.rfc931; | |
85 | ||
86 | return nullptr; | |
87 | } | |
88 | ||
89 | const char * | |
90 | AccessLogEntry::getExtUser() const | |
91 | { | |
92 | if (request && request->extacl_user.size()) | |
93 | return request->extacl_user.termedBuf(); | |
94 | ||
95 | if (cache.extuser && *cache.extuser) | |
96 | return cache.extuser; | |
97 | ||
98 | return nullptr; | |
99 | } | |
100 | ||
36c774f7 EB |
101 | AccessLogEntry::AccessLogEntry() {} |
102 | ||
41ebd397 CT |
103 | AccessLogEntry::~AccessLogEntry() |
104 | { | |
105 | safe_free(headers.request); | |
106 | ||
f5d0906a | 107 | #if USE_ADAPTATION |
41ebd397 CT |
108 | safe_free(adapt.last_meta); |
109 | #endif | |
110 | ||
41ebd397 CT |
111 | safe_free(headers.adapted_request); |
112 | HTTPMSGUNLOCK(adapted_request); | |
113 | ||
4ff6370b | 114 | safe_free(lastAclName); |
4ff6370b | 115 | |
41ebd397 CT |
116 | HTTPMSGUNLOCK(request); |
117 | #if ICAP_CLIENT | |
118 | HTTPMSGUNLOCK(icap.reply); | |
119 | HTTPMSGUNLOCK(icap.request); | |
120 | #endif | |
41ebd397 | 121 | } |
f53969cc | 122 | |
ccfbe8f4 AR |
123 | ScopedId |
124 | AccessLogEntry::codeContextGist() const | |
125 | { | |
126 | if (request) { | |
127 | if (const auto &mx = request->masterXaction) | |
128 | return mx->id.detach(); | |
129 | } | |
130 | // TODO: Carefully merge ALE and MasterXaction. | |
131 | return ScopedId("ALE w/o master"); | |
132 | } | |
133 | ||
134 | std::ostream & | |
135 | AccessLogEntry::detailCodeContext(std::ostream &os) const | |
136 | { | |
137 | // TODO: Consider printing all instead of the first most important detail. | |
138 | ||
139 | if (request) { | |
140 | if (const auto &mx = request->masterXaction) | |
141 | return os << Debug::Extra << "current master transaction: " << mx->id; | |
142 | } | |
143 | ||
144 | // provide helpful details since we cannot identify the transaction exactly | |
145 | ||
146 | if (tcpClient) | |
147 | return os << Debug::Extra << "current from-client connection: " << tcpClient; | |
148 | else if (!cache.caddr.isNoAddr()) | |
149 | return os << Debug::Extra << "current client: " << cache.caddr; | |
150 | ||
151 | const auto optionalMethod = [this,&os]() { | |
152 | if (hasLogMethod()) | |
153 | os << getLogMethod() << ' '; | |
154 | return ""; | |
155 | }; | |
156 | if (const auto uri = effectiveVirginUrl()) | |
157 | return os << Debug::Extra << "current client request: " << optionalMethod() << *uri; | |
158 | else if (!url.isEmpty()) | |
159 | return os << Debug::Extra << "current request: " << optionalMethod() << url; | |
160 | else if (hasLogMethod()) | |
161 | return os << Debug::Extra << "current request method: " << getLogMethod(); | |
162 | ||
163 | return os; | |
164 | } | |
165 | ||
bec110e4 EB |
166 | const SBuf * |
167 | AccessLogEntry::effectiveVirginUrl() const | |
168 | { | |
57a5679b | 169 | const SBuf *effectiveUrl = request ? &request->effectiveRequestUri() : &virginUrlForMissingRequest_; |
bec110e4 EB |
170 | if (effectiveUrl && !effectiveUrl->isEmpty()) |
171 | return effectiveUrl; | |
172 | // We can not use ALE::url here because it may contain a request URI after | |
173 | // adaptation/redirection. When the request is missing, a non-empty ALE::url | |
174 | // means that we missed a setVirginUrlForMissingRequest() call somewhere. | |
175 | return nullptr; | |
176 | } | |
177 | ||
83b053a0 CT |
178 | const Error * |
179 | AccessLogEntry::error() const | |
180 | { | |
181 | // the order ensures that the first-imported error is returned | |
182 | if (error_) // updateError() was called before importing the request | |
183 | return &error_; | |
184 | if (request && request->error) // request was imported before updateError() | |
185 | return &request->error; | |
186 | return nullptr; // we imported no errors and no requests | |
187 | } | |
188 | ||
189 | void | |
190 | AccessLogEntry::updateError(const Error &err) | |
191 | { | |
192 | // the order ensures that error() returns the first-imported error | |
193 | if (request) | |
194 | request->error.update(err); | |
195 | else | |
196 | error_.update(err); | |
197 | } | |
198 | ||
49f57088 EB |
199 | void |
200 | AccessLogEntry::packReplyHeaders(MemBuf &mb) const | |
201 | { | |
202 | if (reply) | |
203 | reply->packHeadersUsingFastPacker(mb); | |
204 | } | |
205 |