301 lines
7.3 KiB
C++
301 lines
7.3 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: ncinet2.cpp
|
|
//
|
|
// Contents: Wrappers for some Urlmon APIs
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.h>
|
|
#pragma hdrstop
|
|
|
|
#include <wininet.h> // for ICU_NO_ENCODE
|
|
#include "ncinet2.h"
|
|
#include "ncstring.h" // WszAllocateAndCopyWsz
|
|
|
|
|
|
|
|
|
|
// note: this uses Urlmon, where the other methods only pull in
|
|
// wininet.
|
|
|
|
HRESULT
|
|
HrCombineUrl(LPCWSTR pszBaseUrl,
|
|
LPCWSTR pszRelativeUrl,
|
|
LPWSTR * ppszResult)
|
|
{
|
|
const DWORD dwCombineFlags = ICU_NO_ENCODE;
|
|
|
|
HRESULT hr;
|
|
LPWSTR pszResult;
|
|
WCHAR wcharTemp;
|
|
DWORD cchNeeded;
|
|
|
|
pszResult = NULL;
|
|
cchNeeded = 0;
|
|
wcharTemp = L'\0';
|
|
|
|
if (!ppszResult)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!pszBaseUrl)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!pszRelativeUrl)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// we use this instead of InternetCombineUrl so that pluggable
|
|
// protocols can do their thing.
|
|
// we're assuming here that the arguments have the same semantics
|
|
// as InternetCombineUrl(), as CoInternetCombineUrl is poorly
|
|
// documented.
|
|
|
|
// note: we don't know what the length of the combined URL is.
|
|
// instead of doing two allocations, we do a dummy call to
|
|
// CoInternetCombineUrl to find the needed length, allocate
|
|
// the string, and then call CoInternetCombineUrl "for real".
|
|
|
|
hr = CoInternetCombineUrl(pszBaseUrl,
|
|
pszRelativeUrl,
|
|
dwCombineFlags, // the url should already be encoded
|
|
&wcharTemp,
|
|
1,
|
|
&cchNeeded,
|
|
0);
|
|
// note(cmr): MSDN says that CoInternetCombineUrl will return S_FALSE
|
|
// if we don't have enough space in our buffer. Its implementation,
|
|
// though, generally calls UrlCombineW, which is supposed to return
|
|
// E_POINTER in this case.
|
|
// Emperically, E_POINTER is returned here. This seems like a case of
|
|
// MSDN just being wrong. We'll expect both E_POINTER and S_FALSE
|
|
// as return values here, to be safe.
|
|
if ((E_POINTER != hr) && FAILED(hr))
|
|
{
|
|
TraceError("HrCombineUrl: CoInternetCombineUrl", hr);
|
|
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
else if ((S_FALSE == hr) || (E_POINTER == hr))
|
|
{
|
|
Assert(cchNeeded);
|
|
|
|
DWORD cchWritten;
|
|
|
|
cchWritten = 0;
|
|
|
|
// call CoInternetCombineUrl for real.
|
|
// cchNeeded includes the room for
|
|
|
|
pszResult = new WCHAR[cchNeeded];
|
|
if (!pszResult)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = CoInternetCombineUrl(pszBaseUrl,
|
|
pszRelativeUrl,
|
|
dwCombineFlags, // the url should already be encoded
|
|
pszResult, // note: this is WRITTEN to...
|
|
cchNeeded, // note: should THIS value include the null-terminator?
|
|
&cchWritten,
|
|
0);
|
|
TraceError("HrCombineUrl: CoInternetCombineUrl", hr);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = E_FAIL;
|
|
goto Error;
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
// this shouldn't have happened. we had enough space.
|
|
|
|
hr = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
Assert(S_OK == hr);
|
|
Assert((cchNeeded - 1) == cchWritten);
|
|
Assert(L'\0' == pszResult[cchWritten]);
|
|
}
|
|
else
|
|
{
|
|
Assert(S_OK == hr);
|
|
Assert(L'\0' == wcharTemp);
|
|
// since the result needs to be null-terminated, the combined url
|
|
// must be the empty string. Wacky. Let's allocate a string and
|
|
// return it regardless.
|
|
|
|
pszResult = new WCHAR [1];
|
|
if (!pszResult)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*pszResult = L'\0';
|
|
}
|
|
|
|
Cleanup:
|
|
Assert(FImplies(SUCCEEDED(hr), pszResult));
|
|
Assert(FImplies(FAILED(hr), !pszResult));
|
|
|
|
if (ppszResult)
|
|
{
|
|
*ppszResult = pszResult;
|
|
}
|
|
|
|
TraceError("HrCombineUrl", hr);
|
|
return hr;
|
|
|
|
Error:
|
|
if (pszResult)
|
|
{
|
|
delete [] pszResult;
|
|
pszResult = NULL;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
// verifies that the given url is a valid url, and if it is,
|
|
// copies it into a newly-allocated string at ppszResult
|
|
// return values
|
|
// S_OK it's a valid url. *ppszResult is a copy
|
|
// S_FALSE it's not a valid url. *ppszResult is NULL
|
|
HRESULT
|
|
HrCopyAndValidateUrl(LPCWSTR pszUrl,
|
|
LPWSTR * ppszResult)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR pszResult;
|
|
|
|
pszResult = NULL;
|
|
|
|
if (!ppszResult)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!pszUrl)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// make sure the URL we're handing back is well-formed
|
|
hr = IsValidURL(NULL, pszUrl, 0);
|
|
TraceError("HrCopyAndValidateUrl: IsValidURL", hr);
|
|
if (S_OK == hr)
|
|
{
|
|
// the url was valid
|
|
|
|
pszResult = WszAllocateAndCopyWsz(pszUrl);
|
|
if (!pszResult)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
Assert(FImplies(S_OK == hr, pszResult));
|
|
Assert(FImplies(S_OK != hr, !pszResult));
|
|
|
|
if (ppszResult)
|
|
{
|
|
*ppszResult = pszResult;
|
|
}
|
|
|
|
TraceError("HrCopyAndValidateUrl", hr);
|
|
return hr;
|
|
}
|
|
|
|
// this returns the security domain of the url, if one exists.
|
|
// if one doesn't exist, it returns null
|
|
HRESULT
|
|
HrGetSecurityDomainOfUrl(LPCWSTR pszUrl,
|
|
LPWSTR * ppszResult)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR pszResult;
|
|
|
|
pszResult = NULL;
|
|
|
|
if (!ppszResult)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*ppszResult = NULL;
|
|
hr = CoInternetGetSecurityUrl(pszUrl,
|
|
&pszResult,
|
|
PSU_DEFAULT,
|
|
0);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("HrGetSecurityDomainOfUrl: CoInternetGetSecurityUrl", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
*ppszResult = pszResult;
|
|
|
|
Cleanup:
|
|
TraceError("HrGetSecurityDomainOfUrl", hr);
|
|
return hr;
|
|
}
|
|
|
|
// Returns TRUE if the scheme of the specified URL is "http"
|
|
// or "https", FALSE otherwise.
|
|
// note: we do this because I really can't justify writing
|
|
// a bunch of code to call a urlmon function that contains
|
|
// a bunch of code to call a wininet function to do this
|
|
// strcmp.
|
|
BOOL
|
|
FIsHttpUrl(LPCWSTR pszUrl)
|
|
{
|
|
Assert(pszUrl);
|
|
|
|
CONST WCHAR rgchHttpScheme [] = L"http:";
|
|
CONST size_t cchHttpScheme = celems(rgchHttpScheme) - 1;
|
|
CONST WCHAR rgchHttpsScheme [] = L"https:";
|
|
CONST size_t cchHttpsScheme = celems(rgchHttpsScheme) - 1;
|
|
|
|
BOOL fResult;
|
|
int result;
|
|
|
|
fResult = FALSE;
|
|
|
|
result = wcsncmp(rgchHttpScheme, pszUrl, cchHttpScheme);
|
|
if (0 == result)
|
|
{
|
|
fResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
result = wcsncmp(rgchHttpsScheme, pszUrl, cchHttpsScheme);
|
|
if (0 == result)
|
|
{
|
|
fResult = TRUE;
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|