netwerk/protocol/data/nsDataHandler.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsDataChannel.h"
     7 #include "nsDataHandler.h"
     8 #include "nsNetCID.h"
     9 #include "nsError.h"
    11 static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
    13 ////////////////////////////////////////////////////////////////////////////////
    15 nsDataHandler::nsDataHandler() {
    16 }
    18 nsDataHandler::~nsDataHandler() {
    19 }
    21 NS_IMPL_ISUPPORTS(nsDataHandler, nsIProtocolHandler)
    23 nsresult
    24 nsDataHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) {
    26     nsDataHandler* ph = new nsDataHandler();
    27     if (ph == nullptr)
    28         return NS_ERROR_OUT_OF_MEMORY;
    29     NS_ADDREF(ph);
    30     nsresult rv = ph->QueryInterface(aIID, aResult);
    31     NS_RELEASE(ph);
    32     return rv;
    33 }
    35 ////////////////////////////////////////////////////////////////////////////////
    36 // nsIProtocolHandler methods:
    38 NS_IMETHODIMP
    39 nsDataHandler::GetScheme(nsACString &result) {
    40     result.AssignLiteral("data");
    41     return NS_OK;
    42 }
    44 NS_IMETHODIMP
    45 nsDataHandler::GetDefaultPort(int32_t *result) {
    46     // no ports for data protocol
    47     *result = -1;
    48     return NS_OK;
    49 }
    51 NS_IMETHODIMP
    52 nsDataHandler::GetProtocolFlags(uint32_t *result) {
    53     *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
    54         URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE |
    55         URI_SYNC_LOAD_IS_OK;
    56     return NS_OK;
    57 }
    59 NS_IMETHODIMP
    60 nsDataHandler::NewURI(const nsACString &aSpec,
    61                       const char *aCharset, // ignore charset info
    62                       nsIURI *aBaseURI,
    63                       nsIURI **result) {
    64     nsresult rv;
    65     nsRefPtr<nsIURI> uri;
    67     nsCString spec(aSpec);
    69     if (aBaseURI && !spec.IsEmpty() && spec[0] == '#') {
    70         // Looks like a reference instead of a fully-specified URI.
    71         // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
    72         rv = aBaseURI->Clone(getter_AddRefs(uri));
    73         if (NS_FAILED(rv))
    74             return rv;
    75         rv = uri->SetRef(spec);
    76     } else {
    77         // Otherwise, we'll assume |spec| is a fully-specified data URI
    78         nsAutoCString contentType, contentCharset, dataBuffer, hashRef;
    79         bool base64;
    80         rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer, hashRef);
    81         if (NS_FAILED(rv))
    82             return rv;
    84         // Strip whitespace unless this is text, where whitespace is important
    85         // Don't strip escaped whitespace though (bug 391951)
    86         if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
    87                        contentType.Find("xml") == kNotFound)) {
    88             // it's ascii encoded binary, don't let any spaces in
    89             spec.StripWhitespace();
    90         }
    92         uri = do_CreateInstance(kSimpleURICID, &rv);
    93         if (NS_FAILED(rv))
    94             return rv;
    95         rv = uri->SetSpec(spec);
    96     }
    98     if (NS_FAILED(rv))
    99         return rv;
   101     uri.forget(result);
   102     return rv;
   103 }
   105 NS_IMETHODIMP
   106 nsDataHandler::NewChannel(nsIURI* uri, nsIChannel* *result) {
   107     NS_ENSURE_ARG_POINTER(uri);
   108     nsDataChannel* channel = new nsDataChannel(uri);
   109     if (!channel)
   110         return NS_ERROR_OUT_OF_MEMORY;
   111     NS_ADDREF(channel);
   113     nsresult rv = channel->Init();
   114     if (NS_FAILED(rv)) {
   115         NS_RELEASE(channel);
   116         return rv;
   117     }
   119     *result = channel;
   120     return NS_OK;
   121 }
   123 NS_IMETHODIMP 
   124 nsDataHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) {
   125     // don't override anything.  
   126     *_retval = false;
   127     return NS_OK;
   128 }
   130 #define BASE64_EXTENSION ";base64"
   132 nsresult
   133 nsDataHandler::ParseURI(nsCString& spec,
   134                         nsCString& contentType,
   135                         nsCString& contentCharset,
   136                         bool&    isBase64,
   137                         nsCString& dataBuffer,
   138                         nsCString& hashRef) {
   139     isBase64 = false;
   141     // move past "data:"
   142     char *buffer = (char *) PL_strcasestr(spec.BeginWriting(), "data:");
   143     if (!buffer) {
   144         // malformed uri
   145         return NS_ERROR_MALFORMED_URI;
   146     }
   147     buffer += 5;
   149     // First, find the start of the data
   150     char *comma = strchr(buffer, ',');
   151     if (!comma)
   152         return NS_ERROR_MALFORMED_URI;
   154     *comma = '\0';
   156     // determine if the data is base64 encoded.
   157     char *base64 = PL_strcasestr(buffer, BASE64_EXTENSION);
   158     if (base64) {
   159         char *beyond = base64 + strlen(BASE64_EXTENSION);
   160         // per the RFC 2397 grammar, "base64" MUST be followed by a comma
   161         // previously substituted by '\0', but we also allow it in between
   162         // parameters so a subsequent ";" is ok as well (this deals with
   163         // *broken* data URIs, see bug 781693 for an example)
   164         if (*beyond == '\0' || *beyond == ';') {
   165             isBase64 = true;
   166             *base64 = '\0';
   167         }
   168     }
   170     if (comma == buffer) {
   171         // nothing but data
   172         contentType.AssignLiteral("text/plain");
   173         contentCharset.AssignLiteral("US-ASCII");
   174     } else {
   175         // everything else is content type
   176         char *semiColon = (char *) strchr(buffer, ';');
   177         if (semiColon)
   178             *semiColon = '\0';
   180         if (semiColon == buffer || base64 == buffer) {
   181             // there is no content type, but there are other parameters
   182             contentType.AssignLiteral("text/plain");
   183         } else {
   184             contentType = buffer;
   185             ToLowerCase(contentType);
   186         }
   188         if (semiColon) {
   189             char *charset = PL_strcasestr(semiColon + 1, "charset=");
   190             if (charset)
   191                 contentCharset = charset + sizeof("charset=") - 1;
   193             *semiColon = ';';
   194         }
   195     }
   197     *comma = ',';
   198     if (isBase64)
   199         *base64 = ';';
   201     contentType.StripWhitespace();
   202     contentCharset.StripWhitespace();
   204     // Split encoded data from terminal "#ref" (if present)
   205     char *data = comma + 1;
   206     char *hash = strchr(data, '#');
   207     if (!hash) {
   208         dataBuffer.Assign(data);
   209         hashRef.Truncate();
   210     } else {
   211         dataBuffer.Assign(data, hash - data);
   212         hashRef.Assign(hash);
   213     }
   215     return NS_OK;
   216 }

mercurial