/src/mozilla-central/uriloader/exthandler/ExternalHelperAppParent.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "mozilla/DebugOnly.h" |
8 | | |
9 | | #include "ExternalHelperAppParent.h" |
10 | | #include "nsIContent.h" |
11 | | #include "nsCExternalHandlerService.h" |
12 | | #include "nsIExternalHelperAppService.h" |
13 | | #include "mozilla/dom/ContentParent.h" |
14 | | #include "mozilla/dom/Element.h" |
15 | | #include "mozilla/dom/TabParent.h" |
16 | | #include "nsIBrowserDOMWindow.h" |
17 | | #include "nsStringStream.h" |
18 | | #include "mozilla/ipc/URIUtils.h" |
19 | | #include "nsNetUtil.h" |
20 | | #include "nsIDocument.h" |
21 | | #include "mozilla/net/ChannelDiverterParent.h" |
22 | | |
23 | | #include "mozilla/Unused.h" |
24 | | |
25 | | using namespace mozilla::ipc; |
26 | | |
27 | | namespace mozilla { |
28 | | namespace dom { |
29 | | |
30 | | NS_IMPL_ISUPPORTS_INHERITED(ExternalHelperAppParent, |
31 | | nsHashPropertyBag, |
32 | | nsIRequest, |
33 | | nsIChannel, |
34 | | nsIMultiPartChannel, |
35 | | nsIPrivateBrowsingChannel, |
36 | | nsIResumableChannel, |
37 | | nsIStreamListener, |
38 | | nsIExternalHelperAppParent) |
39 | | |
40 | | ExternalHelperAppParent::ExternalHelperAppParent( |
41 | | const OptionalURIParams& uri, |
42 | | const int64_t& aContentLength, |
43 | | const bool& aWasFileChannel, |
44 | | const nsCString& aContentDispositionHeader, |
45 | | const uint32_t& aContentDispositionHint, |
46 | | const nsString& aContentDispositionFilename) |
47 | | : mURI(DeserializeURI(uri)) |
48 | | , mPending(false) |
49 | | #ifdef DEBUG |
50 | | , mDiverted(false) |
51 | | #endif |
52 | | , mIPCClosed(false) |
53 | | , mLoadFlags(0) |
54 | | , mStatus(NS_OK) |
55 | | , mContentLength(aContentLength) |
56 | | , mWasFileChannel(aWasFileChannel) |
57 | 0 | { |
58 | 0 | mContentDispositionHeader = aContentDispositionHeader; |
59 | 0 | if (!mContentDispositionHeader.IsEmpty()) { |
60 | 0 | NS_GetFilenameFromDisposition(mContentDispositionFilename, |
61 | 0 | mContentDispositionHeader, |
62 | 0 | mURI); |
63 | 0 | mContentDisposition = |
64 | 0 | NS_GetContentDispositionFromHeader(mContentDispositionHeader, this); |
65 | 0 | } else { |
66 | 0 | mContentDisposition = aContentDispositionHint; |
67 | 0 | mContentDispositionFilename = aContentDispositionFilename; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | already_AddRefed<nsIInterfaceRequestor> |
72 | | GetWindowFromTabParent(PBrowserParent* aBrowser) |
73 | 0 | { |
74 | 0 | if (!aBrowser) { |
75 | 0 | return nullptr; |
76 | 0 | } |
77 | 0 | |
78 | 0 | nsCOMPtr<nsIInterfaceRequestor> window; |
79 | 0 | TabParent* tabParent = TabParent::GetFrom(aBrowser); |
80 | 0 | if (tabParent->GetOwnerElement()) { |
81 | 0 | window = do_QueryInterface(tabParent->GetOwnerElement()->OwnerDoc()->GetWindow()); |
82 | 0 | } |
83 | 0 |
|
84 | 0 | return window.forget(); |
85 | 0 | } |
86 | | |
87 | | void |
88 | | UpdateContentContext(nsIStreamListener* aListener, PBrowserParent* aBrowser) |
89 | 0 | { |
90 | 0 | MOZ_ASSERT(aListener); |
91 | 0 | nsCOMPtr<nsIInterfaceRequestor> window = GetWindowFromTabParent(aBrowser); |
92 | 0 | static_cast<nsExternalAppHandler *>(aListener)->SetContentContext(window); |
93 | 0 | } |
94 | | |
95 | | void |
96 | | ExternalHelperAppParent::Init(ContentParent *parent, |
97 | | const nsCString& aMimeContentType, |
98 | | const bool& aForceSave, |
99 | | const OptionalURIParams& aReferrer, |
100 | | PBrowserParent* aBrowser) |
101 | 0 | { |
102 | 0 | nsCOMPtr<nsIExternalHelperAppService> helperAppService = |
103 | 0 | do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); |
104 | 0 | NS_ASSERTION(helperAppService, "No Helper App Service!"); |
105 | 0 |
|
106 | 0 | nsCOMPtr<nsIURI> referrer = DeserializeURI(aReferrer); |
107 | 0 | if (referrer) |
108 | 0 | SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), referrer); |
109 | 0 |
|
110 | 0 | nsCOMPtr<nsIInterfaceRequestor> window; |
111 | 0 | if (aBrowser) { |
112 | 0 | TabParent* tabParent = TabParent::GetFrom(aBrowser); |
113 | 0 | if (tabParent->GetOwnerElement()) |
114 | 0 | window = do_QueryInterface(tabParent->GetOwnerElement()->OwnerDoc()->GetWindow()); |
115 | 0 |
|
116 | 0 | bool isPrivate = false; |
117 | 0 | nsCOMPtr<nsILoadContext> loadContext = tabParent->GetLoadContext(); |
118 | 0 | loadContext->GetUsePrivateBrowsing(&isPrivate); |
119 | 0 | SetPrivate(isPrivate); |
120 | 0 | } |
121 | 0 |
|
122 | 0 | helperAppService->DoContent(aMimeContentType, this, window, |
123 | 0 | aForceSave, nullptr, |
124 | 0 | getter_AddRefs(mListener)); |
125 | 0 | } |
126 | | |
127 | | void |
128 | | ExternalHelperAppParent::ActorDestroy(ActorDestroyReason why) |
129 | 0 | { |
130 | 0 | mIPCClosed = true; |
131 | 0 | } |
132 | | |
133 | | void |
134 | | ExternalHelperAppParent::Delete() |
135 | 0 | { |
136 | 0 | if (!mIPCClosed) { |
137 | 0 | Unused << Send__delete__(this); |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | mozilla::ipc::IPCResult |
142 | | ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID, |
143 | | PBrowserParent* contentContext) |
144 | 0 | { |
145 | 0 | MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); |
146 | 0 |
|
147 | 0 | UpdateContentContext(mListener, contentContext); |
148 | 0 |
|
149 | 0 | mEntityID = entityID; |
150 | 0 | mPending = true; |
151 | 0 | mStatus = mListener->OnStartRequest(this, nullptr); |
152 | 0 | return IPC_OK(); |
153 | 0 | } |
154 | | |
155 | | mozilla::ipc::IPCResult |
156 | | ExternalHelperAppParent::RecvOnDataAvailable(const nsCString& data, |
157 | | const uint64_t& offset, |
158 | | const uint32_t& count) |
159 | 0 | { |
160 | 0 | if (NS_FAILED(mStatus)) |
161 | 0 | return IPC_OK(); |
162 | 0 | |
163 | 0 | MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); |
164 | 0 | MOZ_ASSERT(mPending, "must be pending!"); |
165 | 0 |
|
166 | 0 | nsCOMPtr<nsIInputStream> stringStream; |
167 | 0 | DebugOnly<nsresult> rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), count, NS_ASSIGNMENT_DEPEND); |
168 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create dependent string!"); |
169 | 0 | mStatus = mListener->OnDataAvailable(this, nullptr, stringStream, offset, count); |
170 | 0 |
|
171 | 0 | return IPC_OK(); |
172 | 0 | } |
173 | | |
174 | | mozilla::ipc::IPCResult |
175 | | ExternalHelperAppParent::RecvOnStopRequest(const nsresult& code) |
176 | 0 | { |
177 | 0 | MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); |
178 | 0 |
|
179 | 0 | mPending = false; |
180 | 0 | mListener->OnStopRequest(this, nullptr, |
181 | 0 | (NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code); |
182 | 0 | Delete(); |
183 | 0 | return IPC_OK(); |
184 | 0 | } |
185 | | |
186 | | mozilla::ipc::IPCResult |
187 | | ExternalHelperAppParent::RecvDivertToParentUsing(PChannelDiverterParent* diverter, |
188 | | PBrowserParent* contentContext) |
189 | 0 | { |
190 | 0 | MOZ_ASSERT(diverter); |
191 | 0 | UpdateContentContext(mListener, contentContext); |
192 | 0 | auto p = static_cast<mozilla::net::ChannelDiverterParent*>(diverter); |
193 | 0 | p->DivertTo(this); |
194 | | #ifdef DEBUG |
195 | | mDiverted = true; |
196 | | #endif |
197 | | Unused << mozilla::net::ChannelDiverterParent::Send__delete__(p); |
198 | 0 | return IPC_OK(); |
199 | 0 | } |
200 | | |
201 | | // |
202 | | // nsIStreamListener |
203 | | // |
204 | | |
205 | | NS_IMETHODIMP |
206 | | ExternalHelperAppParent::OnDataAvailable(nsIRequest *request, |
207 | | nsISupports *ctx, |
208 | | nsIInputStream *input, |
209 | | uint64_t offset, |
210 | | uint32_t count) |
211 | 0 | { |
212 | 0 | MOZ_ASSERT(mDiverted); |
213 | 0 | return mListener->OnDataAvailable(request, ctx, input, offset, count); |
214 | 0 | } |
215 | | |
216 | | NS_IMETHODIMP |
217 | | ExternalHelperAppParent::OnStartRequest(nsIRequest *request, nsISupports *ctx) |
218 | 0 | { |
219 | 0 | MOZ_ASSERT(mDiverted); |
220 | 0 | return mListener->OnStartRequest(request, ctx); |
221 | 0 | } |
222 | | |
223 | | NS_IMETHODIMP |
224 | | ExternalHelperAppParent::OnStopRequest(nsIRequest *request, |
225 | | nsISupports *ctx, |
226 | | nsresult status) |
227 | 0 | { |
228 | 0 | MOZ_ASSERT(mDiverted); |
229 | 0 | nsresult rv = mListener->OnStopRequest(request, ctx, status); |
230 | 0 | Delete(); |
231 | 0 | return rv; |
232 | 0 | } |
233 | | |
234 | | ExternalHelperAppParent::~ExternalHelperAppParent() |
235 | 0 | { |
236 | 0 | } |
237 | | |
238 | | // |
239 | | // nsIRequest implementation... |
240 | | // |
241 | | |
242 | | NS_IMETHODIMP |
243 | | ExternalHelperAppParent::GetName(nsACString& aResult) |
244 | 0 | { |
245 | 0 | if (!mURI) { |
246 | 0 | aResult.Truncate(); |
247 | 0 | return NS_ERROR_NOT_AVAILABLE; |
248 | 0 | } |
249 | 0 | mURI->GetAsciiSpec(aResult); |
250 | 0 | return NS_OK; |
251 | 0 | } |
252 | | |
253 | | NS_IMETHODIMP |
254 | | ExternalHelperAppParent::IsPending(bool *aResult) |
255 | 0 | { |
256 | 0 | *aResult = mPending; |
257 | 0 | return NS_OK; |
258 | 0 | } |
259 | | |
260 | | NS_IMETHODIMP |
261 | | ExternalHelperAppParent::GetStatus(nsresult *aResult) |
262 | 0 | { |
263 | 0 | *aResult = mStatus; |
264 | 0 | return NS_OK; |
265 | 0 | } |
266 | | |
267 | | NS_IMETHODIMP |
268 | | ExternalHelperAppParent::Cancel(nsresult aStatus) |
269 | 0 | { |
270 | 0 | mStatus = aStatus; |
271 | 0 | Unused << SendCancel(aStatus); |
272 | 0 | return NS_OK; |
273 | 0 | } |
274 | | |
275 | | NS_IMETHODIMP |
276 | | ExternalHelperAppParent::Suspend() |
277 | 0 | { |
278 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
279 | 0 | } |
280 | | |
281 | | NS_IMETHODIMP |
282 | | ExternalHelperAppParent::Resume() |
283 | 0 | { |
284 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
285 | 0 | } |
286 | | |
287 | | // |
288 | | // nsIChannel implementation |
289 | | // |
290 | | |
291 | | NS_IMETHODIMP |
292 | | ExternalHelperAppParent::GetOriginalURI(nsIURI * *aURI) |
293 | 0 | { |
294 | 0 | NS_IF_ADDREF(*aURI = mURI); |
295 | 0 | return NS_OK; |
296 | 0 | } |
297 | | |
298 | | NS_IMETHODIMP |
299 | | ExternalHelperAppParent::SetOriginalURI(nsIURI *aURI) |
300 | 0 | { |
301 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
302 | 0 | } |
303 | | |
304 | | NS_IMETHODIMP |
305 | | ExternalHelperAppParent::GetURI(nsIURI **aURI) |
306 | 0 | { |
307 | 0 | NS_IF_ADDREF(*aURI = mURI); |
308 | 0 | return NS_OK; |
309 | 0 | } |
310 | | |
311 | | NS_IMETHODIMP |
312 | | ExternalHelperAppParent::Open(nsIInputStream **aResult) |
313 | 0 | { |
314 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
315 | 0 | } |
316 | | |
317 | | NS_IMETHODIMP |
318 | | ExternalHelperAppParent::Open2(nsIInputStream** aStream) |
319 | 0 | { |
320 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
321 | 0 | } |
322 | | |
323 | | NS_IMETHODIMP |
324 | | ExternalHelperAppParent::AsyncOpen(nsIStreamListener *aListener, |
325 | | nsISupports *aContext) |
326 | 0 | { |
327 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
328 | 0 | } |
329 | | |
330 | | NS_IMETHODIMP |
331 | | ExternalHelperAppParent::AsyncOpen2(nsIStreamListener *aListener) |
332 | 0 | { |
333 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
334 | 0 | } |
335 | | |
336 | | |
337 | | NS_IMETHODIMP |
338 | | ExternalHelperAppParent::GetLoadFlags(nsLoadFlags *aLoadFlags) |
339 | 0 | { |
340 | 0 | *aLoadFlags = mLoadFlags; |
341 | 0 | return NS_OK; |
342 | 0 | } |
343 | | |
344 | | NS_IMETHODIMP |
345 | | ExternalHelperAppParent::SetLoadFlags(nsLoadFlags aLoadFlags) |
346 | 0 | { |
347 | 0 | mLoadFlags = aLoadFlags; |
348 | 0 | return NS_OK; |
349 | 0 | } |
350 | | |
351 | | NS_IMETHODIMP |
352 | | ExternalHelperAppParent::GetIsDocument(bool *aIsDocument) |
353 | 0 | { |
354 | 0 | return NS_GetIsDocumentChannel(this, aIsDocument); |
355 | 0 | } |
356 | | |
357 | | NS_IMETHODIMP |
358 | | ExternalHelperAppParent::GetLoadGroup(nsILoadGroup* *aLoadGroup) |
359 | 0 | { |
360 | 0 | *aLoadGroup = nullptr; |
361 | 0 | return NS_OK; |
362 | 0 | } |
363 | | |
364 | | NS_IMETHODIMP |
365 | | ExternalHelperAppParent::SetLoadGroup(nsILoadGroup* aLoadGroup) |
366 | 0 | { |
367 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
368 | 0 | } |
369 | | |
370 | | NS_IMETHODIMP |
371 | | ExternalHelperAppParent::GetOwner(nsISupports* *aOwner) |
372 | 0 | { |
373 | 0 | *aOwner = nullptr; |
374 | 0 | return NS_OK; |
375 | 0 | } |
376 | | |
377 | | NS_IMETHODIMP |
378 | | ExternalHelperAppParent::SetOwner(nsISupports* aOwner) |
379 | 0 | { |
380 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
381 | 0 | } |
382 | | |
383 | | NS_IMETHODIMP |
384 | | ExternalHelperAppParent::GetLoadInfo(nsILoadInfo* *aLoadInfo) |
385 | 0 | { |
386 | 0 | *aLoadInfo = nullptr; |
387 | 0 | return NS_OK; |
388 | 0 | } |
389 | | |
390 | | NS_IMETHODIMP |
391 | | ExternalHelperAppParent::SetLoadInfo(nsILoadInfo* aLoadInfo) |
392 | 0 | { |
393 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
394 | 0 | } |
395 | | |
396 | | NS_IMETHODIMP |
397 | | ExternalHelperAppParent::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) |
398 | 0 | { |
399 | 0 | *aCallbacks = nullptr; |
400 | 0 | return NS_OK; |
401 | 0 | } |
402 | | |
403 | | NS_IMETHODIMP |
404 | | ExternalHelperAppParent::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) |
405 | 0 | { |
406 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
407 | 0 | } |
408 | | |
409 | | NS_IMETHODIMP |
410 | | ExternalHelperAppParent::GetSecurityInfo(nsISupports * *aSecurityInfo) |
411 | 0 | { |
412 | 0 | *aSecurityInfo = nullptr; |
413 | 0 | return NS_OK; |
414 | 0 | } |
415 | | |
416 | | NS_IMETHODIMP |
417 | | ExternalHelperAppParent::GetContentType(nsACString& aContentType) |
418 | 0 | { |
419 | 0 | aContentType.Truncate(); |
420 | 0 | return NS_OK; |
421 | 0 | } |
422 | | |
423 | | NS_IMETHODIMP |
424 | | ExternalHelperAppParent::SetContentType(const nsACString& aContentType) |
425 | 0 | { |
426 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
427 | 0 | } |
428 | | |
429 | | NS_IMETHODIMP |
430 | | ExternalHelperAppParent::GetContentCharset(nsACString& aContentCharset) |
431 | 0 | { |
432 | 0 | aContentCharset.Truncate(); |
433 | 0 | return NS_OK; |
434 | 0 | } |
435 | | |
436 | | NS_IMETHODIMP |
437 | | ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset) |
438 | 0 | { |
439 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
440 | 0 | } |
441 | | |
442 | | NS_IMETHODIMP |
443 | | ExternalHelperAppParent::GetContentDisposition(uint32_t *aContentDisposition) |
444 | 0 | { |
445 | 0 | // NB: mContentDisposition may or may not be set to a non UINT32_MAX value in |
446 | 0 | // nsExternalHelperAppService::DoContentContentProcessHelper |
447 | 0 | if (mContentDispositionHeader.IsEmpty() && mContentDisposition == UINT32_MAX) |
448 | 0 | return NS_ERROR_NOT_AVAILABLE; |
449 | 0 | |
450 | 0 | *aContentDisposition = mContentDisposition; |
451 | 0 | return NS_OK; |
452 | 0 | } |
453 | | |
454 | | NS_IMETHODIMP |
455 | | ExternalHelperAppParent::SetContentDisposition(uint32_t aContentDisposition) |
456 | 0 | { |
457 | 0 | mContentDisposition = aContentDisposition; |
458 | 0 | return NS_OK; |
459 | 0 | } |
460 | | |
461 | | NS_IMETHODIMP |
462 | | ExternalHelperAppParent::GetContentDispositionFilename(nsAString& aContentDispositionFilename) |
463 | 0 | { |
464 | 0 | if (mContentDispositionFilename.IsEmpty()) |
465 | 0 | return NS_ERROR_NOT_AVAILABLE; |
466 | 0 | |
467 | 0 | aContentDispositionFilename = mContentDispositionFilename; |
468 | 0 | return NS_OK; |
469 | 0 | } |
470 | | |
471 | | NS_IMETHODIMP |
472 | | ExternalHelperAppParent::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) |
473 | 0 | { |
474 | 0 | mContentDispositionFilename = aContentDispositionFilename; |
475 | 0 | return NS_OK; |
476 | 0 | } |
477 | | |
478 | | NS_IMETHODIMP |
479 | | ExternalHelperAppParent::GetContentDispositionHeader(nsACString& aContentDispositionHeader) |
480 | 0 | { |
481 | 0 | if (mContentDispositionHeader.IsEmpty()) |
482 | 0 | return NS_ERROR_NOT_AVAILABLE; |
483 | 0 | |
484 | 0 | aContentDispositionHeader = mContentDispositionHeader; |
485 | 0 | return NS_OK; |
486 | 0 | } |
487 | | |
488 | | NS_IMETHODIMP |
489 | | ExternalHelperAppParent::GetContentLength(int64_t *aContentLength) |
490 | 0 | { |
491 | 0 | if (mContentLength < 0) |
492 | 0 | *aContentLength = -1; |
493 | 0 | else |
494 | 0 | *aContentLength = mContentLength; |
495 | 0 | return NS_OK; |
496 | 0 | } |
497 | | |
498 | | NS_IMETHODIMP |
499 | | ExternalHelperAppParent::SetContentLength(int64_t aContentLength) |
500 | 0 | { |
501 | 0 | mContentLength = aContentLength; |
502 | 0 | return NS_OK; |
503 | 0 | } |
504 | | |
505 | | // |
506 | | // nsIResumableChannel implementation |
507 | | // |
508 | | |
509 | | NS_IMETHODIMP |
510 | | ExternalHelperAppParent::ResumeAt(uint64_t startPos, const nsACString& entityID) |
511 | 0 | { |
512 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
513 | 0 | } |
514 | | |
515 | | NS_IMETHODIMP |
516 | | ExternalHelperAppParent::GetEntityID(nsACString& aEntityID) |
517 | 0 | { |
518 | 0 | aEntityID = mEntityID; |
519 | 0 | return NS_OK; |
520 | 0 | } |
521 | | |
522 | | // |
523 | | // nsIMultiPartChannel implementation |
524 | | // |
525 | | |
526 | | NS_IMETHODIMP |
527 | | ExternalHelperAppParent::GetBaseChannel(nsIChannel* *aChannel) |
528 | 0 | { |
529 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
530 | 0 | } |
531 | | |
532 | | NS_IMETHODIMP |
533 | | ExternalHelperAppParent::GetPartID(uint32_t* aPartID) |
534 | 0 | { |
535 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
536 | 0 | } |
537 | | |
538 | | NS_IMETHODIMP |
539 | | ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart) |
540 | 0 | { |
541 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
542 | 0 | } |
543 | | |
544 | | } // namespace dom |
545 | | } // namespace mozilla |