diff --git a/mozilla/modules/libjar/nsJARURI.cpp b/mozilla/modules/libjar/nsJARURI.cpp index 74804bb673c..d89236e9fc3 100644 --- a/mozilla/modules/libjar/nsJARURI.cpp +++ b/mozilla/modules/libjar/nsJARURI.cpp @@ -24,11 +24,13 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIZipReader.h" + static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); //////////////////////////////////////////////////////////////////////////////// nsJARURI::nsJARURI() + : mJAREntry(nsnull) { NS_INIT_REFCNT(); } @@ -67,14 +69,11 @@ nsJARURI::Init() return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsURI methods: - #define NS_JAR_SCHEME "jar:" #define NS_JAR_DELIMITER "!/" -NS_IMETHODIMP -nsJARURI::GetSpec(char* *aSpec) +nsresult +nsJARURI::FormatSpec(const char* entryPath, char* *result) { nsresult rv; char* jarFileSpec; @@ -85,10 +84,19 @@ nsJARURI::GetSpec(char* *aSpec) spec += jarFileSpec; nsCRT::free(jarFileSpec); spec += NS_JAR_DELIMITER; - spec += mJAREntry; + spec += entryPath; - *aSpec = nsCRT::strdup(spec); - return *aSpec ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + *result = nsCRT::strdup(spec); + return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsURI methods: + +NS_IMETHODIMP +nsJARURI::GetSpec(char* *aSpec) +{ + return FormatSpec(mJAREntry, aSpec); } NS_IMETHODIMP @@ -103,7 +111,7 @@ nsJARURI::SetSpec(const char * aSpec) if (NS_FAILED(rv)) return rv; if (nsCRT::strncmp("jar", &aSpec[startPos], endPos - startPos - 1) != 0) - return NS_ERROR_FAILURE; + return NS_ERROR_MALFORMED_URI; // Search backward from the end for the "!/" delimiter. Remember, jar URLs // can nest, e.g.: @@ -125,11 +133,8 @@ nsJARURI::SetSpec(const char * aSpec) nsCAutoString entry(aSpec); entry.Cut(0, pos + 2); // 2 == strlen(NS_JAR_DELIMITER) - mJAREntry = nsCRT::strdup(entry); - if (mJAREntry == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - return NS_OK; + rv = serv->ResolveRelativePath(entry, nsnull, &mJAREntry); + return rv; } NS_IMETHODIMP @@ -142,7 +147,8 @@ nsJARURI::GetScheme(char * *aScheme) NS_IMETHODIMP nsJARURI::SetScheme(const char * aScheme) { - return NS_ERROR_NOT_IMPLEMENTED; + // doesn't make sense to set the scheme of a jar: URL + return NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -194,61 +200,149 @@ nsJARURI::SetPath(const char * aPath) } NS_IMETHODIMP -nsJARURI::Equals(nsIURI *other, PRBool *_retval) +nsJARURI::Equals(nsIURI *other, PRBool *result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + *result = PR_FALSE; + + nsJARURI* otherJAR; + rv = other->QueryInterface(NS_GET_IID(nsIJARURI), (void**)&otherJAR); + if (NS_FAILED(rv)) + return NS_OK; // not equal + + nsCOMPtr otherJARFile; + rv = otherJAR->GetJARFile(getter_AddRefs(otherJARFile)); + if (NS_FAILED(rv)) return rv; + + PRBool equal; + rv = mJARFile->Equals(otherJARFile, &equal); + if (NS_FAILED(rv)) return rv; + if (!equal) + return NS_OK; // not equal + + char* otherJAREntry; + rv = otherJAR->GetJAREntry(&otherJAREntry); + if (NS_FAILED(rv)) return rv; + + *result = nsCRT::strcmp(mJAREntry, otherJAREntry) == 0; + nsCRT::free(otherJAREntry); + return NS_OK; } NS_IMETHODIMP -nsJARURI::Clone(nsIURI **_retval) +nsJARURI::Clone(nsIURI **result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + + nsCOMPtr newJARFile; + rv = mJARFile->Clone(getter_AddRefs(newJARFile)); + if (NS_FAILED(rv)) return rv; + + char* newJAREntry = nsCRT::strdup(mJAREntry); + if (newJAREntry == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsJARURI* uri = new nsJARURI(); + if (uri == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(uri); + uri->mJARFile = newJARFile; + uri->mJAREntry = newJAREntry; + *result = uri; + + return NS_OK; } NS_IMETHODIMP -nsJARURI::SetRelativePath(const char *i_RelativePath) +nsJARURI::SetRelativePath(const char *relativePath) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path(mJAREntry); + PRInt32 pos = path.RFind("/"); + if (pos >= 0) + path.Truncate(pos + 1); + else + path = ""; + + char* resolvedEntry; + rv = serv->ResolveRelativePath(relativePath, path.GetBuffer(), + &resolvedEntry); + if (NS_FAILED(rv)) return rv; + + nsCRT::free(mJAREntry); + mJAREntry = resolvedEntry; + return NS_OK; } NS_IMETHODIMP -nsJARURI::Resolve(const char *relativePath, char **_retval) +nsJARURI::Resolve(const char *relativePath, char **result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path(mJAREntry); + PRInt32 pos = path.RFind("/"); + if (pos >= 0) + path.Truncate(pos + 1); + else + path = ""; + + char* resolvedEntry; + rv = serv->ResolveRelativePath(relativePath, path.GetBuffer(), + &resolvedEntry); + if (NS_FAILED(rv)) return rv; + + rv = FormatSpec(resolvedEntry, result); + nsCRT::free(resolvedEntry); + return rv; } //////////////////////////////////////////////////////////////////////////////// // nsIJARUri methods: NS_IMETHODIMP -nsJARURI::GetJARFile(nsIURI* *rootURI) +nsJARURI::GetJARFile(nsIURI* *jarFile) { - *rootURI = mJARFile; - NS_ADDREF(*rootURI); + *jarFile = mJARFile; + NS_ADDREF(*jarFile); return NS_OK; } NS_IMETHODIMP -nsJARURI::SetJARFile(nsIURI* rootURI) +nsJARURI::SetJARFile(nsIURI* jarFile) { - mJARFile = rootURI; + mJARFile = jarFile; return NS_OK; } NS_IMETHODIMP -nsJARURI::GetJAREntry(char* *relativeURI) +nsJARURI::GetJAREntry(char* *entryPath) { - *relativeURI = nsCRT::strdup(mJAREntry); - return *relativeURI ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + nsCAutoString entry(mJAREntry); + PRInt32 pos = entry.RFindCharInSet("#?;"); + if (pos >= 0) + entry.Truncate(pos); + *entryPath = entry.ToNewCString(); + return *entryPath ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP -nsJARURI::SetJAREntry(const char* relativeURI) +nsJARURI::SetJAREntry(const char* entryPath) { + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + if (mJAREntry) nsCRT::free(mJAREntry); - mJAREntry = nsCRT::strdup(relativeURI); - return mJAREntry ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + + rv = serv->ResolveRelativePath(entryPath, nsnull, &mJAREntry); + return rv; } //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/modules/libjar/nsJARURI.h b/mozilla/modules/libjar/nsJARURI.h index 3167f12c746..fbbc9e96286 100644 --- a/mozilla/modules/libjar/nsJARURI.h +++ b/mozilla/modules/libjar/nsJARURI.h @@ -45,6 +45,7 @@ public: Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); nsresult Init(); + nsresult FormatSpec(const char* entryPath, char* *result); protected: nsCOMPtr mJARFile; diff --git a/mozilla/netwerk/base/public/nsIIOService.idl b/mozilla/netwerk/base/public/nsIIOService.idl index 395f31a4d03..b63c37b1ef8 100644 --- a/mozilla/netwerk/base/public/nsIIOService.idl +++ b/mozilla/netwerk/base/public/nsIIOService.idl @@ -39,7 +39,7 @@ interface nsIFile; interface nsIInputStream; interface nsIOutputStream; -[scriptable, uuid(1daf19f0-8ea7-11d3-93ad-00104ba0fd40)] +[scriptable, uuid(ab7c3a84-d488-11d3-8cda-0060b0fc14a3)] interface nsIIOService : nsISupports { /** @@ -124,6 +124,17 @@ interface nsIIOService : nsISupports */ readonly attribute wstring userAgent; + /** + * Returns true if networking is in "offline" mode. When in offline mode, attempts + * to access the network will fail (although this is not necessarily corrolated with + * whether there is actually a network available -- that's hard to detect without + * causing the dialer to come up). + */ + attribute boolean offline; + + //////////////////////////////////////////////////////////////////////////// + // URL parsing utilities + /** * Utility for protocol implementors -- extracts the scheme from a URL * string, consistently and according to spec. @@ -145,13 +156,30 @@ interface nsIIOService : nsISupports out string scheme); /** - * Returns true if networking is in "offline" mode. When in offline mode, attempts - * to access the network will fail (although this is not necessarily corrolated with - * whether there is actually a network available -- that's hard to detect without - * causing the dialer to come up). + * Encode characters into % escaped hexcodes. */ - attribute boolean offline; + string escape(in string str, in short mask); + /** + * Decode % escaped hex codes into character values. + */ + string unescape(in string str); + + /** + * Get port from string. + */ + long extractPort(in string str); + + /** + * Resolves a relative path string containing "." and ".." + * with respect to a base path (assumed to already be resolved). + * For example, resolving "../../foo/./bar/../baz.html" w.r.t. + * "/a/b/c/d/e/" yields "/a/b/c/foo/baz.html". Attempting to + * ascend above the base results in the NS_ERROR_MALFORMED_URI + * exception. If basePath is null, it treats it as "/". + */ + string resolveRelativePath(in string relativePath, + in string basePath); }; %{C++ diff --git a/mozilla/netwerk/base/src/nsIOService.cpp b/mozilla/netwerk/base/src/nsIOService.cpp index 6fe274f5e66..550b9b920bc 100644 --- a/mozilla/netwerk/base/src/nsIOService.cpp +++ b/mozilla/netwerk/base/src/nsIOService.cpp @@ -387,3 +387,88 @@ nsIOService::SetOffline(PRBool offline) } //////////////////////////////////////////////////////////////////////////////// +// URL parsing utilities + +NS_IMETHODIMP +nsIOService::Escape(const char *str, PRInt16 mask, char **result) +{ + // XXX Andreas + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsIOService::Unescape(const char *str, char **result) +{ + // XXX Andreas + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsIOService::ExtractPort(const char *str, PRInt32 *result) +{ + // XXX Andreas + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsIOService::ResolveRelativePath(const char *relativePath, const char* basePath, + char **result) +{ + nsCAutoString name; + nsCAutoString path(basePath); + + PRUnichar last = path.Last(); + PRBool needsDelim = !(last == '/' || last == '\\' || last == '\0'); + + PRBool end = PR_FALSE; + char c; + while (!end) { + c = *relativePath++; + switch (c) { + case '\0': + case '#': + case ';': + case '?': + end = PR_TRUE; + // fall through... + case '/': + case '\\': + // delimiter found + if (name.Equals("..")) { + // pop path + PRInt32 pos = path.RFind("/"); + if (pos > 0) { + path.Truncate(pos + 1); + path += name; + } + else { + return NS_ERROR_MALFORMED_URI; + } + } + else if (name.Equals(".") || name.Equals("")) { + // do nothing + } + else { + // append name to path + if (needsDelim) + path += "/"; + path += name; + needsDelim = PR_TRUE; + } + name = ""; + break; + + default: + // append char to name + name += c; + } + } + // append anything left on relativePath (e.g. #..., ;..., ?...) + if (c != '\0') + path += --relativePath; + + *result = path.ToNewCString(); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/netwerk/protocol/jar/src/nsJARURI.cpp b/mozilla/netwerk/protocol/jar/src/nsJARURI.cpp index 74804bb673c..d89236e9fc3 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARURI.cpp +++ b/mozilla/netwerk/protocol/jar/src/nsJARURI.cpp @@ -24,11 +24,13 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIZipReader.h" + static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); //////////////////////////////////////////////////////////////////////////////// nsJARURI::nsJARURI() + : mJAREntry(nsnull) { NS_INIT_REFCNT(); } @@ -67,14 +69,11 @@ nsJARURI::Init() return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsURI methods: - #define NS_JAR_SCHEME "jar:" #define NS_JAR_DELIMITER "!/" -NS_IMETHODIMP -nsJARURI::GetSpec(char* *aSpec) +nsresult +nsJARURI::FormatSpec(const char* entryPath, char* *result) { nsresult rv; char* jarFileSpec; @@ -85,10 +84,19 @@ nsJARURI::GetSpec(char* *aSpec) spec += jarFileSpec; nsCRT::free(jarFileSpec); spec += NS_JAR_DELIMITER; - spec += mJAREntry; + spec += entryPath; - *aSpec = nsCRT::strdup(spec); - return *aSpec ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + *result = nsCRT::strdup(spec); + return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsURI methods: + +NS_IMETHODIMP +nsJARURI::GetSpec(char* *aSpec) +{ + return FormatSpec(mJAREntry, aSpec); } NS_IMETHODIMP @@ -103,7 +111,7 @@ nsJARURI::SetSpec(const char * aSpec) if (NS_FAILED(rv)) return rv; if (nsCRT::strncmp("jar", &aSpec[startPos], endPos - startPos - 1) != 0) - return NS_ERROR_FAILURE; + return NS_ERROR_MALFORMED_URI; // Search backward from the end for the "!/" delimiter. Remember, jar URLs // can nest, e.g.: @@ -125,11 +133,8 @@ nsJARURI::SetSpec(const char * aSpec) nsCAutoString entry(aSpec); entry.Cut(0, pos + 2); // 2 == strlen(NS_JAR_DELIMITER) - mJAREntry = nsCRT::strdup(entry); - if (mJAREntry == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - return NS_OK; + rv = serv->ResolveRelativePath(entry, nsnull, &mJAREntry); + return rv; } NS_IMETHODIMP @@ -142,7 +147,8 @@ nsJARURI::GetScheme(char * *aScheme) NS_IMETHODIMP nsJARURI::SetScheme(const char * aScheme) { - return NS_ERROR_NOT_IMPLEMENTED; + // doesn't make sense to set the scheme of a jar: URL + return NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -194,61 +200,149 @@ nsJARURI::SetPath(const char * aPath) } NS_IMETHODIMP -nsJARURI::Equals(nsIURI *other, PRBool *_retval) +nsJARURI::Equals(nsIURI *other, PRBool *result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + *result = PR_FALSE; + + nsJARURI* otherJAR; + rv = other->QueryInterface(NS_GET_IID(nsIJARURI), (void**)&otherJAR); + if (NS_FAILED(rv)) + return NS_OK; // not equal + + nsCOMPtr otherJARFile; + rv = otherJAR->GetJARFile(getter_AddRefs(otherJARFile)); + if (NS_FAILED(rv)) return rv; + + PRBool equal; + rv = mJARFile->Equals(otherJARFile, &equal); + if (NS_FAILED(rv)) return rv; + if (!equal) + return NS_OK; // not equal + + char* otherJAREntry; + rv = otherJAR->GetJAREntry(&otherJAREntry); + if (NS_FAILED(rv)) return rv; + + *result = nsCRT::strcmp(mJAREntry, otherJAREntry) == 0; + nsCRT::free(otherJAREntry); + return NS_OK; } NS_IMETHODIMP -nsJARURI::Clone(nsIURI **_retval) +nsJARURI::Clone(nsIURI **result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + + nsCOMPtr newJARFile; + rv = mJARFile->Clone(getter_AddRefs(newJARFile)); + if (NS_FAILED(rv)) return rv; + + char* newJAREntry = nsCRT::strdup(mJAREntry); + if (newJAREntry == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsJARURI* uri = new nsJARURI(); + if (uri == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(uri); + uri->mJARFile = newJARFile; + uri->mJAREntry = newJAREntry; + *result = uri; + + return NS_OK; } NS_IMETHODIMP -nsJARURI::SetRelativePath(const char *i_RelativePath) +nsJARURI::SetRelativePath(const char *relativePath) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path(mJAREntry); + PRInt32 pos = path.RFind("/"); + if (pos >= 0) + path.Truncate(pos + 1); + else + path = ""; + + char* resolvedEntry; + rv = serv->ResolveRelativePath(relativePath, path.GetBuffer(), + &resolvedEntry); + if (NS_FAILED(rv)) return rv; + + nsCRT::free(mJAREntry); + mJAREntry = resolvedEntry; + return NS_OK; } NS_IMETHODIMP -nsJARURI::Resolve(const char *relativePath, char **_retval) +nsJARURI::Resolve(const char *relativePath, char **result) { - return NS_ERROR_NOT_IMPLEMENTED; + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path(mJAREntry); + PRInt32 pos = path.RFind("/"); + if (pos >= 0) + path.Truncate(pos + 1); + else + path = ""; + + char* resolvedEntry; + rv = serv->ResolveRelativePath(relativePath, path.GetBuffer(), + &resolvedEntry); + if (NS_FAILED(rv)) return rv; + + rv = FormatSpec(resolvedEntry, result); + nsCRT::free(resolvedEntry); + return rv; } //////////////////////////////////////////////////////////////////////////////// // nsIJARUri methods: NS_IMETHODIMP -nsJARURI::GetJARFile(nsIURI* *rootURI) +nsJARURI::GetJARFile(nsIURI* *jarFile) { - *rootURI = mJARFile; - NS_ADDREF(*rootURI); + *jarFile = mJARFile; + NS_ADDREF(*jarFile); return NS_OK; } NS_IMETHODIMP -nsJARURI::SetJARFile(nsIURI* rootURI) +nsJARURI::SetJARFile(nsIURI* jarFile) { - mJARFile = rootURI; + mJARFile = jarFile; return NS_OK; } NS_IMETHODIMP -nsJARURI::GetJAREntry(char* *relativeURI) +nsJARURI::GetJAREntry(char* *entryPath) { - *relativeURI = nsCRT::strdup(mJAREntry); - return *relativeURI ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + nsCAutoString entry(mJAREntry); + PRInt32 pos = entry.RFindCharInSet("#?;"); + if (pos >= 0) + entry.Truncate(pos); + *entryPath = entry.ToNewCString(); + return *entryPath ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP -nsJARURI::SetJAREntry(const char* relativeURI) +nsJARURI::SetJAREntry(const char* entryPath) { + nsresult rv; + NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + if (mJAREntry) nsCRT::free(mJAREntry); - mJAREntry = nsCRT::strdup(relativeURI); - return mJAREntry ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + + rv = serv->ResolveRelativePath(entryPath, nsnull, &mJAREntry); + return rv; } //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/netwerk/protocol/jar/src/nsJARURI.h b/mozilla/netwerk/protocol/jar/src/nsJARURI.h index 3167f12c746..fbbc9e96286 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARURI.h +++ b/mozilla/netwerk/protocol/jar/src/nsJARURI.h @@ -45,6 +45,7 @@ public: Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); nsresult Init(); + nsresult FormatSpec(const char* entryPath, char* *result); protected: nsCOMPtr mJARFile;