#include "AccessLogEntry.h"
#include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
+#include "client_side.h"
#include "ConfigParser.h"
#include "globals.h"
#include "HttpReply.h"
entries.push_back(new NotePairs::Entry(key, note));
}
+void
+NotePairs::remove(const char *key)
+{
+ std::vector<NotePairs::Entry *>::iterator i = entries.begin();
+ while(i != entries.end()) {
+ if ((*i)->name.cmp(key) == 0) {
+ delete *i;
+ i = entries.erase(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
void
NotePairs::addStrList(const char *key, const char *values)
{
}
}
+void
+NotePairs::replaceOrAdd(const NotePairs *src)
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
+ remove((*i)->name.termedBuf());
+ }
+ append(src);
+}
+
NotePairs &
SyncNotes(AccessLogEntry &ale, HttpRequest &request)
{
}
return *ale.notes;
}
+
+void
+UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
+{
+ // Tag client connection if the helper responded with clt_conn_tag=tag.
+ if (const char *connTag = helperNotes.findFirst("clt_conn_tag")) {
+ if (csd)
+ csd->connectionTag(connTag);
+ }
+ if (!request.notes)
+ request.notes = new NotePairs;
+ request.notes->replaceOrAdd(&helperNotes);
+}
*/
void append(const NotePairs *src);
+ /**
+ * Replace existing list entries with the src NotePairs entries.
+ * Entries which do not exist in the destination set are added.
+ */
+ void replaceOrAdd(const NotePairs *src);
+
/**
* Append any new entries of the src NotePairs list to our list.
* Entries which already exist in the destination set are ignored.
*/
void add(const char *key, const char *value);
+ /**
+ * Remove all notes with a given key.
+ */
+ void remove(const char *key);
+
/**
* Adds a note key and values strList to the notes list.
* If the key name already exists in list, add the new values to its set
*/
NotePairs &SyncNotes(AccessLogEntry &ale, HttpRequest &request);
+class ConnStateData;
+/**
+ * Updates ConnStateData ids and HttpRequest notes from helpers received notes.
+ */
+void UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const ¬es);
#endif
// XXX: we have no access to the transaction / AccessLogEntry so cant SyncNotes().
// workaround by using anything already set in HttpRequest
// OR use new and rely on a later Sync copying these to AccessLogEntry
- if (!request->notes)
- request->notes = new NotePairs;
- request->notes->appendNewOnly(&res->user()->notes);
+ UpdateRequestNotes(conn, *request, res->user()->notes);
}
return res;
log= String to be logged in access.log. Available as
%ea in logformat specifications.
+ clt_conn_tag= Associates a TAG with the client TCP connection.
+ Please see url_rewrite_program related documentation for
+ this kv-pair.
+
Any keywords may be sent on any response whether OK, ERR or BH.
All response keyword values need to be a single token with URL
[channel-ID <SP>] URL [<SP> extras]<NL>
-
+ See url_rewrite_extras on how to send "extras" with optional values to
+ the helper.
After processing the request the helper must reply using the following format:
[channel-ID <SP>] result [<SP> kv-pairs]
reserved for delivering a log message.
- In the future, the interface protocol will be extended with
- key=value pairs ("kv-pairs" shown above). Helper programs
- should be prepared to receive and possibly ignore additional
- whitespace-separated tokens on each input line.
+ In addition to the above kv-pairs Squid also understands the following
+ optional kv-pairs received from URL rewriters:
+ clt_conn_tag=TAG
+ Associates a TAG with the client TCP connection.
+ The TAG is treated as a regular annotation but persists across
+ future requests on the client connection rather than just the
+ current request. A helper may update the TAG during subsequent
+ requests be returning a new kv-pair.
When using the concurrency= option the protocol is changed by
introducing a query channel tag in front of the request/response.
An internal error occured in the helper, preventing
a result being identified.
+ In addition to the above kv-pairs Squid also understands the following
+ optional kv-pairs received from URL rewriters:
+ clt_conn_tag=TAG
+ Associates a TAG with the client TCP connection.
+ Please see url_rewrite_program related documentation for this
+ kv-pair
Helper programs should be prepared to receive and possibly ignore
additional whitespace-separated tokens on each input line.
bool switchedToHttps() const { return false; }
#endif
+ /* clt_conn_tag=tag annotation access */
+ const SBuf &connectionTag() const { return connectionTag_; }
+ void connectionTag(const char *aTag) { connectionTag_ = aTag; }
+
protected:
void startDechunkingRequest();
void finishDechunkingRequest(bool withSuccess);
AsyncCall::Pointer reader; ///< set when we are reading
BodyPipe::Pointer bodyPipe; // set when we are reading request body
+ SBuf connectionTag_; ///< clt_conn_tag=Tag annotation for client connection
+
CBDATA_CLASS2(ConnStateData);
};
// Put helper response Notes into the transaction state record (ALE) eventually
// do it early to ensure that no matter what the outcome the notes are present.
- if (http->al != NULL) {
- NotePairs ¬es = SyncNotes(*http->al, *old_request);
- notes.append(&reply.notes);
- }
+ if (http->al != NULL)
+ (void)SyncNotes(*http->al, *old_request);
+
+ UpdateRequestNotes(http->getConn(), *old_request, reply.notes);
switch (reply.result) {
case HelperReply::Unknown:
// Put helper response Notes into the transaction state record (ALE) eventually
// do it early to ensure that no matter what the outcome the notes are present.
- if (http->al != NULL) {
- NotePairs ¬es = SyncNotes(*http->al, *old_request);
- notes.append(&reply.notes);
- }
+ if (http->al != NULL)
+ (void)SyncNotes(*http->al, *old_request);
+
+ UpdateRequestNotes(http->getConn(), *old_request, reply.notes);
switch (reply.result) {
case HelperReply::Unknown:
if (!calloutContext->http->al->request) {
calloutContext->http->al->request = request;
HTTPMSGLOCK(calloutContext->http->al->request);
+
+ NotePairs ¬es = SyncNotes(*calloutContext->http->al, *calloutContext->http->request);
+ // Make the previously set client connection ID available as annotation.
+ if (ConnStateData *csd = calloutContext->http->getConn()) {
+ if (!csd->connectionTag().isEmpty())
+ notes.add("clt_conn_tag", SBuf(csd->connectionTag()).c_str());
+ }
}
if (!calloutContext->error) {
// XXX: we have no access to the transaction / AccessLogEntry so cant SyncNotes().
// workaround by using anything already set in HttpRequest
// OR use new and rely on a later Sync copying these to AccessLogEntry
- if (!req->notes)
- req->notes = new NotePairs;
- req->notes->appendNewOnly(&checklist->extacl_entry->notes);
+ UpdateRequestNotes(checklist->conn(), *req, checklist->extacl_entry->notes);
}
}