netwerk/protocol/data/nsDataHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial