Back to index

lightning-sunbird  0.9+nobinonly
Classes | Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes
nsUnknownDecoder Class Reference

#include <nsUnknownDecoder.h>

Inheritance diagram for nsUnknownDecoder:
Inheritance graph
[legend]
Collaboration diagram for nsUnknownDecoder:
Collaboration graph
[legend]

List of all members.

Classes

struct  nsSnifferEntry
 An entry struct for our array of sniffers. More...

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMCONVERTER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSICONTENTSNIFFER_MOZILLA_1_8_BRANCH 
nsUnknownDecoder ()
nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType, in string aToType, in nsISupports aCtxt)
 SYNCRONOUS VERSION Converts a stream of one type, to a stream of another type.
void asyncConvertData (in string aFromType, in string aToType, in nsIStreamListener aListener, in nsISupports aCtxt)
 ASYNCRONOUS VERSION Converts data arriving via the converter's nsIStreamListener::OnDataAvailable() method from one type to another, pushing the converted data out to the caller via aListener::OnDataAvailable().
void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, in nsIInputStream aInputStream, in unsigned long aOffset, in unsigned long aCount)
 Called when the next chunk of data (corresponding to the request) may be read without blocking the calling thread.
void onStartRequest (in nsIRequest aRequest, in nsISupports aContext)
 Called to signify the beginning of an asynchronous request.
void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, in nsresult aStatusCode)
 Called to signify the end of an asynchronous request.
ACString getMIMETypeFromContent (in nsIRequest aRequest,[const, array, size_is(aLength)] in octet aData, in unsigned long aLength)
 Given a chunk of data, determines a MIME type.

Protected Member Functions

virtual ~nsUnknownDecoder ()
virtual void DetermineContentType (nsIRequest *aRequest)
nsresult FireListenerNotifications (nsIRequest *request, nsISupports *aCtxt)
PRBool AllowSniffing (nsIRequest *aRequest)
PRBool TryContentSniffers (nsIRequest *aRequest)
PRBool SniffForHTML (nsIRequest *aRequest)
PRBool SniffForXML (nsIRequest *aRequest)
PRBool SniffURI (nsIRequest *aRequest)
PRBool LastDitchSniff (nsIRequest *aRequest)

Protected Attributes

nsCOMPtr< nsIStreamListenermNextListener
char * mBuffer
PRUint32 mBufferLen
PRBool mRequireHTMLsuffix
nsCString mContentType

Static Protected Attributes

static nsSnifferEntry sSnifferEntries []
 This is the array of sniffer entries that depend on "magic numbers" in the file.
static PRUint32 sSnifferEntryNum

Detailed Description

Definition at line 57 of file nsUnknownDecoder.h.


Constructor & Destructor Documentation

Definition at line 70 of file nsUnknownDecoder.cpp.

  : mBuffer(nsnull)
  , mBufferLen(0)
  , mRequireHTMLsuffix(PR_FALSE)
{
  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
  if (prefs) {
    PRBool val;
    if (NS_SUCCEEDED(prefs->GetBoolPref("security.requireHTMLsuffix", &val)))
      mRequireHTMLsuffix = val;
  }
}

Here is the call graph for this function:

nsUnknownDecoder::~nsUnknownDecoder ( ) [protected, virtual]

Definition at line 83 of file nsUnknownDecoder.cpp.

{
  if (mBuffer) {
    delete [] mBuffer;
    mBuffer = nsnull;
  }
}

Member Function Documentation

PRBool nsUnknownDecoder::AllowSniffing ( nsIRequest aRequest) [protected]

Definition at line 288 of file nsUnknownDecoder.cpp.

