]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/mime.cc
transaction_initiator ACL for detecting various unusual transactions
[thirdparty/squid.git] / src / mime.cc
index 4cee8c006cc21a9a319043266d97fcd9318d5c5e..063513dcbae89af4cf5be5b66ba74a3c667567dc 100644 (file)
@@ -1,44 +1,21 @@
 /*
- * DEBUG: section 25    MIME Parsing and Internal Icons
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 25    MIME Parsing and Internal Icons */
+
 #include "squid.h"
-#include "disk.h"
 #include "fde.h"
+#include "fs_io.h"
 #include "globals.h"
 #include "HttpHdrCc.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "internal.h"
-#include "Mem.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "mime.h"
 #include "Store.h"
 #include "StoreClient.h"
 
+#include <array>
+
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 
-#define GET_HDR_SZ 1024
-
 /* forward declarations */
 static void mimeFreeMemory(void);
-static char const *mimeGetIcon(const char *fn);
+static const SBuf mimeGetIcon(const char *fn);
 
 class MimeIcon : public StoreClient
 {
+    MEMPROXY_CLASS(MimeIcon);
+
 public:
-    MimeIcon(const char *aName);
+    explicit MimeIcon(const char *aName);
     ~MimeIcon();
     void setName(char const *);
-    char const * getName() const;
+    SBuf getName() const;
     void load();
-    void created(StoreEntry *newEntry);
-    MEMPROXY_CLASS(MimeIcon);
+
+    /* StoreClient API */
+    virtual void created(StoreEntry *);
 
 private:
-    MimeIcon();
-    const char *icon_;
+    SBuf icon_;
     char *url_;
 };
-MEMPROXY_CLASS_INLINE(MimeIcon);
 
 class MimeEntry
 {
+    MEMPROXY_CLASS(MimeEntry);
+
 public:
-    MimeEntry(const char *aPattern, const regex_t &compiledPattern,
-              const char *aContentType,
-              const char *aContentEncoding, const char *aTransferMode,
-              bool optionViewEnable, bool optionDownloadEnable,
-              const char *anIconName);
+    explicit MimeEntry(const char *aPattern, const regex_t &compiledPattern,
+                       const char *aContentType,
+                       const char *aContentEncoding, const char *aTransferMode,
+                       bool optionViewEnable, bool optionDownloadEnable,
+                       const char *anIconName);
     ~MimeEntry();
-    MEMPROXY_CLASS(MimeEntry);
 
     const char *pattern;
     regex_t compiled_pattern;
@@ -95,10 +74,7 @@ public:
     bool download_option;
     MimeIcon theIcon;
     MimeEntry *next;
-private:
-    MimeEntry();
 };
-MEMPROXY_CLASS_INLINE(MimeEntry);
 
 static MimeEntry *MimeTable = NULL;
 static MimeEntry **MimeTableTail = &MimeTable;
@@ -142,42 +118,37 @@ mimeGetEntry(const char *fn, int skip_encodings)
 }
 
 MimeIcon::MimeIcon(const char *aName) :
-                icon_(xstrdup(aName))
+    url_(nullptr)
 {
-    url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
+    setName(aName);
 }
 
 MimeIcon::~MimeIcon()
 {
-    safe_free (icon_);
-    safe_free (url_);
+    xfree(url_);
 }
 
 void
 MimeIcon::setName(char const *aString)
 {
-    safe_free (icon_);
-    safe_free (url_);
-    icon_ = xstrdup (aString);
-    url_ = xstrdup (internalLocalUri("/squid-internal-static/icons/", icon_));
+    xfree(url_);
+    icon_ = aString;
+    url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
 }
 
-char const *
+SBuf
 MimeIcon::getName() const
 {
     return icon_;
 }
 
-char const *
+const SBuf
 mimeGetIcon(const char *fn)
 {
     MimeEntry *m = mimeGetEntry(fn, 1);
 
-    if (m == NULL)
-        return NULL;
-
-    if (!strcmp(m->theIcon.getName(), dash_str))
-        return NULL;
+    if (!m || !m->theIcon.getName().cmp(dash_str))
+        return SBuf();
 
     return m->theIcon.getName();
 }
