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 +}