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 Py...
[truncated message content] |