netwerk/protocol/data/nsDataHandler.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/data/nsDataHandler.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,216 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsDataChannel.h"
    1.10 +#include "nsDataHandler.h"
    1.11 +#include "nsNetCID.h"
    1.12 +#include "nsError.h"
    1.13 +
    1.14 +static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
    1.15 +
    1.16 +////////////////////////////////////////////////////////////////////////////////
    1.17 +
    1.18 +nsDataHandler::nsDataHandler() {
    1.19 +}
    1.20 +
    1.21 +nsDataHandler::~nsDataHandler() {
    1.22 +}
    1.23 +
    1.24 +NS_IMPL_ISUPPORTS(nsDataHandler, nsIProtocolHandler)
    1.25 +
    1.26 +nsresult
    1.27 +nsDataHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) {
    1.28 +
    1.29 +    nsDataHandler* ph = new nsDataHandler();
    1.30 +    if (ph == nullptr)
    1.31 +        return NS_ERROR_OUT_OF_MEMORY;
    1.32 +    NS_ADDREF(ph);
    1.33 +    nsresult rv = ph->QueryInterface(aIID, aResult);
    1.34 +    NS_RELEASE(ph);
    1.35 +    return rv;
    1.36 +}
    1.37 +    
    1.38 +////////////////////////////////////////////////////////////////////////////////
    1.39 +// nsIProtocolHandler methods:
    1.40 +
    1.41 +NS_IMETHODIMP
    1.42 +nsDataHandler::GetScheme(nsACString &result) {
    1.43 +    result.AssignLiteral("data");
    1.44 +    return NS_OK;
    1.45 +}
    1.46 +
    1.47 +NS_IMETHODIMP
    1.48 +nsDataHandler::GetDefaultPort(int32_t *result) {
    1.49 +    // no ports for data protocol
    1.50 +    *result = -1;
    1.51 +    return NS_OK;
    1.52 +}
    1.53 +
    1.54 +NS_IMETHODIMP
    1.55 +nsDataHandler::GetProtocolFlags(uint32_t *result) {
    1.56 +    *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
    1.57 +        URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE |
    1.58 +        URI_SYNC_LOAD_IS_OK;
    1.59 +    return NS_OK;
    1.60 +}
    1.61 +
    1.62 +NS_IMETHODIMP
    1.63 +nsDataHandler::NewURI(const nsACString &aSpec,
    1.64 +                      const char *aCharset, // ignore charset info
    1.65 +                      nsIURI *aBaseURI,
    1.66 +                      nsIURI **result) {
    1.67 +    nsresult rv;
    1.68 +    nsRefPtr<nsIURI> uri;
    1.69 +
    1.70 +    nsCString spec(aSpec);
    1.71 +
    1.72 +    if (aBaseURI && !spec.IsEmpty() && spec[0] == '#') {
    1.73 +        // Looks like a reference instead of a fully-specified URI.
    1.74 +        // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
    1.75 +        rv = aBaseURI->Clone(getter_AddRefs(uri));
    1.76 +        if (NS_FAILED(rv))
    1.77 +            return rv;
    1.78 +        rv = uri->SetRef(spec);
    1.79 +    } else {
    1.80 +        // Otherwise, we'll assume |spec| is a fully-specified data URI
    1.81 +        nsAutoCString contentType, contentCharset, dataBuffer, hashRef;
    1.82 +        bool base64;
    1.83 +        rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer, hashRef);
    1.84 +        if (NS_FAILED(rv))
    1.85 +            return rv;
    1.86 +
    1.87 +        // Strip whitespace unless this is text, where whitespace is important
    1.88 +        // Don't strip escaped whitespace though (bug 391951)
    1.89 +        if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
    1.90 +                       contentType.Find("xml") == kNotFound)) {
    1.91 +            // it's ascii encoded binary, don't let any spaces in
    1.92 +            spec.StripWhitespace();
    1.93 +        }
    1.94 +
    1.95 +        uri = do_CreateInstance(kSimpleURICID, &rv);
    1.96 +        if (NS_FAILED(rv))
    1.97 +            return rv;
    1.98 +        rv = uri->SetSpec(spec);
    1.99 +    }
   1.100 +
   1.101 +    if (NS_FAILED(rv))
   1.102 +        return rv;
   1.103 +
   1.104 +    uri.forget(result);
   1.105 +    return rv;
   1.106 +}
   1.107 +
   1.108 +NS_IMETHODIMP
   1.109 +nsDataHandler::NewChannel(nsIURI* uri, nsIChannel* *result) {
   1.110 +    NS_ENSURE_ARG_POINTER(uri);
   1.111 +    nsDataChannel* channel = new nsDataChannel(uri);
   1.112 +    if (!channel)
   1.113 +        return NS_ERROR_OUT_OF_MEMORY;
   1.114 +    NS_ADDREF(channel);
   1.115 +
   1.116 +    nsresult rv = channel->Init();
   1.117 +    if (NS_FAILED(rv)) {
   1.118 +        NS_RELEASE(channel);
   1.119 +        return rv;
   1.120 +    }
   1.121 +
   1.122 +    *result = channel;
   1.123 +    return NS_OK;
   1.124 +}
   1.125 +
   1.126 +NS_IMETHODIMP 
   1.127 +nsDataHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) {
   1.128 +    // don't override anything.  
   1.129 +    *_retval = false;
   1.130 +    return NS_OK;
   1.131 +}
   1.132 +
   1.133 +#define BASE64_EXTENSION ";base64"
   1.134 +
   1.135 +nsresult
   1.136 +nsDataHandler::ParseURI(nsCString& spec,
   1.137 +                        nsCString& contentType,
   1.138 +                        nsCString& contentCharset,
   1.139 +                        bool&    isBase64,
   1.140 +                        nsCString& dataBuffer,
   1.141 +                        nsCString& hashRef) {
   1.142 +    isBase64 = false;
   1.143 +
   1.144 +    // move past "data:"
   1.145 +    char *buffer = (char *) PL_strcasestr(spec.BeginWriting(), "data:");
   1.146 +    if (!buffer) {
   1.147 +        // malformed uri
   1.148 +        return NS_ERROR_MALFORMED_URI;
   1.149 +    }
   1.150 +    buffer += 5;
   1.151 +
   1.152 +    // First, find the start of the data
   1.153 +    char *comma = strchr(buffer, ',');
   1.154 +    if (!comma)
   1.155 +        return NS_ERROR_MALFORMED_URI;
   1.156 +
   1.157 +    *comma = '\0';
   1.158 +
   1.159 +    // determine if the data is base64 encoded.
   1.160 +    char *base64 = PL_strcasestr(buffer, BASE64_EXTENSION);
   1.161 +    if (base64) {
   1.162 +        char *beyond = base64 + strlen(BASE64_EXTENSION);
   1.163 +        // per the RFC 2397 grammar, "base64" MUST be followed by a comma
   1.164 +        // previously substituted by '\0', but we also allow it in between
   1.165 +        // parameters so a subsequent ";" is ok as well (this deals with
   1.166 +        // *broken* data URIs, see bug 781693 for an example)
   1.167 +        if (*beyond == '\0' || *beyond == ';') {
   1.168 +            isBase64 = true;
   1.169 +            *base64 = '\0';
   1.170 +        }
   1.171 +    }
   1.172 +
   1.173 +    if (comma == buffer) {
   1.174 +        // nothing but data
   1.175 +        contentType.AssignLiteral("text/plain");
   1.176 +        contentCharset.AssignLiteral("US-ASCII");
   1.177 +    } else {
   1.178 +        // everything else is content type
   1.179 +        char *semiColon = (char *) strchr(buffer, ';');
   1.180 +        if (semiColon)
   1.181 +            *semiColon = '\0';
   1.182 +        
   1.183 +        if (semiColon == buffer || base64 == buffer) {
   1.184 +            // there is no content type, but there are other parameters
   1.185 +            contentType.AssignLiteral("text/plain");
   1.186 +        } else {
   1.187 +            contentType = buffer;
   1.188 +            ToLowerCase(contentType);
   1.189 +        }
   1.190 +
   1.191 +        if (semiColon) {
   1.192 +            char *charset = PL_strcasestr(semiColon + 1, "charset=");
   1.193 +            if (charset)
   1.194 +                contentCharset = charset + sizeof("charset=") - 1;
   1.195 +
   1.196 +            *semiColon = ';';
   1.197 +        }
   1.198 +    }
   1.199 +
   1.200 +    *comma = ',';
   1.201 +    if (isBase64)
   1.202 +        *base64 = ';';
   1.203 +
   1.204 +    contentType.StripWhitespace();
   1.205 +    contentCharset.StripWhitespace();
   1.206 +
   1.207 +    // Split encoded data from terminal "#ref" (if present)
   1.208 +    char *data = comma + 1;
   1.209 +    char *hash = strchr(data, '#');
   1.210 +    if (!hash) {
   1.211 +        dataBuffer.Assign(data);
   1.212 +        hashRef.Truncate();
   1.213 +    } else {
   1.214 +        dataBuffer.Assign(data, hash - data);
   1.215 +        hashRef.Assign(hash);
   1.216 +    }
   1.217 +
   1.218 +    return NS_OK;
   1.219 +}

mercurial