DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (2ccc66480643)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsUnknownDecoder_h__
#define nsUnknownDecoder_h__

#include "nsIStreamConverter.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsIContentSniffer.h"
#include "mozilla/Mutex.h"
#include "mozilla/Atomics.h"

#include "nsCOMPtr.h"
#include "nsString.h"

#define NS_UNKNOWNDECODER_CID                        \
  { /* 7d7008a0-c49a-11d3-9b22-0080c7cb1080 */       \
    0x7d7008a0, 0xc49a, 0x11d3, {                    \
      0x9b, 0x22, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x80 \
    }                                                \
  }

class nsUnknownDecoder : public nsIStreamConverter,
                         public nsIContentSniffer,
                         public nsIThreadRetargetableStreamListener {
 public:
  // nsISupports methods
  NS_DECL_ISUPPORTS

  // nsIStreamConverter methods
  NS_DECL_NSISTREAMCONVERTER

  // nsIStreamListener methods
  NS_DECL_NSISTREAMLISTENER

  // nsIRequestObserver methods
  NS_DECL_NSIREQUESTOBSERVER

  // nsIContentSniffer methods
  NS_DECL_NSICONTENTSNIFFER

  // nsIThreadRetargetableStreamListener methods
  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER

  nsUnknownDecoder();

 protected:
  virtual ~nsUnknownDecoder();

  virtual void DetermineContentType(nsIRequest* aRequest);
  nsresult FireListenerNotifications(nsIRequest* request, nsISupports* aCtxt);

  class ConvertedStreamListener : public nsIStreamListener {
   public:
    explicit ConvertedStreamListener(nsUnknownDecoder* aDecoder);

    NS_DECL_ISUPPORTS
    NS_DECL_NSIREQUESTOBSERVER
    NS_DECL_NSISTREAMLISTENER

   private:
    virtual ~ConvertedStreamListener() = default;
    static nsresult AppendDataToString(nsIInputStream* inputStream,
                                       void* closure, const char* rawSegment,
                                       uint32_t toOffset, uint32_t count,
                                       uint32_t* writeCount);
    nsUnknownDecoder* mDecoder;
  };

 protected:
  nsCOMPtr<nsIStreamListener> mNextListener;

  // Function to use to check whether sniffing some potentially
  // dangerous types (eg HTML) is ok for this request.  We can disable
  // sniffing for local files if needed using this.  Just a security
  // precation thingy... who knows when we suddenly need to flip this
  // pref?
  bool AllowSniffing(nsIRequest* aRequest);

  // Various sniffer functions.  Returning true means that a type
  // was determined; false means no luck.
  bool SniffForHTML(nsIRequest* aRequest);
  bool SniffForXML(nsIRequest* aRequest);

  // SniffURI guesses at the content type based on the URI (typically
  // using the extentsion)
  bool SniffURI(nsIRequest* aRequest);

  // LastDitchSniff guesses at text/plain vs. application/octet-stream
  // by just looking at whether the data contains null bytes, and
  // maybe at the fraction of chars with high bit set.  Use this only
  // as a last-ditch attempt to decide a content type!
  bool LastDitchSniff(nsIRequest* aRequest);

  /**
   * An entry struct for our array of sniffers.  Each entry has either
   * a type associated with it (set these with the SNIFFER_ENTRY macro)
   * or a function to be executed (set these with the
   * SNIFFER_ENTRY_WITH_FUNC macro).  The function should take a single
   * nsIRequest* and returns bool -- true if it sets mContentType,
   * false otherwise
   */
  struct nsSnifferEntry {
    typedef bool (nsUnknownDecoder::*TypeSniffFunc)(nsIRequest* aRequest);

    const char* mBytes;
    uint32_t mByteLen;

    // Exactly one of mMimeType and mContentTypeSniffer should be set non-null
    const char* mMimeType;
    TypeSniffFunc mContentTypeSniffer;
  };

#define SNIFFER_ENTRY(_bytes, _type) \
  { _bytes, sizeof(_bytes) - 1, _type, nullptr }

#define SNIFFER_ENTRY_WITH_FUNC(_bytes, _func) \
  { _bytes, sizeof(_bytes) - 1, nullptr, _func }

  static nsSnifferEntry sSnifferEntries[];
  static uint32_t sSnifferEntryNum;

  // We guarantee in order delivery of OnStart, OnStop and OnData, therefore
  // we do not need proper locking for mBuffer.
  mozilla::Atomic<char*> mBuffer;
  mozilla::Atomic<uint32_t> mBufferLen;
  mozilla::Atomic<bool> mRequireHTMLsuffix;

  nsCString mContentType;

  // This mutex syncs: mContentType, mDecodedData and mNextListener.
  mutable mozilla::Mutex mMutex;

 protected:
  nsresult ConvertEncodedData(nsIRequest* request, const char* data,
                              uint32_t length);
  nsCString mDecodedData;  // If data are encoded this will be uncompress data.
};

#define NS_BINARYDETECTOR_CID                        \
  { /* a2027ec6-ba0d-4c72-805d-148233f5f33c */       \
    0xa2027ec6, 0xba0d, 0x4c72, {                    \
      0x80, 0x5d, 0x14, 0x82, 0x33, 0xf5, 0xf3, 0x3c \
    }                                                \
  }

/**
 * Class that detects whether a data stream is text or binary.  This reuses
 * most of nsUnknownDecoder except the actual content-type determination logic
 * -- our overridden DetermineContentType simply calls LastDitchSniff and sets
 * the type to APPLICATION_GUESS_FROM_EXT if the data is detected as binary.
 */
class nsBinaryDetector : public nsUnknownDecoder {
 protected:
  virtual void DetermineContentType(nsIRequest* aRequest) override;
};

#define NS_BINARYDETECTOR_CATEGORYENTRY             \
  {                                                 \
    NS_CONTENT_SNIFFER_CATEGORY, "Binary Detector", \
        NS_BINARYDETECTOR_CONTRACTID                \
  }

#endif /* nsUnknownDecoder_h__ */