{
  if (!mRequireHTMLsuffix) {
    return PR_TRUE;
  }
  
  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
  if (!channel) {
    NS_ERROR("QI failed");
    return PR_FALSE;
  }

  nsCOMPtr<nsIURI> uri;
  if (NS_FAILED(channel->GetURI(getter_AddRefs(uri))) || !uri) {
    return PR_FALSE;
  }
  
  PRBool isLocalFile = PR_FALSE;
  if (NS_FAILED(uri->SchemeIs("file", &isLocalFile)) || isLocalFile) {
    return PR_FALSE;
  }

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsIStreamConverter::asyncConvertData ( in string  aFromType,
in string  aToType,
in nsIStreamListener  aListener,
in nsISupports  aCtxt 
) [inherited]

ASYNCRONOUS VERSION Converts data arriving via the converter's nsIStreamListener::OnDataAvailable() method from one type to another, pushing the converted data out to the caller via aListener::OnDataAvailable().

Use this method when you want to proxy (and convert) nsIStreamListener callbacks asynchronously.

Parameters:
aFromTypeThe MIME type of the original/raw data.
aToTypeThe MIME type of the converted data.
aListenerThe listener who receives the converted data.
aCtxtEither an opaque context, or a converter specific context (implementation specific).
nsIInputStream nsIStreamConverter::convert ( in nsIInputStream  aFromStream,
in string  aFromType,
in string  aToType,
in nsISupports  aCtxt 
) [inherited]

SYNCRONOUS VERSION Converts a stream of one type, to a stream of another type.

Use this method when you have a stream you want to convert.

Parameters:
aFromStreamThe stream representing the original/raw data.
aFromTypeThe MIME type of aFromStream.
aToTypeThe MIME type of the returned stream.
aCtxtEither an opaque context, or a converter specific context (implementation specific).
Returns:
The converted stream. NOTE: The returned stream may not already be converted. An efficient stream converter implementation will converter data on demand rather than buffering the converted data until it is used.
void nsUnknownDecoder::DetermineContentType ( nsIRequest aRequest) [protected, virtual]

Reimplemented in nsBinaryDetector.

Definition at line 347 of file nsUnknownDecoder.cpp.

{
  NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known.");
  if (!mContentType.IsEmpty()) return;

  // First, run through all the types we can detect reliably based on
  // magic numbers
  PRUint32 i;
  for (i = 0; i < sSnifferEntryNum; ++i) {
    if (mBufferLen >= sSnifferEntries[i].mByteLen &&  // enough data
        memcmp(mBuffer, sSnifferEntries[i].mBytes, sSnifferEntries[i].mByteLen) == 0) {  // and type matches
      NS_ASSERTION(sSnifferEntries[i].mMimeType ||
                   sSnifferEntries[i].mContentTypeSniffer,
                   "Must have either a type string or a function to set the type");
      NS_ASSERTION(sSnifferEntries[i].mMimeType == nsnull ||
                   sSnifferEntries[i].mContentTypeSniffer == nsnull,
                   "Both at type string and a type sniffing function set;"
                   " using type string");
      if (sSnifferEntries[i].mMimeType) {
        mContentType = sSnifferEntries[i].mMimeType;
        return;
      }
      else if ((this->*(sSnifferEntries[i].mContentTypeSniffer))(aRequest)) {
        return;
      }        
    }
  }

  if (TryContentSniffers(aRequest)) {
    return;
  }

  if (SniffForHTML(aRequest)) {
    return;
  }
  
  // We don't know what this is yet.  Before we just give up, try
  // the URI from the request.
  if (SniffURI(aRequest)) {
    return;
  }
  
  LastDitchSniff(aRequest);
}

Here is the call graph for this function:

nsresult nsUnknownDecoder::FireListenerNotifications ( nsIRequest request,
nsISupports *  aCtxt 
) [protected]

Definition at line 607 of file nsUnknownDecoder.cpp.

{
  nsresult rv = NS_OK;

  if (!mNextListener) return NS_ERROR_FAILURE;

  nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = do_QueryInterface(request);
  if (viewSourceChannel) {
    rv = viewSourceChannel->SetOriginalContentType(mContentType);
  } else {
    nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
    if (NS_SUCCEEDED(rv)) {
      // Set the new content type on the channel...
      rv = channel->SetContentType(mContentType);
    }
  }

  NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to set content type on channel!");
  if (NS_FAILED(rv)) {
    // Cancel the request to make sure it has the correct status if
    // mNextListener looks at it.
    request->Cancel(rv);
    mNextListener->OnStartRequest(request, aCtxt);
    return rv;
  }

  // Fire the OnStartRequest(...)
  rv = mNextListener->OnStartRequest(request, aCtxt);

  if (!mBuffer) return NS_ERROR_OUT_OF_MEMORY;

  // If the request was canceled, then we need to treat that equivalently
  // to an error returned by OnStartRequest.
  if (NS_SUCCEEDED(rv))
    request->GetStatus(&rv);

  // Fire the first OnDataAvailable for the data that was read from the
  // stream into the sniffer buffer...
  if (NS_SUCCEEDED(rv) && (mBufferLen > 0)) {
    PRUint32 len = 0;
    nsCOMPtr<nsIInputStream> in;
    nsCOMPtr<nsIOutputStream> out;

    // Create a pipe and fill it with the data from the sniffer buffer.
    rv = NS_NewPipe(getter_AddRefs(in), getter_AddRefs(out),
                    MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);

    if (NS_SUCCEEDED(rv)) {
      rv = out->Write(mBuffer, mBufferLen, &len);
      if (NS_SUCCEEDED(rv)) {
        if (len == mBufferLen) {
          rv = mNextListener->OnDataAvailable(request, aCtxt, in, 0, len);
        } else {
          NS_ERROR("Unable to write all the data into the pipe.");
          rv = NS_ERROR_FAILURE;
        }
      }
    }
  }

  delete [] mBuffer;
  mBuffer = nsnull;
  mBufferLen = 0;

  return rv;
}

Here is the call graph for this function:

ACString nsIContentSniffer_MOZILLA_1_8_BRANCH::getMIMETypeFromContent ( in nsIRequest  aRequest,
[const, array, size_is(aLength)] in octet  aData,
in unsigned long  aLength 
) [inherited]

Given a chunk of data, determines a MIME type.

Information from the given request may be used in order to make a better decision.

Parameters:
aRequestThe request where this data came from. May be null.
aDataData to check
aLengthLength of the data
Returns:
The content type
Exceptions:
NS_ERROR_NOT_AVAILABLEif no MIME type could be determined.
Note:
Implementations should consider the request read-only. Especially, they should not attempt to set the content type property that subclasses of nsIRequest might offer.
PRBool nsUnknownDecoder::LastDitchSniff ( nsIRequest aRequest) [protected]

Definition at line 568 of file nsUnknownDecoder.cpp.

{
  // All we can do now is try to guess whether this is text/plain or
  // application/octet-stream

  // First, check for a BOM.  If we see one, assume this is text/plain
  // in whatever encoding.  If there is a BOM _and_ text we will
  // always have at least 4 bytes in the buffer (since the 2-byte BOMs
  // are for 2-byte encodings and the UTF-8 BOM is 3 bytes).
  if (mBufferLen >= 4) {
    const unsigned char* buf = (const unsigned char*)mBuffer;
    if ((buf[0] == 0xFE && buf[1] == 0xFF) || // UTF-16BE
        (buf[0] == 0xFF && buf[1] == 0xFE) || // UTF-16LE
        (buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) || // UTF-8
        (buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) || // UCS-4BE
        (buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFF && buf[3] == 0xFE)) { // UCS-4
        
      mContentType = TEXT_PLAIN;
      return PR_TRUE;
    }
  }
  
  // Now see whether the buffer has any non-text chars.  If not, then let's
  // just call it text/plain...
  //
  PRUint32 i;
  for (i=0; i<mBufferLen && IS_TEXT_CHAR(mBuffer[i]); i++);

  if (i == mBufferLen) {
    mContentType = TEXT_PLAIN;
  }
  else {
    mContentType = APPLICATION_OCTET_STREAM;
  }

  return PR_TRUE;    
}

Here is the caller graph for this function:

void nsIStreamListener::onDataAvailable ( in nsIRequest  aRequest,
in nsISupports  aContext,
in nsIInputStream  aInputStream,
in unsigned long  aOffset,
in unsigned long  aCount 
) [inherited]

Called when the next chunk of data (corresponding to the request) may be read without blocking the calling thread.

The onDataAvailable impl must read exactly |aCount| bytes of data before returning.

Parameters:
aRequestrequest corresponding to the source of the data
aContextuser defined context
aInputStreaminput stream containing the data chunk
aOffsetNumber of bytes that were sent in previous onDataAvailable calls for this request. In other words, the sum of all previous count parameters. If that number is greater than or equal to 2^32, this parameter will be PR_UINT32_MAX (2^32 - 1).
aCountnumber of bytes available in the stream

NOTE: The aInputStream parameter must implement readSegments.

An exception thrown from onDataAvailable has the side-effect of causing the request to be canceled.

void nsIRequestObserver::onStartRequest ( in nsIRequest  aRequest,
in nsISupports  aContext 
) [inherited]

Called to signify the beginning of an asynchronous request.

Parameters:
aRequestrequest being observed
aContextuser defined context

An exception thrown from onStartRequest has the side-effect of causing the request to be canceled.

Here is the caller graph for this function:

void nsIRequestObserver::onStopRequest ( in nsIRequest  aRequest,
in nsISupports  aContext,
in nsresult  aStatusCode 
) [inherited]

Called to signify the end of an asynchronous request.

This call is always preceded by a call to onStartRequest.

Parameters:
aRequestrequest being observed
aContextuser defined context
aStatusCodereason for stopping (NS_OK if completed successfully)

An exception thrown from onStopRequest is generally ignored.

Here is the caller graph for this function:

PRBool nsUnknownDecoder::SniffForHTML ( nsIRequest aRequest) [protected]

Definition at line 446 of file nsUnknownDecoder.cpp.

{
  /*
   * To prevent a possible attack, we will not consider this to be
   * html content if it comes from the local file system and our prefs
   * are set right
   */
  if (!AllowSniffing(aRequest)) {
    return PR_FALSE;
  }
  
  // Now look for HTML.
  const char* str = mBuffer;
  const char* end = mBuffer + mBufferLen;

  // skip leading whitespace
  while (str != end && nsCRT::IsAsciiSpace(*str)) {
    ++str;
  }

  // did we find something like a start tag?
  if (str == end || *str != '<' || ++str == end) {
    return PR_FALSE;
  }

  // If we seem to be SGML or XML and we got down here, just pretend we're HTML
  if (*str == '!' || *str == '?') {
    mContentType = TEXT_HTML;
    return PR_TRUE;
  }
  
  PRUint32 bufSize = end - str;
  // We use sizeof(_tagstr) below because that's the length of _tagstr
  // with the one char " " or ">" appended.
#define MATCHES_TAG(_tagstr)                                              \
  (bufSize >= sizeof(_tagstr) &&                                          \
   (PL_strncasecmp(str, _tagstr " ", sizeof(_tagstr)) == 0 ||             \
    PL_strncasecmp(str, _tagstr ">", sizeof(_tagstr)) == 0))
    
  if (MATCHES_TAG("html")     ||
      MATCHES_TAG("frameset") ||
      MATCHES_TAG("body")     ||
      MATCHES_TAG("head")     ||
      MATCHES_TAG("script")   ||
      MATCHES_TAG("iframe")   ||
      MATCHES_TAG("a")        ||
      MATCHES_TAG("img")      ||
      MATCHES_TAG("table")    ||
      MATCHES_TAG("title")    ||
      MATCHES_TAG("link")     ||
      MATCHES_TAG("base")     ||
      MATCHES_TAG("style")    ||
      MATCHES_TAG("div")      ||
      MATCHES_TAG("p")        ||
      MATCHES_TAG("font")     ||
      MATCHES_TAG("applet")   ||
      MATCHES_TAG("meta")     ||
      MATCHES_TAG("center")   ||
      MATCHES_TAG("form")     ||
      MATCHES_TAG("isindex")  ||
      MATCHES_TAG("h1")       ||
      MATCHES_TAG("h2")       ||
      MATCHES_TAG("h3")       ||
      MATCHES_TAG("h4")       ||
      MATCHES_TAG("h5")       ||
      MATCHES_TAG("h6")       ||
      MATCHES_TAG("b")        ||
      MATCHES_TAG("pre")) {
  
    mContentType = TEXT_HTML;
    return PR_TRUE;
  }

#undef MATCHES_TAG
  
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsUnknownDecoder::SniffForXML ( nsIRequest aRequest) [protected]

Definition at line 524 of file nsUnknownDecoder.cpp.

{
  // Just like HTML, this should be able to be shut off.
  if (!AllowSniffing(aRequest)) {
    return PR_FALSE;
  }

  // First see whether we can glean anything from the uri...
  if (!SniffURI(aRequest)) {
    // Oh well; just generic XML will have to do
    mContentType = TEXT_XML;
  }
  
  return PR_TRUE;
}

Here is the call graph for this function:

PRBool nsUnknownDecoder::SniffURI ( nsIRequest aRequest) [protected]

Definition at line 540 of file nsUnknownDecoder.cpp.

{
  nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
  if (mimeService) {
    nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
    if (channel) {
      nsCOMPtr<nsIURI> uri;
      nsresult result = channel->GetURI(getter_AddRefs(uri));
      if (NS_SUCCEEDED(result) && uri) {
        nsCAutoString type;
        result = mimeService->GetTypeFromURI(uri, type);
        if (NS_SUCCEEDED(result)) {
          mContentType = type;
          return PR_TRUE;
        }
      }
    }
  }

  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 392 of file nsUnknownDecoder.cpp.

{
  // Enumerate content sniffers
  nsCOMPtr<nsICategoryManager> catMan(do_GetService("@mozilla.org/categorymanager;1"));
  if (!catMan) {
    return PR_FALSE;
  }

  nsCOMPtr<nsISimpleEnumerator> sniffers;
  catMan->EnumerateCategory("content-sniffing-services", getter_AddRefs(sniffers));
  if (!sniffers) {
    return PR_FALSE;
  }

  PRBool hasMore;
  while (NS_SUCCEEDED(sniffers->HasMoreElements(&hasMore)) && hasMore) {
    nsCOMPtr<nsISupports> elem;
    sniffers->GetNext(getter_AddRefs(elem));
    NS_ASSERTION(elem, "No element even though hasMore returned true!?");

    nsCOMPtr<nsISupportsCString> sniffer_id(do_QueryInterface(elem));
    NS_ASSERTION(sniffer_id, "element is no nsISupportsCString!?");
    nsCAutoString contractid;
    nsresult rv = sniffer_id->GetData(contractid);
    if (NS_FAILED(rv)) {
      continue;
    }

    nsCOMPtr<nsISupports> sniffer(do_GetService(contractid.get()));
    if (!sniffer) {
      continue;
    }

    nsCOMPtr<nsIContentSniffer> sniffer1(do_QueryInterface(sniffer));
    nsCOMPtr<nsIContentSniffer_MOZILLA_1_8_BRANCH> sniffer2 =
      do_QueryInterface(sniffer);
    if (sniffer2) {
      rv = sniffer2->GetMIMETypeFromContent(aRequest, (const PRUint8*)mBuffer,
                                            mBufferLen, mContentType);
    } else if (sniffer1) {
      rv = sniffer1->GetMIMETypeFromContent((const PRUint8*)mBuffer,
                                            mBufferLen, mContentType);
    } else {
      continue;
    }

    if (NS_SUCCEEDED(rv)) {
      return PR_TRUE;
    }
  }

  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

char* nsUnknownDecoder::mBuffer [protected]

Definition at line 138 of file nsUnknownDecoder.h.

Definition at line 139 of file nsUnknownDecoder.h.

Definition at line 142 of file nsUnknownDecoder.h.

Definition at line 85 of file nsUnknownDecoder.h.

Definition at line 140 of file nsUnknownDecoder.h.

Initial value:

This is the array of sniffer entries that depend on "magic numbers" in the file.

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 PRBool -- PR_TRUE if it sets mContentType, PR_FALSE otherwise

Definition at line 135 of file nsUnknownDecoder.h.

Initial value:

Definition at line 136 of file nsUnknownDecoder.h.


The documentation for this class was generated from the following files: