]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/format/Format.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / format / Format.cc
index b4596ee43b93ef10ece8ee94adc3e099e333b2d1..94261c18e77f0581617ce638651e125fdfcad88b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -11,7 +11,7 @@
 #include "base64.h"
 #include "client_side.h"
 #include "comm/Connection.h"
-#include "err_detail_type.h"
+#include "error/Detail.h"
 #include "errorpage.h"
 #include "fde.h"
 #include "format/Format.h"
@@ -21,7 +21,9 @@
 #include "http/Stream.h"
 #include "HttpRequest.h"
 #include "MemBuf.h"
+#include "proxyp/Header.h"
 #include "rfc1738.h"
+#include "sbuf/Stream.h"
 #include "sbuf/StringConvert.h"
 #include "security/CertError.h"
 #include "security/NegotiationHistory.h"
@@ -75,7 +77,7 @@ Format::Format::parse(const char *def)
         return false;
     }
 
-    /* very inefficent parser, but who cares, this needs to be simple */
+    /* very inefficient parser, but who cares, this needs to be simple */
     /* First off, let's tokenize, we'll optimize in a second pass.
      * A token can either be a %-prefixed sequence (usually a dynamic
      * token but it can be an escaped sequence), or a string. */
@@ -94,6 +96,23 @@ Format::Format::parse(const char *def)
     return true;
 }
 
+size_t
+Format::AssembleOne(const char *token, MemBuf &mb, const AccessLogEntryPointer &ale)
+{
+    Token tkn;
+    enum Quoting quote = LOG_QUOTE_NONE;
+    const auto tokenSize = tkn.parse(token, &quote);
+    assert(tokenSize > 0);
+    if (ale != nullptr) {
+        Format fmt("SimpleToken");
+        fmt.format = &tkn;
+        fmt.assemble(mb, ale, 0);
+        fmt.format = nullptr;
+    } else
+        mb.append("-", 1);
+    return static_cast<size_t>(tokenSize);
+}
+
 void
 Format::Format::dump(StoreEntry * entry, const char *directiveName, bool eol) const
 {
@@ -322,15 +341,6 @@ log_quoted_string(const char *str, char *out)
     *p = '\0';
 }
 
-#if USE_OPENSSL
-static char *
-sslErrorName(Security::ErrorCode err, char *buf, size_t size)
-{
-    snprintf(buf, size, "SSL_ERR=%d", err);
-    return buf;
-}
-#endif
-
 /// XXX: Misnamed. TODO: Split <h (and this function) to distinguish received
 /// headers from sent headers rather than failing to distinguish requests from responses.
 /// \retval HttpReply sent to the HTTP client (access.log and default context).
