netwerk/protocol/file/nsFileProtocolHandler.cpp
author Jonathan Kew <jkew@mozilla.com>
Thu, 26 Apr 2018 17:08:18 +0100
changeset 460792 f1c7ad9294b3c200d66590f0e7ddd8cf0c47f0cf
parent 454120 12eb3cffb3a54b84c19ef380e819c01bc0a65dcb
child 461394 17e1f96d453f869f9bb64cc1d889320ca2b4adba
permissions -rw-r--r--
Bug 1457103 - patch 3 - Make gfxFontEntry::GetVariationAxes and GetVariationInstances pure virtual, and provide missing subclass implementations. r=jwatt

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
// vim:ts=4 sw=4 sts=4 et cin:
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsIFile.h"
#include "nsFileProtocolHandler.h"
#include "nsFileChannel.h"
#include "nsStandardURL.h"
#include "nsURLHelper.h"
#include "nsIURIMutator.h"

#include "nsNetUtil.h"

#include "FileChannelChild.h"

// URL file handling, copied and modified from xpfe/components/bookmarks/src/nsBookmarksService.cpp
#ifdef XP_WIN
#include <shlobj.h>
#include <intshcut.h>
#include "nsIFileURL.h"
#ifdef CompareString
#undef CompareString
#endif
#endif

// URL file handling for freedesktop.org
#ifdef XP_UNIX
#include "nsINIParser.h"
#define DESKTOP_ENTRY_SECTION "Desktop Entry"
#endif

//-----------------------------------------------------------------------------

nsFileProtocolHandler::nsFileProtocolHandler()
{
}

nsresult
nsFileProtocolHandler::Init()
{
    return NS_OK;
}

NS_IMPL_ISUPPORTS(nsFileProtocolHandler,
                  nsIFileProtocolHandler,
                  nsIProtocolHandler,
                  nsISupportsWeakReference)

//-----------------------------------------------------------------------------
// nsIProtocolHandler methods:

#if defined(XP_WIN)
NS_IMETHODIMP
nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
{
    nsAutoString path;
    nsresult rv = aFile->GetPath(path);
    if (NS_FAILED(rv))
        return rv;

    if (path.Length() < 4)
        return NS_ERROR_NOT_AVAILABLE;
    if (!StringTail(path, 4).LowerCaseEqualsLiteral(".url"))
        return NS_ERROR_NOT_AVAILABLE;

    HRESULT result;

    rv = NS_ERROR_NOT_AVAILABLE;

    IUniformResourceLocatorW* urlLink = nullptr;
    result = ::CoCreateInstance(CLSID_InternetShortcut, nullptr, CLSCTX_INPROC_SERVER,
                                IID_IUniformResourceLocatorW, (void**)&urlLink);
    if (SUCCEEDED(result) && urlLink) {
        IPersistFile* urlFile = nullptr;
        result = urlLink->QueryInterface(IID_IPersistFile, (void**)&urlFile);
        if (SUCCEEDED(result) && urlFile) {
            result = urlFile->Load(path.get(), STGM_READ);
            if (SUCCEEDED(result) ) {
                LPWSTR lpTemp = nullptr;

                // The URL this method will give us back seems to be already
                // escaped. Hence, do not do escaping of our own.
                result = urlLink->GetURL(&lpTemp);
                if (SUCCEEDED(result) && lpTemp) {
                    rv = NS_NewURI(aURI, nsDependentString(lpTemp));
                    // free the string that GetURL alloc'd
                    CoTaskMemFree(lpTemp);
                }
            }
            urlFile->Release();
        }
        urlLink->Release();
    }
    return rv;
}

#elif defined(XP_UNIX)
NS_IMETHODIMP
nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
{
    // We only support desktop files that end in ".desktop" like the spec says:
    // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html
    nsAutoCString leafName;
    nsresult rv = aFile->GetNativeLeafName(leafName);
    if (NS_FAILED(rv) ||
	!StringEndsWith(leafName, NS_LITERAL_CSTRING(".desktop")))
        return NS_ERROR_NOT_AVAILABLE;

    bool isFile = false;
    rv = aFile->IsFile(&isFile);
    if (NS_FAILED(rv) || !isFile) {
        return NS_ERROR_NOT_AVAILABLE;
    }

    nsINIParser parser;
    rv = parser.Init(aFile);
    if (NS_FAILED(rv))
        return rv;

    nsAutoCString type;
    parser.GetString(DESKTOP_ENTRY_SECTION, "Type", type);
    if (!type.EqualsLiteral("Link"))
        return NS_ERROR_NOT_AVAILABLE;

    nsAutoCString url;
    rv = parser.GetString(DESKTOP_ENTRY_SECTION, "URL", url);
    if (NS_FAILED(rv) || url.IsEmpty())
        return NS_ERROR_NOT_AVAILABLE;

    return NS_NewURI(aURI, url);
}

#else // other platforms
NS_IMETHODIMP
nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
{
    return NS_ERROR_NOT_AVAILABLE;
}
#endif // ReadURLFile()

