Fixes to make jar: protocol actually be able to visit html files packaged in zip files. Resolves relative links now, although doesn't handle going to # anchors in html pages properly yet. Good enough for chrome work.

This commit is contained in:
warren%netscape.com 2000-01-27 08:57:14 +00:00
parent 94e7ff67cd
commit c6cf2a3361
6 changed files with 377 additions and 74 deletions

View File

@ -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<nsIURI> 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<nsIURI> 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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -45,6 +45,7 @@ public:
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
nsresult Init();
nsresult FormatSpec(const char* entryPath, char* *result);
protected:
nsCOMPtr<nsIURI> mJARFile;

View File

@ -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++

View File

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<nsIURI> 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<nsIURI> 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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -45,6 +45,7 @@ public:
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
nsresult Init();
nsresult FormatSpec(const char* entryPath, char* *result);
protected:
nsCOMPtr<nsIURI> mJARFile;