updated on Sun Jan 15 08:01:04 UTC 2012
[aur-mirror.git] / firefox-pgo-beta / port_gnomevfs_to_gio.patch
blob797baff42aa422ec9077d41e6369b8e661d54640
1 diff -r 49a1b2aa43c5 extensions/gio/Makefile.in
2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3 +++ b/extensions/gio/Makefile.in Tue Jan 11 11:17:52 2011 +0100
4 @@ -0,0 +1,69 @@
5 +# vim:set ts=8 sw=8 sts=8 noet:
6 +# ***** BEGIN LICENSE BLOCK *****
7 +# Version: MPL 1.1/GPL 2.0/LGPL 2.1
8 +#
9 +# The contents of this file are subject to the Mozilla Public License Version
10 +# 1.1 (the "License"); you may not use this file except in compliance with
11 +# the License. You may obtain a copy of the License at
12 +# http://www.mozilla.org/MPL/
14 +# Software distributed under the License is distributed on an "AS IS" basis,
15 +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 +# for the specific language governing rights and limitations under the
17 +# License.
19 +# The Original Code is the Mozilla gnome-vfs extension.
21 +# The Initial Developer of the Original Code is IBM Corporation.
23 +# Portions created by IBM Corporation are Copyright (C) 2004
24 +# IBM Corporation. All Rights Reserved.
26 +# Contributor(s):
27 +# Darin Fisher <darin@meer.net>
28 +# Jan Horak <jhorak@redhat.com>
30 +# Alternatively, the contents of this file may be used under the terms of
31 +# either the GNU General Public License Version 2 or later (the "GPL"), or
32 +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 +# in which case the provisions of the GPL or the LGPL are applicable instead
34 +# of those above. If you wish to allow use of your version of this file only
35 +# under the terms of either the GPL or the LGPL, and not to allow others to
36 +# use your version of this file under the terms of the MPL, indicate your
37 +# decision by deleting the provisions above and replace them with the notice
38 +# and other provisions required by the GPL or the LGPL. If you do not delete
39 +# the provisions above, a recipient may use your version of this file under
40 +# the terms of any one of the MPL, the GPL or the LGPL.
42 +# ***** END LICENSE BLOCK *****
44 +DEPTH = ../..
45 +topsrcdir = @top_srcdir@
46 +srcdir = @srcdir@
47 +VPATH = @srcdir@
49 +include $(DEPTH)/config/autoconf.mk
51 +MODULE = nkgio
52 +LIBRARY_NAME = nkgio
53 +SHORT_LIBNAME = nkgio
54 +IS_COMPONENT = 1
56 +CPPSRCS = \
57 + nsGIOProtocolHandler.cpp \
58 + $(NULL)
60 +LOCAL_INCLUDES = $(MOZ_GIO_CFLAGS)
62 +EXTRA_DSO_LDOPTS = \
63 + $(XPCOM_GLUE_LDOPTS) \
64 + $(NSPR_LIBS) \
65 + $(MOZ_GIO_LIBS) \
66 + $(NULL)
68 +# make sure this component is never statically linked into the main
69 +# application. this is necessary since we don't want to force users
70 +# to install gio in order to use the rest of mozilla ;-)
71 +FORCE_SHARED_LIB= 1
73 +include $(topsrcdir)/config/rules.mk
74 diff -r 49a1b2aa43c5 extensions/gio/makefiles.sh
75 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76 +++ b/extensions/gio/makefiles.sh Tue Jan 11 11:17:52 2011 +0100
77 @@ -0,0 +1,41 @@
78 +#! /bin/sh
79 +# ***** BEGIN LICENSE BLOCK *****
80 +# Version: MPL 1.1/GPL 2.0/LGPL 2.1
82 +# The contents of this file are subject to the Mozilla Public License Version
83 +# 1.1 (the "License"); you may not use this file except in compliance with
84 +# the License. You may obtain a copy of the License at
85 +# http://www.mozilla.org/MPL/
87 +# Software distributed under the License is distributed on an "AS IS" basis,
88 +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
89 +# for the specific language governing rights and limitations under the
90 +# License.
92 +# The Original Code is Mozilla Build System
94 +# The Initial Developer of the Original Code is
95 +# Ben Turner <mozilla@songbirdnest.com>
97 +# Portions created by the Initial Developer are Copyright (C) 2007
98 +# the Initial Developer. All Rights Reserved.
100 +# Contributor(s):
102 +# Alternatively, the contents of this file may be used under the terms of
103 +# either the GNU General Public License Version 2 or later (the "GPL"), or
104 +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
105 +# in which case the provisions of the GPL or the LGPL are applicable instead
106 +# of those above. If you wish to allow use of your version of this file only
107 +# under the terms of either the GPL or the LGPL, and not to allow others to
108 +# use your version of this file under the terms of the MPL, indicate your
109 +# decision by deleting the provisions above and replace them with the notice
110 +# and other provisions required by the GPL or the LGPL. If you do not delete
111 +# the provisions above, a recipient may use your version of this file under
112 +# the terms of any one of the MPL, the GPL or the LGPL.
114 +# ***** END LICENSE BLOCK *****
116 +add_makefiles "
117 + extensions/gio/Makefile
119 diff -r 49a1b2aa43c5 extensions/gio/nsGIOProtocolHandler.cpp
120 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121 +++ b/extensions/gio/nsGIOProtocolHandler.cpp Tue Jan 11 11:17:52 2011 +0100
122 @@ -0,0 +1,1163 @@
123 +/* vim:set ts=2 sw=2 et cindent: */
124 +/* ***** BEGIN LICENSE BLOCK *****
125 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
127 + * The contents of this file are subject to the Mozilla Public License Version
128 + * 1.1 (the "License"); you may not use this file except in compliance with
129 + * the License. You may obtain a copy of the License at
130 + * http://www.mozilla.org/MPL/
132 + * Software distributed under the License is distributed on an "AS IS" basis,
133 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
134 + * for the specific language governing rights and limitations under the
135 + * License.
137 + * The Original Code is the Mozilla gnome-vfs extension.
139 + * The Initial Developer of the Original Code is IBM Corporation.
141 + * Portions created by IBM Corporation are Copyright (C) 2004
142 + * IBM Corporation. All Rights Reserved.
144 + * Contributor(s):
145 + * Darin Fisher <darin@meer.net>
146 + * Jan Horak <jhorak@redhat.com>
148 + * Alternatively, the contents of this file may be used under the terms of
149 + * either the GNU General Public License Version 2 or later (the "GPL"), or
150 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
151 + * in which case the provisions of the GPL or the LGPL are applicable instead
152 + * of those above. If you wish to allow use of your version of this file only
153 + * under the terms of either the GPL or the LGPL, and not to allow others to
154 + * use your version of this file under the terms of the MPL, indicate your
155 + * decision by deleting the provisions above and replace them with the notice
156 + * and other provisions required by the GPL or the LGPL. If you do not delete
157 + * the provisions above, a recipient may use your version of this file under
158 + * the terms of any one of the MPL, the GPL or the LGPL.
160 + * ***** END LICENSE BLOCK ***** */
163 + * This code is based on original Mozilla gnome-vfs extension. It implements
164 + * input stream provided by GVFS/GIO.
166 +#include "mozilla/ModuleUtils.h"
167 +#include "nsIPrefService.h"
168 +#include "nsIPrefBranch2.h"
169 +#include "nsIObserver.h"
170 +#include "nsThreadUtils.h"
171 +#include "nsProxyRelease.h"
172 +#include "nsIStringBundle.h"
173 +#include "nsIStandardURL.h"
174 +#include "nsMimeTypes.h"
175 +#include "nsNetUtil.h"
176 +#include "mozilla/Monitor.h"
177 +#include <gio/gio.h>
179 +#define MOZ_GIO_SCHEME "moz-gio"
180 +#define MOZ_GIO_SUPPORTED_PROTOCOLS "network.gio.supported-protocols"
182 +//-----------------------------------------------------------------------------
184 +// NSPR_LOG_MODULES=gio:5
185 +#ifdef PR_LOGGING
186 +static PRLogModuleInfo *sGIOLog;
187 +#define LOG(args) PR_LOG(sGIOLog, PR_LOG_DEBUG, args)
188 +#else
189 +#define LOG(args)
190 +#endif
193 +//-----------------------------------------------------------------------------
194 +static nsresult
195 +MapGIOResult(gint code)
197 + switch (code)
199 + case G_IO_ERROR_NOT_FOUND: return NS_ERROR_FILE_NOT_FOUND; // shows error
200 + case G_IO_ERROR_INVALID_ARGUMENT: return NS_ERROR_INVALID_ARG;
201 + case G_IO_ERROR_NOT_SUPPORTED: return NS_ERROR_NOT_AVAILABLE;
202 + case G_IO_ERROR_NO_SPACE: return NS_ERROR_FILE_NO_DEVICE_SPACE;
203 + case G_IO_ERROR_READ_ONLY: return NS_ERROR_FILE_READ_ONLY;
204 + case G_IO_ERROR_PERMISSION_DENIED: return NS_ERROR_FILE_ACCESS_DENIED; // wrong password/login
205 + case G_IO_ERROR_CLOSED: return NS_BASE_STREAM_CLOSED; // was EOF
206 + case G_IO_ERROR_NOT_DIRECTORY: return NS_ERROR_FILE_NOT_DIRECTORY;
207 + case G_IO_ERROR_PENDING: return NS_ERROR_IN_PROGRESS;
208 + case G_IO_ERROR_EXISTS: return NS_ERROR_FILE_ALREADY_EXISTS;
209 + case G_IO_ERROR_IS_DIRECTORY: return NS_ERROR_FILE_IS_DIRECTORY;
210 + case G_IO_ERROR_NOT_MOUNTED: return NS_ERROR_NOT_CONNECTED; // shows error
211 + case G_IO_ERROR_HOST_NOT_FOUND: return NS_ERROR_UNKNOWN_HOST; // shows error
212 + case G_IO_ERROR_CANCELLED: return NS_ERROR_ABORT;
213 + case G_IO_ERROR_NOT_EMPTY: return NS_ERROR_FILE_DIR_NOT_EMPTY;
214 + case G_IO_ERROR_FILENAME_TOO_LONG: return NS_ERROR_FILE_NAME_TOO_LONG;
215 + case G_IO_ERROR_INVALID_FILENAME: return NS_ERROR_FILE_INVALID_PATH;
216 + case G_IO_ERROR_TIMED_OUT: return NS_ERROR_NET_TIMEOUT; // shows error
217 + case G_IO_ERROR_WOULD_BLOCK: return NS_BASE_STREAM_WOULD_BLOCK;
218 + case G_IO_ERROR_FAILED_HANDLED: return NS_ERROR_ABORT; // Cancel on login dialog
220 +/* unhandled:
221 + G_IO_ERROR_NOT_REGULAR_FILE,
222 + G_IO_ERROR_NOT_SYMBOLIC_LINK,
223 + G_IO_ERROR_NOT_MOUNTABLE_FILE,
224 + G_IO_ERROR_TOO_MANY_LINKS,
225 + G_IO_ERROR_ALREADY_MOUNTED,
226 + G_IO_ERROR_CANT_CREATE_BACKUP,
227 + G_IO_ERROR_WRONG_ETAG,
228 + G_IO_ERROR_WOULD_RECURSE,
229 + G_IO_ERROR_BUSY,
230 + G_IO_ERROR_WOULD_MERGE,
231 + G_IO_ERROR_TOO_MANY_OPEN_FILES
233 + // Make GCC happy
234 + default:
235 + return NS_ERROR_FAILURE;
238 + return NS_ERROR_FAILURE;
241 +static nsresult
242 +MapGIOResult(GError *result)
244 + if (!result)
245 + return NS_OK;
246 + else
247 + return MapGIOResult(result->code);
249 +/** Return values for mount operation.
250 + * These enums are used as mount operation return values.
251 + */
252 +typedef enum {
253 + MOUNT_OPERATION_IN_PROGRESS, /** \enum operation in progress */
254 + MOUNT_OPERATION_SUCCESS, /** \enum operation successful */
255 + MOUNT_OPERATION_FAILED /** \enum operation not successful */
256 +} MountOperationResult;
257 +//-----------------------------------------------------------------------------
258 +/**
259 + * Sort function compares according to file type (directory/file)
260 + * and alphabethical order
261 + * @param a pointer to GFileInfo object to compare
262 + * @param b pointer to GFileInfo object to compare
263 + * @return -1 when first object should be before the second, 0 when equal,
264 + * +1 when second object should be before the first
265 + */
266 +static gint
267 +FileInfoComparator(gconstpointer a, gconstpointer b)
269 + GFileInfo *ia = ( GFileInfo *) a;
270 + GFileInfo *ib = ( GFileInfo *) b;
271 + if (g_file_info_get_file_type(ia) == G_FILE_TYPE_DIRECTORY
272 + && g_file_info_get_file_type(ib) != G_FILE_TYPE_DIRECTORY)
273 + return -1;
274 + if (g_file_info_get_file_type(ib) == G_FILE_TYPE_DIRECTORY
275 + && g_file_info_get_file_type(ia) != G_FILE_TYPE_DIRECTORY)
276 + return 1;
278 + return strcasecmp(g_file_info_get_name(ia), g_file_info_get_name(ib));
281 +/* Declaration of mount callback functions */
282 +static void mount_enclosing_volume_finished (GObject *source_object,
283 + GAsyncResult *res,
284 + gpointer user_data);
285 +static void mount_operation_ask_password (GMountOperation *mount_op,
286 + const char *message,
287 + const char *default_user,
288 + const char *default_domain,
289 + GAskPasswordFlags flags,
290 + gpointer user_data);
291 +//-----------------------------------------------------------------------------
293 +class nsGIOInputStream : public nsIInputStream
295 + public:
296 + NS_DECL_ISUPPORTS
297 + NS_DECL_NSIINPUTSTREAM
299 + nsGIOInputStream(const nsCString &uriSpec)
300 + : mSpec(uriSpec)
301 + , mChannel(nsnull)
302 + , mHandle(nsnull)
303 + , mStream(nsnull)
304 + , mBytesRemaining(PR_UINT32_MAX)
305 + , mStatus(NS_OK)
306 + , mDirList(nsnull)
307 + , mDirListPtr(nsnull)
308 + , mDirBufCursor(0)
309 + , mDirOpen(PR_FALSE)
310 + , mMonitorMountInProgress("GIOInputStream::MountFinished") { }
312 + ~nsGIOInputStream() { Close(); }
314 + void SetChannel(nsIChannel *channel)
316 + // We need to hold an owning reference to our channel. This is done
317 + // so we can access the channel's notification callbacks to acquire
318 + // a reference to a nsIAuthPrompt if we need to handle an interactive
319 + // mount operation.
320 + //
321 + // However, the channel can only be accessed on the main thread, so
322 + // we have to be very careful with ownership. Moreover, it doesn't
323 + // support threadsafe addref/release, so proxying is the answer.
324 + //
325 + // Also, it's important to note that this likely creates a reference
326 + // cycle since the channel likely owns this stream. This reference
327 + // cycle is broken in our Close method.
329 + NS_ADDREF(mChannel = channel);
331 + void SetMountResult(MountOperationResult result, gint error_code);
332 + private:
333 + nsresult DoOpen();
334 + nsresult DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead);
335 + nsresult SetContentTypeOfChannel(const char *contentType);
336 + nsresult MountVolume();
337 + nsresult DoOpenDirectory();
338 + nsresult DoOpenFile(GFileInfo *info);
339 + nsCString mSpec;
340 + nsIChannel *mChannel; // manually refcounted
341 + GFile *mHandle;
342 + GFileInputStream *mStream;
343 + PRUint64 mBytesRemaining;
344 + nsresult mStatus;
345 + GList *mDirList;
346 + GList *mDirListPtr;
347 + nsCString mDirBuf;
348 + PRUint32 mDirBufCursor;
349 + PRPackedBool mDirOpen;
350 + MountOperationResult mMountRes;
351 + mozilla::Monitor mMonitorMountInProgress;
352 + gint mMountErrorCode;
354 +/**
355 + * Set result of mount operation and notify monitor waiting for results.
356 + * This method is called in main thread as long as it is used only
357 + * in mount_enclosing_volume_finished function.
358 + * @param result Result of mount operation
359 + */
360 +void
361 +nsGIOInputStream::SetMountResult(MountOperationResult result, gint error_code)
363 + mozilla::MonitorAutoEnter mon(mMonitorMountInProgress);
364 + mMountRes = result;
365 + mMountErrorCode = error_code;
366 + mon.Notify();
369 +/**
370 + * Start mount operation and wait in loop until it is finished. This method is
371 + * called from thread which is trying to read from location.
372 + */
373 +nsresult
374 +nsGIOInputStream::MountVolume() {
375 + GMountOperation* mount_op = g_mount_operation_new();
376 + g_signal_connect (mount_op, "ask-password",
377 + G_CALLBACK (mount_operation_ask_password), mChannel);
378 + mMountRes = MOUNT_OPERATION_IN_PROGRESS;
379 + /* g_file_mount_enclosing_volume uses a dbus request to mount the volume.
380 + Callback mount_enclosing_volume_finished is called in main thread
381 + (not this thread on which this method is called). */
382 + g_file_mount_enclosing_volume(mHandle,
383 + G_MOUNT_MOUNT_NONE,
384 + mount_op,
385 + NULL,
386 + mount_enclosing_volume_finished,
387 + this);
388 + mozilla::MonitorAutoEnter mon(mMonitorMountInProgress);
389 + /* Waiting for finish of mount operation thread */
390 + while (mMountRes == MOUNT_OPERATION_IN_PROGRESS)
391 + mon.Wait();
393 + g_object_unref(mount_op);
395 + if (mMountRes == MOUNT_OPERATION_FAILED) {
396 + return MapGIOResult(mMountErrorCode);
397 + } else {
398 + return NS_OK;
402 +/**
403 + * Create list of infos about objects in opened directory
404 + * Return: NS_OK when list obtained, otherwise error code according
405 + * to failed operation.
406 + */
407 +nsresult
408 +nsGIOInputStream::DoOpenDirectory()
410 + GError *error = NULL;
412 + GFileEnumerator *f_enum = g_file_enumerate_children(mHandle,
413 + "standard::*,time::*",
414 + G_FILE_QUERY_INFO_NONE,
415 + NULL,
416 + &error);
417 + if (!f_enum) {
418 + nsresult rv = MapGIOResult(error);
419 + g_warning("Cannot read from directory: %s", error->message);
420 + g_error_free(error);
421 + return rv;
423 + // fill list of file infos
424 + GFileInfo *info = g_file_enumerator_next_file(f_enum, NULL, &error);
425 + while (info) {
426 + mDirList = g_list_append(mDirList, info);
427 + info = g_file_enumerator_next_file(f_enum, NULL, &error);
429 + g_object_unref(f_enum);
430 + if (error) {
431 + g_warning("Error reading directory content: %s", error->message);
432 + nsresult rv = MapGIOResult(error);
433 + g_error_free(error);
434 + return rv;
436 + mDirOpen = PR_TRUE;
438 + // Sort list of file infos by using FileInfoComparator function
439 + mDirList = g_list_sort(mDirList, FileInfoComparator);
440 + mDirListPtr = mDirList;
442 + // Write base URL (make sure it ends with a '/')
443 + mDirBuf.Append("300: ");
444 + mDirBuf.Append(mSpec);
445 + if (mSpec.get()[mSpec.Length() - 1] != '/')
446 + mDirBuf.Append('/');
447 + mDirBuf.Append('\n');
449 + // Write column names
450 + mDirBuf.Append("200: filename content-length last-modified file-type\n");
452 + // Write charset (assume UTF-8)
453 + // XXX is this correct?
454 + mDirBuf.Append("301: UTF-8\n");
455 + SetContentTypeOfChannel(APPLICATION_HTTP_INDEX_FORMAT);
456 + return NS_OK;
459 +/**
460 + * Create file stream and set mime type for channel
461 + * @param info file info used to determine mime type
462 + * @return NS_OK when file stream created successfuly, error code otherwise
463 + */
464 +nsresult
465 +nsGIOInputStream::DoOpenFile(GFileInfo *info)
467 + GError *error = NULL;
469 + mStream = g_file_read(mHandle, NULL, &error);
470 + if (!mStream) {
471 + nsresult rv = MapGIOResult(error);
472 + g_warning("Cannot read from file: %s", error->message);
473 + g_error_free(error);
474 + return rv;
477 + const char * content_type = g_file_info_get_content_type(info);
478 + if (content_type) {
479 + char *mime_type = g_content_type_get_mime_type(content_type);
480 + if (mime_type) {
481 + if (strcmp(mime_type, APPLICATION_OCTET_STREAM) != 0) {
482 + SetContentTypeOfChannel(mime_type);
484 + g_free(mime_type);
486 + } else {
487 + g_warning("Missing content type.");
490 + mBytesRemaining = g_file_info_get_size(info);
491 + // Update the content length attribute on the channel. We do this
492 + // synchronously without proxying. This hack is not as bad as it looks!
493 + mChannel->SetContentLength(mBytesRemaining);
495 + return NS_OK;
498 +/**
499 + * Start file open operation, mount volume when needed and according to file type
500 + * create file output stream or read directory content.
501 + * @return NS_OK when file or directory opened successfully, error code otherwise
502 + */
503 +nsresult
504 +nsGIOInputStream::DoOpen()
506 + nsresult rv;
507 + GError *error = NULL;
509 + NS_ASSERTION(mHandle == nsnull, "already open");
511 + mHandle = g_file_new_for_uri( mSpec.get() );
513 + GFileInfo *info = g_file_query_info(mHandle,
514 + "standard::*",
515 + G_FILE_QUERY_INFO_NONE,
516 + NULL,
517 + &error);
519 + if (error) {
520 + if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED) {
521 + // location is not yet mounted, try to mount
522 + g_error_free(error);
523 + if (NS_IsMainThread())
524 + return NS_ERROR_NOT_CONNECTED;
525 + error = NULL;
526 + rv = MountVolume();
527 + if (rv != NS_OK) {
528 + return rv;
530 + // get info again
531 + info = g_file_query_info(mHandle,
532 + "standard::*",
533 + G_FILE_QUERY_INFO_NONE,
534 + NULL,
535 + &error);
536 + // second try to get file info from remote files after media mount
537 + if (!info) {
538 + g_warning("Unable to get file info: %s", error->message);
539 + rv = MapGIOResult(error);
540 + g_error_free(error);
541 + return rv;
543 + } else {
544 + g_warning("Unable to get file info: %s", error->message);
545 + rv = MapGIOResult(error);
546 + g_error_free(error);
547 + return rv;
550 + // Get file type to handle directories and file differently
551 + GFileType f_type = g_file_info_get_file_type(info);
552 + if (f_type == G_FILE_TYPE_DIRECTORY) {
553 + // directory
554 + rv = DoOpenDirectory();
555 + } else if (f_type != G_FILE_TYPE_UNKNOWN) {
556 + // file
557 + rv = DoOpenFile(info);
558 + } else {
559 + g_warning("Unable to get file type.");
560 + rv = NS_ERROR_FILE_NOT_FOUND;
562 + if (info)
563 + g_object_unref(info);
564 + return rv;
567 +/**
568 + * Read content of file or create file list from directory
569 + * @param aBuf read destination buffer
570 + * @param aCount length of destination buffer
571 + * @param aCountRead number of read characters
572 + * @return NS_OK when read successfully, NS_BASE_STREAM_CLOSED when end of file,
573 + * error code otherwise
574 + */
575 +nsresult
576 +nsGIOInputStream::DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead)
578 + nsresult rv = NS_ERROR_NOT_AVAILABLE;
579 + if (mStream) {
580 + // file read
581 + GError *error = NULL;
582 + PRUint32 bytes_read = g_input_stream_read(G_INPUT_STREAM(mStream),
583 + aBuf,
584 + aCount,
585 + NULL,
586 + &error);
587 + if (error) {
588 + rv = MapGIOResult(error);
589 + *aCountRead = 0;
590 + g_warning("Cannot read from file: %s", error->message);
591 + g_error_free(error);
592 + return rv;
594 + *aCountRead = bytes_read;
595 + mBytesRemaining -= *aCountRead;
596 + return NS_OK;
598 + else if (mDirOpen) {
599 + // directory read
600 + while (aCount && rv != NS_BASE_STREAM_CLOSED)
602 + // Copy data out of our buffer
603 + PRUint32 bufLen = mDirBuf.Length() - mDirBufCursor;
604 + if (bufLen)
606 + PRUint32 n = PR_MIN(bufLen, aCount);
607 + memcpy(aBuf, mDirBuf.get() + mDirBufCursor, n);
608 + *aCountRead += n;
609 + aBuf += n;
610 + aCount -= n;
611 + mDirBufCursor += n;
614 + if (!mDirListPtr) // Are we at the end of the directory list?
616 + rv = NS_BASE_STREAM_CLOSED;
618 + else if (aCount) // Do we need more data?
620 + GFileInfo *info = (GFileInfo *) mDirListPtr->data;
622 + // Prune '.' and '..' from directory listing.
623 + const char * fname = g_file_info_get_name(info);
624 + if (fname && fname[0] == '.' &&
625 + (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
627 + mDirListPtr = mDirListPtr->next;
628 + continue;
631 + mDirBuf.Assign("201: ");
633 + // The "filename" field
634 + nsCString escName;
635 + nsCOMPtr<nsINetUtil> nu = do_GetService(NS_NETUTIL_CONTRACTID);
636 + if (nu && fname) {
637 + nu->EscapeString(nsDependentCString(fname),
638 + nsINetUtil::ESCAPE_URL_PATH, escName);
640 + mDirBuf.Append(escName);
641 + mDirBuf.Append(' ');
644 + // The "content-length" field
645 + // XXX truncates size from 64-bit to 32-bit
646 + mDirBuf.AppendInt(PRInt32(g_file_info_get_size(info)));
647 + mDirBuf.Append(' ');
649 + // The "last-modified" field
650 + //
651 + // NSPR promises: PRTime is compatible with time_t
652 + // we just need to convert from seconds to microseconds
653 + GTimeVal gtime;
654 + g_file_info_get_modification_time(info, &gtime);
656 + PRExplodedTime tm;
657 + PRTime pt = ((PRTime) gtime.tv_sec) * 1000000;
658 + PR_ExplodeTime(pt, PR_GMTParameters, &tm);
660 + char buf[64];
661 + PR_FormatTimeUSEnglish(buf, sizeof(buf),
662 + "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
663 + mDirBuf.Append(buf);
666 + // The "file-type" field
667 + switch (g_file_info_get_file_type(info))
669 + case G_FILE_TYPE_REGULAR:
670 + mDirBuf.Append("FILE ");
671 + break;
672 + case G_FILE_TYPE_DIRECTORY:
673 + mDirBuf.Append("DIRECTORY ");
674 + break;
675 + case G_FILE_TYPE_SYMBOLIC_LINK:
676 + mDirBuf.Append("SYMBOLIC-LINK ");
677 + break;
678 + default:
679 + break;
681 + mDirBuf.Append('\n');
683 + mDirBufCursor = 0;
684 + mDirListPtr = mDirListPtr->next;
688 + return rv;
691 +/**
692 + * This class is used to implement SetContentTypeOfChannel.
693 + */
694 +class nsGIOSetContentTypeEvent : public nsRunnable
696 + public:
697 + nsGIOSetContentTypeEvent(nsIChannel *channel, const char *contentType)
698 + : mChannel(channel), mContentType(contentType)
700 + // stash channel reference in mChannel. no AddRef here! see note
701 + // in SetContentTypeOfchannel.
704 + NS_IMETHOD Run()
706 + mChannel->SetContentType(mContentType);
707 + return NS_OK;
710 + private:
711 + nsIChannel *mChannel;
712 + nsCString mContentType;
715 +nsresult
716 +nsGIOInputStream::SetContentTypeOfChannel(const char *contentType)
718 + // We need to proxy this call over to the main thread. We post an
719 + // asynchronous event in this case so that we don't delay reading data, and
720 + // we know that this is safe to do since the channel's reference will be
721 + // released asynchronously as well. We trust the ordering of the main
722 + // thread's event queue to protect us against memory corruption.
724 + nsresult rv;
725 + nsCOMPtr<nsIRunnable> ev =
726 + new nsGIOSetContentTypeEvent(mChannel, contentType);
727 + if (!ev)
729 + rv = NS_ERROR_OUT_OF_MEMORY;
731 + else
733 + rv = NS_DispatchToMainThread(ev);
735 + return rv;
738 +NS_IMPL_THREADSAFE_ISUPPORTS1(nsGIOInputStream, nsIInputStream)
740 +/**
741 + * Free all used memory and close stream.
742 + */
743 +NS_IMETHODIMP
744 +nsGIOInputStream::Close()
746 + if (mStream)
748 + g_object_unref(mStream);
749 + mStream = nsnull;
752 + if (mHandle)
754 + g_object_unref(mHandle);
755 + mHandle = nsnull;
758 + if (mDirList)
760 + // Destroy the list of GIOFileInfo objects...
761 + g_list_foreach(mDirList, (GFunc) g_object_unref, nsnull);
762 + g_list_free(mDirList);
763 + mDirList = nsnull;
764 + mDirListPtr = nsnull;
767 + if (mChannel)
769 + nsresult rv = NS_OK;
771 + nsCOMPtr<nsIThread> thread = do_GetMainThread();
772 + if (thread)
773 + rv = NS_ProxyRelease(thread, mChannel);
775 + NS_ASSERTION(thread && NS_SUCCEEDED(rv), "leaking channel reference");
776 + mChannel = nsnull;
779 + mSpec.Truncate(); // free memory
781 + // Prevent future reads from re-opening the handle.
782 + if (NS_SUCCEEDED(mStatus))
783 + mStatus = NS_BASE_STREAM_CLOSED;
785 + return NS_OK;
788 +/**
789 + * Return number of remaining bytes available on input
790 + * @param aResult remaining bytes
791 + */
792 +NS_IMETHODIMP
793 +nsGIOInputStream::Available(PRUint32 *aResult)
795 + if (NS_FAILED(mStatus))
796 + return mStatus;
798 + /* When remaining bytes are bigger than max PRUint32 value an aResult must
799 + be set to PRUint32 maximum */
800 + if (mBytesRemaining > PR_UINT32_MAX)
801 + *aResult = PR_UINT32_MAX;
802 + else
803 + *aResult = mBytesRemaining;
805 + return NS_OK;
808 +/**
809 + * Trying to read from stream. When location is not available it tries to mount it.
810 + * @param aBuf buffer to put read data
811 + * @param aCount length of aBuf
812 + * @param aCountRead number of bytes actually read
813 + */
814 +NS_IMETHODIMP
815 +nsGIOInputStream::Read(char *aBuf,
816 + PRUint32 aCount,
817 + PRUint32 *aCountRead)
819 + *aCountRead = 0;
820 + // Check if file is already opened, otherwise open it
821 + if (!mStream && !mDirOpen && mStatus == NS_OK) {
822 + mStatus = DoOpen();
823 + if (NS_FAILED(mStatus)) {
824 + return mStatus;
828 + mStatus = DoRead(aBuf, aCount, aCountRead);
829 + // Check if all data has been read
830 + if (mStatus == NS_BASE_STREAM_CLOSED)
831 + return NS_OK;
833 + // Check whenever any error appears while reading
834 + return mStatus;
837 +NS_IMETHODIMP
838 +nsGIOInputStream::ReadSegments(nsWriteSegmentFun aWriter,
839 + void *aClosure,
840 + PRUint32 aCount,
841 + PRUint32 *aResult)
843 + // There is no way to implement this using GnomeVFS, but fortunately
844 + // that doesn't matter. Because we are a blocking input stream, Necko
845 + // isn't going to call our ReadSegments method.
846 + NS_NOTREACHED("nsGIOInputStream::ReadSegments");
847 + return NS_ERROR_NOT_IMPLEMENTED;
850 +NS_IMETHODIMP
851 +nsGIOInputStream::IsNonBlocking(PRBool *aResult)
853 + *aResult = PR_FALSE;
854 + return NS_OK;
857 +//-----------------------------------------------------------------------------
859 +/**
860 + * Called when finishing mount operation. Result of operation is set in
861 + * nsGIOInputStream. This function is called in main thread as an async request
862 + * typically from dbus.
863 + * @param source_object GFile object which requested the mount
864 + * @param res result object
865 + * @param user_data pointer to nsGIOInputStream
866 + */
867 +static void
868 +mount_enclosing_volume_finished (GObject *source_object,
869 + GAsyncResult *res,
870 + gpointer user_data)
872 + GError *error = NULL;
874 + nsGIOInputStream* istream = static_cast<nsGIOInputStream*>(user_data);
876 + g_file_mount_enclosing_volume_finish(G_FILE (source_object), res, &error);
878 + if (error) {
879 + g_warning("Mount failed: %s %d", error->message, error->code);
880 + istream->SetMountResult(MOUNT_OPERATION_FAILED, error->code);
881 + g_error_free(error);
882 + } else {
883 + istream->SetMountResult(MOUNT_OPERATION_SUCCESS, 0);
887 +/**
888 + * This function is called when username or password are requested from user.
889 + * This function is called in main thread as async request from dbus.
890 + * @param mount_op mount operation
891 + * @param message message to show to user
892 + * @param default_user preffered user
893 + * @param default_domain domain name
894 + * @param flags what type of information is required
895 + * @param user_data nsIChannel
896 + */
897 +static void
898 +mount_operation_ask_password (GMountOperation *mount_op,
899 + const char *message,
900 + const char *default_user,
901 + const char *default_domain,
902 + GAskPasswordFlags flags,
903 + gpointer user_data)
905 + nsIChannel *channel = (nsIChannel *) user_data;
906 + if (!channel) {
907 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
908 + return;
910 + // We can't handle request for domain
911 + if (flags & G_ASK_PASSWORD_NEED_DOMAIN) {
912 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
913 + return;
916 + nsCOMPtr<nsIAuthPrompt> prompt;
917 + NS_QueryNotificationCallbacks(channel, prompt);
919 + // If no auth prompt, then give up. We could failover to using the
920 + // WindowWatcher service, but that might defeat a consumer's purposeful
921 + // attempt to disable authentication (for whatever reason).
922 + if (!prompt) {
923 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
924 + return;
926 + // Parse out the host and port...
927 + nsCOMPtr<nsIURI> uri;
928 + channel->GetURI(getter_AddRefs(uri));
929 + if (!uri) {
930 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
931 + return;
934 + nsCAutoString scheme, hostPort;
935 + uri->GetScheme(scheme);
936 + uri->GetHostPort(hostPort);
938 + // It doesn't make sense for either of these strings to be empty. What kind
939 + // of funky URI is this?
940 + if (scheme.IsEmpty() || hostPort.IsEmpty()) {
941 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
942 + return;
944 + // Construct the single signon key. Altering the value of this key will
945 + // cause people's remembered passwords to be forgotten. Think carefully
946 + // before changing the way this key is constructed.
947 + nsAutoString key, realm;
949 + NS_ConvertUTF8toUTF16 dispHost(scheme);
950 + dispHost.Append(NS_LITERAL_STRING("://"));
951 + dispHost.Append(NS_ConvertUTF8toUTF16(hostPort));
953 + key = dispHost;
954 + if (*default_domain != '\0')
956 + // We assume the realm string is ASCII. That might be a bogus assumption,
957 + // but we have no idea what encoding GnomeVFS is using, so for now we'll
958 + // limit ourselves to ISO-Latin-1. XXX What is a better solution?
959 + realm.Append('"');
960 + realm.Append(NS_ConvertASCIItoUTF16(default_domain));
961 + realm.Append('"');
962 + key.Append(' ');
963 + key.Append(realm);
965 + // Construct the message string...
966 + //
967 + // We use Necko's string bundle here. This code really should be encapsulated
968 + // behind some Necko API, after all this code is based closely on the code in
969 + // nsHttpChannel.cpp.
970 + nsCOMPtr<nsIStringBundleService> bundleSvc =
971 + do_GetService(NS_STRINGBUNDLE_CONTRACTID);
972 + if (!bundleSvc) {
973 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
974 + return;
976 + nsCOMPtr<nsIStringBundle> bundle;
977 + bundleSvc->CreateBundle("chrome://global/locale/commonDialogs.properties",
978 + getter_AddRefs(bundle));
979 + if (!bundle) {
980 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
981 + return;
983 + nsAutoString nsmessage;
985 + if (flags & G_ASK_PASSWORD_NEED_PASSWORD) {
986 + if (flags & G_ASK_PASSWORD_NEED_USERNAME) {
987 + if (!realm.IsEmpty()) {
988 + const PRUnichar *strings[] = { realm.get(), dispHost.get() };
989 + bundle->FormatStringFromName(NS_LITERAL_STRING("EnterLoginForRealm").get(),
990 + strings, 2, getter_Copies(nsmessage));
991 + } else {
992 + const PRUnichar *strings[] = { dispHost.get() };
993 + bundle->FormatStringFromName(NS_LITERAL_STRING("EnterUserPasswordFor").get(),
994 + strings, 1, getter_Copies(nsmessage));
996 + } else {
997 + NS_ConvertUTF8toUTF16 userName(default_user);
998 + const PRUnichar *strings[] = { userName.get(), dispHost.get() };
999 + bundle->FormatStringFromName(NS_LITERAL_STRING("EnterPasswordFor").get(),
1000 + strings, 2, getter_Copies(nsmessage));
1002 + } else {
1003 + g_warning("Unknown mount operation request (flags: %x)", flags);
1006 + if (nsmessage.IsEmpty()) {
1007 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
1008 + return;
1010 + // Prompt the user...
1011 + nsresult rv;
1012 + PRBool retval = PR_FALSE;
1013 + PRUnichar *user = nsnull, *pass = nsnull;
1014 + if (default_user) {
1015 + // user will be freed by PromptUsernameAndPassword
1016 + user = ToNewUnicode(NS_ConvertUTF8toUTF16(default_user));
1018 + if (flags & G_ASK_PASSWORD_NEED_USERNAME) {
1019 + rv = prompt->PromptUsernameAndPassword(nsnull, nsmessage.get(),
1020 + key.get(),
1021 + nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
1022 + &user, &pass, &retval);
1023 + } else {
1024 + rv = prompt->PromptPassword(nsnull, nsmessage.get(),
1025 + key.get(),
1026 + nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
1027 + &pass, &retval);
1029 + if (NS_FAILED(rv) || !retval) { // was || user == '\0' || pass == '\0'
1030 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
1031 + return;
1033 + /* GIO should accept UTF8 */
1034 + g_mount_operation_set_username(mount_op, NS_ConvertUTF16toUTF8(user).get());
1035 + g_mount_operation_set_password(mount_op, NS_ConvertUTF16toUTF8(pass).get());
1036 + nsMemory::Free(user);
1037 + nsMemory::Free(pass);
1038 + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_HANDLED);
1041 +//-----------------------------------------------------------------------------
1043 +class nsGIOProtocolHandler : public nsIProtocolHandler
1044 + , public nsIObserver
1046 + public:
1047 + NS_DECL_ISUPPORTS
1048 + NS_DECL_NSIPROTOCOLHANDLER
1049 + NS_DECL_NSIOBSERVER
1051 + nsresult Init();
1053 + private:
1054 + void InitSupportedProtocolsPref(nsIPrefBranch *prefs);
1055 + PRBool IsSupportedProtocol(const nsCString &spec);
1057 + nsCString mSupportedProtocols;
1060 +NS_IMPL_ISUPPORTS2(nsGIOProtocolHandler, nsIProtocolHandler, nsIObserver)
1062 +nsresult
1063 +nsGIOProtocolHandler::Init()
1065 +#ifdef PR_LOGGING
1066 + sGIOLog = PR_NewLogModule("gio");
1067 +#endif
1069 + nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
1070 + if (prefs)
1072 + InitSupportedProtocolsPref(prefs);
1073 + prefs->AddObserver(MOZ_GIO_SUPPORTED_PROTOCOLS, this, PR_FALSE);
1076 + return NS_OK;
1079 +void
1080 +nsGIOProtocolHandler::InitSupportedProtocolsPref(nsIPrefBranch *prefs)
1082 + // Get user preferences to determine which protocol is supported.
1083 + // Gvfs/GIO has a set of supported protocols like obex, network, archive,
1084 + // computer, dav, cdda, gphoto2, trash, etc. Some of these seems to be
1085 + // irrelevant to process by browser. By default accept only smb and sftp
1086 + // protocols so far.
1087 + nsresult rv = prefs->GetCharPref(MOZ_GIO_SUPPORTED_PROTOCOLS,
1088 + getter_Copies(mSupportedProtocols));
1089 + if (NS_SUCCEEDED(rv)) {
1090 + mSupportedProtocols.StripWhitespace();
1091 + ToLowerCase(mSupportedProtocols);
1093 + else
1094 + mSupportedProtocols.Assign("smb:,sftp:"); // use defaults
1096 + LOG(("gio: supported protocols \"%s\"\n", mSupportedProtocols.get()));
1099 +PRBool
1100 +nsGIOProtocolHandler::IsSupportedProtocol(const nsCString &aSpec)
1102 + const char *specString = aSpec.get();
1103 + const char *colon = strchr(specString, ':');
1104 + if (!colon)
1105 + return PR_FALSE;
1107 + PRUint32 length = colon - specString + 1;
1109 + // <scheme> + ':'
1110 + nsCString scheme(specString, length);
1112 + char *found = PL_strcasestr(mSupportedProtocols.get(), scheme.get());
1113 + if (!found)
1114 + return PR_FALSE;
1116 + if (found[length] != ',' && found[length] != '\0')
1117 + return PR_FALSE;
1119 + return PR_TRUE;
1122 +NS_IMETHODIMP
1123 +nsGIOProtocolHandler::GetScheme(nsACString &aScheme)
1125 + aScheme.Assign(MOZ_GIO_SCHEME);
1126 + return NS_OK;
1129 +NS_IMETHODIMP
1130 +nsGIOProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
1132 + *aDefaultPort = -1;
1133 + return NS_OK;
1136 +NS_IMETHODIMP
1137 +nsGIOProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
1139 + // Is URI_STD true of all GnomeVFS URI types?
1140 + *aProtocolFlags = URI_STD | URI_DANGEROUS_TO_LOAD;
1141 + return NS_OK;
1144 +NS_IMETHODIMP
1145 +nsGIOProtocolHandler::NewURI(const nsACString &aSpec,
1146 + const char *aOriginCharset,
1147 + nsIURI *aBaseURI,
1148 + nsIURI **aResult)
1150 + const nsCString flatSpec(aSpec);
1151 + LOG(("gio: NewURI [spec=%s]\n", flatSpec.get()));
1153 + if (!aBaseURI)
1155 + // XXX Is it good to support all GIO protocols?
1156 + if (!IsSupportedProtocol(flatSpec))
1157 + return NS_ERROR_UNKNOWN_PROTOCOL;
1159 + PRInt32 colon_location = flatSpec.FindChar(':');
1160 + if (colon_location <= 0)
1161 + return NS_ERROR_UNKNOWN_PROTOCOL;
1163 + // Verify that GIO supports this URI scheme.
1164 + PRBool uri_scheme_supported = PR_FALSE;
1166 + GVfs *gvfs = g_vfs_get_default();
1168 + if (!gvfs) {
1169 + g_warning("Cannot get GVfs object.");
1170 + return NS_ERROR_UNKNOWN_PROTOCOL;
1173 + const gchar* const * uri_schemes = g_vfs_get_supported_uri_schemes(gvfs);
1175 + while (*uri_schemes != NULL) {
1176 + // While flatSpec ends with ':' the uri_scheme does not. Therefore do not
1177 + // compare last character.
1178 + if (StringHead(flatSpec, colon_location).Equals(*uri_schemes)) {
1179 + uri_scheme_supported = PR_TRUE;
1180 + break;
1182 + uri_schemes++;
1185 + if (!uri_scheme_supported) {
1186 + return NS_ERROR_UNKNOWN_PROTOCOL;
1190 + nsresult rv;
1191 + nsCOMPtr<nsIStandardURL> url =
1192 + do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
1193 + if (NS_FAILED(rv))
1194 + return rv;
1196 + rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, flatSpec,
1197 + aOriginCharset, aBaseURI);
1198 + if (NS_SUCCEEDED(rv))
1199 + rv = CallQueryInterface(url, aResult);
1200 + return rv;
1204 +NS_IMETHODIMP
1205 +nsGIOProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult)
1207 + NS_ENSURE_ARG_POINTER(aURI);
1208 + nsresult rv;
1210 + nsCAutoString spec;
1211 + rv = aURI->GetSpec(spec);
1212 + if (NS_FAILED(rv))
1213 + return rv;
1215 + nsRefPtr<nsGIOInputStream> stream = new nsGIOInputStream(spec);
1216 + if (!stream)
1218 + rv = NS_ERROR_OUT_OF_MEMORY;
1220 + else
1222 + // start out assuming an unknown content-type. we'll set the content-type
1223 + // to something better once we open the URI.
1224 + rv = NS_NewInputStreamChannel(aResult,
1225 + aURI,
1226 + stream,
1227 + NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
1228 + if (NS_SUCCEEDED(rv))
1229 + stream->SetChannel(*aResult);
1231 + return rv;
1234 +NS_IMETHODIMP
1235 +nsGIOProtocolHandler::AllowPort(PRInt32 aPort,
1236 + const char *aScheme,
1237 + PRBool *aResult)
1239 + // Don't override anything.
1240 + *aResult = PR_FALSE;
1241 + return NS_OK;
1244 +NS_IMETHODIMP
1245 +nsGIOProtocolHandler::Observe(nsISupports *aSubject,
1246 + const char *aTopic,
1247 + const PRUnichar *aData)
1249 + if (strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1250 + nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
1251 + InitSupportedProtocolsPref(prefs);
1253 + return NS_OK;
1256 +//-----------------------------------------------------------------------------
1258 +#define NS_GIOPROTOCOLHANDLER_CID \
1259 +{ /* ee706783-3af8-4d19-9e84-e2ebfe213480 */ \
1260 + 0xee706783, \
1261 + 0x3af8, \
1262 + 0x4d19, \
1263 + {0x9e, 0x84, 0xe2, 0xeb, 0xfe, 0x21, 0x34, 0x80} \
1266 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGIOProtocolHandler, Init)
1267 +NS_DEFINE_NAMED_CID(NS_GIOPROTOCOLHANDLER_CID);
1269 +static const mozilla::Module::CIDEntry kVFSCIDs[] = {
1270 + { &kNS_GIOPROTOCOLHANDLER_CID, false, NULL, nsGIOProtocolHandlerConstructor },
1271 + { NULL }
1274 +static const mozilla::Module::ContractIDEntry kVFSContracts[] = {
1275 + { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MOZ_GIO_SCHEME, &kNS_GIOPROTOCOLHANDLER_CID },
1276 + { NULL }
1279 +static const mozilla::Module kVFSModule = {
1280 + mozilla::Module::kVersion,
1281 + kVFSCIDs,
1282 + kVFSContracts
1285 +NSMODULE_DEFN(nsGIOModule) = &kVFSModule;
1286 diff -r 49a1b2aa43c5 netwerk/base/src/nsIOService.cpp
1287 --- a/netwerk/base/src/nsIOService.cpp Tue Dec 21 12:42:59 2010 +0100
1288 +++ b/netwerk/base/src/nsIOService.cpp Tue Jan 11 11:17:52 2011 +0100
1289 @@ -454,6 +454,27 @@
1292 #ifdef MOZ_X11
1293 + // check to see whether GVFS can handle this URI scheme. if it can
1294 + // create a nsIURI for the "scheme:", then we assume it has support for
1295 + // the requested protocol. otherwise, we failover to using the default
1296 + // protocol handler.
1298 + rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gio",
1299 + result);
1300 + if (NS_SUCCEEDED(rv)) {
1301 + nsCAutoString spec(scheme);
1302 + spec.Append(':');
1304 + nsIURI *uri;
1305 + rv = (*result)->NewURI(spec, nsnull, nsnull, &uri);
1306 + if (NS_SUCCEEDED(rv)) {
1307 + NS_RELEASE(uri);
1308 + return rv;
1311 + NS_RELEASE(*result);
1314 // check to see whether GnomeVFS can handle this URI scheme. if it can
1315 // create a nsIURI for the "scheme:", then we assume it has support for
1316 // the requested protocol. otherwise, we failover to using the default