357 lines
8.9 KiB
C++
357 lines
8.9 KiB
C++
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.cpp
|
|
|
|
Abstract:
|
|
|
|
Utilities for the BITS server extensions
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
const char *LookupHTTPStatusCodeText(
|
|
DWORD HttpCode
|
|
)
|
|
{
|
|
switch( HttpCode )
|
|
{
|
|
case 100: return "100 Continue";
|
|
case 101: return "101 Switching Protocols";
|
|
case 200: return "200 OK";
|
|
case 201: return "201 Created";
|
|
case 202: return "202 Accepted";
|
|
case 203: return "203 Non-Authoritative Information";
|
|
case 204: return "204 No Content";
|
|
case 205: return "205 Reset Content";
|
|
case 206: return "206 Partial Content";
|
|
case 300: return "300 Multiple Choices";
|
|
case 301: return "301 Moved Permanently";
|
|
case 302: return "302 Found";
|
|
case 303: return "303 See Other";
|
|
case 304: return "304 Not Modified";
|
|
case 305: return "305 Use Proxy";
|
|
case 306: return "306 (Unused)";
|
|
case 307: return "307 Temporary Redirect";
|
|
case 400: return "400 Bad Request";
|
|
case 401: return "401 Unauthorized";
|
|
case 402: return "402 Payment Required";
|
|
case 403: return "403 Forbidden";
|
|
case 404: return "404 Not Found";
|
|
case 405: return "405 Method Not Allowed";
|
|
case 406: return "406 Not Acceptable";
|
|
case 407: return "407 Proxy Authentication Required";
|
|
case 408: return "408 Request Timeout";
|
|
case 409: return "409 Conflict";
|
|
case 410: return "410 Gone";
|
|
case 411: return "411 Length Required";
|
|
case 412: return "412 Precondition Failed";
|
|
case 413: return "413 Request Entity Too Large";
|
|
case 414: return "414 Request-URI Too Long";
|
|
case 415: return "415 Unsupported Media Type";
|
|
case 416: return "416 Requested Range Not Satisfiable";
|
|
case 417: return "417 Expectation Failed";
|
|
case 500: return "500 Internal Server Error";
|
|
case 501: return "501 Not Implemented";
|
|
case 502: return "502 Bad Gateway";
|
|
case 503: return "503 Service Unavailable";
|
|
case 504: return "504 Gateway Timeout";
|
|
case 505: return "505 HTTP Version Not Supported";
|
|
|
|
default:
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
ServerException::SendErrorResponse(
|
|
EXTENSION_CONTROL_BLOCK * ExtensionControlBlock
|
|
) const
|
|
{
|
|
|
|
char Headers[255];
|
|
StringCbPrintfA(
|
|
Headers,
|
|
sizeof( Headers ),
|
|
"Pragma: no-cache\r\n"
|
|
"BITS-packet-type: Ack\r\n"
|
|
"BITS-Error: 0x%8.8X\r\n"
|
|
"\r\n",
|
|
m_Code );
|
|
|
|
ExtensionControlBlock->dwHttpStatusCode = m_HttpCode;
|
|
|
|
BOOL Result;
|
|
BOOL KeepConnection;
|
|
|
|
Result =
|
|
(ExtensionControlBlock->ServerSupportFunction)(
|
|
ExtensionControlBlock->ConnID,
|
|
HSE_REQ_IS_KEEP_CONN,
|
|
&KeepConnection,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !Result )
|
|
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
// IIS5.0(Win2k) has a bug where KeepConnect is returned as -1
|
|
// to keep the connection alive. Apparently, this confuses the
|
|
// HSE_REQ_SEND_RESPONSE_HEADER_EX call. Bash the value into a real bool.
|
|
|
|
KeepConnection = KeepConnection ? 1 : 0;
|
|
|
|
HSE_SEND_HEADER_EX_INFO HeaderInfo;
|
|
HeaderInfo.pszStatus = LookupHTTPStatusCodeText( m_HttpCode );
|
|
HeaderInfo.cchStatus = strlen( HeaderInfo.pszStatus );
|
|
HeaderInfo.pszHeader = Headers;
|
|
HeaderInfo.cchHeader = strlen( Headers );
|
|
HeaderInfo.fKeepConn = KeepConnection;
|
|
|
|
Result =
|
|
(ExtensionControlBlock->ServerSupportFunction)(
|
|
ExtensionControlBlock->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
&HeaderInfo,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !Result )
|
|
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
}
|
|
|
|
DWORD
|
|
ServerException::MapStatus( HRESULT Hr ) const
|
|
{
|
|
switch( Hr )
|
|
{
|
|
case E_INVALIDARG: return 400;
|
|
// case HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ): return 400;
|
|
case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ): return 404;
|
|
case HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ): return 404;
|
|
case HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ): return 403;
|
|
// case E_ACCESSDENIED: return 401;
|
|
default: return 500;
|
|
}
|
|
}
|
|
|
|
void * _cdecl ::operator new( size_t Size )
|
|
{
|
|
void *Memory = HeapAlloc( GetProcessHeap(), 0, Size );
|
|
if ( !Memory )
|
|
{
|
|
Log( LOG_ERROR, "Out of memory!\n" );
|
|
throw ServerException( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
return Memory;
|
|
}
|
|
|
|
void _cdecl ::operator delete( void *Memory )
|
|
{
|
|
if ( !Memory )
|
|
return;
|
|
|
|
HeapFree( GetProcessHeap(), 0, Memory );
|
|
}
|
|
|
|
|
|
StringHandle
|
|
GetMetaDataString(
|
|
IMSAdminBase *IISAdminBase,
|
|
METADATA_HANDLE Handle,
|
|
LPCWSTR Path,
|
|
DWORD dwIdentifier,
|
|
LPCSTR DefaultValue )
|
|
{
|
|
HRESULT Hr;
|
|
DWORD BufferRequired = 0;
|
|
|
|
StringHandleW Data;
|
|
|
|
METADATA_RECORD MdRecord;
|
|
MdRecord.dwMDAttributes = METADATA_INHERIT;
|
|
MdRecord.dwMDUserType = ALL_METADATA;
|
|
MdRecord.dwMDDataType = STRING_METADATA;
|
|
MdRecord.dwMDIdentifier = dwIdentifier;
|
|
MdRecord.dwMDDataLen = 0;
|
|
MdRecord.pbMDData = (PBYTE)NULL;
|
|
MdRecord.dwMDDataTag = 0;
|
|
|
|
Hr =
|
|
IISAdminBase->GetData(
|
|
Handle,
|
|
Path,
|
|
&MdRecord,
|
|
&BufferRequired );
|
|
|
|
if ( SUCCEEDED( Hr ) )
|
|
return (StringHandle)Data;
|
|
|
|
if ( MD_ERROR_DATA_NOT_FOUND == Hr ||
|
|
HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr )
|
|
return (StringHandle)DefaultValue;
|
|
|
|
if ( Hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) )
|
|
throw ServerException( Hr );
|
|
|
|
MdRecord.pbMDData = (PBYTE)Data.AllocBuffer( BufferRequired / 2 );
|
|
MdRecord.dwMDDataLen = BufferRequired;
|
|
|
|
Hr =
|
|
IISAdminBase->GetData(
|
|
Handle,
|
|
Path,
|
|
&MdRecord,
|
|
&BufferRequired );
|
|
|
|
if ( FAILED( Hr ) )
|
|
throw ServerException( Hr );
|
|
|
|
Data.SetStringSize();
|
|
return (StringHandle)Data;
|
|
|
|
}
|
|
|
|
DWORD
|
|
GetMetaDataDWORD(
|
|
IMSAdminBase *IISAdminBase,
|
|
METADATA_HANDLE Handle,
|
|
LPCWSTR Path,
|
|
DWORD dwIdentifier,
|
|
DWORD DefaultValue )
|
|
{
|
|
|
|
DWORD BufferRequired;
|
|
DWORD MetabaseValue;
|
|
|
|
METADATA_RECORD MdRecord;
|
|
memset( &MdRecord, 0, sizeof( MdRecord ) );
|
|
|
|
MdRecord.dwMDAttributes = METADATA_INHERIT;
|
|
MdRecord.dwMDUserType = ALL_METADATA;
|
|
MdRecord.dwMDDataType = DWORD_METADATA;
|
|
MdRecord.dwMDIdentifier = dwIdentifier;
|
|
MdRecord.dwMDDataLen = sizeof(MetabaseValue);
|
|
MdRecord.pbMDData = (PBYTE)&MetabaseValue;
|
|
|
|
HRESULT Hr =
|
|
IISAdminBase->GetData(
|
|
Handle,
|
|
Path,
|
|
&MdRecord,
|
|
&BufferRequired );
|
|
|
|
if ( MD_ERROR_DATA_NOT_FOUND == Hr ||
|
|
HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr )
|
|
return DefaultValue;
|
|
|
|
if ( FAILED( Hr ) )
|
|
throw ServerException( Hr );
|
|
|
|
return MetabaseValue;
|
|
}
|
|
|
|
StringHandle
|
|
BITSUnicodeToStringHandle( const WCHAR *pStr )
|
|
{
|
|
|
|
StringHandle RetValString;
|
|
|
|
int RetVal =
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pStr,
|
|
-1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !RetVal )
|
|
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
char *pRetBuffer = RetValString.AllocBuffer( RetVal );
|
|
|
|
RetVal =
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pStr,
|
|
-1,
|
|
pRetBuffer,
|
|
RetVal,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !RetVal )
|
|
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
RetValString.SetStringSize();
|
|
|
|
return RetValString;
|
|
}
|
|
|
|
StringHandle
|
|
BITSUrlCombine(
|
|
const char *Base,
|
|
const char *Relative,
|
|
DWORD dwFlags )
|
|
{
|
|
|
|
DWORD dwCombined = 0;
|
|
|
|
HRESULT Hr =
|
|
UrlCombine(
|
|
Base,
|
|
Relative,
|
|
NULL,
|
|
&dwCombined,
|
|
dwFlags );
|
|
|
|
if ( FAILED(Hr) && ( Hr != E_POINTER ) )
|
|
throw ServerException( Hr );
|
|
|
|
StringHandle RetVal;
|
|
char *Buffer = RetVal.AllocBuffer( dwCombined + 1 );
|
|
|
|
Hr =
|
|
UrlCombine(
|
|
Base,
|
|
Relative,
|
|
Buffer,
|
|
&dwCombined,
|
|
dwFlags );
|
|
|
|
if ( FAILED(Hr) )
|
|
throw ServerException( Hr );
|
|
|
|
RetVal.SetStringSize();
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
StringHandle
|
|
BITSUrlCanonicalize(
|
|
const char *URL,
|
|
DWORD dwFlags )
|
|
{
|
|
|
|
return
|
|
BITSUrlCombine(
|
|
"",
|
|
URL,
|
|
dwFlags );
|
|
|
|
}
|
|
|
|
|