Mozilla/mozilla/netwerk/base/src/nsURLHelper.cpp
leaf%mozilla.org e1e7037575 backout darin's checkin from around noon yesterday to remove the regression
in 161921


git-svn-id: svn://10.0.0.236/trunk@126917 18797224-902f-48f8-a5cc-f745e15eee43
2002-08-09 23:46:19 +00:00

358 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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.
*
* The Original Code is mozilla.org code.
*
* 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.
*
* Contributor(s):
*
* 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
* use your version of this file under the terms of the NPL, indicate your
* 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
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsURLHelper.h"
#include "prprf.h"
#include "nsCRT.h"
#include "nsMemory.h"
#include "nsIIOService.h"
#include "nsIURI.h"
#include "nsEscape.h"
#include "netCore.h"
#if defined(XP_WIN)
#include <windows.h> // ::IsDBCSLeadByte need
#endif
#if 0
/* extracts first number from a string and assumes that this is the port number*/
PRInt32
ExtractPortFrom(const nsACString &src)
{
// search for digits up to a slash or the string ends
const nsPromiseFlatCString flat( PromiseFlatCString(src) );
const char* port = flat.get();
PRInt32 returnValue = -1;
// skip leading white space
while (nsCRT::IsAsciiSpace(*port))
port++;
char c;
while ((c = *port++) != '\0') {
// stop if slash or ? or # reached
if (c == '/' || c == '?' || c == '#')
break;
else if (!nsCRT::IsAsciiDigit(c))
return returnValue;
}
return (0 < PR_sscanf(flat.get(), "%d", &returnValue)) ? returnValue : -1;
}
#endif
/* extract string from other string */
nsresult
ExtractString(char* i_Src, char* *o_Dest, PRUint32 length)
{
NS_PRECONDITION( (nsnull != i_Src), "Extract called on empty string!");
CRTFREEIF(*o_Dest);
*o_Dest = PL_strndup(i_Src, length);
return (*o_Dest ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
/* duplicate string */
nsresult
DupString(char* *o_Dest, const char* i_Src)
{
if (!o_Dest)
return NS_ERROR_NULL_POINTER;
if (i_Src)
{
*o_Dest = nsCRT::strdup(i_Src);
return (*o_Dest == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
}
else
{
*o_Dest = nsnull;
return NS_OK;
}
}
// Replace all /./ with a / while resolving relative URLs
// But only till #?
void
CoalesceDirsRel(char* io_Path)
{
/* 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/
*/
char *fwdPtr = io_Path;
char *urlPtr = io_Path;
for(; (*fwdPtr != '\0') &&
(*fwdPtr != '?') &&
(*fwdPtr != '#'); ++fwdPtr)
{
#if defined(XP_WIN)
// At first, If this is DBCS character, it skips next character.
if (::IsDBCSLeadByte(*fwdPtr) && *(fwdPtr+1) != '\0') {
*urlPtr++ = *fwdPtr++;
*urlPtr++ = *fwdPtr;
continue;
}
#endif
if (*fwdPtr == '/' && *(fwdPtr+1) == '.' && *(fwdPtr+2) == '/' )
{
// remove . followed by slash
fwdPtr += 1;
}
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(urlPtr != io_Path)
urlPtr--; // we must be going back at least by one
for(;*urlPtr != '/' && urlPtr != io_Path; urlPtr--)
; // null body
// forward the fwd_prt past the ../
fwdPtr += 2;
// special case if we have reached the end to preserve the last /
if (*fwdPtr == '.' && *(fwdPtr+1) == '\0')
urlPtr +=1;
}
else
{
// 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/
*/
if ((urlPtr > (io_Path+1)) && (*(urlPtr-1) == '.') && (*(urlPtr-2) == '/'))
*(urlPtr-1) = '\0';
}
// Replace all /./ with a / while resolving absolute URLs
// But only till #?
void
CoalesceDirsAbs(char* io_Path)
{
/* 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/
*/
char *fwdPtr = io_Path;
char *urlPtr = io_Path;
PRUint32 traversal = 0;
for(; (*fwdPtr != '\0') &&
(*fwdPtr != '?') &&
(*fwdPtr != '#'); ++fwdPtr)
{
#if defined(XP_WIN)
// At first, If this is DBCS character, it skips next character.
if (::IsDBCSLeadByte(*fwdPtr) && *(fwdPtr+1) != '\0') {
*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
if(traversal > 0 )
{
if (urlPtr != io_Path)
urlPtr--; // we must be going back at least by one
for(;*urlPtr != '/' && urlPtr != io_Path; urlPtr--)
; // null body
--traversal; // count back
// forward the fwdPtr past the ../
fwdPtr += 2;
// special case if we have reached the end
// to preserve the last /
if (*fwdPtr == '.' && *(fwdPtr+1) == '\0')
++urlPtr;
} else {
// there are to much /.. in this path, just copy them instead.
// forward the urlPtr past the /.. and copying it
*urlPtr++ = *fwdPtr;
++fwdPtr;
*urlPtr++ = *fwdPtr;
++fwdPtr;
*urlPtr++ = *fwdPtr;
}
}
else
{
if(*fwdPtr == '/' && *(fwdPtr+1) != '.')
{
// count the hierachie
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/
*/
if ((urlPtr > (io_Path+1)) && (*(urlPtr-1) == '.') && (*(urlPtr-2) == '/'))
*(urlPtr-1) = '\0';
}
static inline
void ToLower(char &c)
{
if ((unsigned)(c - 'A') <= (unsigned)('Z' - 'A'))
c += 'a' - 'A';
}
void
ToLowerCase(char *str, PRUint32 length)
{
for (char *end = str + length; str < end; ++str)
ToLower(*str);
}
void
ToLowerCase(char *str)
{
for (; *str; ++str)
ToLower(*str);
}
/* Extract URI-Scheme if possible */
nsresult ExtractURLScheme(const nsACString &inURI, PRUint32 *startPos,
PRUint32 *endPos, nsACString *scheme)
{
// search for something up to a colon, and call it the scheme
const nsPromiseFlatCString flatURI( PromiseFlatCString(inURI) );
const char* uri_start = flatURI.get();
const char* uri = uri_start;
// skip leading white space
while (nsCRT::IsAsciiSpace(*uri))
uri++;
PRUint32 start = uri - uri_start;
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) {
*endPos = start + length + 1;
}
if (scheme)
scheme->Assign(Substring(inURI, start, length));
return NS_OK;
}
else
break;
}
return NS_ERROR_MALFORMED_URI;
}
PRBool
IsValidScheme(const char *scheme, PRUint32 schemeLen)
{
// 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;
}