358 lines
11 KiB
C++
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;
|
|
}
|