Update of /cvsroot/pywin32/pywin32/isapi/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17001/isapi/src
Added Files:
ControlBlock.h FilterContext.h PyExtensionObjects.cpp
PyExtensionObjects.h PyFilterObjects.cpp PyFilterObjects.h
PythonEng.cpp PythonEng.h StdAfx.cpp StdAfx.h Utils.cpp
Utils.h pyISAPI.cpp pyISAPI.h
Log Message:
Rename pyisapi directory to isapi, so it matches what the user sees, as
part of the process of integrating it with the rest of the build.
--- NEW FILE: ControlBlock.h ---
#ifndef __CONTROL_BLOCK_H__
#define __CONTROL_BLOCK_H__
// wrapper for the session context (ECB block for IIS)
// If we move away from IIS these will have to change
class CControlBlock
{
public:
CControlBlock(EXTENSION_CONTROL_BLOCK *pECB=NULL) :
m_pECB(pECB)
{
}
~CControlBlock()
{
}
CControlBlock(const CControlBlock & rhs)
{
Copy(rhs);
}
CControlBlock & operator=(const CControlBlock & rhs)
{
if (this != &rhs)
Copy(rhs);
return *this;
}
// member retrieval functions
EXTENSION_CONTROL_BLOCK * GetECB(void)
{
return m_pECB;
}
// wrappers for IIS ECB structures
void SetStatus(const DWORD status)
{
m_pECB->dwHttpStatusCode = status;
}
void SetLogMessage(LPCTSTR msg)
{
strncpy(m_pECB->lpszLogData, msg, HSE_LOG_BUFFER_LEN);
}
DWORD WriteHeaders(LPCTSTR szStatus, LPCTSTR szHeader, const bool bKeepAlive=true)
{
// NOTE we must send Content-Length header with correct byte count
// in order for keep-alive to work, the bKeepAlive flag is not enough
// by itself..
HSE_SEND_HEADER_EX_INFO SendHeaderExInfo;
DWORD cchStatus = lstrlen(szStatus);
DWORD cchHeader = lstrlen(szHeader);
// Populate SendHeaderExInfo struct
SendHeaderExInfo.pszStatus = szStatus;
SendHeaderExInfo.pszHeader = szHeader;
SendHeaderExInfo.cchStatus = cchStatus;
SendHeaderExInfo.cchHeader = cchHeader;
SendHeaderExInfo.fKeepConn = (bKeepAlive) ? TRUE:FALSE;
// Send header
return m_pECB->ServerSupportFunction(m_pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &SendHeaderExInfo, NULL,NULL);
}
DWORD WriteStream(LPCTSTR buffer, const int buffLen, const int reserved=0)
{
DWORD dwBufLen = buffLen;
m_pECB->WriteClient(m_pECB->ConnID, (void *) buffer, &dwBufLen, reserved);
return dwBufLen;
}
bool ReadClient(LPVOID lpvBuffer, LPDWORD lpdwSize)
{
return m_pECB->ReadClient(m_pECB->ConnID, lpvBuffer, lpdwSize) ? true : false;
}
void DoneWithSession(DWORD dwState)
{
// Let IIS know that this worker thread is done with this request. This will allow
// IIS to recycle the EXTENSION_CONTROL_BLOCK.
m_pECB->ServerSupportFunction(m_pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);
}
bool GetServerVariable(LPCTSTR varName, LPSTR lpBuff, DWORD *pBuffSize)
{
BOOL bOK = m_pECB->GetServerVariable(m_pECB->ConnID,(LPSTR) varName,lpBuff,pBuffSize);
if (!bOK)
*pBuffSize = 0;
if (lpBuff[(*pBuffSize)-1]=='\0')
(*pBuffSize)--;
return (bOK) ? true : false;
}
bool GetImpersonationToken(HANDLE *ret)
{
return (m_pECB->ServerSupportFunction)( m_pECB->ConnID, HSE_REQ_GET_IMPERSONATION_TOKEN, ret, 0,0) ?
true : false;
}
BOOL Redirect(LPCTSTR url)
{
DWORD buffSize = strlen(url);
BOOL bOK = (m_pECB->ServerSupportFunction)( m_pECB->ConnID, HSE_REQ_SEND_URL_REDIRECT_RESP, (LPSTR) url, &buffSize,0);
return bOK;
}
bool IsKeepAlive(void)
{
bool bKeepAlive = false;
char buf[256];
DWORD bufsize = sizeof(buf)/sizeof(buf[0]);
if (GetServerVariable("HTTP_CONNECTION",buf, &bufsize)){
bKeepAlive = strcmpi(buf, "keep-alive")==0;
}
return bKeepAlive;
}
private:
EXTENSION_CONTROL_BLOCK * m_pECB; // IIS control block
private:
void Copy(const CControlBlock & rhs)
{
m_pECB = rhs.m_pECB;
}
};
#endif // __CONTROL_BLOCK_H__
--- NEW FILE: Utils.h ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#ifndef __UTILS_H
#define __UTILS_H
// ---------------------------------------------------------------------------
// Class: CSLock
// Locking class which handles the serialisation of objects using CSingleLock.
//
class CSLock
{
public:
inline CSLock(CRITICAL_SECTION &sem)
: m_Lock(sem)
{
::EnterCriticalSection(&m_Lock);
}
~CSLock()
{
::LeaveCriticalSection(&m_Lock);
}
private:
CRITICAL_SECTION &m_Lock;
}; // CSLock
// Formats a system error code
char *FormatSysError(const DWORD nErrNo);
// Dump out an HTML error response page
char *HTMLErrorResp(LPCTSTR msg);
// returns the pathname of this module
char *GetModulePath(void);
#endif // __UTILS_H
--- NEW FILE: PyFilterObjects.h ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#ifndef __PyHFC_H
#define __PyHFC_H
#include "FilterContext.h"
#include "structmember.h"
#include "tupleobject.h"
class PyFILTER_VERSION :public PyObject
{
HTTP_FILTER_VERSION * m_pfv;
public:
PyFILTER_VERSION(HTTP_FILTER_VERSION* pfv);
~PyFILTER_VERSION();
public:
void Reset() {m_pfv = NULL;}
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
};
class PyHFC :public PyObject
{
CFilterContext * m_pfc;
public:
PyHFC(CFilterContext* pfc = NULL);
~PyHFC();
void Reset() {m_pfc = NULL;}
CFilterContext *GetFilterContext() {return m_pfc;}
public:
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
// class methods
static PyObject * GetData(PyObject *self, PyObject *args);
static PyObject * WriteClient(PyObject *self, PyObject *args);
static PyObject * GetServerVariable(PyObject *self, PyObject *args);
// ServerSupportFunction implemented functions.
static PyObject * SendResponseHeader(PyObject *self, PyObject *args);
protected:
#pragma warning( disable : 4251 )
static struct memberlist PyHFC_memberlist[];
#pragma warning( default : 4251 )
DWORD m_notificationType;
DWORD m_revision;
BOOL m_isSecurePort;
};
class PyURL_MAP :public PyObject
{
public:
PyHFC *m_parent;
public:
PyURL_MAP(PyHFC *);
~PyURL_MAP();
HTTP_FILTER_URL_MAP *GetURLMap();
public:
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
};
class PyPREPROC_HEADERS :public PyObject
{
public:
PyHFC *m_parent;
public:
PyPREPROC_HEADERS(PyHFC *);
~PyPREPROC_HEADERS();
HTTP_FILTER_CONTEXT *GetFILTER_CONTEXT();
HTTP_FILTER_PREPROC_HEADERS *GetPREPROC_HEADERS();
public:
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
};
// error handling
static PyObject * PyHFC_Error = NULL;
PyObject * SetPyHFCError(char *fnName, long err=0);
#endif // __PyHFC_H
--- NEW FILE: pyISAPI.cpp ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
// PYISAPI.CPP - Implementation file for your Internet Server
// Python ISAPI Extension
#include "stdafx.h"
#include "pyISAPI.h"
#include "pyExtensionObjects.h"
#include "pyFilterObjects.h"
static const char *name_ext_factory = "__ExtensionFactory__";
static const char *name_ext_init = "GetExtensionVersion";
static const char *name_ext_do = "HttpExtensionProc";
static const char *name_ext_term = "TerminateExtension";
static const char *name_filter_factory = "__FilterFactory__";
static const char *name_filter_init = "GetFilterVersion";
static const char *name_filter_do = "HttpFilterProc";
static const char *name_filter_term = "TerminateFilter";
static CPythonEngine pyEngine;
static CPythonHandler filterHandler;
static CPythonHandler extensionHandler;
bool g_IsFrozen = false;
char g_CallbackModuleName[_MAX_PATH + _MAX_FNAME] = "";
#define TRACE OutputDebugString
// This is an entry point for py2exe.
void WINAPI PyISAPISetOptions(const char *modname, BOOL is_frozen)
{
strncpy(g_CallbackModuleName, modname,
sizeof(g_CallbackModuleName)/sizeof(g_CallbackModuleName[0]));
// cast BOOL->bool without compiler warning!
g_IsFrozen = is_frozen ? TRUE : FALSE;
}
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
// ensure our handler ready to go
if (!extensionHandler.Init(&pyEngine, name_ext_factory,
name_ext_init, name_ext_do, name_ext_term)) {
// already have reported any errors to Python.
TRACE("Unable to load Python handler");
return false;
}
PyObject *resultobject = NULL;
bool bRetStatus = true;
PyGILState_STATE state = PyGILState_Ensure();
// create the Python object
PyVERSION_INFO *pyVO = new PyVERSION_INFO(pVer);
resultobject = extensionHandler.Callback(HANDLER_INIT, "N", pyVO);
if (! resultobject) {
ExtensionError(NULL, "Extension version function failed!");
bRetStatus = false;
} else {
if (resultobject == Py_None)
bRetStatus = TRUE;
else if (PyInt_Check(resultobject))
bRetStatus = PyInt_AsLong(resultobject) ? true : false;
else {
ExtensionError(NULL, "Filter init should return an int, or None");
bRetStatus = FALSE;
}
}
Py_XDECREF(resultobject);
PyGILState_Release(state);
return bRetStatus;
}
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
DWORD result;
PyGILState_STATE state = PyGILState_Ensure();
CControlBlock * pcb = new CControlBlock(pECB);
PyECB *pyECB = new PyECB(pcb);
PyObject *resultobject = extensionHandler.Callback(HANDLER_DO, "N", pyECB);
if (! resultobject) {
ExtensionError(pcb, "HttpExtensionProc function failed!");
result = HSE_STATUS_ERROR;
} else {
if (PyInt_Check(resultobject))
result = PyInt_AsLong(resultobject);
else {
ExtensionError(pcb, "HttpExtensionProc should return an int");
result = HSE_STATUS_ERROR;
}
}
Py_XDECREF(resultobject);
PyGILState_Release(state);
return result;
}
BOOL WINAPI TerminateExtension(DWORD dwFlags)
{
// extension is being terminated
BOOL bRetStatus;
PyGILState_STATE state = PyGILState_Ensure();
PyObject *resultobject = extensionHandler.Callback(HANDLER_TERM, "i", dwFlags);
if (! resultobject) {
ExtensionError(NULL, "Extension term function failed!");
bRetStatus = false;
} else {
if (resultobject == Py_None)
bRetStatus = TRUE;
else if (PyInt_Check(resultobject))
bRetStatus = PyInt_AsLong(resultobject) ? true : false;
else {
ExtensionError(NULL, "Extension term should return an int, or None");
bRetStatus = FALSE;
}
}
Py_XDECREF(resultobject);
PyGILState_Release(state);
extensionHandler.Term();
return bRetStatus;
}
BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
// ensure our handler ready to go
if (!filterHandler.Init(&pyEngine, name_filter_factory,
name_filter_init, name_filter_do, name_filter_term))
// error already imported.
return FALSE;
PyGILState_STATE state = PyGILState_Ensure();
PyFILTER_VERSION *pyFV = new PyFILTER_VERSION(pVer);
PyObject *resultobject = filterHandler.Callback(HANDLER_INIT, "N", pyFV);
BOOL bRetStatus;
if (! resultobject) {
FilterError(NULL, "Filter version function failed!");
bRetStatus = false;
} else {
if (resultobject == Py_None)
bRetStatus = TRUE;
else if (PyInt_Check(resultobject))
bRetStatus = PyInt_AsLong(resultobject) ? true : false;
else {
FilterError(NULL, "Filter init should return an int, or None");
bRetStatus = FALSE;
}
}
Py_XDECREF(resultobject);
PyGILState_Release(state);
return bRetStatus;
}
DWORD WINAPI HttpFilterProc(HTTP_FILTER_CONTEXT *phfc, DWORD NotificationType, VOID *pvData)
{
DWORD action;
PyGILState_STATE state = PyGILState_Ensure();
PyObject *resultobject = NULL;
// create the Python object
CFilterContext fc(phfc, NotificationType, pvData);
PyHFC *pyHFC = new PyHFC(&fc);
resultobject = filterHandler.Callback(HANDLER_DO, "O", pyHFC);
if (! resultobject) {
FilterError(&fc, "Filter function failed!");
action = SF_STATUS_REQ_ERROR;
} else {
DWORD action;
if (resultobject == Py_None)
action = SF_STATUS_REQ_NEXT_NOTIFICATION;
else if (PyInt_Check(resultobject))
action = PyInt_AsLong(resultobject);
else {
FilterError(&fc, "Filter should return an int, or None");
action = SF_STATUS_REQ_ERROR;
}
}
pyHFC->Reset();
Py_DECREF(pyHFC);
Py_XDECREF(resultobject);
PyGILState_Release(state);
return action;
}
BOOL WINAPI TerminateFilter(DWORD status)
{
BOOL bRetStatus;
PyGILState_STATE state = PyGILState_Ensure();
PyObject *resultobject = filterHandler.Callback(HANDLER_TERM, "i", status);
if (! resultobject) {
FilterError(NULL, "Filter version function failed!");
bRetStatus = false;
} else {
if (resultobject == Py_None)
bRetStatus = TRUE;
else if (PyInt_Check(resultobject))
bRetStatus = PyInt_AsLong(resultobject) ? true : false;
else {
FilterError(NULL, "Filter term should return an int, or None");
bRetStatus = FALSE;
}
}
Py_XDECREF(resultobject);
PyGILState_Release(state);
// filter is being terminated
filterHandler.Term();
return bRetStatus;
}
///////////////////////////////////////////////////////////////////////
// If your extension will not use MFC, you'll need this code to make
// sure the extension objects can find the resource handle for the
// module. If you convert your extension to not be dependent on MFC,
// remove the comments arounn the following AfxGetResourceHandle()
// and DllMain() functions, as well as the g_hInstance global.
HINSTANCE g_hInstance = 0;
BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason,
LPVOID lpReserved)
{
if (ulReason == DLL_PROCESS_ATTACH)
{
g_hInstance = hInst;
}
return TRUE;
}
--- NEW FILE: PythonEng.cpp ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
// NOTE: This code used to host the thread-pool used by dispatch to Python
// Some of the methods etc made alot more sense then.
#include "stdafx.h"
#include "Utils.h"
#include "PythonEng.h"
#include "pyExtensionObjects.h"
#include "pyFilterObjects.h"
extern HINSTANCE g_hInstance;
extern bool g_IsFrozen;
extern char g_CallbackModuleName[_MAX_PATH + _MAX_FNAME];
/////////////////////////////////////////////////////////////////////
// Python Engine
/////////////////////////////////////////////////////////////////////
CRITICAL_SECTION CPythonEngine::m_initLock;
bool CPythonEngine::m_haveInit = false;
PyObject * CPythonEngine::m_reload_exception = NULL;
CPythonEngine::CPythonEngine()
{
InitializeCriticalSection(&m_initLock);
}
CPythonEngine::~CPythonEngine()
{
DeleteCriticalSection(&m_initLock);
}
bool CPythonEngine::InitMainInterp(void)
{
// ensure only 1 engine/thread initialises this only
CSLock l(m_initLock);
if (!m_haveInit) {
PyGILState_STATE old_state;
if (Py_IsInitialized())
old_state = PyGILState_Ensure();
else {
Py_Initialize();
old_state = PyGILState_UNLOCKED;
}
PyEval_InitThreads();
if (!g_IsFrozen) {
char *dll_path = GetModulePath();
AddToPythonPath(dll_path);
free(dll_path);
PyErr_Clear();
}
// isapidllhandle to match dllhandle, frozendllhandle, etc :) Also a
// nice way for a program to know they are in an ISAPI context.
PyObject *obh = PyLong_FromVoidPtr(g_hInstance);
PySys_SetObject("isapidllhandle", obh);
Py_XDECREF(obh);
// Locate the special exception we use to trigger a reload.
PyObject *isapi_package = PyImport_ImportModule("isapi");
if (isapi_package)
m_reload_exception = PyObject_GetAttrString(isapi_package,
"InternalReloadException");
Py_XDECREF(isapi_package);
PyGILState_Release(old_state);
FindModuleName();
m_haveInit = true;
}
return true;
}
void CPythonEngine::FindModuleName()
{
TCHAR szFilePath[_MAX_PATH];
TCHAR szBase[_MAX_FNAME];
TCHAR *module_name;
// If a name for the module has been magically setup (eg, via a frozen
// app), then use it. Otherwise, assume it is the DLL name without the
// first character (ie, without the leading _)
if (g_CallbackModuleName && *g_CallbackModuleName)
module_name = g_CallbackModuleName;
else {
// find out where our DLL/EXE module lives
// NOTE: the long file name does not get returned (don't know why)
::GetModuleFileName(g_hInstance, szFilePath, sizeof(szFilePath));
::_splitpath( szFilePath, NULL, NULL, szBase, NULL);
module_name = szBase + 1; // skip first char.
}
strncpy(m_module_name, module_name, sizeof(m_module_name)/sizeof(m_module_name[0]));
}
bool CPythonEngine::AddToPythonPath(LPCTSTR pPathName)
{
PyObject *obPathList = PySys_GetObject(_T("path"));
if (obPathList==NULL) {
return false;
}
PyObject *obNew = PyString_FromString(pPathName);
if (obNew==NULL) {
return false;
}
bool bFnd=false;
for (int i=0; i<PyList_Size(obPathList); i++){
PyObject * obItem = PyList_GetItem(obPathList, i);
if(PyObject_Compare(obNew, obItem) == 0){
bFnd = true;
break;
}
}
if (!bFnd)
PyList_Insert(obPathList, 0, obNew);
Py_XDECREF(obNew);
return true;
}
///////////////////////////////////////////////////////////////////////
//
// The callback manager
//
CPythonHandler::CPythonHandler() :
m_namefactory(0),
m_nameinit(0),
m_namedo(0),
m_nameterm(0),
m_callback_init(0),
m_callback_do(0),
m_callback_term(0),
m_handler(0)
{
return;
}
bool CPythonHandler::Init(
CPythonEngine *engine,
const char *factory, const char *nameinit, const char *namedo,
const char *nameterm)
{
if (!engine->InitMainInterp())
return false;
m_nameinit = nameinit;
m_namedo = namedo;
m_nameterm = nameterm;
m_namefactory = factory;
m_engine = engine;
return LoadHandler(false);
}
bool CPythonHandler::LoadHandler(bool reload)
{
char szErrBuf[1024];
PyObject *m;
PyGILState_STATE old_state = PyGILState_Ensure();
m = PyImport_ImportModule(m_engine->m_module_name);
if (m && reload) {
PyObject *m_orig = m;
m = PyImport_ReloadModule(m);
Py_DECREF(m_orig);
}
if (!m) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
"Failed to import callback module '%s'", m_engine->m_module_name);
ExtensionError(NULL, szErrBuf);
}
if (m) {
Py_XDECREF(m_handler);
if (!((m_handler = PyObject_CallMethod(m, (char *)m_namefactory, NULL)))) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
"Factory function '%s' failed", m_namefactory);
ExtensionError(NULL, szErrBuf);
}
Py_DECREF(m);
}
PyGILState_Release(old_state);
return m_handler != NULL;
}
bool CPythonHandler::CheckCallback(const char *cbname, PyObject **cb)
{
if (*cb!=NULL)
return true; // already have the callback.
PyGILState_STATE old_state = PyGILState_Ensure();
if (!m_handler) {
PyErr_SetString(PyExc_RuntimeError, "The handler failed to load");
return false;
}
*cb = PyObject_GetAttrString(m_handler, (char *)cbname);
if (!*cb)
ExtensionError(NULL, "Failed to locate the callback");
PyGILState_Release(old_state);
return (*cb) != NULL;
}
// NOTE: Caller must setup and release thread-state - as we return a PyObject,
// the caller must at least Py_DECREF it, so must hold the lock.
PyObject *CPythonHandler::DoCallback(
HANDLER_TYPE typ,
PyObject *args
)
{
PyObject **ppcb;
const char *cb_name;
switch(typ) {
case HANDLER_INIT:
ppcb = &m_callback_init;
cb_name = m_nameinit;
break;
case HANDLER_TERM:
ppcb = &m_callback_term;
cb_name = m_nameterm;
break;
default:
ppcb = &m_callback_do;
cb_name = m_namedo;
break;
}
if (!CheckCallback(cb_name, ppcb))
return NULL;
return PyObject_Call(*ppcb, args, NULL);
}
PyObject *CPythonHandler::Callback(
HANDLER_TYPE typ,
const char *format /* = NULL */,
...
)
{
va_list va;
PyObject *args;
if (format && *format) {
va_start(va, format);
args = Py_VaBuildValue((char *)format, va);
va_end(va);
}
else
args = PyTuple_New(0);
if (args == NULL)
return NULL;
if (!PyTuple_Check(args)) {
PyObject *a;
a = PyTuple_New(1);
if (a == NULL)
return NULL;
if (PyTuple_SetItem(a, 0, args) < 0)
return NULL;
args = a;
}
PyObject *ret = DoCallback(typ, args);
if (!ret) {
if (m_engine->m_reload_exception &&
PyErr_ExceptionMatches(m_engine->m_reload_exception)) {
PyErr_Clear();
// Need to call term first
PyObject *temp_args = Py_BuildValue("(i)", 0);
ret = DoCallback(HANDLER_TERM, temp_args);
Py_XDECREF(temp_args);
if (!ret) {
ExtensionError(NULL, "Terminating for reload failed");
PyErr_Clear();
}
Py_XDECREF(ret);
// Now force the reload and refresh of all callbacks.
if (!LoadHandler(true))
return NULL;
Py_XDECREF(m_callback_init);
m_callback_init = NULL;
Py_XDECREF(m_callback_do);
m_callback_do = NULL;
Py_XDECREF(m_callback_term);
m_callback_term = NULL;
// call init again
temp_args = Py_BuildValue("(z)", NULL);
ret = DoCallback(HANDLER_INIT, temp_args);
Py_XDECREF(temp_args);
if (!ret) {
ExtensionError(NULL, "Reinitializing after import failed");
PyErr_Clear();
}
Py_XDECREF(ret);
// And make the original call again.
ret = DoCallback(typ, args);
}
}
Py_DECREF(args);
return ret;
}
void CPythonHandler::Term(void)
{
// never shut down - Python leaks badly and has other
// side effects if you repeatedly Init then Term
Py_XDECREF(m_callback_init);
Py_XDECREF(m_callback_do);
Py_XDECREF(m_callback_term);
}
//////////////////////////////////////////////////////////////////////////////
// general error handler
void ExtensionError(CControlBlock *pcb, LPCTSTR errmsg)
{
char *windows_error = ::GetLastError() ?
::FormatSysError(::GetLastError()) : NULL;
PyGILState_STATE s = PyGILState_Ensure();
PySys_WriteStderr("Internal Extension Error: %s\n", errmsg);
if (windows_error)
PySys_WriteStderr("Last Windows error: %s\n", windows_error);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
PyGILState_Release(s);
if (pcb) {
char *htmlStream = HTMLErrorResp(errmsg);
pcb->SetStatus(HSE_STATUS_ERROR);
pcb->SetLogMessage(errmsg);
pcb->WriteHeaders(_T("200 OK"), _T("Content-type: text/html\r\n\r\n"), false);
pcb->WriteStream(htmlStream, strlen(htmlStream));
if (windows_error) {
static char *chunk = "<br>Last Windows error:";
pcb->WriteStream(chunk, strlen(chunk));
pcb->WriteStream(windows_error, strlen(windows_error));
}
}
if (windows_error)
free(windows_error);
}
void FilterError(CFilterContext *pfc, LPCTSTR errmsg)
{
PyGILState_STATE s = PyGILState_Ensure();
PySys_WriteStderr("Internal Filter Error: %s\n", errmsg);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
PyGILState_Release(s);
// what else to do here? AddResponseHeaders->WriteClient?
}
--- NEW FILE: PyExtensionObjects.h ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#ifndef __PyExtensionObjects_H__
#define __PyExtensionObjects_H__
#include "ControlBlock.h"
#include "structmember.h"
#include "tupleobject.h"
class PyVERSION_INFO :public PyObject
{
HSE_VERSION_INFO * m_pvi;
public:
PyVERSION_INFO(HSE_VERSION_INFO* pfv);
~PyVERSION_INFO();
public:
void Reset() {m_pvi = NULL;}
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
};
class PyECB :public PyObject
{
CControlBlock * m_pcb;
DWORD m_version; // Version info of this spec
HCONN m_connID; // Context number not to be modified!
PyObject * m_method; // REQUEST_METHOD
PyObject * m_queryString; // QUERY_STRING
PyObject * m_pathInfo; // PATH_INFO
PyObject * m_pathTranslated; // PATH_TRANSLATED
DWORD m_totalBytes; // Total bytes indicated from client
DWORD m_available; // Available number of bytes
PyObject * m_data; // Pointer to cbAvailable bytes
PyObject * m_contentType; // Content type of client data
DWORD m_HttpStatusCode; // The status of the current transaction when the request is completed.
PyObject * m_logData; // log data string
bool m_bAsyncDone; // sent the async done
public:
PyECB(CControlBlock * pcb = NULL);
~PyECB();
bool FinishedResponse(void) { return m_bAsyncDone; }
public:
// Python support
static void deallocFunc(PyObject *ob);
static PyObject *getattr(PyObject *self, char *name);
static int setattr(PyObject *self, char *name, PyObject *v);
// class methods
static PyObject * WriteClient(PyObject *self, PyObject *args);
static PyObject * GetServerVariable(PyObject *self, PyObject *args);
static PyObject * ReadClient(PyObject *self, PyObject *args);
// Server support function wrappers
// these wrap the various server support functions supported through the
// ServerSupportFunction routine.
static PyObject * SendResponseHeaders(PyObject *self, PyObject * args); // HSE_REQ_SEND_RESPONSE_HEADER_EX
static PyObject * Redirect(PyObject *self, PyObject * args); // HSE_REQ_SEND_URL_REDIRECT_RESP.
static PyObject * IsKeepAlive(PyObject *self, PyObject * args); // Keep alive flag set
static PyObject * DoneWithSession(PyObject *self, PyObject * args); //HSE_REQ_DONE_WITH_SESSION
static PyObject * GetImpersonationToken(PyObject *self, PyObject * args); // HSE_REQ_GET_IMPERSONATION_TOKEN
static PyObject * IsSessionActive(PyObject *self, PyObject * args);
protected:
#pragma warning( disable : 4251 )
static struct memberlist PyECB_memberlist[];
#pragma warning( default : 4251 )
};
// error handling
static PyObject * PyECB_Error = NULL;
PyObject * SetPyECBError(char *fnName, long err=0);
#endif // __PyExtensionObjects_H__
--- NEW FILE: PyFilterObjects.cpp ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#include "stdafx.h"
#include "Utils.h"
#include "pyFilterObjects.h"
// @doc
// @object HTTP_FILTER_VERSION|A Python interface to the ISAPI HTTP_FILTER_VERSION
// structure.
PyTypeObject PyFILTER_VERSIONType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"HTTP_FILTER_VERSION",
sizeof(PyFILTER_VERSION),
0,
PyFILTER_VERSION::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyFILTER_VERSION::getattr, /* tp_getattr */
PyFILTER_VERSION::setattr, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyFILTER_VERSION::PyFILTER_VERSION(HTTP_FILTER_VERSION *pfv)
{
ob_type = &PyFILTER_VERSIONType;
_Py_NewReference(this);
m_pfv = pfv;
}
PyFILTER_VERSION::~PyFILTER_VERSION()
{
}
PyObject *PyFILTER_VERSION::getattr(PyObject *self, char *name)
{
PyFILTER_VERSION *me = (PyFILTER_VERSION *)self;
if (!me->m_pfv)
return PyErr_Format(PyExc_RuntimeError, "FILTER_VERSION structure no longer exists");
// @prop int|ServerFilterVersion|(read-only)
if (strcmp(name, "ServerFilterVersion")==0) {
return PyInt_FromLong(me->m_pfv->dwServerFilterVersion);
}
// @prop int|FilterVersion|
if (strcmp(name, "FilterVersion")==0) {
return PyInt_FromLong(me->m_pfv->dwFilterVersion);
}
// @prop int|Flags|
if (strcmp(name, "Flags")==0) {
return PyInt_FromLong(me->m_pfv->dwFlags);
}
// @prop string|FilterDesc|
if (strcmp(name, "FilterDesc")==0) {
return PyString_FromString(me->m_pfv->lpszFilterDesc);
}
return PyErr_Format(PyExc_AttributeError, "PyFILTER_VERSION has no attribute '%s'", name);
}
int PyFILTER_VERSION::setattr(PyObject *self, char *name, PyObject *v)
{
PyFILTER_VERSION *me = (PyFILTER_VERSION *)self;
if (!me->m_pfv) {
PyErr_Format(PyExc_RuntimeError, "FILTER_VERSION structure no longer exists");
return -1;
}
if (v == NULL) {
PyErr_SetString(PyExc_AttributeError, "can't delete FILTER_VERSION attributes");
return -1;
}
if (strcmp(name, "FilterVersion")==0) {
if (!PyInt_Check(v)) {
PyErr_Format(PyExc_ValueError, "FilterVersion must be an int (got %s)", v->ob_type->tp_name);
return -1;
}
me->m_pfv->dwFilterVersion = PyInt_AsLong(v);
}
else if (strcmp(name, "Flags")==0) {
if (!PyInt_Check(v)) {
PyErr_Format(PyExc_ValueError, "Flags must be an int (got %s)", v->ob_type->tp_name);
return -1;
}
me->m_pfv->dwFlags = PyInt_AsLong(v);
}
else if (strcmp(name, "FilterDesc")==0) {
if (!PyString_Check(v)) {
PyErr_Format(PyExc_ValueError, "FilterDesc must be a string (got %s)", v->ob_type->tp_name);
return -1;
}
if (PyString_Size(v) > SF_MAX_FILTER_DESC_LEN) {
PyErr_Format(PyExc_ValueError, "String is too long - max of %d chars", SF_MAX_FILTER_DESC_LEN);
return -1;
}
strcpy(me->m_pfv->lpszFilterDesc, PyString_AsString(v));
} else {
PyErr_SetString(PyExc_AttributeError, "can't modify read only FILTER_VERSION attributes.");
return -1;
}
return 0;
}
void PyFILTER_VERSION::deallocFunc(PyObject *ob)
{
delete (PyFILTER_VERSION *)ob;
}
/////////////////////////////////////////////////////////////////////
// filter context wrapper
/////////////////////////////////////////////////////////////////////
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#define ECBOFF(e) offsetof(PyHFC, e)
// @pymethod object|HTTP_FILTER_CONTEXT|GetData|Obtains the data passed to
// The HttpFilterProc function. This is not techinally part of the
// HTTP_FILTER_CONTEXT structure, but packaged here for convenience.
PyObject * PyHFC::GetData(PyObject *self, PyObject *args)
{
PyHFC *me = (PyHFC *)self;
// @rdesc The result depends on the value of <om HTTP_FILTER_CONTEXT.NotificationType>
// @flagh NotificationType|Result type
switch (me->m_notificationType) {
// @flag SF_NOTIFY_URL_MAP|<o HTTP_FILTER_URL_MAP>
case SF_NOTIFY_URL_MAP:
return new PyURL_MAP(me);
// @flag SF_NOTIFY_PREPROC_HEADERS|<o HTTP_FILTER_PREPROC_HEADERS>
case SF_NOTIFY_PREPROC_HEADERS:
return new PyPREPROC_HEADERS(me);
default:
PyErr_Format(PyExc_ValueError, "Don't understand data of type 0x%x", me->m_notificationType);
return NULL;
}
/* not reached */
assert(false);
}
// @pymethod |HTTP_FILTER_CONTEXT|WriteClient|
PyObject * PyHFC::WriteClient(PyObject *self, PyObject *args)
{
BOOL bRes = FALSE;
TCHAR * buffer = NULL;
int buffLen = 0;
int reserved = 0;
PyHFC * phfc = (PyHFC *) self;
// @pyparm string|data||
// @pyparm int|reserverd|0|
if (!PyArg_ParseTuple(args, "s#|l:WriteClient", &buffer, &buffLen, &reserved))
return NULL;
if (phfc->m_pfc){
Py_BEGIN_ALLOW_THREADS
bRes = phfc->m_pfc->WriteClient(buffer, buffLen, reserved);
Py_END_ALLOW_THREADS
if (!bRes)
return SetPyHFCError("WriteClient");
}
Py_INCREF(Py_None);
return Py_None;
}
// @pymethod string|HTTP_FILTER_CONTEXT|GetServerVariable|
PyObject * PyHFC::GetServerVariable(PyObject *self, PyObject *args)
{
BOOL bRes = FALSE;
TCHAR * variable = NULL;
PyObject *def = NULL;
PyHFC * phfc = (PyHFC *) self;
// @pyparm string|variable||
// @pyparm object|default||If specified, the function will return this
// value instead of raising an error if the variable could not be fetched.
if (!PyArg_ParseTuple(args, "s|O:GetServerVariable", &variable, &def))
return NULL;
char buf[8192] = "";
DWORD bufsize = sizeof(buf)/sizeof(buf[0]);
if (phfc->m_pfc){
Py_BEGIN_ALLOW_THREADS
bRes = phfc->m_pfc->GetServerVariable(variable, buf, &bufsize);
Py_END_ALLOW_THREADS
if (!bRes) {
if (def) {
Py_INCREF(def);
return def;
}
return SetPyHFCError("GetServerVariable");
}
}
return PyString_FromStringAndSize(buf, bufsize);
}
// @pymethod |HTTP_FILTER_CONTEXT|SendResponseHeader|
PyObject * PyHFC::SendResponseHeader(PyObject *self, PyObject *args)
{
BOOL bRes = FALSE;
char *status, *header;
PyHFC * phfc = (PyHFC *) self;
// @pyparm string|status||
// @pyparm string|header||
if (!PyArg_ParseTuple(args, "zz:SendResponseHeader", &status, &header))
return NULL;
if (!phfc->m_pfc)
return PyErr_Format(PyExc_RuntimeError, "No filtercontext!");
Py_BEGIN_ALLOW_THREADS
// The Java code passes "\r\n" as first DWORD, and header in second,
// but docs clearly have second as unused. Either way, I can't see the
// specific header!
bRes = phfc->m_pfc->ServerSupportFunction(SF_REQ_SEND_RESPONSE_HEADER,
status, (DWORD)header, 0);
Py_END_ALLOW_THREADS
if (!bRes)
return SetPyHFCError("SendResponseHeader");
Py_INCREF(Py_None);
return Py_None;
}
// @object HTTP_FILTER_CONTEXT|A Python representation of an ISAPI
// HTTP_FILTER_CONTEXT structure.
static struct PyMethodDef PyHFC_methods[] = {
{"GetData", PyHFC::GetData, 1}, // @pymeth GetData|
{"GetServerVariable", PyHFC::GetServerVariable, 1}, // @pymeth GetServerVariable|
{"WriteClient", PyHFC::WriteClient, 1}, // @pymeth WriteClient|
{"write", PyHFC::WriteClient, 1}, // @pymeth write|A synonym for WriteClient, this allows you to 'print >> fc'
{"SendResponseHeader", PyHFC::SendResponseHeader, 1}, // @pymeth SendResponseHeader|
{NULL}
};
struct memberlist PyHFC::PyHFC_memberlist[] = {
// @prop int|Revision|(read-only)
{"Revision", T_INT,ECBOFF(m_revision), READONLY},
// @prop bool|fIsSecurePort|(read-only)
{"fIsSecurePort", T_INT, ECBOFF(m_isSecurePort), READONLY},
// @prop int|NotificationType|(read-only)
{"NotificationType", T_INT,ECBOFF(m_notificationType), READONLY},
{NULL}
};
PyTypeObject PyHFCType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"HTTP_FILTER_CONTEXT",
sizeof(PyHFC),
0,
PyHFC::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyHFC::getattr, /* tp_getattr */
PyHFC::setattr, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyHFC::PyHFC(CFilterContext* pfc)
{
ob_type = &PyHFCType;
_Py_NewReference(this);
m_pfc = pfc;
HTTP_FILTER_CONTEXT *phfc;
VOID *pData;
pfc->GetFilterData(&phfc, &m_notificationType, &pData);
m_revision = phfc->Revision;
m_isSecurePort = phfc->fIsSecurePort;
}
PyHFC::~PyHFC()
{
if (m_pfc)
delete m_pfc;
}
PyObject *PyHFC::getattr(PyObject *self, char *name)
{
// see if its a member variable
for (int i=0; i<ARRAYSIZE(PyHFC::PyHFC_memberlist); i++){
if (PyHFC::PyHFC_memberlist[i].name && _tcsicmp(name, PyHFC::PyHFC_memberlist[i].name) == 0)
return PyMember_Get((char *)self, PyHFC::PyHFC_memberlist, name);
}
// see if its the special members attribute
if (_tcscmp(name, _T("__members__"))==0)
return PyMember_Get((char *)self, PyHFC::PyHFC_memberlist, name);
// must be a method
return Py_FindMethod(PyHFC_methods, self, name);
}
int PyHFC::setattr(PyObject *self, char *name, PyObject *v)
{
if (v == NULL) {
PyErr_SetString(PyExc_AttributeError, "can't delete ECB attributes");
return -1;
}
PyErr_SetString(PyExc_AttributeError, "can't modify read only ECB attributes.");
return -1;
}
void PyHFC::deallocFunc(PyObject *ob)
{
delete (PyHFC *)ob;
}
// Setup an exception
PyObject * SetPyHFCError(char *fnName, long err /*= 0*/)
{
DWORD errorCode = err == 0 ? GetLastError() : err;
if (PyHFC_Error==NULL) {
PyObject *mod = PyImport_ImportModule("isapi");
if (mod)
PyHFC_Error = PyObject_GetAttrString(mod, "FilterError");
else
PyHFC_Error = PyExc_RuntimeError; // what's the alternative?
Py_XDECREF(mod);
}
PyObject *v = Py_BuildValue("(izs)", errorCode, NULL, fnName);
if (v != NULL) {
PyErr_SetObject(PyHFC_Error, v);
Py_DECREF(v);
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////
// PyURL_MAP object
/////////////////////////////////////////////////////////////////////////
// @object HTTP_FILTER_URL_MAP|A Python representation of an ISAPI
// HTTP_FILTER_URL_MAP structure.
PyTypeObject PyURL_MAPType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"HTTP_FILTER_URL_MAP",
sizeof(PyURL_MAP),
0,
PyURL_MAP::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyURL_MAP::getattr, /* tp_getattr */
PyURL_MAP::setattr, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyURL_MAP::PyURL_MAP(PyHFC *pParent)
{
ob_type = &PyURL_MAPType;
_Py_NewReference(this);
m_parent = pParent;
Py_INCREF(m_parent);
}
PyURL_MAP::~PyURL_MAP()
{
Py_XDECREF(m_parent);
}
HTTP_FILTER_URL_MAP *PyURL_MAP::GetURLMap()
{
HTTP_FILTER_CONTEXT *pFC;
void *vdata;
DWORD requestType;
m_parent->GetFilterContext()->GetFilterData(&pFC, &requestType, &vdata);
assert(requestType==SF_NOTIFY_URL_MAP);
return (HTTP_FILTER_URL_MAP *)vdata;
}
PyObject *PyURL_MAP::getattr(PyObject *self, char *name)
{
HTTP_FILTER_URL_MAP *pMap = ((PyURL_MAP *)self)->GetURLMap();
if (!pMap)
return NULL;
// @prop string|URL|
if (strcmp(name, "URL")==0) {
return PyString_FromString(pMap->pszURL);
}
// @prop string|PhysicalPath|
if (strcmp(name, "PhysicalPath")==0) {
return PyString_FromString(pMap->pszPhysicalPath);
}
PyErr_Format(PyExc_AttributeError, "PyURL_MAP objects have no attribute '%s'", name);
return NULL;
}
int PyURL_MAP::setattr(PyObject *self, char *name, PyObject *v)
{
HTTP_FILTER_URL_MAP *pMap = ((PyURL_MAP *)self)->GetURLMap();
if (!pMap)
return NULL;
if (strcmp(name, "PhysicalPath")==0) {
if (!PyString_Check(v)) {
PyErr_Format(PyExc_TypeError, "PhysicalPath must be a string");
return -1;
}
int cc = PyString_Size(v);
if ((DWORD)cc >= pMap->cbPathBuff) {
PyErr_Format(PyExc_ValueError, "The string is too long - got %d chars, but max is %d", cc, pMap->cbPathBuff-1);
return -1;
}
_tcscpy(pMap->pszPhysicalPath, PyString_AS_STRING(v));
return 0;
}
PyErr_SetString(PyExc_AttributeError, "can't modify read only PyURL_MAP attributes.");
return -1;
}
void PyURL_MAP::deallocFunc(PyObject *ob)
{
delete (PyURL_MAP *)ob;
}
/////////////////////////////////////////////////////////////////////////
// PyPREPROC_HEADERS object
/////////////////////////////////////////////////////////////////////////
// @pymethod string|HTTP_FILTER_PREPROC_HEADERS|GetHeader|
PyObject * PyPREPROC_HEADERS_GetHeader(PyObject *self, PyObject *args)
{
TCHAR buffer[8192];
DWORD bufSize = sizeof(buffer) / sizeof(TCHAR);
char *name;
// @pyparm string|header||
if (!PyArg_ParseTuple(args, "s:GetHeader", &name))
return NULL;
BOOL ok;
HTTP_FILTER_PREPROC_HEADERS *pp = ((PyPREPROC_HEADERS *)self)->GetPREPROC_HEADERS();
HTTP_FILTER_CONTEXT *pfc = ((PyPREPROC_HEADERS *)self)->GetFILTER_CONTEXT();
if (!pp || !pfc)
return NULL;
Py_BEGIN_ALLOW_THREADS
ok = pp->GetHeader(pfc, name, buffer, &bufSize);
Py_END_ALLOW_THREADS
if (!ok)
return SetPyHFCError("GetHeader");
return PyString_FromStringAndSize(buffer, bufSize-1);
}
// @pymethod |HTTP_FILTER_PREPROC_HEADERS|SetHeader|
PyObject * PyPREPROC_HEADERS_SetHeader(PyObject *self, PyObject *args)
{
BOOL ok;
char *name, *val;
HTTP_FILTER_PREPROC_HEADERS *pp = ((PyPREPROC_HEADERS *)self)->GetPREPROC_HEADERS();
HTTP_FILTER_CONTEXT *pfc = ((PyPREPROC_HEADERS *)self)->GetFILTER_CONTEXT();
if (!pp || !pfc)
return NULL;
// @pyparm string|name||
// @pyparm string|val||
if (!PyArg_ParseTuple(args, "ss:SetHeader", &name, &val))
return NULL;
Py_BEGIN_ALLOW_THREADS
ok = pp->SetHeader(pfc, name, val);
Py_END_ALLOW_THREADS
if (!ok)
return SetPyHFCError("SetHeader");
Py_INCREF(Py_None);
return Py_None;
}
// @pymethod |HTTP_FILTER_PREPROC_HEADERS|AddHeader|
PyObject * PyPREPROC_HEADERS_AddHeader(PyObject *self, PyObject *args)
{
BOOL ok;
char *name, *val;
HTTP_FILTER_PREPROC_HEADERS *pp = ((PyPREPROC_HEADERS *)self)->GetPREPROC_HEADERS();
HTTP_FILTER_CONTEXT *pfc = ((PyPREPROC_HEADERS *)self)->GetFILTER_CONTEXT();
if (!pp || !pfc)
return NULL;
if (!PyArg_ParseTuple(args, "ss:AddHeader", &name, &val))
return NULL;
Py_BEGIN_ALLOW_THREADS
ok = pp->AddHeader(pfc, name, val);
Py_END_ALLOW_THREADS
if (!ok)
return SetPyHFCError("AddHeader");
Py_INCREF(Py_None);
return Py_None;
}
// @object HTTP_FILTER_PREPROC_HEADERS|A Python representation of an ISAPI
// HTTP_FILTER_PREPROC_HEADERS structure.
static struct PyMethodDef PyPREPROC_HEADERS_methods[] = {
{"GetHeader", PyPREPROC_HEADERS_GetHeader, 1}, // @pymeth GetHeader|
{"SetHeader", PyPREPROC_HEADERS_SetHeader, 1}, // @pymeth SetHeader|
{"AddHeader", PyPREPROC_HEADERS_AddHeader, 1}, // @pymeth AddHeader|
{NULL}
};
PyTypeObject PyPREPROC_HEADERSType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"HTTP_FILTER_PREPROC_HEADERS",
sizeof(PyPREPROC_HEADERS),
0,
PyPREPROC_HEADERS::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyPREPROC_HEADERS::getattr, /* tp_getattr */
0, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyPREPROC_HEADERS::PyPREPROC_HEADERS(PyHFC *pParent)
{
ob_type = &PyPREPROC_HEADERSType;
_Py_NewReference(this);
m_parent = pParent;
Py_INCREF(m_parent);
}
PyPREPROC_HEADERS::~PyPREPROC_HEADERS()
{
Py_XDECREF(m_parent);
}
HTTP_FILTER_CONTEXT *PyPREPROC_HEADERS::GetFILTER_CONTEXT()
{
HTTP_FILTER_CONTEXT *pFC;
m_parent->GetFilterContext()->GetFilterData(&pFC, NULL, NULL);
return pFC;
}
HTTP_FILTER_PREPROC_HEADERS *PyPREPROC_HEADERS::GetPREPROC_HEADERS()
{
HTTP_FILTER_CONTEXT *pFC;
void *vdata;
DWORD requestType;
m_parent->GetFilterContext()->GetFilterData(&pFC, &requestType, &vdata);
assert(requestType==SF_NOTIFY_PREPROC_HEADERS);
return (HTTP_FILTER_PREPROC_HEADERS *)vdata;
}
PyObject *PyPREPROC_HEADERS::getattr(PyObject *self, char *name)
{
return Py_FindMethod(PyPREPROC_HEADERS_methods, self, name);
}
void PyPREPROC_HEADERS::deallocFunc(PyObject *ob)
{
delete (PyPREPROC_HEADERS *)ob;
}
--- NEW FILE: pyISAPI.h ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#ifndef __PYISAPI_H__
#define __PYISAPI_H__
// PYISAPI.H - Header file for your Internet Server
// Python ISAPI Extension
#include "PythonEng.h"
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer);
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB);
BOOL WINAPI TerminateExtension(DWORD dwFlags);
#endif // __PYISAPI_H__
--- NEW FILE: Utils.cpp ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#include "stdafx.h"
#include "Utils.h"
extern HINSTANCE g_hInstance;
// returns the pathname of this module
char *GetModulePath(void)
{
// directory values
TCHAR szFilePath[_MAX_PATH];
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
// find out where the exe lives
// NOTE: the long file name does not get returned (don't know why)
::GetModuleFileName(g_hInstance, szFilePath, sizeof(szFilePath));
::_splitpath( szFilePath, szDrive, szDir, NULL, NULL );
int dir_len = strlen(szDir);
if (dir_len && szDir[dir_len-1] == '\\')
szDir[dir_len-1] = '\0';
char *result = (char *)malloc(strlen(szDrive)+strlen(szDir)+1);
if (result) {
strcpy(result, szDrive);
strcat(result, szDir);
}
return result;
}
// Formats a system error code
char *FormatSysError(const DWORD nErrNo)
{
// This should never happen, so we can be a little brutal.
char *result = (char *)malloc(1024);
if (!result) return NULL;
int nLen =FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
nErrNo,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
result,
1024,
NULL);
if (nLen > 2) {
if ( result[nLen - 1] == '\n')
result[nLen - 1] = 0;
if (result[nLen - 2] == '\r')
result[nLen - 2] = 0;
}
return result;
}
// format an error
char *HTMLErrorResp(LPCTSTR msg)
{
const char *htmlBody = "<html><head><title>Python ISAPI Error</title></head>"
"<body><h2>An Error occured while processing your request</h2>"
"<font color=\"Red\"> %s </font></body></html>";
// should not need the "+1" as the "%s" will be consumed, but...
int newLen = strlen(htmlBody) + strlen(msg) + 1;
char *result = (char *)malloc(newLen);
if (result)
sprintf(result, htmlBody, msg);
return result;
}
--- NEW FILE: PyExtensionObjects.cpp ---
/*
======================================================================
Copyright 2002-2003 by Blackdog Software Pty Ltd.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
Blackdog Software not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
======================================================================
*/
#include "stdafx.h"
#include "Utils.h"
#include "PyExtensionObjects.h"
// @doc
// @object HSE_VERSION_INFO|An object used by ISAPI GetExtensionVersion
PyTypeObject PyVERSION_INFOType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"HSE_VERSION_INFO",
sizeof(PyVERSION_INFO),
0,
PyVERSION_INFO::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyVERSION_INFO::getattr, /* tp_getattr */
PyVERSION_INFO::setattr, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyVERSION_INFO::PyVERSION_INFO(HSE_VERSION_INFO *pvi)
{
ob_type = &PyVERSION_INFOType;
_Py_NewReference(this);
m_pvi = pvi;
}
PyVERSION_INFO::~PyVERSION_INFO()
{
}
PyObject *PyVERSION_INFO::getattr(PyObject *self, char *name)
{
PyVERSION_INFO *me = (PyVERSION_INFO *)self;
if (!me->m_pvi)
return PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists");
if (strcmp(name, "ExtensionDesc")==0) {
return PyString_FromString(me->m_pvi->lpszExtensionDesc);
}
return PyErr_Format(PyExc_AttributeError, "PyVERSION_INFO has no attribute '%s'", name);
}
int PyVERSION_INFO::setattr(PyObject *self, char *name, PyObject *v)
{
PyVERSION_INFO *me = (PyVERSION_INFO *)self;
if (!me->m_pvi) {
PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists");
return -1;
}
if (v == NULL) {
PyErr_SetString(PyExc_AttributeError, "can't delete VERSION_INFO attributes");
return -1;
}
// @prop string|ExtensionDesc|The description of the extension.
else if (strcmp(name, "ExtensionDesc")==0) {
if (!PyString_Check(v)) {
PyErr_Format(PyExc_ValueError, "FilterDesc must be a string (got %s)", v->ob_type->tp_name);
return -1;
}
if (PyString_Size(v) > HSE_MAX_EXT_DLL_NAME_LEN) {
PyErr_Format(PyExc_ValueError, "String is too long - max of %d chars", HSE_MAX_EXT_DLL_NAME_LEN);
return -1;
}
strcpy(me->m_pvi->lpszExtensionDesc, PyString_AsString(v));
} else {
PyErr_SetString(PyExc_AttributeError, "can't modify read only VERSION_INFO attributes.");
return -1;
}
return 0;
}
void PyVERSION_INFO::deallocFunc(PyObject *ob)
{
delete (PyVERSION_INFO *)ob;
}
/////////////////////////////////////////////////////////////////////
// Extension block wrapper
/////////////////////////////////////////////////////////////////////
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#define ECBOFF(e) offsetof(PyECB, e)
// @object EXTENSION_CONTROL_BLOCK|A python representation of an ISAPI
// EXTENSION_CONTROL_BLOCK.
struct memberlist PyECB::PyECB_memberlist[] = {
{"Version", T_INT, ECBOFF(m_version), READONLY},
{"ConnID", T_INT, ECBOFF(m_connID), READONLY},
{"Method", T_OBJECT, ECBOFF(m_method), READONLY},
{"QueryString", T_OBJECT, ECBOFF(m_queryString), READONLY},
{"PathInfo", T_OBJECT, ECBOFF(m_pathInfo), READONLY},
{"PathTranslated", T_OBJECT, ECBOFF(m_pathTranslated), READONLY},
{"TotalBytes", T_INT, ECBOFF(m_totalBytes), READONLY},
{"AvailableBytes", T_INT, ECBOFF(m_available), READONLY},
{"AvailableData", T_OBJECT, ECBOFF(m_data), READONLY},
{"ContentType", T_OBJECT, ECBOFF(m_contentType), READONLY},
{"HttpStatusCode", T_INT, ECBOFF(m_HttpStatusCode)},
{"LogData", T_OBJECT, ECBOFF(m_logData)},
{NULL}
};
static struct PyMethodDef PyECB_methods[] = {
{"write", PyECB::WriteClient, 1}, // @pymeth write|A synonym for WriteClient, this allows you to 'print >> ecb'
{"WriteClient", PyECB::WriteClient, 1}, // @pymeth WriteClient|
{"GetServerVariable", PyECB::GetServerVariable, 1}, // @pymeth GetServerVariable|
{"ReadClient", PyECB::ReadClient, 1}, // @pymeth ReadClient|
{"SendResponseHeaders", PyECB::SendResponseHeaders, 1}, // @pymeth SendResponseHeaders|
{"DoneWithSession", PyECB::DoneWithSession, 1}, // @pymeth DoneWithSession|
{"close", PyECB::DoneWithSession, 1}, // @pymeth close|A synonym for DoneWithSession.
{"IsSessionActive", PyECB::IsSessionActive,1}, // @pymeth IsSessionActive|Indicates if DoneWithSession has been called
{"Redirect", PyECB::Redirect,1}, // @pymeth Redirect|
{"IsKeepAlive", PyECB::IsKeepAlive,1}, // @pymeth IsKeepAlive|
{"GetImpersonationToken", PyECB::GetImpersonationToken, 1}, // @pymeth GetImpersonationToken|
{NULL}
};
PyTypeObject PyECBType =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"EXTENSION_CONTROL_BLOCK",
sizeof(PyECB),
0,
PyECB::deallocFunc, /* tp_dealloc */
0, /* tp_print */
PyECB::getattr, /* tp_getattr */
PyECB::setattr, /* tp_setattr */
0,
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0,
0, /* tp_call */
0, /* tp_str */
};
PyECB::PyECB(CControlBlock * pcb):
m_version(0), // @prop integer|Version|Version info of this spec (read-only)
m_connID(0), // @prop integer|ConnID|Context number (read-only)
m_method(NULL), // @prop string|Method|REQUEST_METHOD
m_queryString(NULL), // @prop string|QueryString|QUERY_STRING
m_pathInfo(NULL), // @prop string|PathInfo|PATH_INFO
m_pathTranslated(NULL), // @prop string|PathTranslated|PATH_TRANSLATED
m_totalBytes(0), // @prop int|TotalBytes|Total bytes indicated from client
m_available(0), // @prop int|AvailableBytes|Available number of bytes
m_data(NULL), // @prop string|AvailableData|Pointer to cbAvailable bytes
m_contentType(NULL), // @prop string|ContentType|Content type of client data
m_HttpStatusCode(0), // @prop int|HttpStatusCode|The status of the current transaction when the request is completed.
m_logData(NULL), // @prop string|LogData|log data string
m_bAsyncDone(false) // async done
{
ob_type = &PyECBType;
_Py_NewReference(this);
m_pcb = pcb;
EXTENSION_CONTROL_BLOCK * pecb = pcb->GetECB();
m_version = pecb->dwVersion;
m_connID = pecb->ConnID;
m_HttpStatusCode = pecb->dwHttpStatusCode;
m_logData = PyString_FromString("");
m_method = PyString_FromString(pecb->lpszMethod);
m_queryString = PyString_FromString(pecb->lpszQueryString);
m_pathInfo = PyString_FromString(pecb->lpszPathInfo);
m_pathTranslated = PyString_FromString(pecb->lpszPath...
[truncated message content] |