📄 hxurl.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
#include "hlxclib/string.h"
#include "hlxclib/stdlib.h"
//#include "hlxclib/stdio.h"
#include <ctype.h>
#include "hxcom.h"
#include "hxtypes.h"
#include "hxresult.h"
#include "hxcomm.h"
#include "tparse.h"
#include "dbcs.h"
#include "protdefs.h"
#include "hxstrutl.h"
#include "hxslist.h"
#include "hxurl.h"
#include "ihxpckts.h"
#include "chxminiccf.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
/* We should really define it in a common header file */
#if defined (_WINDOWS ) || defined (WIN32) || defined(_SYMBIAN)
#define OS_SEPARATOR_CHAR '\\'
#define OS_SEPARATOR_STRING "\\"
#elif defined (_UNIX) || defined(_OPENWAVE)
#define OS_SEPARATOR_CHAR '/'
#define OS_SEPARATOR_STRING "/"
#elif defined (_MACINTOSH)
#define OS_SEPARATOR_CHAR ':'
#define OS_SEPARATOR_STRING ":"
#else
#error "undefined platform hxurl.cpp"
#endif // defined (_WINDOWS ) || defined (WIN32)
CHXURL::CHXURL (const char* pszURL)
:m_LastError (HXR_OK)
,m_pActualURL(NULL)
,m_pszURL(NULL)
,m_pszEscapedURL(NULL)
,m_pszOptions (NULL)
,m_pszHost (NULL)
,m_pszPort (NULL)
,m_pszUsername(NULL)
,m_pszPassword(NULL)
,m_unProtocol(fileProtocol)
,m_unDefaultPort(0)
,m_bNetworkProtocol (FALSE)
,m_pszResource (NULL)
,m_pProperties (NULL)
,m_pOptions (NULL)
,m_pCCF(CreateCCF())
{
if (m_pCCF)
{
m_pCCF->AddRef();
}
ConstructURL(pszURL);
}
CHXURL::CHXURL (const char* pszURL, IUnknown* pContext)
:m_LastError (HXR_OK)
,m_pActualURL(NULL)
,m_pszURL(NULL)
,m_pszEscapedURL(NULL)
,m_pszOptions (NULL)
,m_pszHost (NULL)
,m_pszPort (NULL)
,m_pszUsername(NULL)
,m_pszPassword(NULL)
,m_unProtocol(fileProtocol)
,m_unDefaultPort(0)
,m_bNetworkProtocol (FALSE)
,m_pszResource (NULL)
,m_pProperties (NULL)
,m_pOptions (NULL)
,m_pCCF(0)
{
if (pContext)
{
pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pCCF);
}
ConstructURL(pszURL);
}
void CHXURL::ConstructURL(const char* pszURL)
{
char* pszInputURL = NULL;
char* pszTemp = NULL;
char* pFragment = NULL;
char* pNewURL = NULL;
char* pResource = NULL;
char* pszDollarSign = NULL;
HX_ASSERT(pszURL != NULL);
if (!pszURL)
{
m_LastError = HXR_INVALID_PATH;
return;
}
if (!m_pCCF)
{
m_LastError = HXR_UNEXPECTED;
return;
}
pszInputURL = new char[strlen(pszURL) + 1];
if(!pszInputURL)
{
m_LastError = HXR_OUTOFMEMORY;
return;
}
strcpy(pszInputURL, pszURL); /* Flawfinder: ignore */
// Keep permanent copy of input url
m_pszEscapedURL = new char[strlen(pszInputURL)+1];
strcpy(m_pszEscapedURL, pszInputURL); /* Flawfinder: ignore */
// IHXValues
if (m_pCCF)
{
m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pProperties);
m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pOptions);
}
// protocol: determine whether it's network or local
if (0 == StringNCompare(pszInputURL, "http:", 5))
{
m_unProtocol = httpProtocol;
m_unDefaultPort = DEFAULT_HTTP_PORT;
}
else if (0 == StringNCompare(pszInputURL, "chttp:", 6))
{
m_unProtocol = httpProtocol;
m_unDefaultPort = DEFAULT_HTTP_PORT;
}
else if (0 == StringNCompare(pszInputURL, "pnm:", 4))
{
m_unProtocol = pnmProtocol;
m_bNetworkProtocol = TRUE;
m_unDefaultPort = DEFAULT_PNA_PORT;
}
else if (0 == StringNCompare(pszInputURL, "rtsp:", 5))
{
m_unProtocol = rtspProtocol;
m_bNetworkProtocol = TRUE;
m_unDefaultPort = DEFAULT_RTSP_PORT;
}
else if (0 == StringNCompare(pszInputURL, "helix-sdp:", 10))
{
m_unProtocol = helixSDPProtocol;
m_bNetworkProtocol = TRUE;
m_unDefaultPort = DEFAULT_RTSP_PORT;
}
else if (0 == StringNCompare(pszInputURL, "https:", 6))
{
m_unProtocol = httpsProtocol;
m_unDefaultPort = DEFAULT_HTTPS_PORT;
}
if (m_pProperties)
{
m_pProperties->SetPropertyULONG32(PROPERTY_PROTOCOL, (ULONG32)m_unProtocol);
}
else
{
m_LastError = HXR_UNEXPECTED;
goto cleanup;
}
// no need to further parse helix-sdp protocol
if (helixSDPProtocol != m_unProtocol)
{
// separate fragment from the URL
if (0!=(pszTemp = (char*) ::HXFindChar(pszInputURL, '#')))
{
// save fragment
pFragment = pszTemp + 1;
::SaveStringToHeader(m_pProperties, PROPERTY_FRAGMENT, pFragment);
*pszTemp = '\0';
}
// HP - allow '$' in directory/file name
//
// still need to take care of that obsolete $ sign option:
// rtsp://moe.cr.prognet.com/ambush.rm$1:00
// time after the $ is assumed to be the start time.
//
// the solution is to compare the string following the $ to
// a properly formed time. If the string is a time and only
// a time, then we know its the old-style start-time option
// otherwise, '$' is part of the directory/file name and we
// will keep it.
pszDollarSign = (char*) ::HXFindChar(pszInputURL, '$');
while (pszDollarSign)
{
pszTemp = pszDollarSign + 1;
if (::TimeParse(pszTemp))
{
*pszDollarSign = '\0';
INT32 lLen = (2 * strlen(pszURL)) + 8;
pNewURL = new char[lLen];
memset(pNewURL, 0, lLen);
// upgrade to a new URL
SafeSprintf(pNewURL, lLen, "%s?start=%s", pszInputURL, pszTemp);
HX_VECTOR_DELETE(pszInputURL);
pszInputURL = pNewURL;
break;
}
pszDollarSign = (char*) ::HXFindChar(pszTemp, '$');
}
}
#if !defined(_MACINTOSH) && !defined(_MAC_UNIX)
// on Mac, unescaping can put /'s and ?'s back into file and folder names, which is deadly inside URLs
//if (0 == StringNCompare(pszInputURL, "file:", 5))
{
// we only unescape the URL on local source since we are
// *responding* instead of *requesting* for the given source
Unescape(pszInputURL);
}
#endif
if (!CompressURL(pszInputURL, m_pszURL))
{
// make a copy of the URL
m_pszURL = new char[strlen(pszInputURL)+1];
strcpy(m_pszURL, pszInputURL); /* Flawfinder: ignore */
}
m_pActualURL = new char[strlen(m_pszURL)+1];
strcpy(m_pActualURL, m_pszURL); /* Flawfinder: ignore */
::SaveStringToHeader(m_pProperties, PROPERTY_URL, m_pszURL);
// no need to further parse helix-sdp protocol
if (helixSDPProtocol != m_unProtocol)
{
// separate options from the URL
if (0 != (pszTemp = (char*) ::HXFindChar(m_pszURL, '?')))
{
// options
m_pszOptions = pszTemp + 1;
}
// collect protocol, host, port and resource info
ParseURL (m_pszURL);
// collect other options info if it has
if (m_pszOptions)
{
if (HXR_INCOMPLETE == CollectOptions(m_pszOptions) && m_pszResource)
{
// bad options and remove it from the URL
pszTemp = (char*) ::HXFindChar(m_pszResource, '?');
if (pszTemp)
{
*pszTemp = '\0';
ParseResource();
}
}
}
}
cleanup:
HX_VECTOR_DELETE(pszInputURL);
}
CHXURL::~CHXURL ()
{
HX_VECTOR_DELETE(m_pActualURL);
HX_VECTOR_DELETE(m_pszURL);
HX_VECTOR_DELETE(m_pszEscapedURL);
HX_RELEASE(m_pProperties);
HX_RELEASE(m_pOptions);
HX_RELEASE(m_pCCF);
}
CHXURL::CHXURL(const CHXURL& rhs)
:m_LastError (HXR_OK)
,m_pActualURL(NULL)
,m_pszURL(NULL)
,m_pszOptions (NULL)
,m_pszHost (NULL)
,m_pszPort (NULL)
,m_pszUsername(NULL)
,m_pszPassword(NULL)
,m_unProtocol (fileProtocol)
,m_bNetworkProtocol (FALSE)
,m_pszResource (NULL)
,m_pProperties (NULL)
,m_pOptions (NULL)
,m_pCCF(rhs.m_pCCF)
{
if (m_pCCF)
{
m_pCCF->AddRef();
}
ConstructURL(rhs.GetEscapedURL());
}
CHXURL& CHXURL::operator=(const CHXURL& rhs)
{
if (&rhs != this)
{
// Clean out old data
HX_VECTOR_DELETE(m_pActualURL);
HX_VECTOR_DELETE(m_pszURL);
HX_VECTOR_DELETE(m_pszEscapedURL);
HX_RELEASE(m_pProperties);
HX_RELEASE(m_pOptions);
HX_RELEASE(m_pCCF);
m_LastError = HXR_OK;
m_pszOptions = NULL;
m_pszHost = NULL;
m_pszPort = NULL;
m_pszUsername = NULL;
m_pszPassword = NULL;
m_unProtocol = fileProtocol;
m_bNetworkProtocol = FALSE;
m_pszResource = NULL;
ConstructURL(rhs.GetEscapedURL());
m_pCCF = rhs.m_pCCF;
if (m_pCCF)
{
m_pCCF->AddRef();
}
}
return *this;
}
HX_RESULT CHXURL::ParseURL (char* pszURL)
{
char* pszOption = NULL;
char* pszTemp = NULL;
char* pszSlash = NULL;
char* pszCursor = NULL;
if (HXR_OK != m_LastError)
{
goto cleanup;
}
pszCursor = pszURL;
//
// let's start
//
// find the scheme - note that ParseURL only succeeds
// for absolute URLs
m_LastError = HXR_INVALID_PROTOCOL; // assume the worst
pszTemp = (char *) FindURLSchemeEnd(pszURL);
if (pszTemp)
{
char* pScheme = new_string(pszURL, pszTemp - pszURL);
m_LastError = HXR_OK;
::SaveStringToHeader(m_pProperties, PROPERTY_SCHEME, pScheme);
delete[] pScheme;
}
if(HXR_OK != m_LastError)
{
goto cleanup;
}
pszCursor = pszTemp + 1;
if(strncmp(pszCursor, "//", 2) == 0)
{
pszCursor += 2; // skip '//'
}
else if(strncmp(pszCursor, "/", 1) == 0)
{
pszCursor += 1; // skip '/' (ill-formed url?)
}
if (fileProtocol == m_unProtocol)
{
// resource
if (*(m_pszResource = pszCursor) == '\0')
{
m_LastError = HXR_INVALID_URL_PATH;
goto cleanup;
}
}
// network URL + http
else
{
// First check for optional username and password parameters.
// The colon is also optional if either username or password
// is not given Form in context:
// protocol://username:password@host:port/resource (From RFC
// 1738)
pszTemp = (char*) ::HXFindChar(pszCursor, ':');
pszSlash = (char*) ::HXFindChar(pszCursor, '/');
pszOption = (char*) ::HXFindChar(pszCursor, '@');
// There is a username or password if we see a '@' character
// according to RFC 1738 this is a reserved character
if (pszOption && pszOption < pszSlash)
{
// Username
if (*(m_pszUsername = pszCursor) == '\0')
{
m_LastError = HXR_INVALID_URL_HOST;
goto cleanup;
}
// If the is a ':' and it is before the '@' then we have a
// password, so zero terminate the username and move the
// cursor to the password
if (pszTemp && (pszTemp < pszOption))
{
*pszTemp = '\0';
pszCursor = pszTemp+1;
}
// There is no ':' so move the cursor to the '@' character
// so it will be a zero terminated empty string
else
pszCursor = pszOption;
// Password
if (*(m_pszPassword = pszCursor) == '\0')
{
m_LastError = HXR_INVALID_URL_HOST;
goto cleanup;
}
// Zero terminate password and move the cursor to the hostname
*pszOption = '\0';
if (m_pszUsername)
{
::SaveStringToHeader(m_pProperties, PROPERTY_USERNAME, m_pszUsername);
}
if (m_pszPassword)
{
::SaveStringToHeader(m_pProperties, PROPERTY_PASSWORD, m_pszPassword);
}
pszCursor = pszOption+1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -