nsresult
SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
{
  nsresult rv;

  nsAutoCString host;
  nsAutoCString path;

  rv = uri->GetAsciiHost(host);
  if (NS_FAILED(rv)) return rv;

  rv = uri->GetPath(path);
  if (NS_FAILED(rv)) return rv;

  if (ResolveSpecialCases(host, path, result)) {
    return NS_OK;
  }

  nsCOMPtr<nsIURI> baseURI;
  rv = GetSubstitution(host, getter_AddRefs(baseURI));
  if (NS_FAILED(rv)) return rv;

  // Unescape the path so we can perform some checks on it.
  nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
  if (!url) {
    return NS_ERROR_MALFORMED_URI;
  }

  nsAutoCString unescapedPath;
  rv = url->GetFilePath(unescapedPath);
  if (NS_FAILED(rv)) return rv;

  NS_UnescapeURL(unescapedPath);
  if (unescapedPath.FindChar('\\') != -1) {
    return NS_ERROR_MALFORMED_URI;
  }

  // Some code relies on an empty path resolving to a file rather than a
  // directory.
  NS_ASSERTION(path.CharAt(0) == '/', "Path must begin with '/'");
  if (path.Length() == 1) {
    rv = baseURI->GetSpec(result);
  } else {
    // Make sure we always resolve the path as file-relative to our target URI.
    path.InsertLiteral(".", 0);

    rv = baseURI->Resolve(path, result);
  }

  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) {
    nsAutoCString spec;
    uri->GetAsciiSpec(spec);
    MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
  }
  return rv;
}
nsresult
nsResProtocolHandler::Init()
{
    if (!mSubstitutions.Init(32))
        return NS_ERROR_UNEXPECTED;

    nsresult rv;

    mIOService = do_GetIOService(&rv);
    NS_ENSURE_SUCCESS(rv, rv);

#ifdef MOZ_OMNIJAR
    nsCOMPtr<nsIFile> omniJar(mozilla::OmnijarPath());
    if (omniJar)
        return Init(omniJar);
#endif

    // these entries should be kept in sync with the omnijar Init function

    //
    // make resource:/// point to the application directory
    //
    rv = AddSpecialDir(NS_OS_CURRENT_PROCESS_DIR, EmptyCString());
    NS_ENSURE_SUCCESS(rv, rv);

    //
    // make resource://gre/ point to the GRE directory
    //
    rv = AddSpecialDir(NS_GRE_DIR, kGRE);
    NS_ENSURE_SUCCESS(rv, rv);

    // make resource://gre-resources/ point to gre toolkit[.jar]/res
    nsCOMPtr<nsIURI> greURI;
    nsCOMPtr<nsIURI> greResURI;
    GetSubstitution(kGRE, getter_AddRefs(greURI));
#ifdef MOZ_CHROME_FILE_FORMAT_JAR
    NS_NAMED_LITERAL_CSTRING(strGRE_RES_URL, "jar:chrome/toolkit.jar!/res/");
#else
    NS_NAMED_LITERAL_CSTRING(strGRE_RES_URL, "chrome/toolkit/res/");
#endif
    rv = mIOService->NewURI(strGRE_RES_URL, nsnull, greURI,
                            getter_AddRefs(greResURI));
    SetSubstitution(kGRE_RESOURCES, greResURI);
    //XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
    // but once I finish multiple chrome registration I'm not sure that it is needed

    // XXX dveditz: resource://pchrome/ defeats profile directory salting
    // if web content can load it. Tread carefully.

    return rv;
}
NS_IMETHODIMP
nsResProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
{
    nsresult rv;

    nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
    if (!url)
        return NS_NOINTERFACE;

    nsCAutoString host;
    nsCAutoString path;

    rv = uri->GetAsciiHost(host);
    if (NS_FAILED(rv)) return rv;

    rv = uri->GetPath(path);
    if (NS_FAILED(rv)) return rv;

    nsCAutoString filepath;
    url->GetFilePath(filepath);

    // Don't misinterpret the filepath as an absolute URI.
    if (filepath.FindChar(':') != -1)
        return NS_ERROR_MALFORMED_URI;

    NS_UnescapeURL(filepath);
    if (filepath.FindChar('\\') != -1)
        return NS_ERROR_MALFORMED_URI;

    const char *p = path.get() + 1; // path always starts with a slash
    NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!");

    if (*p == '/')
        return NS_ERROR_MALFORMED_URI;

    nsCOMPtr<nsIURI> baseURI;
    rv = GetSubstitution(host, getter_AddRefs(baseURI));
    if (NS_FAILED(rv)) return rv;

    rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result);

#if defined(PR_LOGGING)
    if (PR_LOG_TEST(gResLog, PR_LOG_DEBUG)) {
        nsCAutoString spec;
        uri->GetAsciiSpec(spec);
        LOG(("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
    }
#endif
    return rv;
}
nsresult
SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
{
  nsresult rv;

  nsAutoCString host;
  nsAutoCString path;

  rv = uri->GetAsciiHost(host);
  if (NS_FAILED(rv)) return rv;

  rv = uri->GetPath(path);
  if (NS_FAILED(rv)) return rv;

  if (ResolveSpecialCases(host, path, result)) {
    return NS_OK;
  }

  // Unescape the path so we can perform some checks on it.
  nsAutoCString unescapedPath(path);
  NS_UnescapeURL(unescapedPath);

  // Don't misinterpret the filepath as an absolute URI.
  if (unescapedPath.FindChar(':') != -1)
    return NS_ERROR_MALFORMED_URI;

  if (unescapedPath.FindChar('\\') != -1)
    return NS_ERROR_MALFORMED_URI;

  const char *p = path.get() + 1; // path always starts with a slash
  NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!");

  if (*p == '/')
    return NS_ERROR_MALFORMED_URI;

  nsCOMPtr<nsIURI> baseURI;
  rv = GetSubstitution(host, getter_AddRefs(baseURI));
  if (NS_FAILED(rv)) return rv;

  rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result);

  if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) {
    nsAutoCString spec;
    uri->GetAsciiSpec(spec);
    MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
  }
  return rv;
}