windows-nt/Source/XPSP1/NT/net/upnp/host/upnphost/inc/request.h
2020-09-26 16:20:57 +08:00

352 lines
11 KiB
C++

/*--
Copyright (c) 1995-1998 Microsoft Corporation
Module Name: REQUEST.H
Author: Arul Menezes
Abstract: HTTP request class
--*/
// Scalar types used by CHTTPRequest
typedef enum {
TOK_GET=1,
TOK_HEAD,
TOK_POST,
TOK_UNKNOWN_VERB,
TOK_DATE,
TOK_PRAGMA,
TOK_COOKIE,
TOK_ACCEPT,
TOK_REFERER,
TOK_UAGENT,
TOK_AUTH,
TOK_IFMOD,
TOK_TYPE,
TOK_LENGTH,
TOK_ENCODING,
TOK_CONNECTION,
}
TOKEN;
typedef enum
{
CONN_NONE = 0,
CONN_CLOSE = 1,
CONN_KEEP = 2,
}
CONNHEADER;
#define CHTTPREQUEST_SIG 0xAB0D
// This object is the top-level object for an incoming HTTP request. One such object
// is created per request & a thread is created to handle it.
class CFilterInfo;
class CHttpRequest
{
// socket
DWORD m_dwSig;
SOCKET m_socket;
// buffers
CBuffer m_bufRequest;
CBuffer m_bufRespBody;
// method, version, URL etc. Direct results of parse
PSTR m_pszMethod;
PSTR m_pszURL;
PSTR m_pszContentType;
DWORD m_dwContentLength;
PSTR m_pszAccept;
FILETIME m_ftIfModifiedSince;
DWORD m_dwIfModifiedLength;
BOOL m_fKeepAlive;
PSTR m_pszCookie;
// Decoded URL (indirect results of parse)
PSTR m_pszQueryString;
PWSTR m_wszPath;
PWSTR m_wszExt;
PSTR m_pszPathInfo;
PSTR m_pszPathTranslated;
// VRoot information
SCRIPT_TYPE m_VRootScriptType;
DWORD m_dwPermissions;
AUTHLEVEL m_AuthLevelReqd;
// Logging members
PSTR m_pszLogParam;
RESPONSESTATUS m_rs;
BOOL m_fBufferedResponse; // Are we using m_bufResponse or sending straight to client?
// Async support
HANDLE m_hEvent;
DWORD m_dwStatus;
LPEXTENSION_CONTROL_BLOCK m_pECB;
PVOID m_pvContext;
PFN_HSE_IO_COMPLETION m_pfnCompletion;
// Parsing functions
void FreeHeaders(void)
{
MyFree(m_pszMethod);
MyFree(m_pszURL);
MyFree(m_pszContentType);
MyFree(m_pszAccept);
MyFree(m_pszQueryString);
MyFree(m_wszPath);
MyFree(m_wszExt);
MyFree(m_pszCookie);
MyFree(m_pszLogParam);
MyFree(m_pszPathInfo);
MyFree(m_pszPathTranslated);
}
BOOL ParseHeaders();
BOOL MyCrackURL(PSTR pszRawURL, int iLen);
public:
BOOL ParseMethod(PCSTR pszMethod, int cbMethod);
BOOL ParseContentLength(PCSTR pszMethod, TOKEN id);
BOOL ParseContentType(PCSTR pszMethod, TOKEN id);
BOOL ParseIfModifiedSince(PCSTR pszMethod, TOKEN id);
BOOL ParseAuthorization(PCSTR pszMethod, TOKEN id);
BOOL ParseAccept(PCSTR pszMethod, TOKEN id);
BOOL ParseConnection(PCSTR pszMethod, TOKEN id);
BOOL ParseCookie(PCSTR pszMethod, TOKEN id);
BOOL HandleNTLMAuth(PSTR pszNTLMData);
PSTR m_pszNTLMOutBuf; // buffer to send client on NTLM response, Base64 encoded
DWORD m_dwVersion; // LOWORD=minor, HIWORD=major.
TOKEN m_idMethod;
CBuffer m_bufRespHeaders;
CFilterInfo *m_pFInfo; // Filter state information
private:
// Authentication data members
AUTHLEVEL m_AuthLevelGranted;
PSTR m_pszAuthType;
PSTR m_pszRawRemoteUser; // Holds base64 encoded data, before auth decodes it
PSTR m_pszRemoteUser;
PSTR m_pszPassword;
AUTH_NTLM m_NTLMState; // state info for NTLM process, needs to be saved across requests
DWORD m_dwAuthFlags;
WCHAR *m_wszVRootUserList; // Do NOT free this, points to global mem. Contains user/group ACL
// Authentication functions
void FreeAuth(void)
{
MyFree(m_pszAuthType);
MyFree(m_pszRawRemoteUser);
MyFree(m_pszRemoteUser);
MyFree(m_pszPassword);
MyFree(m_pszNTLMOutBuf);
// Don't free NTLM structs in here
}
BOOL CheckAuth(AUTHLEVEL AuthLevelReqd)
{
return ( (AuthLevelReqd <= m_AuthLevelGranted));
}
BOOL CheckAuth() { return CheckAuth(m_AuthLevelReqd); }
// File GET/HEAD handling functions
BOOL IsNotModified(HANDLE hFile, DWORD dwLength);
static RESPONSESTATUS GLEtoStatus(int iGLE);
// Directory: Default page & browsing functions
BOOL MapDirToDefaultPage(void);
BOOL EmitDirListing(void);
void Init();
BOOL ReadPostData(DWORD dwMaxSizeToRead, BOOL fInitialPostRead);
CONNHEADER GetConnHeader() { return m_fKeepAlive ? CONN_KEEP : CONN_CLOSE; }
// ISAPI extension handling functions
BOOL HandleScript();
BOOL ExecuteISAPI(void);
void FillECB(LPEXTENSION_CONTROL_BLOCK pECB);
BOOL GetServerVariable(PSTR pszVar, PVOID pvOutBuf, PDWORD pdwOutSize, BOOL fFromFilter);
BOOL WriteClient(PVOID pvBuf, PDWORD pdwSize, BOOL fFromFilter);
BOOL WriteClientAsync(PVOID pvBuf, PDWORD pdwSize, BOOL fFromFilter);
BOOL ServerSupportFunction(DWORD dwReq, PVOID pvBuf, PDWORD pdwSize, PDWORD pdwType);
BOOL ReadClient(PVOID pv, PDWORD pdw);
void StartRemoveISAPICacheIfNeeded();
// Filter Specific
BOOL FillFC(PHTTP_FILTER_CONTEXT pfc, DWORD dwNotifyType,
LPVOID *ppStFilter, LPVOID *ppStFilterOrg,
PSTR *ppvBuf1, int *pcbBuf, PSTR *ppvBuf2, int *pcbBuf2);
void CleanupFC(DWORD dwNotifyType, LPVOID* pFilterStruct, LPVOID *pFilterStructOrg,
PSTR *ppvBuf1, int *pcbBuf, PSTR *ppvBuf2);
BOOL AuthenticateFilter();
BOOL FilterMapURL(PSTR pvBuf, WCHAR *wszPath, DWORD *pdwSize, DWORD dwBufNeeded, PSTR pszURLEx=NULL);
BOOL MapURLToPath(PSTR pszBuffer, PDWORD pdwSize, LPHSE_URL_MAPEX_INFO pUrlMapEx=NULL);
// Filter Callbacks
BOOL ServerSupportFunction(enum SF_REQ_TYPE sfReq,PVOID pData,ULONG_PTR ul1, ULONG_PTR ul2);
BOOL GetHeader(LPSTR lpszName, LPVOID lpvBuffer, LPDWORD lpdwSize);
BOOL SetHeader(LPSTR lpszName, LPSTR lpszValue);
BOOL AddResponseHeaders(LPSTR lpszHeaders,DWORD dwReserved);
// ASP Setup Fcns
BOOL ExecuteASP();
BOOL FillACB(void *p, HINSTANCE hInst);
public:
CHttpRequest(SOCKET sock)
{
Init();
m_socket = sock;
// Fixes BUG 11771. On a poorly formatted request line, if we didn't
// read in the http version right we assumed it's value was 0, since 0 < 1.0
// we'd treat this as a http/0.9 request, no headers would be sent.
m_dwVersion = MAKELONG(0,1);
}
~CHttpRequest();
BOOL ReInit();
void HandleRequest();
friend DWORD WINAPI HttpConnectionThread(LPVOID lpv);
void GenerateLog(PSTR szBuffer, DWORD_PTR *pdwToWrite);
// BOOL SetupHeader(PSTR *ppszHeader, int *piHeader, PSTR *ppszExtra, int *piExtra, BOOL fAccessDenied);
DWORD GetLogBufferSize();
// ISAPI Extension / ASP Specific
friend BOOL WINAPI GetServerVariable(HCONN hConn, PSTR psz, PVOID pv, PDWORD pdw);
friend BOOL WINAPI ReadClient(HCONN hConn, PVOID pv, PDWORD pdw);
friend BOOL WINAPI WriteClient(HCONN hConn, PVOID pv, PDWORD pdw, DWORD dw);
friend BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwReq, PVOID pvBuf, PDWORD pdwSize, PDWORD pdwType);
// ASP SPECIFIC
friend BOOL WINAPI Flush(HCONN hConn);
friend BOOL WINAPI Clear(HCONN hConn);
friend BOOL WINAPI SetBuffer(HCONN hConn, BOOL fBuffer);
friend BOOL WINAPI AddHeader (HCONN hConn, LPSTR lpszName, LPSTR lpszValue);
// FILTER SPECIFIC
BOOL CallFilter(DWORD dwNotifyType, PSTR *ppvBuf1 = NULL,int *pcbBuf = NULL,
PSTR *ppvBuf2 = NULL, int *pcbBuf2 = NULL);
BOOL FilterNoResponse(void);
// Filters Friends (exposed to Filter dll)
friend BOOL WINAPI GetServerVariable(PHTTP_FILTER_CONTEXT pfc, PSTR psz, PVOID pv, PDWORD pdw);
friend BOOL WINAPI AddResponseHeaders(PHTTP_FILTER_CONTEXT pfc,LPSTR lpszHeaders,DWORD dwReserved);
friend VOID* WINAPI AllocMem(PHTTP_FILTER_CONTEXT pfc, DWORD cbSize, DWORD dwReserved);
friend BOOL WINAPI WriteClient(PHTTP_FILTER_CONTEXT pfc, PVOID pv, PDWORD pdw, DWORD dwFlags);
friend BOOL WINAPI ServerSupportFunction(PHTTP_FILTER_CONTEXT pfc,enum SF_REQ_TYPE sfReq,
PVOID pData, ULONG_PTR ul1, ULONG_PTR ul2);
friend BOOL WINAPI SetHeader(PHTTP_FILTER_CONTEXT pfc, LPSTR lpszName, LPSTR lpszValue);
friend BOOL WINAPI GetHeader(PHTTP_FILTER_CONTEXT pfc, LPSTR lpszName, LPVOID lpvBuffer, LPDWORD lpdwSize);
};
void SendFile(SOCKET sock, HANDLE hFile, CHttpRequest *pRequest);
// Response object. This object doesn't own any of the handles or pointers
// it uses so it doesnt free anything. The caller is responsible in all cases
// for keeping the handles & memory alive while this object is extant & freeing
// them as approp at a later time
class CHttpResponse
{
SOCKET m_socket;
RESPONSESTATUS m_rs;
CONNHEADER m_connhdr;
PCSTR m_pszType;
DWORD m_dwLength;
PCSTR m_pszRedirect;
PCSTR m_pszExtraHeaders;
PCSTR m_pszBody;
HANDLE m_hFile;
char m_szMime[MAXMIME];
CHttpRequest *m_pRequest; // calling request class, for callbacks
private:
void SetTypeFromExtW(PCWSTR wszExt)
{
DEBUGCHK(!m_pszType);
m_szMime[0] = 0;
if(wszExt)
{
CReg reg(HKEY_CLASSES_ROOT, wszExt);
MyW2A(reg.ValueSZ(L"Content Type"), m_szMime, sizeof(m_szMime));
}
if(m_szMime[0])
m_pszType = m_szMime;
else
m_pszType = cszTextHtml;
}
public:
CHttpResponse(SOCKET sock, RESPONSESTATUS status, CONNHEADER connhdr, CHttpRequest *pRequest=NULL)
{
ZEROMEM(this);
m_socket = sock;
m_rs = status;
m_connhdr = connhdr;
m_pRequest = pRequest;
}
// for generated bodies (dir listings, redirects etc) & default bodies
void SetBody(PCSTR pszBody, PCSTR pszType)
{
DEBUGCHK(!m_hFile && !m_pszBody && !m_pszType && !m_dwLength);
m_pszType = pszType;
m_dwLength = strlen(pszBody);
m_pszBody = pszBody;
}
// for error reponses (NOTE: some have no body, and hence psztatusBdy will be NULL in the table)
void SetDefaultBody()
{
if(rgStatus[m_rs].pszStatusBody)
SetBody(rgStatus[m_rs].pszStatusBody, cszTextHtml);
}
// for real files
void SetBody(HANDLE hFile, PCWSTR wszExt=NULL, DWORD dwLen=0)
{
DEBUGCHK(!m_hFile && !m_pszBody && !m_pszType && !m_dwLength);
m_hFile = hFile;
SetTypeFromExtW(wszExt);
if (dwLen)
m_dwLength = dwLen;
else
{
m_dwLength = GetFileSize(m_hFile, 0);
if (m_dwLength == 0)
m_dwLength = -1; // Use this to signify empty file, needed for keep-alives
}
}
private:
void SendBody();
public:
void SendHeaders(PCSTR pszExtraHeaders, PCSTR pszNewRespStatus);
void SendRedirect(PCSTR pszRedirect, BOOL fFromFilter=FALSE);
void SendResponse(PCSTR pszExtraHeaders=NULL, PCSTR pszNewRespStatus=NULL, BOOL fFromFilter=FALSE)
{
// see FilterNoResponse for comments on this
if (!fFromFilter && m_pRequest->FilterNoResponse())
return;
SendHeaders(pszExtraHeaders,pszNewRespStatus);
SendBody();
}
};