windows-nt/Source/XPSP1/NT/net/upnp/host/udhisapi/udhiutil.cpp
2020-09-26 16:20:57 +08:00

307 lines
8.4 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000.
//
// File: U D H I U T I L . C P P
//
// Contents: Implementation of various utility functions used by the
// UPnP Device Host ISAPI extension
//
// Notes:
//
// Author: spather 2000/09/8
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include <httpext.h>
#include "wininet.h"
#include "udhiutil.h"
//+---------------------------------------------------------------------------
//
// Function: bSendResponseToClient
//
// Purpose: Sends an HTTP response to the originator of a request
//
// Arguments:
// pecb [in] The extension control block for the request
// pszStatus [in] HTTP status string e.g. "200 OK" or "400 Bad Request"
// cchHeaders [in] Number of characters in pszHeaders string
// pszHeaders [in] Headers string e.g. "Content-type: text/html\r\n\r\n"
// cchBody [in] Number of bytes in pszBody
// pszBody [in] Response body (may be NULL to send no body)
//
// Returns:
// TRUE if successful
// FALSE if unsuccessful (call GetLastError() to get error info)
//
// Author: spather 2000/09/7
//
// Notes:
// All strings passed in must be NULL terminated.
// pszHeaders string may contain multiple headers separated by \r\n pairs.
// pszHeaders string must end in "\r\n\r\n" as required by HTTP
// If a body is specified at pszBody, the pszHeaders string should contain
// a Content-Length header.
//
BOOL
bSendResponseToClient(
IN LPEXTENSION_CONTROL_BLOCK pecb,
IN LPCSTR pcszStatus,
IN DWORD cchHeaders,
IN LPCSTR pcszHeaders,
IN DWORD cchBody,
IN LPCSTR pcszBody)
{
BOOL bRet = TRUE;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
AssertSz(pecb,
"bSendResponseToClient(): NULL pecb");
AssertSz(pcszStatus,
"bSendResponseToClient(): NULL pcszStatus");
AssertSz(pcszHeaders,
"bSendResponseToClient(): NULL pcszHeaders");
BOOL fKeepConn = FALSE;
bRet = pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_IS_KEEP_CONN,
&fKeepConn,
NULL,
NULL);
//
// Prepare headers.
//
HeaderExInfo.pszStatus = pcszStatus;
HeaderExInfo.pszHeader = pcszHeaders;
HeaderExInfo.cchStatus = lstrlenA(pcszStatus);
HeaderExInfo.cchHeader = cchHeaders;
HeaderExInfo.fKeepConn = fKeepConn;
//
// Send the headers.
//
TraceTag(ttidUDHISAPI,
"bSendResponseHeaders(): "
"Sending Status \"%s\" and Headers:\n%s",
pcszStatus,
pcszHeaders);
bRet = pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL);
if (bRet)
{
//
// Send the body if there is one.
//
if (pcszBody)
{
DWORD dwBytesToWrite = cchBody;
bRet = pecb->WriteClient(pecb->ConnID,
(LPVOID) pcszBody,
&dwBytesToWrite,
HSE_IO_SYNC);
if (bRet)
{
AssertSz((cchBody == dwBytesToWrite),
"bSendResponseToClient(): "
"Didn't write the correct number of bytes");
}
else
{
TraceLastWin32Error("bSendResponseToClient(): "
"Failed to send response body");
}
}
}
else
{
TraceLastWin32Error("bSendResponseToClient(): "
"Failed to send response headers");
}
TraceTag(ttidUDHISAPI,
"bSendResponseToClient(): "
"Exiting - returning %d",
bRet);
return bRet;
}
VOID
SendSimpleResponse(
IN LPEXTENSION_CONTROL_BLOCK pecb,
IN DWORD dwStatusCode)
{
BOOL fRet;
static const CHAR c_szErrorHeaders[] = "\r\n";
LPSTR szaResponse;
switch(dwStatusCode)
{
case HTTP_STATUS_OK:
szaResponse = "200 OK";
break;
case HTTP_STATUS_CREATED:
szaResponse = "201 Created";
break;
case HTTP_STATUS_ACCEPTED:
szaResponse = "202 Accepted";
break;
case HTTP_STATUS_NO_CONTENT:
szaResponse = "204 No Content";
break;
case HTTP_STATUS_AMBIGUOUS:
szaResponse = "300 Multiple";
break;
case HTTP_STATUS_MOVED:
szaResponse = "301 Moved Permanently";
break;
case HTTP_STATUS_REDIRECT:
szaResponse = "302 Moved Temporarily";
break;
case HTTP_STATUS_NOT_MODIFIED:
szaResponse = "304 Not Modified";
break;
case HTTP_STATUS_BAD_REQUEST:
szaResponse = "400 Bad Request";
break;
case HTTP_STATUS_DENIED:
szaResponse = "401 Unauthorized";
break;
case HTTP_STATUS_FORBIDDEN:
szaResponse = "403 Forbidden";
break;
case HTTP_STATUS_NOT_FOUND:
szaResponse = "404 Not Found";
break;
case HTTP_STATUS_BAD_METHOD:
szaResponse = "405 Method Not Allowed";
break;
case HTTP_STATUS_LENGTH_REQUIRED:
szaResponse = "411 The Server Refused to Accept Request Without a Length";
break;
case HTTP_STATUS_PRECOND_FAILED:
szaResponse = "412 Precondition Failed";
break;
case HTTP_STATUS_UNSUPPORTED_MEDIA:
szaResponse = "415 Unsupported Media Type";
break;
case HTTP_STATUS_SERVER_ERROR:
szaResponse = "500 Internal Server Error";
break;
case HTTP_STATUS_NOT_SUPPORTED:
szaResponse = "501 Not Implemented";
break;
case HTTP_STATUS_BAD_GATEWAY:
szaResponse = "502 Bad Gateway";
break;
case HTTP_STATUS_SERVICE_UNAVAIL:
szaResponse = "503 Service Unavailable";
break;
default:
AssertSz(FALSE, "You must pass in a known HTTP status code to "
"SendErrorResponse()");
break;
}
if (bSendResponseToClient(pecb, szaResponse, lstrlenA(c_szErrorHeaders),
c_szErrorHeaders, 0, NULL))
{
pecb->dwHttpStatusCode = dwStatusCode;
}
DWORD dwHseStatus;
dwHseStatus = (dwStatusCode >= HTTP_STATUS_BAD_REQUEST) ?
HSE_STATUS_ERROR : HSE_STATUS_SUCCESS;
}
//+---------------------------------------------------------------------------
//
// Function: DwQueryHeader
//
// Purpose: Queries one of the headers sent in an HTTP request
//
// Arguments:
// pecb [in] Exetnsion control block
// szaHeader [in] Header name to query
// pszaResult [out] Returns value of header or NULL if not present
//
// Returns: ERROR_SUCCESS, ERROR_OUTOFMEMORY, or an ISAPI error code
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwQueryHeader(LPEXTENSION_CONTROL_BLOCK pecb, LPCSTR szaHeader,
LPSTR *pszaResult)
{
DWORD cbHeader = 0;
LPSTR szaBuf = NULL;
DWORD dwReturn = ERROR_SUCCESS;
Assert(pszaResult);
*pszaResult = 0;
if (!pecb->GetServerVariable(pecb->ConnID, (LPSTR)szaHeader, NULL, &cbHeader))
{
dwReturn = GetLastError();
if (dwReturn == ERROR_INSUFFICIENT_BUFFER)
{
szaBuf = new CHAR[cbHeader / sizeof(CHAR)];
if (szaBuf)
{
if (!pecb->GetServerVariable(pecb->ConnID, (LPSTR)szaHeader,
(LPVOID)szaBuf, &cbHeader))
{
dwReturn = GetLastError();
}
else
{
*pszaResult = szaBuf;
dwReturn = ERROR_SUCCESS;
}
}
else
{
dwReturn = ERROR_OUTOFMEMORY;
}
}
else
{
AssertSz(dwReturn != ERROR_SUCCESS, "How can it succeed if I gave"
" it a NULL pointer!");
}
}
return dwReturn;
}