Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 :
8 : A directory viewer object. Parses "application/http-index-format"
9 : per Lou Montulli's original spec:
10 :
11 : http://www.mozilla.org/projects/netlib/dirindexformat.html
12 :
13 : One added change is for a description entry, for when the
14 : target does not match the filename
15 :
16 : */
17 :
18 : #include "nsDirectoryViewer.h"
19 : #include "nsArray.h"
20 : #include "nsArrayUtils.h"
21 : #include "nsIDirIndex.h"
22 : #include "nsIDocShell.h"
23 : #include "jsapi.h"
24 : #include "nsCOMPtr.h"
25 : #include "nsEnumeratorUtils.h"
26 : #include "nsEscape.h"
27 : #include "nsIRDFService.h"
28 : #include "nsRDFCID.h"
29 : #include "rdf.h"
30 : #include "nsIServiceManager.h"
31 : #include "nsIXPConnect.h"
32 : #include "nsEnumeratorUtils.h"
33 : #include "nsString.h"
34 : #include "nsXPIDLString.h"
35 : #include "nsReadableUtils.h"
36 : #include "nsITextToSubURI.h"
37 : #include "nsIInterfaceRequestor.h"
38 : #include "nsIInterfaceRequestorUtils.h"
39 : #include "nsIFTPChannel.h"
40 : #include "nsIWindowWatcher.h"
41 : #include "nsIPrompt.h"
42 : #include "nsIAuthPrompt.h"
43 : #include "nsIProgressEventSink.h"
44 : #include "nsIDOMWindow.h"
45 : #include "nsIDOMElement.h"
46 : #include "nsIStreamConverterService.h"
47 : #include "nsICategoryManager.h"
48 : #include "nsXPCOMCID.h"
49 : #include "nsIDocument.h"
50 : #include "mozilla/Preferences.h"
51 : #include "mozilla/dom/ScriptSettings.h"
52 : #include "nsContentUtils.h"
53 : #include "nsIURI.h"
54 : #include "nsNetUtil.h"
55 :
56 : using namespace mozilla;
57 :
58 : static const int FORMAT_XUL = 3;
59 :
60 : //----------------------------------------------------------------------
61 : //
62 : // Common CIDs
63 : //
64 :
65 : static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
66 :
67 : // Various protocols we have to special case
68 : static const char kFTPProtocol[] = "ftp://";
69 :
70 : //----------------------------------------------------------------------
71 : //
72 : // nsHTTPIndex
73 : //
74 :
75 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTTPIndex)
76 0 : NS_INTERFACE_MAP_ENTRY(nsIHTTPIndex)
77 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
78 0 : NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
79 0 : NS_INTERFACE_MAP_ENTRY(nsIDirIndexListener)
80 0 : NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
81 0 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
82 0 : NS_INTERFACE_MAP_ENTRY(nsIFTPEventSink)
83 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTTPIndex)
84 0 : NS_INTERFACE_MAP_END
85 :
86 0 : NS_IMPL_CYCLE_COLLECTION(nsHTTPIndex, mInner)
87 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTTPIndex)
88 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTTPIndex)
89 :
90 : NS_IMETHODIMP
91 0 : nsHTTPIndex::GetInterface(const nsIID &anIID, void **aResult )
92 : {
93 0 : if (anIID.Equals(NS_GET_IID(nsIFTPEventSink))) {
94 : // If we don't have a container to store the logged data
95 : // then don't report ourselves back to the caller
96 :
97 0 : if (!mRequestor)
98 0 : return NS_ERROR_NO_INTERFACE;
99 0 : *aResult = static_cast<nsIFTPEventSink*>(this);
100 0 : NS_ADDREF(this);
101 0 : return NS_OK;
102 : }
103 :
104 0 : if (anIID.Equals(NS_GET_IID(nsIPrompt))) {
105 :
106 0 : if (!mRequestor)
107 0 : return NS_ERROR_NO_INTERFACE;
108 :
109 0 : nsCOMPtr<nsPIDOMWindowOuter> aDOMWindow = do_GetInterface(mRequestor);
110 0 : if (!aDOMWindow)
111 0 : return NS_ERROR_NO_INTERFACE;
112 :
113 0 : nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
114 :
115 0 : return wwatch->GetNewPrompter(aDOMWindow, (nsIPrompt**)aResult);
116 : }
117 :
118 0 : if (anIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
119 :
120 0 : if (!mRequestor)
121 0 : return NS_ERROR_NO_INTERFACE;
122 :
123 0 : nsCOMPtr<nsPIDOMWindowOuter> aDOMWindow = do_GetInterface(mRequestor);
124 0 : if (!aDOMWindow)
125 0 : return NS_ERROR_NO_INTERFACE;
126 :
127 0 : nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
128 :
129 0 : return wwatch->GetNewAuthPrompter(aDOMWindow, (nsIAuthPrompt**)aResult);
130 : }
131 :
132 0 : if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
133 :
134 0 : if (!mRequestor)
135 0 : return NS_ERROR_NO_INTERFACE;
136 :
137 0 : nsCOMPtr<nsIProgressEventSink> sink = do_GetInterface(mRequestor);
138 0 : if (!sink)
139 0 : return NS_ERROR_NO_INTERFACE;
140 :
141 0 : *aResult = sink;
142 0 : NS_ADDREF((nsISupports*)*aResult);
143 0 : return NS_OK;
144 : }
145 :
146 0 : return NS_ERROR_NO_INTERFACE;
147 : }
148 :
149 : NS_IMETHODIMP
150 0 : nsHTTPIndex::OnFTPControlLog(bool server, const char *msg)
151 : {
152 0 : NS_ENSURE_TRUE(mRequestor, NS_OK);
153 :
154 0 : nsCOMPtr<nsIGlobalObject> globalObject = do_GetInterface(mRequestor);
155 0 : NS_ENSURE_TRUE(globalObject, NS_OK);
156 :
157 : // We're going to run script via JS_CallFunctionName, so we need an
158 : // AutoEntryScript. This is Gecko specific and not in any spec.
159 : dom::AutoEntryScript aes(globalObject,
160 0 : "nsHTTPIndex OnFTPControlLog");
161 0 : JSContext* cx = aes.cx();
162 :
163 0 : JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
164 0 : NS_ENSURE_TRUE(global, NS_OK);
165 :
166 0 : nsString unicodeMsg;
167 0 : unicodeMsg.AssignWithConversion(msg);
168 0 : JSString* jsMsgStr = JS_NewUCStringCopyZ(cx, unicodeMsg.get());
169 0 : NS_ENSURE_TRUE(jsMsgStr, NS_ERROR_OUT_OF_MEMORY);
170 :
171 0 : JS::AutoValueArray<2> params(cx);
172 0 : params[0].setBoolean(server);
173 0 : params[1].setString(jsMsgStr);
174 :
175 0 : JS::Rooted<JS::Value> val(cx);
176 0 : JS_CallFunctionName(cx,
177 : global,
178 : "OnFTPControlLog",
179 : params,
180 0 : &val);
181 0 : return NS_OK;
182 : }
183 :
184 : NS_IMETHODIMP
185 0 : nsHTTPIndex::SetEncoding(const char *encoding)
186 : {
187 0 : mEncoding = encoding;
188 0 : return(NS_OK);
189 : }
190 :
191 : NS_IMETHODIMP
192 0 : nsHTTPIndex::GetEncoding(char **encoding)
193 : {
194 0 : NS_PRECONDITION(encoding, "null ptr");
195 0 : if (! encoding)
196 0 : return(NS_ERROR_NULL_POINTER);
197 :
198 0 : *encoding = ToNewCString(mEncoding);
199 0 : if (!*encoding)
200 0 : return(NS_ERROR_OUT_OF_MEMORY);
201 :
202 0 : return(NS_OK);
203 : }
204 :
205 : NS_IMETHODIMP
206 0 : nsHTTPIndex::OnStartRequest(nsIRequest *request, nsISupports* aContext)
207 : {
208 : nsresult rv;
209 :
210 0 : mParser = do_CreateInstance(NS_DIRINDEXPARSER_CONTRACTID, &rv);
211 0 : if (NS_FAILED(rv)) return rv;
212 :
213 0 : rv = mParser->SetEncoding(mEncoding.get());
214 0 : if (NS_FAILED(rv)) return rv;
215 :
216 0 : rv = mParser->SetListener(this);
217 0 : if (NS_FAILED(rv)) return rv;
218 :
219 0 : rv = mParser->OnStartRequest(request,aContext);
220 0 : if (NS_FAILED(rv)) return rv;
221 :
222 : // This should only run once...
223 : // Unless we don't have a container to start with
224 : // (ie called from bookmarks as an rdf datasource)
225 0 : if (mBindToGlobalObject && mRequestor) {
226 0 : mBindToGlobalObject = false;
227 :
228 0 : nsCOMPtr<nsIGlobalObject> globalObject = do_GetInterface(mRequestor);
229 0 : NS_ENSURE_TRUE(globalObject, NS_ERROR_FAILURE);
230 :
231 : // We might run script via JS_SetProperty, so we need an AutoEntryScript.
232 : // This is Gecko specific and not in any spec.
233 : dom::AutoEntryScript aes(globalObject,
234 0 : "nsHTTPIndex set HTTPIndex property");
235 0 : JSContext* cx = aes.cx();
236 :
237 0 : JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
238 :
239 : // Using XPConnect, wrap the HTTP index object...
240 : static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
241 0 : nsCOMPtr<nsIXPConnect> xpc(do_GetService(kXPConnectCID, &rv));
242 0 : if (NS_FAILED(rv)) return rv;
243 :
244 0 : JS::Rooted<JSObject*> jsobj(cx);
245 0 : rv = xpc->WrapNative(cx,
246 : global,
247 : static_cast<nsIHTTPIndex*>(this),
248 : NS_GET_IID(nsIHTTPIndex),
249 0 : jsobj.address());
250 :
251 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index");
252 0 : if (NS_FAILED(rv)) return rv;
253 :
254 0 : NS_ASSERTION(jsobj,
255 : "unable to get jsobj from xpconnect wrapper");
256 0 : if (!jsobj) return NS_ERROR_UNEXPECTED;
257 :
258 0 : JS::Rooted<JS::Value> jslistener(cx, JS::ObjectValue(*jsobj));
259 :
260 : // ...and stuff it into the global context
261 0 : bool ok = JS_SetProperty(cx, global, "HTTPIndex", jslistener);
262 0 : NS_ASSERTION(ok, "unable to set Listener property");
263 0 : if (!ok)
264 0 : return NS_ERROR_FAILURE;
265 : }
266 :
267 0 : if (!aContext) {
268 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
269 0 : NS_ASSERTION(channel, "request should be a channel");
270 :
271 : // lets hijack the notifications:
272 0 : channel->SetNotificationCallbacks(this);
273 :
274 : // now create the top most resource
275 0 : nsCOMPtr<nsIURI> uri;
276 0 : channel->GetURI(getter_AddRefs(uri));
277 :
278 0 : nsAutoCString entryuriC;
279 0 : rv = uri->GetSpec(entryuriC);
280 0 : if (NS_FAILED(rv)) return rv;
281 :
282 0 : nsCOMPtr<nsIRDFResource> entry;
283 0 : rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
284 :
285 0 : NS_ConvertUTF8toUTF16 uriUnicode(entryuriC);
286 :
287 0 : nsCOMPtr<nsIRDFLiteral> URLVal;
288 0 : rv = mDirRDF->GetLiteral(uriUnicode.get(), getter_AddRefs(URLVal));
289 :
290 0 : Assert(entry, kNC_URL, URLVal, true);
291 0 : mDirectory = do_QueryInterface(entry);
292 : }
293 : else
294 : {
295 : // Get the directory from the context
296 0 : mDirectory = do_QueryInterface(aContext);
297 : }
298 :
299 0 : if (!mDirectory) {
300 0 : request->Cancel(NS_BINDING_ABORTED);
301 0 : return NS_BINDING_ABORTED;
302 : }
303 :
304 : // Mark the directory as "loading"
305 0 : rv = Assert(mDirectory, kNC_Loading,
306 0 : kTrueLiteral, true);
307 0 : if (NS_FAILED(rv)) return rv;
308 :
309 0 : return NS_OK;
310 : }
311 :
312 :
313 : NS_IMETHODIMP
314 0 : nsHTTPIndex::OnStopRequest(nsIRequest *request,
315 : nsISupports* aContext,
316 : nsresult aStatus)
317 : {
318 : // If mDirectory isn't set, then we should just bail. Either an
319 : // error occurred and OnStartRequest() never got called, or
320 : // something exploded in OnStartRequest().
321 0 : if (! mDirectory)
322 0 : return NS_BINDING_ABORTED;
323 :
324 0 : mParser->OnStopRequest(request,aContext,aStatus);
325 :
326 : nsresult rv;
327 :
328 0 : nsXPIDLCString commentStr;
329 0 : mParser->GetComment(getter_Copies(commentStr));
330 :
331 0 : nsCOMPtr<nsIRDFLiteral> comment;
332 0 : rv = mDirRDF->GetLiteral(NS_ConvertASCIItoUTF16(commentStr).get(), getter_AddRefs(comment));
333 0 : if (NS_FAILED(rv)) return rv;
334 :
335 0 : rv = Assert(mDirectory, kNC_Comment, comment, true);
336 0 : if (NS_FAILED(rv)) return rv;
337 :
338 : // hack: Remove the 'loading' annotation (ignore errors)
339 0 : AddElement(mDirectory, kNC_Loading, kTrueLiteral);
340 :
341 0 : return NS_OK;
342 : }
343 :
344 :
345 : NS_IMETHODIMP
346 0 : nsHTTPIndex::OnDataAvailable(nsIRequest *request,
347 : nsISupports* aContext,
348 : nsIInputStream* aStream,
349 : uint64_t aSourceOffset,
350 : uint32_t aCount)
351 : {
352 : // If mDirectory isn't set, then we should just bail. Either an
353 : // error occurred and OnStartRequest() never got called, or
354 : // something exploded in OnStartRequest().
355 0 : if (! mDirectory)
356 0 : return NS_BINDING_ABORTED;
357 :
358 0 : return mParser->OnDataAvailable(request, mDirectory, aStream, aSourceOffset, aCount);
359 : }
360 :
361 :
362 : nsresult
363 0 : nsHTTPIndex::OnIndexAvailable(nsIRequest* aRequest, nsISupports *aContext,
364 : nsIDirIndex* aIndex)
365 : {
366 0 : nsCOMPtr<nsIRDFResource> parentRes = do_QueryInterface(aContext);
367 0 : if (!parentRes) {
368 0 : NS_ERROR("Could not obtain parent resource");
369 0 : return(NS_ERROR_UNEXPECTED);
370 : }
371 :
372 : const char* baseStr;
373 0 : parentRes->GetValueConst(&baseStr);
374 0 : if (! baseStr) {
375 0 : NS_ERROR("Could not reconstruct base uri");
376 0 : return NS_ERROR_UNEXPECTED;
377 : }
378 :
379 : // we found the filename; construct a resource for its entry
380 0 : nsAutoCString entryuriC(baseStr);
381 :
382 0 : nsXPIDLCString filename;
383 0 : nsresult rv = aIndex->GetLocation(getter_Copies(filename));
384 0 : if (NS_FAILED(rv)) return rv;
385 0 : entryuriC.Append(filename);
386 :
387 : // if its a directory, make sure it ends with a trailing slash.
388 : uint32_t type;
389 0 : rv = aIndex->GetType(&type);
390 0 : if (NS_FAILED(rv))
391 0 : return rv;
392 :
393 0 : bool isDirType = (type == nsIDirIndex::TYPE_DIRECTORY);
394 0 : if (isDirType && entryuriC.Last() != '/') {
395 0 : entryuriC.Append('/');
396 : }
397 :
398 0 : nsCOMPtr<nsIRDFResource> entry;
399 0 : rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
400 :
401 : // At this point, we'll (hopefully) have found the filename and
402 : // constructed a resource for it, stored in entry. So now take a
403 : // second pass through the values and add as statements to the RDF
404 : // datasource.
405 :
406 0 : if (entry && NS_SUCCEEDED(rv)) {
407 0 : nsCOMPtr<nsIRDFLiteral> lit;
408 0 : nsString str;
409 :
410 0 : str.AssignWithConversion(entryuriC.get());
411 :
412 0 : rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit));
413 :
414 0 : if (NS_SUCCEEDED(rv)) {
415 0 : rv = Assert(entry, kNC_URL, lit, true);
416 0 : if (NS_FAILED(rv)) return rv;
417 :
418 0 : nsXPIDLString xpstr;
419 :
420 : // description
421 0 : rv = aIndex->GetDescription(getter_Copies(xpstr));
422 0 : if (NS_FAILED(rv)) return rv;
423 0 : if (xpstr.Last() == '/')
424 0 : xpstr.Truncate(xpstr.Length() - 1);
425 :
426 0 : rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit));
427 0 : if (NS_FAILED(rv)) return rv;
428 0 : rv = Assert(entry, kNC_Description, lit, true);
429 0 : if (NS_FAILED(rv)) return rv;
430 :
431 : // contentlength
432 : int64_t size;
433 0 : rv = aIndex->GetSize(&size);
434 0 : if (NS_FAILED(rv)) return rv;
435 0 : int64_t minus1 = UINT64_MAX;
436 0 : if (size != minus1) {
437 0 : int32_t intSize = int32_t(size);
438 : // XXX RDF should support 64 bit integers (bug 240160)
439 0 : nsCOMPtr<nsIRDFInt> val;
440 0 : rv = mDirRDF->GetIntLiteral(intSize, getter_AddRefs(val));
441 0 : if (NS_FAILED(rv)) return rv;
442 0 : rv = Assert(entry, kNC_ContentLength, val, true);
443 0 : if (NS_FAILED(rv)) return rv;
444 : }
445 :
446 : // lastmodified
447 : PRTime tm;
448 0 : rv = aIndex->GetLastModified(&tm);
449 0 : if (NS_FAILED(rv)) return rv;
450 0 : if (tm != -1) {
451 0 : nsCOMPtr<nsIRDFDate> val;
452 0 : rv = mDirRDF->GetDateLiteral(tm, getter_AddRefs(val));
453 0 : if (NS_FAILED(rv)) return rv;
454 0 : rv = Assert(entry, kNC_LastModified, val, true);
455 : }
456 :
457 : // filetype
458 : uint32_t type;
459 0 : rv = aIndex->GetType(&type);
460 0 : switch (type) {
461 : case nsIDirIndex::TYPE_UNKNOWN:
462 0 : rv = mDirRDF->GetLiteral(u"UNKNOWN", getter_AddRefs(lit));
463 0 : break;
464 : case nsIDirIndex::TYPE_DIRECTORY:
465 0 : rv = mDirRDF->GetLiteral(u"DIRECTORY", getter_AddRefs(lit));
466 0 : break;
467 : case nsIDirIndex::TYPE_FILE:
468 0 : rv = mDirRDF->GetLiteral(u"FILE", getter_AddRefs(lit));
469 0 : break;
470 : case nsIDirIndex::TYPE_SYMLINK:
471 0 : rv = mDirRDF->GetLiteral(u"SYMLINK", getter_AddRefs(lit));
472 0 : break;
473 : }
474 :
475 0 : if (NS_FAILED(rv)) return rv;
476 0 : rv = Assert(entry, kNC_FileType, lit, true);
477 0 : if (NS_FAILED(rv)) return rv;
478 : }
479 :
480 : // Since the definition of a directory depends on the protocol, we would have
481 : // to do string comparisons all the time.
482 : // But we're told if we're a container right here - so save that fact
483 0 : if (isDirType)
484 0 : Assert(entry, kNC_IsContainer, kTrueLiteral, true);
485 : else
486 0 : Assert(entry, kNC_IsContainer, kFalseLiteral, true);
487 :
488 : // instead of
489 : // rv = Assert(parentRes, kNC_Child, entry, true);
490 : // if (NS_FAILED(rv)) return rv;
491 : // defer insertion onto a timer so that the UI isn't starved
492 0 : AddElement(parentRes, kNC_Child, entry);
493 : }
494 :
495 0 : return rv;
496 : }
497 :
498 : nsresult
499 0 : nsHTTPIndex::OnInformationAvailable(nsIRequest *aRequest,
500 : nsISupports *aCtxt,
501 : const nsAString& aInfo) {
502 0 : return NS_ERROR_NOT_IMPLEMENTED;
503 : }
504 :
505 : //----------------------------------------------------------------------
506 : //
507 : // nsHTTPIndex implementation
508 : //
509 :
510 0 : nsHTTPIndex::nsHTTPIndex()
511 : : mBindToGlobalObject(true),
512 0 : mRequestor(nullptr)
513 : {
514 0 : }
515 :
516 :
517 0 : nsHTTPIndex::nsHTTPIndex(nsIInterfaceRequestor* aRequestor)
518 : : mBindToGlobalObject(true),
519 0 : mRequestor(aRequestor)
520 : {
521 0 : }
522 :
523 :
524 0 : nsHTTPIndex::~nsHTTPIndex()
525 : {
526 : // note: these are NOT statics due to the native of nsHTTPIndex
527 : // where it may or may not be treated as a singleton
528 :
529 0 : if (mTimer)
530 : {
531 : // be sure to cancel the timer, as it holds a
532 : // weak reference back to nsHTTPIndex
533 0 : mTimer->Cancel();
534 0 : mTimer = nullptr;
535 : }
536 :
537 0 : mConnectionList = nullptr;
538 0 : mNodeList = nullptr;
539 :
540 0 : if (mDirRDF)
541 : {
542 : // UnregisterDataSource() may fail; just ignore errors
543 0 : mDirRDF->UnregisterDataSource(this);
544 : }
545 0 : }
546 :
547 :
548 :
549 : nsresult
550 0 : nsHTTPIndex::CommonInit()
551 : {
552 0 : nsresult rv = NS_OK;
553 :
554 : // set initial/default encoding to windows-1252 (not UTF-8)
555 0 : mEncoding = "windows-1252";
556 :
557 0 : mDirRDF = do_GetService(kRDFServiceCID, &rv);
558 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
559 0 : if (NS_FAILED(rv)) {
560 0 : return(rv);
561 : }
562 :
563 0 : mInner = do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource", &rv);
564 :
565 0 : if (NS_FAILED(rv))
566 0 : return rv;
567 :
568 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
569 0 : getter_AddRefs(kNC_Child));
570 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"),
571 0 : getter_AddRefs(kNC_Loading));
572 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Comment"),
573 0 : getter_AddRefs(kNC_Comment));
574 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"),
575 0 : getter_AddRefs(kNC_URL));
576 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
577 0 : getter_AddRefs(kNC_Description));
578 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"),
579 0 : getter_AddRefs(kNC_ContentLength));
580 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"),
581 0 : getter_AddRefs(kNC_LastModified));
582 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Type"),
583 0 : getter_AddRefs(kNC_ContentType));
584 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "File-Type"),
585 0 : getter_AddRefs(kNC_FileType));
586 0 : mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsContainer"),
587 0 : getter_AddRefs(kNC_IsContainer));
588 :
589 0 : rv = mDirRDF->GetLiteral(u"true", getter_AddRefs(kTrueLiteral));
590 0 : if (NS_FAILED(rv)) return(rv);
591 0 : rv = mDirRDF->GetLiteral(u"false", getter_AddRefs(kFalseLiteral));
592 0 : if (NS_FAILED(rv)) return(rv);
593 :
594 0 : mConnectionList = nsArray::Create();
595 :
596 : // note: don't register DS here
597 0 : return rv;
598 : }
599 :
600 :
601 : nsresult
602 0 : nsHTTPIndex::Init()
603 : {
604 : nsresult rv;
605 :
606 : // set initial/default encoding to windows-1252 (not UTF-8)
607 0 : mEncoding = "windows-1252";
608 :
609 0 : rv = CommonInit();
610 0 : if (NS_FAILED(rv)) return(rv);
611 :
612 : // (do this last) register this as a named data source with the RDF service
613 0 : rv = mDirRDF->RegisterDataSource(this, false);
614 0 : if (NS_FAILED(rv)) return(rv);
615 :
616 0 : return(NS_OK);
617 : }
618 :
619 :
620 :
621 : nsresult
622 0 : nsHTTPIndex::Init(nsIURI* aBaseURL)
623 : {
624 0 : NS_PRECONDITION(aBaseURL != nullptr, "null ptr");
625 0 : if (! aBaseURL)
626 0 : return NS_ERROR_NULL_POINTER;
627 :
628 : nsresult rv;
629 :
630 0 : rv = CommonInit();
631 0 : if (NS_FAILED(rv)) return(rv);
632 :
633 : // note: don't register DS here (singleton case)
634 :
635 0 : rv = aBaseURL->GetSpec(mBaseURL);
636 0 : if (NS_FAILED(rv)) return rv;
637 :
638 : // Mark the base url as a container
639 0 : nsCOMPtr<nsIRDFResource> baseRes;
640 0 : mDirRDF->GetResource(mBaseURL, getter_AddRefs(baseRes));
641 0 : Assert(baseRes, kNC_IsContainer, kTrueLiteral, true);
642 :
643 0 : return NS_OK;
644 : }
645 :
646 :
647 :
648 : nsresult
649 0 : nsHTTPIndex::Create(nsIURI* aBaseURL, nsIInterfaceRequestor* aRequestor,
650 : nsIHTTPIndex** aResult)
651 : {
652 0 : *aResult = nullptr;
653 :
654 0 : nsHTTPIndex* result = new nsHTTPIndex(aRequestor);
655 0 : nsresult rv = result->Init(aBaseURL);
656 0 : if (NS_SUCCEEDED(rv))
657 : {
658 0 : NS_ADDREF(result);
659 0 : *aResult = result;
660 : }
661 : else
662 : {
663 0 : delete result;
664 : }
665 0 : return rv;
666 : }
667 :
668 : NS_IMETHODIMP
669 0 : nsHTTPIndex::GetBaseURL(char** _result)
670 : {
671 0 : *_result = ToNewCString(mBaseURL);
672 0 : if (! *_result)
673 0 : return NS_ERROR_OUT_OF_MEMORY;
674 :
675 0 : return NS_OK;
676 : }
677 :
678 : NS_IMETHODIMP
679 0 : nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result)
680 : {
681 0 : NS_ADDREF(*_result = this);
682 0 : return NS_OK;
683 : }
684 :
685 : // This function finds the destination when following a given nsIRDFResource
686 : // If the resource has a URL attribute, we use that. If not, just use
687 : // the uri.
688 : //
689 : // Do NOT try to get the destination of a uri in any other way
690 0 : void nsHTTPIndex::GetDestination(nsIRDFResource* r, nsXPIDLCString& dest) {
691 : // First try the URL attribute
692 0 : nsCOMPtr<nsIRDFNode> node;
693 :
694 0 : GetTarget(r, kNC_URL, true, getter_AddRefs(node));
695 0 : nsCOMPtr<nsIRDFLiteral> url;
696 :
697 0 : if (node)
698 0 : url = do_QueryInterface(node);
699 :
700 0 : if (!url) {
701 : const char* temp;
702 0 : r->GetValueConst(&temp);
703 0 : dest.Adopt(temp ? strdup(temp) : 0);
704 : } else {
705 : const char16_t* uri;
706 0 : url->GetValueConst(&uri);
707 0 : dest.Adopt(ToNewUTF8String(nsDependentString(uri)));
708 : }
709 0 : }
710 :
711 : // rjc: isWellknownContainerURI() decides whether a URI is a container for which,
712 : // when asked (say, by the template builder), we'll make a network connection
713 : // to get its contents. For the moment, all we speak is ftp:// URLs, even though
714 : // a) we can get "http-index" mimetypes for really anything
715 : // b) we could easily handle file:// URLs here
716 : // Q: Why don't we?
717 : // A: The file system datasource ("rdf:file"); at some point, the two
718 : // should be perhaps united. Until then, we can't aggregate both
719 : // "rdf:file" and "http-index" (such as with bookmarks) because we'd
720 : // get double the # of answers we really want... also, "rdf:file" is
721 : // less expensive in terms of both memory usage as well as speed
722 :
723 :
724 :
725 : // We use an rdf attribute to mark if this is a container or not.
726 : // Note that we still have to do string comparisons as a fallback
727 : // because stuff like the personal toolbar and bookmarks check whether
728 : // a URL is a container, and we have no attribute in that case.
729 : bool
730 0 : nsHTTPIndex::isWellknownContainerURI(nsIRDFResource *r)
731 : {
732 0 : nsCOMPtr<nsIRDFNode> node;
733 0 : GetTarget(r, kNC_IsContainer, true, getter_AddRefs(node));
734 0 : if (node) {
735 : bool isContainerFlag;
736 0 : if (NS_SUCCEEDED(node->EqualsNode(kTrueLiteral, &isContainerFlag)))
737 0 : return isContainerFlag;
738 : }
739 :
740 0 : nsXPIDLCString uri;
741 0 : GetDestination(r, uri);
742 0 : return uri.get() && !strncmp(uri, kFTPProtocol, sizeof(kFTPProtocol) - 1) &&
743 0 : (uri.Last() == '/');
744 : }
745 :
746 :
747 : NS_IMETHODIMP
748 0 : nsHTTPIndex::GetURI(char * *uri)
749 : {
750 0 : NS_PRECONDITION(uri != nullptr, "null ptr");
751 0 : if (! uri)
752 0 : return(NS_ERROR_NULL_POINTER);
753 :
754 0 : if ((*uri = strdup("rdf:httpindex")) == nullptr)
755 0 : return(NS_ERROR_OUT_OF_MEMORY);
756 :
757 0 : return(NS_OK);
758 : }
759 :
760 :
761 :
762 : NS_IMETHODIMP
763 0 : nsHTTPIndex::GetSource(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue,
764 : nsIRDFResource **_retval)
765 : {
766 0 : nsresult rv = NS_ERROR_UNEXPECTED;
767 :
768 0 : *_retval = nullptr;
769 :
770 0 : if (mInner)
771 : {
772 0 : rv = mInner->GetSource(aProperty, aTarget, aTruthValue, _retval);
773 : }
774 0 : return(rv);
775 : }
776 :
777 : NS_IMETHODIMP
778 0 : nsHTTPIndex::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue,
779 : nsISimpleEnumerator **_retval)
780 : {
781 0 : nsresult rv = NS_ERROR_UNEXPECTED;
782 :
783 0 : if (mInner)
784 : {
785 0 : rv = mInner->GetSources(aProperty, aTarget, aTruthValue, _retval);
786 : }
787 : else
788 : {
789 0 : rv = NS_NewEmptyEnumerator(_retval);
790 : }
791 0 : return(rv);
792 : }
793 :
794 : NS_IMETHODIMP
795 0 : nsHTTPIndex::GetTarget(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue,
796 : nsIRDFNode **_retval)
797 : {
798 0 : nsresult rv = NS_ERROR_UNEXPECTED;
799 :
800 0 : *_retval = nullptr;
801 :
802 0 : if ((aTruthValue) && (aProperty == kNC_Child) && isWellknownContainerURI(aSource))
803 : {
804 : // fake out the generic builder (i.e. return anything in this case)
805 : // so that search containers never appear to be empty
806 0 : NS_IF_ADDREF(aSource);
807 0 : *_retval = aSource;
808 0 : return(NS_OK);
809 : }
810 :
811 0 : if (mInner)
812 : {
813 0 : rv = mInner->GetTarget(aSource, aProperty, aTruthValue, _retval);
814 : }
815 0 : return(rv);
816 : }
817 :
818 : NS_IMETHODIMP
819 0 : nsHTTPIndex::GetTargets(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue,
820 : nsISimpleEnumerator **_retval)
821 : {
822 0 : nsresult rv = NS_ERROR_UNEXPECTED;
823 :
824 0 : if (mInner)
825 : {
826 0 : rv = mInner->GetTargets(aSource, aProperty, aTruthValue, _retval);
827 : }
828 : else
829 : {
830 0 : rv = NS_NewEmptyEnumerator(_retval);
831 : }
832 :
833 0 : if ((aProperty == kNC_Child) && isWellknownContainerURI(aSource))
834 : {
835 0 : bool doNetworkRequest = true;
836 0 : if (NS_SUCCEEDED(rv) && (_retval))
837 : {
838 : // check and see if we already have data for the search in question;
839 : // if we do, don't bother doing the search again
840 : bool hasResults;
841 0 : if (NS_SUCCEEDED((*_retval)->HasMoreElements(&hasResults)) &&
842 : hasResults)
843 0 : doNetworkRequest = false;
844 : }
845 :
846 : // Note: if we need to do a network request, do it out-of-band
847 : // (because the XUL template builder isn't re-entrant)
848 : // by using a global connection list and an immediately-firing timer
849 0 : if (doNetworkRequest && mConnectionList)
850 : {
851 : uint32_t connectionIndex;
852 0 : nsresult idx_rv = mConnectionList->IndexOf(0, aSource, &connectionIndex);
853 0 : if (NS_FAILED(idx_rv))
854 : {
855 : // add aSource into list of connections to make
856 0 : mConnectionList->AppendElement(aSource, /*weak =*/ false);
857 :
858 : // if we don't have a timer about to fire, create one
859 : // which should fire as soon as possible (out-of-band)
860 0 : if (!mTimer)
861 : {
862 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
863 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
864 0 : if (NS_SUCCEEDED(rv))
865 : {
866 0 : mTimer->InitWithNamedFuncCallback(
867 : nsHTTPIndex::FireTimer,
868 : this,
869 : 1,
870 : nsITimer::TYPE_ONE_SHOT,
871 0 : "nsHTTPIndex::GetTargets");
872 : // Note: don't addref "this" as we'll cancel the
873 : // timer in the httpIndex destructor
874 : }
875 : }
876 : }
877 : }
878 : }
879 :
880 0 : return(rv);
881 : }
882 :
883 :
884 : nsresult
885 0 : nsHTTPIndex::AddElement(nsIRDFResource *parent, nsIRDFResource *prop, nsIRDFNode *child)
886 : {
887 : nsresult rv;
888 :
889 0 : if (!mNodeList)
890 : {
891 0 : mNodeList = nsArray::Create();
892 : }
893 :
894 : // order required: parent, prop, then child
895 0 : mNodeList->AppendElement(parent, /*weak =*/ false);
896 0 : mNodeList->AppendElement(prop, /*weak =*/ false);
897 0 : mNodeList->AppendElement(child, /*weak = */ false);
898 :
899 0 : if (!mTimer)
900 : {
901 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
902 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
903 0 : if (NS_FAILED(rv)) return(rv);
904 :
905 0 : mTimer->InitWithNamedFuncCallback(nsHTTPIndex::FireTimer,
906 : this,
907 : 1,
908 : nsITimer::TYPE_ONE_SHOT,
909 0 : "nsHTTPIndex::AddElement");
910 : // Note: don't addref "this" as we'll cancel the
911 : // timer in the httpIndex destructor
912 : }
913 :
914 0 : return(NS_OK);
915 : }
916 :
917 : void
918 0 : nsHTTPIndex::FireTimer(nsITimer* aTimer, void* aClosure)
919 : {
920 0 : nsHTTPIndex *httpIndex = static_cast<nsHTTPIndex *>(aClosure);
921 0 : if (!httpIndex)
922 0 : return;
923 :
924 : // don't return out of this loop as mTimer may need to be cancelled afterwards
925 0 : uint32_t numItems = 0;
926 0 : if (httpIndex->mConnectionList)
927 : {
928 0 : httpIndex->mConnectionList->GetLength(&numItems);
929 0 : if (numItems > 0)
930 : {
931 : nsCOMPtr<nsIRDFResource> source =
932 0 : do_QueryElementAt(httpIndex->mConnectionList, 0);
933 0 : httpIndex->mConnectionList->RemoveElementAt(0);
934 :
935 0 : nsXPIDLCString uri;
936 0 : if (source) {
937 0 : httpIndex->GetDestination(source, uri);
938 : }
939 :
940 0 : if (!uri) {
941 0 : NS_ERROR("Could not reconstruct uri");
942 0 : return;
943 : }
944 :
945 0 : nsresult rv = NS_OK;
946 0 : nsCOMPtr<nsIURI> url;
947 :
948 0 : rv = NS_NewURI(getter_AddRefs(url), uri.get());
949 0 : nsCOMPtr<nsIChannel> channel;
950 0 : if (NS_SUCCEEDED(rv) && (url)) {
951 0 : rv = NS_NewChannel(getter_AddRefs(channel),
952 : url,
953 : nsContentUtils::GetSystemPrincipal(),
954 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
955 0 : nsIContentPolicy::TYPE_OTHER);
956 : }
957 0 : if (NS_SUCCEEDED(rv) && (channel)) {
958 0 : channel->SetNotificationCallbacks(httpIndex);
959 0 : rv = channel->AsyncOpen2(httpIndex);
960 : }
961 : }
962 : }
963 :
964 0 : if (httpIndex->mNodeList)
965 : {
966 0 : httpIndex->mNodeList->GetLength(&numItems);
967 0 : if (numItems > 0)
968 : {
969 : // account for order required: src, prop, then target
970 0 : numItems /=3;
971 0 : if (numItems > 10)
972 0 : numItems = 10;
973 :
974 : int32_t loop;
975 0 : for (loop=0; loop<(int32_t)numItems; loop++)
976 : {
977 0 : nsCOMPtr<nsIRDFResource> src = do_QueryElementAt(httpIndex->mNodeList, 0);
978 0 : httpIndex->mNodeList->RemoveElementAt(0);
979 :
980 0 : nsCOMPtr<nsIRDFResource> prop = do_QueryElementAt(httpIndex->mNodeList, 0);
981 0 : httpIndex->mNodeList->RemoveElementAt(0);
982 :
983 0 : nsCOMPtr<nsIRDFNode> target = do_QueryElementAt(httpIndex->mNodeList, 0);
984 0 : httpIndex->mNodeList->RemoveElementAt(0);
985 :
986 0 : if (src && prop && target)
987 : {
988 0 : if (prop.get() == httpIndex->kNC_Loading)
989 : {
990 0 : httpIndex->Unassert(src, prop, target);
991 : }
992 : else
993 : {
994 0 : httpIndex->Assert(src, prop, target, true);
995 : }
996 : }
997 : }
998 : }
999 : }
1000 :
1001 0 : bool refireTimer = false;
1002 : // check both lists to see if the timer needs to continue firing
1003 0 : if (httpIndex->mConnectionList)
1004 : {
1005 0 : httpIndex->mConnectionList->GetLength(&numItems);
1006 0 : if (numItems > 0)
1007 : {
1008 0 : refireTimer = true;
1009 : }
1010 : else
1011 : {
1012 0 : httpIndex->mConnectionList->Clear();
1013 : }
1014 : }
1015 :
1016 0 : if (httpIndex->mNodeList)
1017 : {
1018 0 : httpIndex->mNodeList->GetLength(&numItems);
1019 0 : if (numItems > 0)
1020 : {
1021 0 : refireTimer = true;
1022 : }
1023 : else
1024 : {
1025 0 : httpIndex->mNodeList->Clear();
1026 : }
1027 : }
1028 :
1029 : // be sure to cancel the timer, as it holds a
1030 : // weak reference back to nsHTTPIndex
1031 0 : httpIndex->mTimer->Cancel();
1032 0 : httpIndex->mTimer = nullptr;
1033 :
1034 : // after firing off any/all of the connections be sure
1035 : // to cancel the timer if we don't need to refire it
1036 0 : if (refireTimer)
1037 : {
1038 0 : httpIndex->mTimer = do_CreateInstance("@mozilla.org/timer;1");
1039 0 : if (httpIndex->mTimer)
1040 : {
1041 0 : httpIndex->mTimer->InitWithNamedFuncCallback(nsHTTPIndex::FireTimer,
1042 : aClosure,
1043 : 10,
1044 : nsITimer::TYPE_ONE_SHOT,
1045 0 : "nsHTTPIndex::FireTimer");
1046 : // Note: don't addref "this" as we'll cancel the
1047 : // timer in the httpIndex destructor
1048 : }
1049 : }
1050 : }
1051 :
1052 : NS_IMETHODIMP
1053 0 : nsHTTPIndex::Assert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget,
1054 : bool aTruthValue)
1055 : {
1056 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1057 0 : if (mInner)
1058 : {
1059 0 : rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
1060 : }
1061 0 : return(rv);
1062 : }
1063 :
1064 : NS_IMETHODIMP
1065 0 : nsHTTPIndex::Unassert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget)
1066 : {
1067 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1068 0 : if (mInner)
1069 : {
1070 0 : rv = mInner->Unassert(aSource, aProperty, aTarget);
1071 : }
1072 0 : return(rv);
1073 : }
1074 :
1075 : NS_IMETHODIMP
1076 0 : nsHTTPIndex::Change(nsIRDFResource *aSource, nsIRDFResource *aProperty,
1077 : nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget)
1078 : {
1079 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1080 0 : if (mInner)
1081 : {
1082 0 : rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
1083 : }
1084 0 : return(rv);
1085 : }
1086 :
1087 : NS_IMETHODIMP
1088 0 : nsHTTPIndex::Move(nsIRDFResource *aOldSource, nsIRDFResource *aNewSource,
1089 : nsIRDFResource *aProperty, nsIRDFNode *aTarget)
1090 : {
1091 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1092 0 : if (mInner)
1093 : {
1094 0 : rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
1095 : }
1096 0 : return(rv);
1097 : }
1098 :
1099 : NS_IMETHODIMP
1100 0 : nsHTTPIndex::HasAssertion(nsIRDFResource *aSource, nsIRDFResource *aProperty,
1101 : nsIRDFNode *aTarget, bool aTruthValue, bool *_retval)
1102 : {
1103 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1104 0 : if (mInner)
1105 : {
1106 0 : rv = mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, _retval);
1107 : }
1108 0 : return(rv);
1109 : }
1110 :
1111 : NS_IMETHODIMP
1112 0 : nsHTTPIndex::AddObserver(nsIRDFObserver *aObserver)
1113 : {
1114 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1115 0 : if (mInner)
1116 : {
1117 0 : rv = mInner->AddObserver(aObserver);
1118 : }
1119 0 : return(rv);
1120 : }
1121 :
1122 : NS_IMETHODIMP
1123 0 : nsHTTPIndex::RemoveObserver(nsIRDFObserver *aObserver)
1124 : {
1125 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1126 0 : if (mInner)
1127 : {
1128 0 : rv = mInner->RemoveObserver(aObserver);
1129 : }
1130 0 : return(rv);
1131 : }
1132 :
1133 : NS_IMETHODIMP
1134 0 : nsHTTPIndex::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
1135 : {
1136 0 : if (!mInner) {
1137 0 : *result = false;
1138 0 : return NS_OK;
1139 : }
1140 0 : return mInner->HasArcIn(aNode, aArc, result);
1141 : }
1142 :
1143 : NS_IMETHODIMP
1144 0 : nsHTTPIndex::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
1145 : {
1146 0 : if (aArc == kNC_Child && isWellknownContainerURI(aSource)) {
1147 0 : *result = true;
1148 0 : return NS_OK;
1149 : }
1150 :
1151 0 : if (mInner) {
1152 0 : return mInner->HasArcOut(aSource, aArc, result);
1153 : }
1154 :
1155 0 : *result = false;
1156 0 : return NS_OK;
1157 : }
1158 :
1159 : NS_IMETHODIMP
1160 0 : nsHTTPIndex::ArcLabelsIn(nsIRDFNode *aNode, nsISimpleEnumerator **_retval)
1161 : {
1162 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1163 0 : if (mInner)
1164 : {
1165 0 : rv = mInner->ArcLabelsIn(aNode, _retval);
1166 : }
1167 0 : return(rv);
1168 : }
1169 :
1170 : NS_IMETHODIMP
1171 0 : nsHTTPIndex::ArcLabelsOut(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
1172 : {
1173 0 : *_retval = nullptr;
1174 :
1175 0 : nsCOMPtr<nsISimpleEnumerator> child, anonArcs;
1176 0 : if (isWellknownContainerURI(aSource))
1177 : {
1178 0 : NS_NewSingletonEnumerator(getter_AddRefs(child), kNC_Child);
1179 : }
1180 :
1181 0 : if (mInner)
1182 : {
1183 0 : mInner->ArcLabelsOut(aSource, getter_AddRefs(anonArcs));
1184 : }
1185 :
1186 0 : return NS_NewUnionEnumerator(_retval, child, anonArcs);
1187 : }
1188 :
1189 : NS_IMETHODIMP
1190 0 : nsHTTPIndex::GetAllResources(nsISimpleEnumerator **_retval)
1191 : {
1192 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1193 0 : if (mInner)
1194 : {
1195 0 : rv = mInner->GetAllResources(_retval);
1196 : }
1197 0 : return(rv);
1198 : }
1199 :
1200 : NS_IMETHODIMP
1201 0 : nsHTTPIndex::IsCommandEnabled(nsISupports *aSources, nsIRDFResource *aCommand,
1202 : nsISupports *aArguments, bool *_retval)
1203 : {
1204 0 : return NS_ERROR_NOT_IMPLEMENTED;
1205 : }
1206 :
1207 : NS_IMETHODIMP
1208 0 : nsHTTPIndex::DoCommand(nsISupports *aSources, nsIRDFResource *aCommand,
1209 : nsISupports *aArguments)
1210 : {
1211 0 : return NS_ERROR_NOT_IMPLEMENTED;
1212 : }
1213 :
1214 : NS_IMETHODIMP
1215 0 : nsHTTPIndex::BeginUpdateBatch()
1216 : {
1217 0 : return mInner->BeginUpdateBatch();
1218 : }
1219 :
1220 : NS_IMETHODIMP
1221 0 : nsHTTPIndex::EndUpdateBatch()
1222 : {
1223 0 : return mInner->EndUpdateBatch();
1224 : }
1225 :
1226 : NS_IMETHODIMP
1227 0 : nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
1228 : {
1229 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1230 0 : if (mInner)
1231 : {
1232 0 : rv = mInner->GetAllCmds(aSource, _retval);
1233 : }
1234 0 : return(rv);
1235 : }
1236 :
1237 :
1238 : //----------------------------------------------------------------------
1239 : //
1240 : // nsDirectoryViewerFactory
1241 : //
1242 0 : nsDirectoryViewerFactory::nsDirectoryViewerFactory()
1243 : {
1244 0 : }
1245 :
1246 :
1247 :
1248 0 : nsDirectoryViewerFactory::~nsDirectoryViewerFactory()
1249 : {
1250 0 : }
1251 :
1252 :
1253 0 : NS_IMPL_ISUPPORTS(nsDirectoryViewerFactory, nsIDocumentLoaderFactory)
1254 :
1255 :
1256 :
1257 : NS_IMETHODIMP
1258 0 : nsDirectoryViewerFactory::CreateInstance(const char *aCommand,
1259 : nsIChannel* aChannel,
1260 : nsILoadGroup* aLoadGroup,
1261 : const nsACString& aContentType,
1262 : nsIDocShell* aContainer,
1263 : nsISupports* aExtraInfo,
1264 : nsIStreamListener** aDocListenerResult,
1265 : nsIContentViewer** aDocViewerResult)
1266 : {
1267 : nsresult rv;
1268 :
1269 0 : bool viewSource = FindInReadable(NS_LITERAL_CSTRING("view-source"),
1270 0 : aContentType);
1271 :
1272 0 : if (!viewSource &&
1273 0 : Preferences::GetInt("network.dir.format", FORMAT_XUL) == FORMAT_XUL) {
1274 : // ... and setup the original channel's content type
1275 0 : (void)aChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml"));
1276 :
1277 : // This is where we shunt the HTTP/Index stream into our datasource,
1278 : // and open the directory viewer XUL file as the content stream to
1279 : // load in its place.
1280 :
1281 : // Create a dummy loader that will load a stub XUL document.
1282 0 : nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
1283 0 : if (NS_FAILED(rv))
1284 0 : return rv;
1285 0 : nsXPIDLCString contractID;
1286 0 : rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "application/vnd.mozilla.xul+xml",
1287 0 : getter_Copies(contractID));
1288 0 : if (NS_FAILED(rv))
1289 0 : return rv;
1290 :
1291 0 : nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
1292 0 : if (NS_FAILED(rv)) return rv;
1293 :
1294 0 : nsCOMPtr<nsIURI> uri;
1295 0 : rv = NS_NewURI(getter_AddRefs(uri), "chrome://communicator/content/directory/directory.xul");
1296 0 : if (NS_FAILED(rv)) return rv;
1297 :
1298 0 : nsCOMPtr<nsIChannel> channel;
1299 0 : rv = NS_NewChannel(getter_AddRefs(channel),
1300 : uri,
1301 : nsContentUtils::GetSystemPrincipal(),
1302 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1303 : nsIContentPolicy::TYPE_OTHER,
1304 : aLoadGroup);
1305 0 : if (NS_FAILED(rv)) return rv;
1306 :
1307 0 : nsCOMPtr<nsIStreamListener> listener;
1308 0 : rv = factory->CreateInstance(aCommand, channel, aLoadGroup,
1309 0 : NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml"),
1310 0 : aContainer, aExtraInfo, getter_AddRefs(listener),
1311 0 : aDocViewerResult);
1312 0 : if (NS_FAILED(rv)) return rv;
1313 :
1314 0 : rv = channel->AsyncOpen2(listener);
1315 0 : if (NS_FAILED(rv)) return rv;
1316 :
1317 : // Create an HTTPIndex object so that we can stuff it into the script context
1318 0 : nsCOMPtr<nsIURI> baseuri;
1319 0 : rv = aChannel->GetURI(getter_AddRefs(baseuri));
1320 0 : if (NS_FAILED(rv)) return rv;
1321 :
1322 0 : nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aContainer,&rv);
1323 0 : if (NS_FAILED(rv)) return rv;
1324 :
1325 0 : nsCOMPtr<nsIHTTPIndex> httpindex;
1326 0 : rv = nsHTTPIndex::Create(baseuri, requestor, getter_AddRefs(httpindex));
1327 0 : if (NS_FAILED(rv)) return rv;
1328 :
1329 : // Now shanghai the stream into our http-index parsing datasource
1330 : // wrapper beastie.
1331 0 : listener = do_QueryInterface(httpindex,&rv);
1332 0 : *aDocListenerResult = listener.get();
1333 0 : NS_ADDREF(*aDocListenerResult);
1334 :
1335 0 : return NS_OK;
1336 : }
1337 :
1338 : // setup the original channel's content type
1339 0 : (void)aChannel->SetContentType(NS_LITERAL_CSTRING("text/html"));
1340 :
1341 : // Otherwise, lets use the html listing
1342 0 : nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
1343 0 : if (NS_FAILED(rv))
1344 0 : return rv;
1345 0 : nsXPIDLCString contractID;
1346 0 : rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html",
1347 0 : getter_Copies(contractID));
1348 0 : if (NS_FAILED(rv))
1349 0 : return rv;
1350 :
1351 0 : nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
1352 0 : if (NS_FAILED(rv)) return rv;
1353 :
1354 0 : nsCOMPtr<nsIStreamListener> listener;
1355 :
1356 0 : if (viewSource) {
1357 0 : rv = factory->CreateInstance("view-source", aChannel, aLoadGroup,
1358 0 : NS_LITERAL_CSTRING("text/html; x-view-type=view-source"),
1359 0 : aContainer, aExtraInfo, getter_AddRefs(listener),
1360 0 : aDocViewerResult);
1361 : } else {
1362 0 : rv = factory->CreateInstance("view", aChannel, aLoadGroup,
1363 0 : NS_LITERAL_CSTRING("text/html"),
1364 0 : aContainer, aExtraInfo, getter_AddRefs(listener),
1365 0 : aDocViewerResult);
1366 : }
1367 :
1368 0 : if (NS_FAILED(rv)) return rv;
1369 :
1370 0 : nsCOMPtr<nsIStreamConverterService> scs = do_GetService("@mozilla.org/streamConverters;1", &rv);
1371 0 : if (NS_FAILED(rv)) return rv;
1372 :
1373 0 : rv = scs->AsyncConvertData("application/http-index-format",
1374 : "text/html",
1375 : listener,
1376 : nullptr,
1377 0 : aDocListenerResult);
1378 :
1379 0 : if (NS_FAILED(rv)) return rv;
1380 :
1381 0 : return NS_OK;
1382 : }
1383 :
1384 :
1385 :
1386 : NS_IMETHODIMP
1387 0 : nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer,
1388 : nsIDocument* aDocument,
1389 : const char *aCommand,
1390 : nsIContentViewer** aDocViewerResult)
1391 : {
1392 0 : NS_NOTYETIMPLEMENTED("didn't expect to get here");
1393 0 : return NS_ERROR_NOT_IMPLEMENTED;
1394 : }
1395 :
1396 : NS_IMETHODIMP
1397 0 : nsDirectoryViewerFactory::CreateBlankDocument(nsILoadGroup *aLoadGroup,
1398 : nsIPrincipal *aPrincipal,
1399 : nsIDocument **_retval) {
1400 :
1401 0 : NS_NOTYETIMPLEMENTED("didn't expect to get here");
1402 0 : return NS_ERROR_NOT_IMPLEMENTED;
1403 : }
|