@@ -339,7 +349,7 @@ sslErrorName(Security::ErrorCode err, char *buf, size_t size)
 static const Http::Message *
 actualReplyHeader(const AccessLogEntry::Pointer &al)
 {
-    const Http::Message *msg = al->reply;
+    const Http::Message *msg = al->reply.getRaw();
 #if ICAP_CLIENT
     // al->icap.reqMethod is methodNone in access.log context
     if (!msg && al->icap.reqMethod == Adaptation::methodReqmod)
@@ -380,6 +390,8 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         struct timeval outtv = {0, 0};
         int doMsec = 0;
         int doSec = 0;
+        bool doUint64 = false;
+        uint64_t outUint64 = 0;
 
         switch (fmt->type) {
 
@@ -487,6 +499,13 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             }
             break;
 
+        case LFT_TRANSPORT_CLIENT_CONNECTION_ID:
+            if (al->tcpClient) {
+                outUint64 = al->tcpClient->id.value;
+                doUint64 = true;
+            }
+            break;
+
         case LFT_CLIENT_LOCAL_NFMARK:
             if (al->tcpClient) {
                 sb.appendf("0x%x", al->tcpClient->nfmark);
@@ -616,7 +635,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         case LFT_DNS_WAIT_TIME:
             if (al->request && al->request->dnsWait >= 0) {
                 // TODO: microsecond precision for dns wait time.
-                // Convert miliseconds to timeval struct:
+                // Convert milliseconds to timeval struct:
                 outtv.tv_sec = al->request->dnsWait / 1000;
                 outtv.tv_usec = (al->request->dnsWait % 1000) * 1000;
                 doMsec = 1;
@@ -683,7 +702,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             if (al->request) {
                 const Adaptation::History::Pointer ah = al->request->adaptHistory();
                 if (ah) { // XXX: add adapt::<all_h but use lastMeta here
-                    sb = StringToSBuf(ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                    sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
                     out = sb.c_str();
                     quote = 1;
                 }
@@ -742,7 +761,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
 
         case LFT_ICAP_REQ_HEADER_ELEM:
             if (al->icap.request) {
-                sb = StringToSBuf(al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
                 out = sb.c_str();
                 quote = 1;
             }
@@ -772,7 +791,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
 
         case LFT_ICAP_REP_HEADER_ELEM:
             if (al->icap.reply) {
-                sb = StringToSBuf(al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
                 out = sb.c_str();
                 quote = 1;
             }
@@ -818,7 +837,31 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
 #endif
         case LFT_REQUEST_HEADER_ELEM:
             if (const Http::Message *msg = actualRequestHeader(al)) {
-                sb = StringToSBuf(msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
+                out = sb.c_str();
+                quote = 1;
+            }
+            break;
+
+        case LFT_PROXY_PROTOCOL_RECEIVED_HEADER:
+            if (al->proxyProtocolHeader) {
+                sb = al->proxyProtocolHeader->getValues(fmt->data.headerId, fmt->data.header.separator);
+                out = sb.c_str();
+                quote = 1;
+            }
+            break;
+
+        case LFT_PROXY_PROTOCOL_RECEIVED_ALL_HEADERS:
+            if (al->proxyProtocolHeader) {
+                sb = al->proxyProtocolHeader->toMime();
+                out = sb.c_str();
+                quote = 1;
+            }
+            break;
+
+        case LFT_PROXY_PROTOCOL_RECEIVED_HEADER_ELEM:
+            if (al->proxyProtocolHeader) {
+                sb = al->proxyProtocolHeader->getElem(fmt->data.headerId, fmt->data.header.element, fmt->data.header.separator);
                 out = sb.c_str();
                 quote = 1;
             }
@@ -826,7 +869,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
 
         case LFT_ADAPTED_REQUEST_HEADER_ELEM:
             if (al->adapted_request) {
-                sb = StringToSBuf(al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
                 out = sb.c_str();
                 quote = 1;
             }
@@ -834,7 +877,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
 
         case LFT_REPLY_HEADER_ELEM:
             if (const Http::Message *msg = actualReplyHeader(al)) {
-                sb = StringToSBuf(msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator));
+                sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
                 out = sb.c_str();
                 quote = 1;
             }
@@ -849,24 +892,35 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             } else
 #endif
             {
+                // just headers without start-line and CRLF
+                // XXX: reconcile with '<h'
                 out = al->headers.request;
                 quote = 1;
             }
             break;
 
         case LFT_ADAPTED_REQUEST_ALL_HEADERS:
+            // just headers without start-line and CRLF
+            // XXX: reconcile with '<h'
             out = al->headers.adapted_request;
             quote = 1;
             break;
 
-        case LFT_REPLY_ALL_HEADERS:
-            out = al->headers.reply;
+        case LFT_REPLY_ALL_HEADERS: {
+            MemBuf allHeaders;
+            allHeaders.init();
+            // status-line + headers + CRLF
+            // XXX: reconcile with '>h' and '>ha'
+            al->packReplyHeaders(allHeaders);
+            sb.assign(allHeaders.content(), allHeaders.contentSize());
+            out = sb.c_str();
 #if ICAP_CLIENT
             if (!out && al->icap.reqMethod == Adaptation::methodReqmod)
                 out = al->headers.adapted_request;
 #endif
             quote = 1;
-            break;
+        }
+        break;
 
         case LFT_USER_NAME:
 #if USE_AUTH
@@ -906,7 +960,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         /* case LFT_USER_SCHEME: */
 
         // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
-        // but compiler complains if ommited
+        // but compiler complains if omitted
         case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
         case LFT_HTTP_SENT_STATUS_CODE:
             outint = al->http.code;
@@ -939,31 +993,17 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             break;
 
         case LFT_SQUID_ERROR:
-            if (al->request && al->request->errType != ERR_NONE)
-                out = errorPageName(al->request->errType);
+            if (const auto error = al->error())
+                out = errorPageName(error->category);
             break;
 
         case LFT_SQUID_ERROR_DETAIL:
-#if USE_OPENSSL
-            if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
-                out = Ssl::GetErrorName(al->request->errDetail);
-                if (!out)
-                    out = sslErrorName(al->request->errDetail, tmp, sizeof(tmp));
-            } else
-#endif
-                if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
-                    if (al->request->errDetail > ERR_DETAIL_START && al->request->errDetail < ERR_DETAIL_MAX)
-                        out = errorDetailName(al->request->errDetail);
-                    else {
-                        if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
-                            sb.appendf("%s=0x%X",
-                                       errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
-                        else
-                            sb.appendf("%s=%d",
-                                       errorDetailName(al->request->errDetail), al->request->errDetail);
-                        out = sb.c_str();
-                    }
+            if (const auto error = al->error()) {
+                if (const auto detail = error->detail) {
+                    sb = detail->brief();
+                    out = sb.c_str();
                 }
+            }
             break;
 
         case LFT_SQUID_HIERARCHY:
@@ -1031,9 +1071,11 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             break;
 
         case LFT_REQUEST_METHOD:
-            sb = al->getLogMethod();
-            out = sb.c_str();
-            quote = 1;
+            if (al->hasLogMethod()) {
+                sb = al->getLogMethod();
+                out = sb.c_str();
+                quote = 1;
+            }
             break;
 
         case LFT_REQUEST_URI:
@@ -1254,10 +1296,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
                     for (const Security::CertErrors *sslError = srvBump->sslErrors(); sslError; sslError = sslError->next) {
                         if (!sb.isEmpty())
                             sb.append(separator);
-                        if (const char *errorName = Ssl::GetErrorName(sslError->element.code))
-                            sb.append(errorName);
-                        else
-                            sb.append(sslErrorName(sslError->element.code, tmp, sizeof(tmp)));
+                        sb.append(Ssl::GetErrorName(sslError->element.code, true));
                         if (sslError->element.depth >= 0)
                             sb.appendf("@depth=%d", sslError->element.depth);
                     }
@@ -1389,6 +1428,13 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             if (!al->lastAclData.isEmpty())
                 out = al->lastAclData.c_str();
             break;
+
+        case LFT_MASTER_XACTION:
+            if (al->request) {
+                doUint64 = true;
+                outUint64 = static_cast<uint64_t>(al->request->masterXaction->id.value);
+                break;
+            }
         }
 
         if (dooff) {
@@ -1398,6 +1444,9 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         } else if (doint) {
             sb.appendf("%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
             out = sb.c_str();
+        } else if (doUint64) {
+            sb.appendf("%0*" PRIu64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outUint64);
+            out = sb.c_str();
         } else if (doMsec) {
             if (fmt->widthMax < 0) {
                 sb.appendf("%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, tvToMsec(outtv));
@@ -1473,7 +1522,7 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
             }
 
             // enforce width limits if configured
-            const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !doMsec && !doSec;
+            const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !doMsec && !doSec && !doUint64;
             if (haveMaxWidth || fmt->widthMin) {
                 const int minWidth = fmt->widthMin >= 0 ?
                                      fmt->widthMin :0;