@@ -185,16 +156,17 @@ mimeGetIcon(const char *fn)
 const char *
 mimeGetIconURL(const char *fn)
 {
-    char const *icon = mimeGetIcon(fn);
+    SBuf icon(mimeGetIcon(fn));
 
-    if (icon == NULL)
+    if (icon.isEmpty())
         return null_string;
 
     if (Config.icons.use_short_names) {
-        static MemBuf mb;
-        mb.reset();
-        mb.Printf("/squid-internal-static/icons/%s", icon);
-        return mb.content();
+        static SBuf mb;
+        mb.clear();
+        mb.append("/squid-internal-static/icons/");
+        mb.append(icon);
+        return mb.c_str();
     } else {
         return internalLocalUri("/squid-internal-static/icons/", icon);
     }
@@ -277,7 +249,8 @@ mimeInit(char *filename)
         return;
 
     if ((fp = fopen(filename, "r")) == NULL) {
-        debugs(25, DBG_IMPORTANT, "mimeInit: " << filename << ": " << xstrerror());
+        int xerrno = errno;
+        debugs(25, DBG_IMPORTANT, "mimeInit: " << filename << ": " << xstrerr(xerrno));
         return;
     }
 
@@ -345,7 +318,7 @@ mimeInit(char *filename)
         }
 
         m = new MimeEntry(pattern,re,type,encoding,mode,view_option,
-            download_option,icon);
+                          download_option,icon);
 
         *MimeTableTail = m;
 
@@ -377,7 +350,7 @@ mimeFreeMemory(void)
 void
 MimeIcon::load()
 {
-    const char *type = mimeGetContentType(icon_);
+    const char *type = mimeGetContentType(icon_.c_str());
 
     if (type == NULL)
         fatal("Unknown icon format while reading mime.conf\n");
@@ -386,87 +359,104 @@ MimeIcon::load()
 }
 
 void
-MimeIcon::created (StoreEntry *newEntry)
+MimeIcon::created(StoreEntry *newEntry)
 {
     /* if the icon is already in the store, do nothing */
     if (!newEntry->isNull())
         return;
+    // XXX: if a 204 is cached due to earlier load 'failure' we should try to reload.
 
-    int fd;
-    int n;
-    RequestFlags flags;
-    struct stat sb;
-    LOCAL_ARRAY(char, path, MAXPATHLEN);
-    char *buf;
+    // default is a 200 object with image data.
+    // set to the backup value of 204 on image loading errors
+    Http::StatusCode status = Http::scOkay;
 
-    snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon_);
+    static char path[MAXPATHLEN];
+    *path = 0;
+    if (snprintf(path, sizeof(path)-1, "%s/" SQUIDSBUFPH, Config.icons.directory, SQUIDSBUFPRINT(icon_)) < 0) {
+        debugs(25, DBG_CRITICAL, "ERROR: icon file '" << Config.icons.directory << "/" << icon_ << "' path is longer than " << MAXPATHLEN << " bytes");
+        status = Http::scNoContent;
+    }
 
