1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 : * the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Josh Matthews <josh@joshmatthews.net> (Initial Developer)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef mozilla_net_NeckoMessageUtils_h
40 : #define mozilla_net_NeckoMessageUtils_h
41 :
42 : #include "IPC/IPCMessageUtils.h"
43 : #include "nsStringGlue.h"
44 : #include "nsIURI.h"
45 : #include "nsIIPCSerializable.h"
46 : #include "nsIClassInfo.h"
47 : #include "nsComponentManagerUtils.h"
48 : #include "nsNetUtil.h"
49 : #include "nsStringStream.h"
50 : #include "prio.h"
51 : #include "mozilla/Util.h" // for DebugOnly
52 :
53 : namespace IPC {
54 :
55 : // Since IPDL doesn't have any knowledge of pointers, there's no easy way to
56 : // pass around nsIURI pointers. This is a very thin wrapper that IPDL can
57 : // easily work with, allowing for conversion to and from an nsIURI pointer.
58 :
59 0 : class URI {
60 : public:
61 0 : URI() : mURI(nsnull) {}
62 0 : URI(nsIURI* aURI) : mURI(aURI) {}
63 0 : operator nsIURI*() const { return mURI.get(); }
64 :
65 : friend struct ParamTraits<URI>;
66 :
67 : private:
68 : // Unimplemented
69 : URI& operator=(URI&);
70 :
71 : nsCOMPtr<nsIURI> mURI;
72 : };
73 :
74 : template<>
75 : struct ParamTraits<URI>
76 : {
77 : typedef URI paramType;
78 :
79 0 : static void Write(Message* aMsg, const paramType& aParam)
80 : {
81 0 : bool isNull = !aParam.mURI;
82 0 : WriteParam(aMsg, isNull);
83 0 : if (isNull)
84 0 : return;
85 :
86 0 : nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mURI);
87 0 : if (!serializable) {
88 0 : nsCString scheme;
89 0 : aParam.mURI->GetScheme(scheme);
90 0 : if (!scheme.EqualsASCII("about:") &&
91 0 : !scheme.EqualsASCII("javascript:") &&
92 0 : !scheme.EqualsASCII("javascript"))
93 0 : NS_WARNING("All IPDL URIs must be serializable or an allowed scheme");
94 : }
95 :
96 0 : bool isSerialized = !!serializable;
97 0 : WriteParam(aMsg, isSerialized);
98 0 : if (!isSerialized) {
99 0 : nsCString spec, charset;
100 0 : aParam.mURI->GetSpec(spec);
101 0 : aParam.mURI->GetOriginCharset(charset);
102 0 : WriteParam(aMsg, spec);
103 0 : WriteParam(aMsg, charset);
104 : return;
105 : }
106 :
107 0 : nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aParam.mURI);
108 : char cidStr[NSID_LENGTH];
109 : nsCID cid;
110 0 : mozilla::DebugOnly<nsresult> rv = classInfo->GetClassIDNoAlloc(&cid);
111 0 : NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "All IPDL URIs must report a valid class ID");
112 :
113 0 : cid.ToProvidedString(cidStr);
114 0 : WriteParam(aMsg, nsCAutoString(cidStr));
115 0 : serializable->Write(aMsg);
116 : }
117 :
118 0 : static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
119 : {
120 : bool isNull;
121 0 : if (!ReadParam(aMsg, aIter, &isNull))
122 0 : return false;
123 0 : if (isNull) {
124 0 : aResult->mURI = nsnull;
125 0 : return true;
126 : }
127 :
128 : bool isSerialized;
129 0 : if (!ReadParam(aMsg, aIter, &isSerialized))
130 0 : return false;
131 0 : if (!isSerialized) {
132 0 : nsCString spec, charset;
133 0 : if (!ReadParam(aMsg, aIter, &spec) ||
134 0 : !ReadParam(aMsg, aIter, &charset))
135 0 : return false;
136 :
137 0 : nsCOMPtr<nsIURI> uri;
138 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), spec, charset.get());
139 0 : if (NS_FAILED(rv))
140 0 : return false;
141 :
142 0 : uri.swap(aResult->mURI);
143 0 : return true;
144 : }
145 :
146 0 : nsCAutoString cidStr;
147 : nsCID cid;
148 0 : if (!ReadParam(aMsg, aIter, &cidStr) ||
149 0 : !cid.Parse(cidStr.get()))
150 0 : return false;
151 :
152 0 : nsCOMPtr<nsIURI> uri = do_CreateInstance(cid);
153 0 : if (!uri)
154 0 : return false;
155 0 : nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(uri);
156 0 : if (!serializable || !serializable->Read(aMsg, aIter))
157 0 : return false;
158 :
159 0 : uri.swap(aResult->mURI);
160 0 : return true;
161 : }
162 :
163 : static void Log(const paramType& aParam, std::wstring* aLog)
164 : {
165 : nsIURI* uri = aParam.mURI;
166 : if (uri) {
167 : nsCString spec;
168 : uri->GetSpec(spec);
169 : aLog->append(StringPrintf(L"[%s]", spec.get()));
170 : }
171 : else {
172 : aLog->append(L"[]");
173 : }
174 : }
175 : };
176 :
177 0 : class InputStream {
178 : public:
179 0 : InputStream() : mStream(nsnull) {}
180 0 : InputStream(nsIInputStream* aStream) : mStream(aStream) {}
181 0 : operator nsIInputStream*() const { return mStream.get(); }
182 :
183 : friend struct ParamTraits<InputStream>;
184 :
185 : private:
186 : // Unimplemented
187 : InputStream& operator=(InputStream&);
188 :
189 : nsCOMPtr<nsIInputStream> mStream;
190 : };
191 :
192 : template<>
193 : struct ParamTraits<InputStream>
194 : {
195 : typedef InputStream paramType;
196 :
197 0 : static void Write(Message* aMsg, const paramType& aParam)
198 : {
199 0 : bool isNull = !aParam.mStream;
200 0 : aMsg->WriteBool(isNull);
201 :
202 0 : if (isNull)
203 0 : return;
204 :
205 0 : nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mStream);
206 0 : bool isSerializable = !!serializable;
207 0 : WriteParam(aMsg, isSerializable);
208 :
209 0 : if (!serializable) {
210 0 : NS_WARNING("nsIInputStream implementation doesn't support nsIIPCSerializable; falling back to copying data");
211 :
212 0 : nsCString streamString;
213 : PRUint32 bytes;
214 :
215 0 : aParam.mStream->Available(&bytes);
216 0 : if (bytes > 0) {
217 : mozilla::DebugOnly<nsresult> rv =
218 0 : NS_ReadInputStreamToString(aParam.mStream, streamString, bytes);
219 0 : NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't read input stream into a string!");
220 : }
221 :
222 0 : WriteParam(aMsg, streamString);
223 : return;
224 : }
225 :
226 0 : nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aParam.mStream);
227 : char cidStr[NSID_LENGTH];
228 : nsCID cid;
229 0 : mozilla::DebugOnly<nsresult> rv = classInfo->GetClassIDNoAlloc(&cid);
230 0 : NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "All IPDL streams must report a valid class ID");
231 :
232 0 : cid.ToProvidedString(cidStr);
233 0 : WriteParam(aMsg, nsCAutoString(cidStr));
234 0 : serializable->Write(aMsg);
235 : }
236 :
237 0 : static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
238 : {
239 : bool isNull;
240 0 : if (!ReadParam(aMsg, aIter, &isNull))
241 0 : return false;
242 :
243 0 : if (isNull) {
244 0 : aResult->mStream = nsnull;
245 0 : return true;
246 : }
247 :
248 : bool isSerializable;
249 0 : if (!ReadParam(aMsg, aIter, &isSerializable))
250 0 : return false;
251 :
252 0 : nsCOMPtr<nsIInputStream> stream;
253 0 : if (!isSerializable) {
254 0 : nsCString streamString;
255 0 : if (!ReadParam(aMsg, aIter, &streamString))
256 0 : return false;
257 :
258 0 : nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), streamString);
259 0 : if (NS_FAILED(rv))
260 0 : return false;
261 : } else {
262 0 : nsCAutoString cidStr;
263 : nsCID cid;
264 0 : if (!ReadParam(aMsg, aIter, &cidStr) ||
265 0 : !cid.Parse(cidStr.get()))
266 0 : return false;
267 :
268 0 : stream = do_CreateInstance(cid);
269 0 : if (!stream)
270 0 : return false;
271 0 : nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(stream);
272 0 : if (!serializable || !serializable->Read(aMsg, aIter))
273 0 : return false;
274 : }
275 :
276 0 : stream.swap(aResult->mStream);
277 0 : return true;
278 : }
279 : };
280 :
281 : // nsIPermissionManager utilities
282 :
283 : struct Permission
284 513 : {
285 : nsCString host, type;
286 : PRUint32 capability, expireType;
287 : PRInt64 expireTime;
288 :
289 0 : Permission() { }
290 513 : Permission(const nsCString& aHost,
291 : const nsCString& aType,
292 : const PRUint32 aCapability,
293 : const PRUint32 aExpireType,
294 : const PRInt64 aExpireTime) : host(aHost),
295 : type(aType),
296 : capability(aCapability),
297 : expireType(aExpireType),
298 513 : expireTime(aExpireTime) { }
299 : };
300 :
301 : template<>
302 : struct ParamTraits<Permission>
303 : {
304 0 : static void Write(Message* aMsg, const Permission& aParam)
305 : {
306 0 : WriteParam(aMsg, aParam.host);
307 0 : WriteParam(aMsg, aParam.type);
308 0 : WriteParam(aMsg, aParam.capability);
309 0 : WriteParam(aMsg, aParam.expireType);
310 0 : WriteParam(aMsg, aParam.expireTime);
311 0 : }
312 :
313 0 : static bool Read(const Message* aMsg, void** aIter, Permission* aResult)
314 : {
315 0 : return ReadParam(aMsg, aIter, &aResult->host) &&
316 0 : ReadParam(aMsg, aIter, &aResult->type) &&
317 0 : ReadParam(aMsg, aIter, &aResult->capability) &&
318 0 : ReadParam(aMsg, aIter, &aResult->expireType) &&
319 0 : ReadParam(aMsg, aIter, &aResult->expireTime);
320 : }
321 :
322 : static void Log(const Permission& aParam, std::wstring* aLog)
323 : {
324 : aLog->append(StringPrintf(L"[%s]", aParam.host.get()));
325 : }
326 : };
327 :
328 : template<>
329 : struct ParamTraits<PRNetAddr>
330 : {
331 0 : static void Write(Message* aMsg, const PRNetAddr &aParam)
332 : {
333 0 : WriteParam(aMsg, aParam.raw.family);
334 0 : if (aParam.raw.family == PR_AF_UNSPEC) {
335 0 : aMsg->WriteBytes(aParam.raw.data, sizeof(aParam.raw.data));
336 0 : } else if (aParam.raw.family == PR_AF_INET) {
337 0 : WriteParam(aMsg, aParam.inet.port);
338 0 : WriteParam(aMsg, aParam.inet.ip);
339 0 : } else if (aParam.raw.family == PR_AF_INET6) {
340 0 : WriteParam(aMsg, aParam.ipv6.port);
341 0 : WriteParam(aMsg, aParam.ipv6.flowinfo);
342 0 : WriteParam(aMsg, aParam.ipv6.ip.pr_s6_addr64[0]);
343 0 : WriteParam(aMsg, aParam.ipv6.ip.pr_s6_addr64[1]);
344 0 : WriteParam(aMsg, aParam.ipv6.scope_id);
345 : #if defined(XP_UNIX) || defined(XP_OS2)
346 0 : } else if (aParam.raw.family == PR_AF_LOCAL) {
347 : // Train's already off the rails: let's get a stack trace at least...
348 : NS_RUNTIMEABORT("Error: please post stack trace to "
349 0 : "https://bugzilla.mozilla.org/show_bug.cgi?id=661158");
350 0 : aMsg->WriteBytes(aParam.local.path, sizeof(aParam.local.path));
351 : #endif
352 : }
353 :
354 : /* If we get here without hitting any of the cases above, there's not much
355 : * we can do but let the deserializer fail when it gets this message */
356 0 : }
357 :
358 0 : static bool Read(const Message* aMsg, void** aIter, PRNetAddr* aResult)
359 : {
360 0 : if (!ReadParam(aMsg, aIter, &aResult->raw.family))
361 0 : return false;
362 :
363 0 : if (aResult->raw.family == PR_AF_UNSPEC) {
364 : return aMsg->ReadBytes(aIter,
365 : reinterpret_cast<const char**>(&aResult->raw.data),
366 0 : sizeof(aResult->raw.data));
367 0 : } else if (aResult->raw.family == PR_AF_INET) {
368 0 : return ReadParam(aMsg, aIter, &aResult->inet.port) &&
369 0 : ReadParam(aMsg, aIter, &aResult->inet.ip);
370 0 : } else if (aResult->raw.family == PR_AF_INET6) {
371 0 : return ReadParam(aMsg, aIter, &aResult->ipv6.port) &&
372 0 : ReadParam(aMsg, aIter, &aResult->ipv6.flowinfo) &&
373 0 : ReadParam(aMsg, aIter, &aResult->ipv6.ip.pr_s6_addr64[0]) &&
374 0 : ReadParam(aMsg, aIter, &aResult->ipv6.ip.pr_s6_addr64[1]) &&
375 0 : ReadParam(aMsg, aIter, &aResult->ipv6.scope_id);
376 : #if defined(XP_UNIX) || defined(XP_OS2)
377 0 : } else if (aResult->raw.family == PR_AF_LOCAL) {
378 : return aMsg->ReadBytes(aIter,
379 : reinterpret_cast<const char**>(&aResult->local.path),
380 0 : sizeof(aResult->local.path));
381 : #endif
382 : }
383 :
384 : /* We've been tricked by some socket family we don't know about! */
385 0 : return false;
386 : }
387 : };
388 :
389 : }
390 :
391 : #endif // mozilla_net_NeckoMessageUtils_h
|