|
|
/*--
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(); } };
|