-    fd = file_open(path, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        debugs(25, DBG_CRITICAL, "Problem opening icon file " << path << ": " << xstrerror());
-        return;
+    int fd = -1;
+    errno = 0;
+    if (status == Http::scOkay && (fd = file_open(path, O_RDONLY | O_BINARY)) < 0) {
+        int xerrno = errno;
+        debugs(25, DBG_CRITICAL, "ERROR: opening icon file " << path << ": " << xstrerr(xerrno));
+        status = Http::scNoContent;
     }
-    if (fstat(fd, &sb) < 0) {
-        debugs(25, DBG_CRITICAL, "Problem opening icon file. Fd: " << fd << ", fstat error " << xstrerror());
+
+    struct stat sb;
+    errno = 0;
+    if (status == Http::scOkay && fstat(fd, &sb) < 0) {
+        int xerrno = errno;
+        debugs(25, DBG_CRITICAL, "ERROR: opening icon file " << path << " FD " << fd << ", fstat error " << xstrerr(xerrno));
         file_close(fd);
-        return;
+        status = Http::scNoContent;
     }
 
+    // fill newEntry with a canned 2xx response object
+    RequestFlags flags;
     flags.cachable = true;
     StoreEntry *e = storeCreateEntry(url_,url_,flags,Http::METHOD_GET);
     assert(e != NULL);
     EBIT_SET(e->flags, ENTRY_SPECIAL);
     e->setPublicKey();
     e->buffer();
-    HttpRequest *r = HttpRequest::CreateFromUrl(url_);
 
-    if (NULL == r)
-        fatal("mimeLoadIcon: cannot parse internal URL");
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIcon);
+    HttpRequestPointer r(HttpRequest::FromUrl(url_, mx));
+    if (!r)
+        fatalf("mimeLoadIcon: cannot parse internal URL: %s", url_);
 
     e->mem_obj->request = r;
-    HTTPMSGLOCK(e->mem_obj->request);
 
-    HttpReply *reply = new HttpReply;
+    HttpReplyPointer reply(new HttpReply);
 
-    reply->setHeaders(HTTP_OK, NULL, mimeGetContentType(icon_), sb.st_size, sb.st_mtime, -1);
+    if (status == Http::scNoContent)
+        reply->setHeaders(status, NULL, NULL, 0, -1, -1);
+    else
+        reply->setHeaders(status, NULL, mimeGetContentType(icon_.c_str()), sb.st_size, sb.st_mtime, -1);
     reply->cache_control = new HttpHdrCc();
     reply->cache_control->maxAge(86400);
     reply->header.putCc(reply->cache_control);
-    e->replaceHttpReply(reply);
+    e->replaceHttpReply(reply.getRaw());
 
-    /* read the file into the buffer and append it to store */
-    buf = (char *)memAllocate(MEM_4K_BUF);
-    while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
-        e->append(buf, n);
+    if (status == Http::scOkay) {
+        /* read the file into the buffer and append it to store */
+        int n;
+        std::array<char, 4096> buf;
+        while ((n = FD_READ_METHOD(fd, buf.data(), buf.size())) > 0)
+            e->append(buf.data(), n);
+
+        file_close(fd);
+    }
 
-    file_close(fd);
     e->flush();
     e->complete();
     e->timestampsSet();
-    e->unlock();
-    memFree(buf, MEM_4K_BUF);
+    e->unlock("MimeIcon::created");
     debugs(25, 3, "Loaded icon " << url_);
 }
 
 MimeEntry::~MimeEntry()
 {
-    safe_free(pattern);
-    safe_free(content_type);
-    safe_free(content_encoding);
+    xfree(pattern);
+    xfree(content_type);
+    xfree(content_encoding);
     regfree(&compiled_pattern);
 }
 
 MimeEntry::MimeEntry(const char *aPattern, const regex_t &compiledPattern,
-                const char *aContentType, const char *aContentEncoding,
-                const char *aTransferMode, bool optionViewEnable,
-                bool optionDownloadEnable, const char *anIconName) :
-                                    pattern(xstrdup(aPattern)),
-                                    compiled_pattern(compiledPattern),
-                                    content_type(xstrdup(aContentType)),
-                                    content_encoding(xstrdup(aContentEncoding)),
-                                    view_option(optionViewEnable),
-                                    download_option(optionViewEnable),
-                                    theIcon(anIconName), next(NULL)
+                     const char *aContentType, const char *aContentEncoding,
+                     const char *aTransferMode, bool optionViewEnable,
+                     bool optionDownloadEnable, const char *anIconName) :
+    pattern(xstrdup(aPattern)),
+    compiled_pattern(compiledPattern),
+    content_type(xstrdup(aContentType)),
+    content_encoding(xstrdup(aContentEncoding)),
+    view_option(optionViewEnable),
+    download_option(optionDownloadEnable),
+    theIcon(anIconName), next(NULL)
 {
     if (!strcasecmp(aTransferMode, "ascii"))
         transfer_mode = 'A';
@@ -475,3 +465,4 @@ MimeEntry::MimeEntry(const char *aPattern, const regex_t &compiledPattern,
     else
         transfer_mode = 'I';
 }
+