1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nspr.h"
39 : #include "nsDataChannel.h"
40 : #include "nsDataHandler.h"
41 : #include "nsIURL.h"
42 : #include "nsCRT.h"
43 : #include "nsIComponentManager.h"
44 : #include "nsIServiceManager.h"
45 : #include "nsIInterfaceRequestor.h"
46 : #include "nsIInterfaceRequestorUtils.h"
47 : #include "nsIProgressEventSink.h"
48 : #include "nsNetCID.h"
49 : #include "nsNetError.h"
50 :
51 : static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
52 :
53 : ////////////////////////////////////////////////////////////////////////////////
54 :
55 52 : nsDataHandler::nsDataHandler() {
56 52 : }
57 :
58 104 : nsDataHandler::~nsDataHandler() {
59 208 : }
60 :
61 7976 : NS_IMPL_ISUPPORTS1(nsDataHandler, nsIProtocolHandler)
62 :
63 : nsresult
64 52 : nsDataHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) {
65 :
66 52 : nsDataHandler* ph = new nsDataHandler();
67 52 : if (ph == nsnull)
68 0 : return NS_ERROR_OUT_OF_MEMORY;
69 52 : NS_ADDREF(ph);
70 52 : nsresult rv = ph->QueryInterface(aIID, aResult);
71 52 : NS_RELEASE(ph);
72 52 : return rv;
73 : }
74 :
75 : ////////////////////////////////////////////////////////////////////////////////
76 : // nsIProtocolHandler methods:
77 :
78 : NS_IMETHODIMP
79 0 : nsDataHandler::GetScheme(nsACString &result) {
80 0 : result.AssignLiteral("data");
81 0 : return NS_OK;
82 : }
83 :
84 : NS_IMETHODIMP
85 0 : nsDataHandler::GetDefaultPort(PRInt32 *result) {
86 : // no ports for data protocol
87 0 : *result = -1;
88 0 : return NS_OK;
89 : }
90 :
91 : NS_IMETHODIMP
92 318 : nsDataHandler::GetProtocolFlags(PRUint32 *result) {
93 : *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
94 318 : URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE;
95 318 : return NS_OK;
96 : }
97 :
98 : NS_IMETHODIMP
99 556 : nsDataHandler::NewURI(const nsACString &aSpec,
100 : const char *aCharset, // ignore charset info
101 : nsIURI *aBaseURI,
102 : nsIURI **result) {
103 : nsresult rv;
104 1112 : nsRefPtr<nsIURI> uri;
105 :
106 1112 : nsCString spec(aSpec);
107 :
108 556 : if (aBaseURI && !spec.IsEmpty() && spec[0] == '#') {
109 : // Looks like a reference instead of a fully-specified URI.
110 : // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
111 5 : rv = aBaseURI->Clone(getter_AddRefs(uri));
112 5 : if (NS_FAILED(rv))
113 0 : return rv;
114 5 : rv = uri->SetRef(spec);
115 : } else {
116 : // Otherwise, we'll assume |spec| is a fully-specified data URI
117 1653 : nsCAutoString contentType, contentCharset, dataBuffer, hashRef;
118 : bool base64;
119 551 : rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer, hashRef);
120 551 : if (NS_FAILED(rv))
121 0 : return rv;
122 :
123 : // Strip whitespace unless this is text, where whitespace is important
124 : // Don't strip escaped whitespace though (bug 391951)
125 562 : if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
126 11 : contentType.Find("xml") == kNotFound)) {
127 : // it's ascii encoded binary, don't let any spaces in
128 122 : spec.StripWhitespace();
129 : }
130 :
131 551 : uri = do_CreateInstance(kSimpleURICID, &rv);
132 551 : if (NS_FAILED(rv))
133 0 : return rv;
134 1102 : rv = uri->SetSpec(spec);
135 : }
136 :
137 556 : if (NS_FAILED(rv))
138 0 : return rv;
139 :
140 556 : uri.forget(result);
141 556 : return rv;
142 : }
143 :
144 : NS_IMETHODIMP
145 401 : nsDataHandler::NewChannel(nsIURI* uri, nsIChannel* *result) {
146 401 : NS_ENSURE_ARG_POINTER(uri);
147 401 : nsDataChannel* channel = new nsDataChannel(uri);
148 401 : if (!channel)
149 0 : return NS_ERROR_OUT_OF_MEMORY;
150 401 : NS_ADDREF(channel);
151 :
152 401 : nsresult rv = channel->Init();
153 401 : if (NS_FAILED(rv)) {
154 0 : NS_RELEASE(channel);
155 0 : return rv;
156 : }
157 :
158 401 : *result = channel;
159 401 : return NS_OK;
160 : }
161 :
162 : NS_IMETHODIMP
163 0 : nsDataHandler::AllowPort(PRInt32 port, const char *scheme, bool *_retval) {
164 : // don't override anything.
165 0 : *_retval = false;
166 0 : return NS_OK;
167 : }
168 :
169 : nsresult
170 951 : nsDataHandler::ParseURI(nsCString& spec,
171 : nsCString& contentType,
172 : nsCString& contentCharset,
173 : bool& isBase64,
174 : nsCString& dataBuffer,
175 : nsCString& hashRef) {
176 951 : isBase64 = false;
177 :
178 : // move past "data:"
179 951 : char *buffer = (char *) PL_strcasestr(spec.BeginWriting(), "data:");
180 951 : if (!buffer) {
181 : // malformed uri
182 0 : return NS_ERROR_MALFORMED_URI;
183 : }
184 951 : buffer += 5;
185 :
186 : // First, find the start of the data
187 951 : char *comma = strchr(buffer, ',');
188 951 : if (!comma)
189 0 : return NS_ERROR_MALFORMED_URI;
190 :
191 951 : *comma = '\0';
192 :
193 : // determine if the data is base64 encoded.
194 951 : char *base64 = PL_strcasestr(buffer, ";base64");
195 951 : if (base64) {
196 222 : isBase64 = true;
197 222 : *base64 = '\0';
198 : }
199 :
200 951 : if (comma == buffer) {
201 : // nothing but data
202 224 : contentType.AssignLiteral("text/plain");
203 224 : contentCharset.AssignLiteral("US-ASCII");
204 : } else {
205 : // everything else is content type
206 727 : char *semiColon = (char *) strchr(buffer, ';');
207 727 : if (semiColon)
208 406 : *semiColon = '\0';
209 :
210 727 : if (semiColon == buffer || base64 == buffer) {
211 : // there is no content type, but there are other parameters
212 0 : contentType.AssignLiteral("text/plain");
213 : } else {
214 727 : contentType = buffer;
215 727 : ToLowerCase(contentType);
216 : }
217 :
218 727 : if (semiColon) {
219 406 : char *charset = PL_strcasestr(semiColon + 1, "charset=");
220 406 : if (charset)
221 406 : contentCharset = charset + sizeof("charset=") - 1;
222 :
223 406 : *semiColon = ';';
224 : }
225 : }
226 :
227 951 : *comma = ',';
228 951 : if (isBase64)
229 222 : *base64 = ';';
230 :
231 951 : contentType.StripWhitespace();
232 951 : contentCharset.StripWhitespace();
233 :
234 : // Split encoded data from terminal "#ref" (if present)
235 951 : char *data = comma + 1;
236 951 : char *hash = strchr(data, '#');
237 951 : if (!hash) {
238 921 : dataBuffer.Assign(data);
239 921 : hashRef.Truncate();
240 : } else {
241 30 : dataBuffer.Assign(data, hash - data);
242 30 : hashRef.Assign(hash);
243 : }
244 :
245 951 : return NS_OK;
246 : }
|