NS_IMETHODIMP
nsFileProtocolHandler::GetScheme(nsACString &result)
{
    result.AssignLiteral("file");
    return NS_OK;
}

NS_IMETHODIMP
nsFileProtocolHandler::GetDefaultPort(int32_t *result)
{
    *result = -1;        // no port for file: URLs
    return NS_OK;
}

NS_IMETHODIMP
nsFileProtocolHandler::GetProtocolFlags(uint32_t *result)
{
    *result = URI_NOAUTH | URI_IS_LOCAL_FILE | URI_IS_LOCAL_RESOURCE;
    return NS_OK;
}

NS_IMETHODIMP
nsFileProtocolHandler::NewURI(const nsACString &spec,
                              const char *charset,
                              nsIURI *aBaseURI,
                              nsIURI **result)
{
    nsAutoCString buf(spec);
#if defined(XP_WIN)
    buf.Truncate();
    if (!net_NormalizeFileURL(spec, buf)) {
        buf = spec;
    }
#endif

    nsCOMPtr<nsIURI> base(aBaseURI);
    return NS_MutateURI(new nsStandardURL::Mutator())
      .Apply(NS_MutatorMethod(&nsIFileURLMutator::MarkFileURL))
      .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
                              nsIStandardURL::URLTYPE_NO_AUTHORITY,
                              -1, buf, charset, base, nullptr))
      .Finalize(result);
}

NS_IMETHODIMP
nsFileProtocolHandler::NewChannel2(nsIURI* uri,
                                   nsILoadInfo* aLoadInfo,
                                   nsIChannel** result)
{
    nsresult rv;

    nsFileChannel *chan;
    if (IsNeckoChild()) {
        chan = new mozilla::net::FileChannelChild(uri);
    } else {
        chan = new nsFileChannel(uri);
    }
    if (!chan)
        return NS_ERROR_OUT_OF_MEMORY;
    NS_ADDREF(chan);

    // set the loadInfo on the new channel ; must do this
    // before calling Init() on it, since it needs the load
    // info be already set.
    rv = chan->SetLoadInfo(aLoadInfo);
    if (NS_FAILED(rv)) {
        NS_RELEASE(chan);
        return rv;
    }

    rv = chan->Init();
    if (NS_FAILED(rv)) {
        NS_RELEASE(chan);
        return rv;
    }

    *result = chan;
    return NS_OK;
}

NS_IMETHODIMP
nsFileProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
{
    return NewChannel2(uri, nullptr, result);
}

NS_IMETHODIMP
nsFileProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *result)
{
    // don't override anything.
    *result = false;
    return NS_OK;
}

//-----------------------------------------------------------------------------
// nsIFileProtocolHandler methods:

NS_IMETHODIMP
nsFileProtocolHandler::NewFileURI(nsIFile *aFile, nsIURI **aResult)
{
    NS_ENSURE_ARG_POINTER(aFile);

    RefPtr<nsIFile> file(aFile);
    // NOTE: the origin charset is assigned the value of the platform
    // charset by the SetFile method.
    return NS_MutateURI(new nsStandardURL::Mutator())
             .Apply(NS_MutatorMethod(&nsIFileURLMutator::SetFile, file))
             .Finalize(aResult);
}

NS_IMETHODIMP
nsFileProtocolHandler::NewFileURIMutator(nsIFile *aFile, nsIURIMutator **aResult)
{
    NS_ENSURE_ARG_POINTER(aFile);
    nsresult rv;

    nsCOMPtr<nsIURIMutator> mutator = new nsStandardURL::Mutator();
    nsCOMPtr<nsIFileURLMutator> fileMutator = do_QueryInterface(mutator, &rv);
    if (NS_FAILED(rv)) {
        return rv;
    }

    // NOTE: the origin charset is assigned the value of the platform
    // charset by the SetFile method.
    rv = fileMutator->SetFile(aFile);
    if (NS_FAILED(rv)) {
        return rv;
    }

    mutator.forget(aResult);
    return NS_OK;
}

NS_IMETHODIMP
nsFileProtocolHandler::GetURLSpecFromFile(nsIFile *file, nsACString &result)
{
    NS_ENSURE_ARG_POINTER(file);
    return net_GetURLSpecFromFile(file, result);
}

NS_IMETHODIMP
nsFileProtocolHandler::GetURLSpecFromActualFile(nsIFile *file,
                                                nsACString &result)
{
    NS_ENSURE_ARG_POINTER(file);
    return net_GetURLSpecFromActualFile(file, result);
}

NS_IMETHODIMP
nsFileProtocolHandler::GetURLSpecFromDir(nsIFile *file, nsACString &result)
{
    NS_ENSURE_ARG_POINTER(file);
    return net_GetURLSpecFromDir(file, result);
}

NS_IMETHODIMP
nsFileProtocolHandler::GetFileFromURLSpec(const nsACString &spec, nsIFile **result)
{
    return net_GetFileFromURLSpec(spec, result);
}