2001-12-22 09:15:51 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2004-08-04 17:08:27 +00:00
|
|
|
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
2001-12-22 09:15:51 +00:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-04-18 22:01:16 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
2000-01-17 06:05:43 +00:00
|
|
|
*
|
2004-04-18 22:01:16 +00:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
2000-01-17 06:05:43 +00:00
|
|
|
*
|
2001-12-22 09:15:51 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
2000-01-17 06:05:43 +00:00
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2001-12-22 09:15:51 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Andreas Otte.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2000-01-17 06:05:43 +00:00
|
|
|
*
|
2001-12-22 09:15:51 +00:00
|
|
|
* Contributor(s):
|
2002-09-13 19:32:45 +00:00
|
|
|
* Darin Fisher <darin@netscape.com>
|
2001-12-22 09:15:51 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
2004-04-18 22:01:16 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2001-12-22 09:15:51 +00:00
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
2004-04-18 22:01:16 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2001-12-22 09:15:51 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
2000-01-17 06:05:43 +00:00
|
|
|
#include "nsURLHelper.h"
|
2002-09-27 01:26:52 +00:00
|
|
|
#include "nsReadableUtils.h"
|
2002-09-13 19:32:45 +00:00
|
|
|
#include "nsIServiceManager.h"
|
2000-03-18 11:07:04 +00:00
|
|
|
#include "nsIIOService.h"
|
2002-09-13 19:32:45 +00:00
|
|
|
#include "nsIURLParser.h"
|
2000-05-07 10:43:36 +00:00
|
|
|
#include "nsIURI.h"
|
2002-09-13 19:32:45 +00:00
|
|
|
#include "nsMemory.h"
|
2001-09-08 12:47:05 +00:00
|
|
|
#include "nsEscape.h"
|
2002-09-13 19:32:45 +00:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsNetCID.h"
|
2002-03-06 07:48:55 +00:00
|
|
|
#include "netCore.h"
|
2002-09-13 19:32:45 +00:00
|
|
|
#include "prprf.h"
|
2000-05-11 22:24:39 +00:00
|
|
|
|
2001-04-11 11:06:25 +00:00
|
|
|
#if defined(XP_WIN)
|
2000-05-02 03:58:25 +00:00
|
|
|
#include <windows.h> // ::IsDBCSLeadByte need
|
|
|
|
#endif
|
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Init/Shutdown
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static PRBool gInitialized = PR_FALSE;
|
|
|
|
static nsIURLParser *gNoAuthURLParser = nsnull;
|
|
|
|
static nsIURLParser *gAuthURLParser = nsnull;
|
|
|
|
static nsIURLParser *gStdURLParser = nsnull;
|
|
|
|
|
|
|
|
static void
|
|
|
|
InitGlobals()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURLParser> parser;
|
|
|
|
|
|
|
|
parser = do_GetService(NS_NOAUTHURLPARSER_CONTRACTID);
|
|
|
|
NS_ASSERTION(parser, "failed getting 'noauth' url parser");
|
|
|
|
if (parser) {
|
|
|
|
gNoAuthURLParser = parser.get();
|
|
|
|
NS_ADDREF(gNoAuthURLParser);
|
|
|
|
}
|
|
|
|
|
|
|
|
parser = do_GetService(NS_AUTHURLPARSER_CONTRACTID);
|
|
|
|
NS_ASSERTION(parser, "failed getting 'auth' url parser");
|
|
|
|
if (parser) {
|
|
|
|
gAuthURLParser = parser.get();
|
|
|
|
NS_ADDREF(gAuthURLParser);
|
|
|
|
}
|
|
|
|
|
|
|
|
parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
|
|
|
|
NS_ASSERTION(parser, "failed getting 'std' url parser");
|
|
|
|
if (parser) {
|
|
|
|
gStdURLParser = parser.get();
|
|
|
|
NS_ADDREF(gStdURLParser);
|
|
|
|
}
|
|
|
|
|
|
|
|
gInitialized = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
net_ShutdownURLHelper()
|
|
|
|
{
|
|
|
|
if (gInitialized) {
|
|
|
|
NS_IF_RELEASE(gNoAuthURLParser);
|
|
|
|
NS_IF_RELEASE(gAuthURLParser);
|
|
|
|
NS_IF_RELEASE(gStdURLParser);
|
|
|
|
gInitialized = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// nsIURLParser getters
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsIURLParser *
|
|
|
|
net_GetAuthURLParser()
|
|
|
|
{
|
|
|
|
if (!gInitialized)
|
|
|
|
InitGlobals();
|
|
|
|
return gAuthURLParser;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIURLParser *
|
|
|
|
net_GetNoAuthURLParser()
|
|
|
|
{
|
|
|
|
if (!gInitialized)
|
|
|
|
InitGlobals();
|
|
|
|
return gNoAuthURLParser;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIURLParser *
|
|
|
|
net_GetStdURLParser()
|
|
|
|
{
|
|
|
|
if (!gInitialized)
|
|
|
|
InitGlobals();
|
|
|
|
return gStdURLParser;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// file:// URL parsing
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
net_ParseFileURL(const nsACString &inURL,
|
|
|
|
nsACString &outDirectory,
|
|
|
|
nsACString &outFileBaseName,
|
|
|
|
nsACString &outFileExtension)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
outDirectory.Truncate();
|
|
|
|
outFileBaseName.Truncate();
|
|
|
|
outFileExtension.Truncate();
|
|
|
|
|
2003-07-09 05:11:10 +00:00
|
|
|
const nsPromiseFlatCString &flatURL = PromiseFlatCString(inURL);
|
|
|
|
const char *url = flatURL.get();
|
|
|
|
|
|
|
|
PRUint32 schemeBeg, schemeEnd;
|
|
|
|
rv = net_ExtractURLScheme(flatURL, &schemeBeg, &schemeEnd, nsnull);
|
2002-09-13 19:32:45 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2003-07-09 05:11:10 +00:00
|
|
|
if (strncmp(url + schemeBeg, "file", schemeEnd - schemeBeg) != 0) {
|
2002-09-13 19:32:45 +00:00
|
|
|
NS_ERROR("must be a file:// url");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIURLParser *parser = net_GetNoAuthURLParser();
|
|
|
|
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
PRUint32 pathPos, filepathPos, directoryPos, basenamePos, extensionPos;
|
|
|
|
PRInt32 pathLen, filepathLen, directoryLen, basenameLen, extensionLen;
|
|
|
|
|
|
|
|
// invoke the parser to extract the URL path
|
|
|
|
rv = parser->ParseURL(url, flatURL.Length(),
|
|
|
|
nsnull, nsnull, // dont care about scheme
|
|
|
|
nsnull, nsnull, // dont care about authority
|
|
|
|
&pathPos, &pathLen);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// invoke the parser to extract filepath from the path
|
|
|
|
rv = parser->ParsePath(url + pathPos, pathLen,
|
|
|
|
&filepathPos, &filepathLen,
|
|
|
|
nsnull, nsnull, // dont care about param
|
|
|
|
nsnull, nsnull, // dont care about query
|
|
|
|
nsnull, nsnull); // dont care about ref
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
filepathPos += pathPos;
|
|
|
|
|
|
|
|
// invoke the parser to extract the directory and filename from filepath
|
|
|
|
rv = parser->ParseFilePath(url + filepathPos, filepathLen,
|
|
|
|
&directoryPos, &directoryLen,
|
|
|
|
&basenamePos, &basenameLen,
|
|
|
|
&extensionPos, &extensionLen);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
if (directoryLen > 0)
|
|
|
|
outDirectory = Substring(inURL, filepathPos + directoryPos, directoryLen);
|
|
|
|
if (basenameLen > 0)
|
|
|
|
outFileBaseName = Substring(inURL, filepathPos + basenamePos, basenameLen);
|
|
|
|
if (extensionLen > 0)
|
|
|
|
outFileExtension = Substring(inURL, filepathPos + extensionPos, extensionLen);
|
|
|
|
// since we are using a no-auth url parser, there will never be a host
|
|
|
|
// XXX not strictly true... file://localhost/foo/bar.html is a valid URL
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// path manipulation functions
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2003-07-16 19:09:00 +00:00
|
|
|
// Replace all /./ with a / while resolving URLs
|
2001-08-21 20:35:01 +00:00
|
|
|
// But only till #?
|
2001-10-23 01:37:21 +00:00
|
|
|
void
|
2003-07-16 19:09:00 +00:00
|
|
|
net_CoalesceDirs(netCoalesceFlags flags, char* path)
|
2000-01-17 06:05:43 +00:00
|
|
|
{
|
|
|
|
/* Stolen from the old netlib's mkparse.c.
|
|
|
|
*
|
|
|
|
* modifies a url of the form /foo/../foo1 -> /foo1
|
|
|
|
* and /foo/./foo1 -> /foo/foo1
|
|
|
|
* and /foo/foo1/.. -> /foo/
|
|
|
|
*/
|
2003-07-16 19:09:00 +00:00
|
|
|
char *fwdPtr = path;
|
|
|
|
char *urlPtr = path;
|
2003-11-19 06:03:01 +00:00
|
|
|
char *lastslash = path;
|
2003-07-16 19:09:00 +00:00
|
|
|
PRUint32 traversal = 0;
|
|
|
|
PRUint32 special_ftp_len = 0;
|
2000-05-02 03:58:25 +00:00
|
|
|
|
2003-07-16 19:09:00 +00:00
|
|
|
/* Remember if this url is a special ftp one: */
|
|
|
|
if (flags & NET_COALESCE_DOUBLE_SLASH_IS_ROOT)
|
2000-01-17 06:05:43 +00:00
|
|
|
{
|
2003-07-16 19:09:00 +00:00
|
|
|
/* some schemes (for example ftp) have the speciality that
|
|
|
|
the path can begin // or /%2F to mark the root of the
|
|
|
|
servers filesystem, a simple / only marks the root relative
|
|
|
|
to the user loging in. We remember the length of the marker */
|
|
|
|
if (nsCRT::strncasecmp(path,"/%2F",4) == 0)
|
|
|
|
special_ftp_len = 4;
|
|
|
|
else if (nsCRT::strncmp(path,"//",2) == 0 )
|
|
|
|
special_ftp_len = 2;
|
2000-01-17 06:05:43 +00:00
|
|
|
}
|
2002-01-25 22:19:29 +00:00
|
|
|
|
2003-11-19 06:03:01 +00:00
|
|
|
/* find the last slash before # or ? */
|
2003-07-25 18:36:34 +00:00
|
|
|
for(; (*fwdPtr != '\0') &&
|
|
|
|
(*fwdPtr != '?') &&
|
|
|
|
(*fwdPtr != '#'); ++fwdPtr)
|
2003-11-19 06:03:01 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* found nothing, but go back one only */
|
|
|
|
/* if there is something to go back to */
|
|
|
|
if (fwdPtr != path && *fwdPtr == '\0')
|
|
|
|
{
|
|
|
|
--fwdPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* search the slash */
|
|
|
|
for(; (fwdPtr != path) &&
|
|
|
|
(*fwdPtr != '/'); --fwdPtr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
lastslash = fwdPtr;
|
|
|
|
fwdPtr = path;
|
|
|
|
|
|
|
|
/* replace all %2E or %2e with . in the path */
|
|
|
|
/* but stop at lastchar if non null */
|
|
|
|
for(; (*fwdPtr != '\0') &&
|
|
|
|
(*fwdPtr != '?') &&
|
|
|
|
(*fwdPtr != '#') &&
|
|
|
|
(*lastslash == '\0' || fwdPtr != lastslash); ++fwdPtr)
|
2003-07-25 18:36:34 +00:00
|
|
|
{
|
|
|
|
if (*fwdPtr == '%' && *(fwdPtr+1) == '2' &&
|
|
|
|
(*(fwdPtr+2) == 'E' || *(fwdPtr+2) == 'e'))
|
|
|
|
{
|
|
|
|
*urlPtr++ = '.';
|
|
|
|
++fwdPtr;
|
|
|
|
++fwdPtr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy remaining stuff past the #?;
|
|
|
|
for (; *fwdPtr != '\0'; ++fwdPtr)
|
|
|
|
{
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
}
|
|
|
|
*urlPtr = '\0'; // terminate the url
|
|
|
|
|
|
|
|
// start again, this time for real
|
|
|
|
fwdPtr = path;
|
|
|
|
urlPtr = path;
|
|
|
|
|
2002-01-25 22:19:29 +00:00
|
|
|
for(; (*fwdPtr != '\0') &&
|
|
|
|
(*fwdPtr != '?') &&
|
|
|
|
(*fwdPtr != '#'); ++fwdPtr)
|
|
|
|
{
|
|
|
|
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
// At first, If this is DBCS character, it skips next character.
|
2003-07-16 19:09:00 +00:00
|
|
|
if (::IsDBCSLeadByte(*fwdPtr) && *(fwdPtr+1) != '\0')
|
|
|
|
{
|
2002-01-25 22:19:29 +00:00
|
|
|
*urlPtr++ = *fwdPtr++;
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (*fwdPtr == '/' && *(fwdPtr+1) == '.' && *(fwdPtr+2) == '/' )
|
|
|
|
{
|
|
|
|
// remove . followed by slash
|
|
|
|
++fwdPtr;
|
|
|
|
}
|
|
|
|
else if(*fwdPtr == '/' && *(fwdPtr+1) == '.' && *(fwdPtr+2) == '.' &&
|
|
|
|
(*(fwdPtr+3) == '/' ||
|
|
|
|
*(fwdPtr+3) == '\0' || // This will take care of
|
|
|
|
*(fwdPtr+3) == '?' || // something like foo/bar/..#sometag
|
|
|
|
*(fwdPtr+3) == '#'))
|
|
|
|
{
|
|
|
|
// remove foo/..
|
|
|
|
// reverse the urlPtr to the previous slash if possible
|
2003-07-16 19:09:00 +00:00
|
|
|
// if url does not allow relative root then drop .. above root
|
|
|
|
// otherwise retain them in the path
|
|
|
|
if(traversal > 0 || !(flags &
|
|
|
|
NET_COALESCE_ALLOW_RELATIVE_ROOT))
|
2002-01-25 22:19:29 +00:00
|
|
|
{
|
2003-07-16 19:09:00 +00:00
|
|
|
if (urlPtr != path)
|
2002-01-25 22:19:29 +00:00
|
|
|
urlPtr--; // we must be going back at least by one
|
2003-07-16 19:09:00 +00:00
|
|
|
for(;*urlPtr != '/' && urlPtr != path; urlPtr--)
|
2002-01-25 22:19:29 +00:00
|
|
|
; // null body
|
|
|
|
--traversal; // count back
|
|
|
|
// forward the fwdPtr past the ../
|
|
|
|
fwdPtr += 2;
|
2003-07-16 19:09:00 +00:00
|
|
|
// if we have reached the beginning of the path
|
|
|
|
// while searching for the previous / and we remember
|
|
|
|
// that it is an url that begins with /%2F then
|
|
|
|
// advance urlPtr again by 3 chars because /%2F already
|
|
|
|
// marks the root of the path
|
|
|
|
if (urlPtr == path && special_ftp_len > 3)
|
|
|
|
{
|
|
|
|
++urlPtr;
|
|
|
|
++urlPtr;
|
|
|
|
++urlPtr;
|
|
|
|
}
|
2002-01-25 22:19:29 +00:00
|
|
|
// special case if we have reached the end
|
|
|
|
// to preserve the last /
|
|
|
|
if (*fwdPtr == '.' && *(fwdPtr+1) == '\0')
|
|
|
|
++urlPtr;
|
2003-07-16 19:09:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-01-25 22:19:29 +00:00
|
|
|
// there are to much /.. in this path, just copy them instead.
|
|
|
|
// forward the urlPtr past the /.. and copying it
|
2003-07-16 19:09:00 +00:00
|
|
|
|
|
|
|
// However if we remember it is an url that starts with
|
|
|
|
// /%2F and urlPtr just points at the "F" of "/%2F" then do
|
|
|
|
// not overwrite it with the /, just copy .. and move forward
|
|
|
|
// urlPtr.
|
|
|
|
if (special_ftp_len > 3 && urlPtr == path+special_ftp_len-1)
|
|
|
|
++urlPtr;
|
|
|
|
else
|
|
|
|
*urlPtr++ = *fwdPtr;
|
2002-01-25 22:19:29 +00:00
|
|
|
++fwdPtr;
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
++fwdPtr;
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-16 19:09:00 +00:00
|
|
|
// count the hierachie, but only if we do not have reached
|
|
|
|
// the root of some special urls with a special root marker
|
|
|
|
if (*fwdPtr == '/' && *(fwdPtr+1) != '.' &&
|
|
|
|
(special_ftp_len != 2 || *(fwdPtr+1) != '/'))
|
2002-01-25 22:19:29 +00:00
|
|
|
traversal++;
|
|
|
|
// copy the url incrementaly
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy remaining stuff past the #?;
|
|
|
|
for (; *fwdPtr != '\0'; ++fwdPtr)
|
|
|
|
{
|
|
|
|
*urlPtr++ = *fwdPtr;
|
|
|
|
}
|
|
|
|
*urlPtr = '\0'; // terminate the url
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now lets remove trailing . case
|
|
|
|
* /foo/foo1/. -> /foo/foo1/
|
|
|
|
*/
|
|
|
|
|
2003-07-16 19:09:00 +00:00
|
|
|
if ((urlPtr > (path+1)) && (*(urlPtr-1) == '.') && (*(urlPtr-2) == '/'))
|
2002-01-25 22:19:29 +00:00
|
|
|
*(urlPtr-1) = '\0';
|
|
|
|
}
|
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
nsresult
|
|
|
|
net_ResolveRelativePath(const nsACString &relativePath,
|
|
|
|
const nsACString &basePath,
|
|
|
|
nsACString &result)
|
2002-01-16 03:23:23 +00:00
|
|
|
{
|
2002-09-13 19:32:45 +00:00
|
|
|
nsCAutoString name;
|
|
|
|
nsCAutoString path(basePath);
|
2003-07-09 05:11:10 +00:00
|
|
|
PRBool needsDelim = PR_FALSE;
|
2002-01-16 03:23:23 +00:00
|
|
|
|
2003-07-09 05:11:10 +00:00
|
|
|
if ( !path.IsEmpty() ) {
|
|
|
|
PRUnichar last = path.Last();
|
|
|
|
needsDelim = !(last == '/');
|
|
|
|
}
|
2002-01-16 03:23:23 +00:00
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
nsACString::const_iterator beg, end;
|
|
|
|
relativePath.BeginReading(beg);
|
|
|
|
relativePath.EndReading(end);
|
|
|
|
|
|
|
|
PRBool stop = PR_FALSE;
|
|
|
|
char c;
|
|
|
|
for (; !stop; ++beg) {
|
|
|
|
c = (beg == end) ? '\0' : *beg;
|
|
|
|
//printf("%c [name=%s] [path=%s]\n", c, name.get(), path.get());
|
|
|
|
switch (c) {
|
|
|
|
case '\0':
|
|
|
|
case '#':
|
|
|
|
case ';':
|
|
|
|
case '?':
|
|
|
|
stop = PR_TRUE;
|
|
|
|
// fall through...
|
|
|
|
case '/':
|
|
|
|
// delimiter found
|
|
|
|
if (name.Equals("..")) {
|
|
|
|
// pop path
|
|
|
|
// If we already have the delim at end, then
|
|
|
|
// skip over that when searching for next one to the left
|
|
|
|
PRInt32 offset = path.Length() - (needsDelim ? 1 : 2);
|
2003-03-15 20:00:20 +00:00
|
|
|
// First check for errors
|
|
|
|
if (offset < 0 )
|
|
|
|
return NS_ERROR_MALFORMED_URI;
|
2002-09-13 19:32:45 +00:00
|
|
|
PRInt32 pos = path.RFind("/", PR_FALSE, offset);
|
2003-03-15 20:00:20 +00:00
|
|
|
if (pos >= 0)
|
2002-09-13 19:32:45 +00:00
|
|
|
path.Truncate(pos + 1);
|
|
|
|
else
|
2003-03-15 20:00:20 +00:00
|
|
|
path.Truncate();
|
2002-09-13 19:32:45 +00:00
|
|
|
}
|
|
|
|
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 += Substring(--beg, end);
|
|
|
|
|
|
|
|
result = path;
|
|
|
|
return NS_OK;
|
2000-01-17 06:05:43 +00:00
|
|
|
}
|
2000-05-07 10:43:36 +00:00
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// scheme fu
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2000-05-07 10:43:36 +00:00
|
|
|
/* Extract URI-Scheme if possible */
|
2002-09-13 19:32:45 +00:00
|
|
|
nsresult
|
|
|
|
net_ExtractURLScheme(const nsACString &inURI,
|
|
|
|
PRUint32 *startPos,
|
|
|
|
PRUint32 *endPos,
|
|
|
|
nsACString *scheme)
|
2000-05-07 10:43:36 +00:00
|
|
|
{
|
|
|
|
// search for something up to a colon, and call it the scheme
|
2002-09-26 02:24:49 +00:00
|
|
|
const nsPromiseFlatCString &flatURI = PromiseFlatCString(inURI);
|
2002-03-06 07:48:55 +00:00
|
|
|
const char* uri_start = flatURI.get();
|
|
|
|
const char* uri = uri_start;
|
2000-05-07 10:43:36 +00:00
|
|
|
|
2002-09-26 02:24:49 +00:00
|
|
|
if (!uri)
|
|
|
|
return NS_ERROR_MALFORMED_URI;
|
|
|
|
|
2000-05-07 10:43:36 +00:00
|
|
|
// skip leading white space
|
|
|
|
while (nsCRT::IsAsciiSpace(*uri))
|
|
|
|
uri++;
|
|
|
|
|
2002-03-06 07:48:55 +00:00
|
|
|
PRUint32 start = uri - uri_start;
|
2000-05-07 10:43:36 +00:00
|
|
|
if (startPos) {
|
|
|
|
*startPos = start;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 length = 0;
|
|
|
|
char c;
|
|
|
|
while ((c = *uri++) != '\0') {
|
|
|
|
// First char must be Alpha
|
|
|
|
if (length == 0 && nsCRT::IsAsciiAlpha(c)) {
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
// Next chars can be alpha + digit + some special chars
|
|
|
|
else if (length > 0 && (nsCRT::IsAsciiAlpha(c) ||
|
|
|
|
nsCRT::IsAsciiDigit(c) || c == '+' ||
|
|
|
|
c == '.' || c == '-')) {
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
// stop if colon reached but not as first char
|
|
|
|
else if (c == ':' && length > 0) {
|
|
|
|
if (endPos) {
|
2002-09-13 19:32:45 +00:00
|
|
|
*endPos = start + length;
|
2000-05-07 10:43:36 +00:00
|
|
|
}
|
|
|
|
|
2002-03-06 07:48:55 +00:00
|
|
|
if (scheme)
|
|
|
|
scheme->Assign(Substring(inURI, start, length));
|
2000-05-07 10:43:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NS_ERROR_MALFORMED_URI;
|
|
|
|
}
|
2001-11-26 23:28:44 +00:00
|
|
|
|
|
|
|
PRBool
|
2002-09-13 19:32:45 +00:00
|
|
|
net_IsValidScheme(const char *scheme, PRUint32 schemeLen)
|
2001-11-26 23:28:44 +00:00
|
|
|
{
|
|
|
|
// first char much be alpha
|
|
|
|
if (!nsCRT::IsAsciiAlpha(*scheme))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
for (; schemeLen && *scheme; ++scheme, --schemeLen) {
|
|
|
|
if (!(nsCRT::IsAsciiAlpha(*scheme) ||
|
|
|
|
nsCRT::IsAsciiDigit(*scheme) ||
|
|
|
|
*scheme == '+' ||
|
|
|
|
*scheme == '.' ||
|
|
|
|
*scheme == '-'))
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2002-08-15 18:38:46 +00:00
|
|
|
|
2003-07-08 20:09:17 +00:00
|
|
|
PRBool
|
|
|
|
net_FilterURIString(const char *str, nsACString& result)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(str, "Must have a non-null string!");
|
|
|
|
PRBool writing = PR_FALSE;
|
|
|
|
result.Truncate();
|
|
|
|
const char *p = str;
|
|
|
|
|
|
|
|
// Remove leading spaces, tabs, CR, LF if any.
|
|
|
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
|
|
|
writing = PR_TRUE;
|
|
|
|
str = p + 1;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p == '\t' || *p == '\r' || *p == '\n') {
|
|
|
|
writing = PR_TRUE;
|
|
|
|
// append chars up to but not including *p
|
|
|
|
if (p > str)
|
|
|
|
result.Append(str, p - str);
|
|
|
|
str = p + 1;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove trailing spaces if any
|
|
|
|
while (((p-1) >= str) && (*(p-1) == ' ')) {
|
|
|
|
writing = PR_TRUE;
|
|
|
|
p--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (writing && p > str)
|
|
|
|
result.Append(str, p - str);
|
|
|
|
|
|
|
|
return writing;
|
|
|
|
}
|
|
|
|
|
2004-08-04 17:08:27 +00:00
|
|
|
#if defined(XP_WIN) || defined(XP_OS2)
|
|
|
|
PRBool
|
|
|
|
net_NormalizeFileURL(const nsACString &aURL, nsCString &aResultBuf)
|
|
|
|
{
|
|
|
|
PRBool writing = PR_FALSE;
|
|
|
|
|
|
|
|
nsACString::const_iterator beginIter, endIter;
|
|
|
|
aURL.BeginReading(beginIter);
|
|
|
|
aURL.EndReading(endIter);
|
|
|
|
|
|
|
|
const char *begin = beginIter.get();
|
|
|
|
|
|
|
|
for (const char *s = begin; s != endIter.get(); ++s)
|
|
|
|
{
|
|
|
|
if (*s == '\\')
|
|
|
|
{
|
|
|
|
writing = PR_TRUE;
|
|
|
|
if (s > begin)
|
|
|
|
aResultBuf.Append(begin, s - begin);
|
|
|
|
aResultBuf += '/';
|
|
|
|
begin = s + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (writing && s > begin)
|
|
|
|
aResultBuf.Append(begin, s - begin);
|
|
|
|
|
|
|
|
return writing;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// miscellaneous (i.e., stuff that should really be elsewhere)
|
|
|
|
//----------------------------------------------------------------------------
|
2002-08-15 18:38:46 +00:00
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
static inline
|
|
|
|
void ToLower(char &c)
|
|
|
|
{
|
|
|
|
if ((unsigned)(c - 'A') <= (unsigned)('Z' - 'A'))
|
|
|
|
c += 'a' - 'A';
|
|
|
|
}
|
2002-08-15 18:38:46 +00:00
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
void
|
|
|
|
net_ToLowerCase(char *str, PRUint32 length)
|
|
|
|
{
|
|
|
|
for (char *end = str + length; str < end; ++str)
|
|
|
|
ToLower(*str);
|
|
|
|
}
|
2002-08-15 18:38:46 +00:00
|
|
|
|
2002-09-13 19:32:45 +00:00
|
|
|
void
|
|
|
|
net_ToLowerCase(char *str)
|
|
|
|
{
|
|
|
|
for (; *str; ++str)
|
|
|
|
ToLower(*str);
|
2002-08-15 18:38:46 +00:00
|
|
|
}
|
2003-06-18 23:16:17 +00:00
|
|
|
|
|
|
|
char *
|
|
|
|
net_FindCharInSet(const char *iter, const char *stop, const char *set)
|
|
|
|
{
|
|
|
|
for (; iter != stop && *iter; ++iter) {
|
|
|
|
for (const char *s = set; *s; ++s) {
|
|
|
|
if (*iter == *s)
|
|
|
|
return (char *) iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (char *) iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
net_RFindCharInSet(const char *stop, const char *iter, const char *set)
|
|
|
|
{
|
|
|
|
--iter;
|
|
|
|
--stop;
|
|
|
|
for (; iter != stop; --iter) {
|
|
|
|
for (const char *s = set; *s; ++s) {
|
|
|
|
if (*iter == *s)
|
|
|
|
return (char *) iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (char *) iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
net_FindCharNotInSet(const char *iter, const char *stop, const char *set)
|
|
|
|
{
|
|
|
|
repeat:
|
|
|
|
for (const char *s = set; *s; ++s) {
|
|
|
|
if (*iter == *s) {
|
|
|
|
if (++iter == stop)
|
|
|
|
break;
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (char *) iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
net_RFindCharNotInSet(const char *stop, const char *iter, const char *set)
|
|
|
|
{
|
|
|
|
--iter;
|
|
|
|
--stop;
|
2003-06-23 05:51:33 +00:00
|
|
|
|
|
|
|
if (iter == stop)
|
|
|
|
return (char *) iter;
|
|
|
|
|
2003-06-18 23:16:17 +00:00
|
|
|
repeat:
|
|
|
|
for (const char *s = set; *s; ++s) {
|
|
|
|
if (*iter == *s) {
|
|
|
|
if (--iter == stop)
|
|
|
|
break;
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (char *) iter;
|
|
|
|
}
|