65.9K
CodeProject 正在变化。 阅读更多。
Home

Apache 2.x 模块的 C++ 实现 (第二部分)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2012 年 11 月 12 日

CPOL

2分钟阅读

viewsIcon

15834

第二部分 - 进入 C++ 世界

引言

在上一篇文章 (第一部分) 中,我们专注于配置构建 Apache 自定义模块。 在本文中,我们将探讨添加我们的第一个 C++ 类,从而从 Apache C 的世界过渡到 C++ 领域。

我们的第一个类,CApplication

那么,让我们从上一篇文章中停止的地方开始。 以下是 foo_handler() 函数的代码,让我们回顾并仔细看看:

EXTERN_C_FUNC
int foo_handler( request_rec* inpRequest )
{
    int nReturnVal = DECLINED;
	
    if ( inpRequest->handler != NULL && strcmp( inpRequest->handler, "foo" ) == 0 )
    {
        ap_rputs( "Hello World from FOO", inpRequest );
        nReturnVal = OK;
    }

    return nReturnVal;
}

首先要注意的是,处理程序使用指向 Apache API 请求记录 request_rec* inpRequest 的指针被调用。 反过来,该指针用于获取一些数据(处理程序名称,“foo”)并在输出中使用(在 ap_rputs() 函数中)。 现在让我们引入我们的第一个类,CApplication。 在你的 Netbeans 项目中创建以下两个文件

  • 头文件 > Application > CApplication.hpp
  • 源文件 > Application > CApplication.cpp

现在,在这些文件中是以下代码

CApplication.hpp

#ifndef CAPPLICATION_HPP
#define	CAPPLICATION_HPP

#include "mod_foo.hpp"

class CApplication
{
private:

    request_rec*    m_pRequestRec;
	
public:
	
    CApplication( request_rec* inpRequestRec ) :
        m_pRequestRec( inpRequestRec )
    {}
	
    int RunHandler();
};

#endif	/* CAPPLICATION_HPP */

CApplication.cpp

#include "CApplication.hpp"

int
CApplication::RunHandler()
{
    int nReturnVal = DECLINED;
	
    if ( inpRequest->handler != NULL && strcmp( inpRequest->handler, "foo" ) == 0 )
    {
        ap_rputs( "Hello World from FOO", inpRequest );
        nReturnVal = OK;
    }

    return nReturnVal;
}

如你所见,核心功能已从 foo_handler() 移动到 CApplication::RunHandler()。 现在我们所要做的就是返回到 mod_foo.cpp 并将其更改为创建我们的应用程序的实例并调用其 CApplication::RunHandler() 方法(请注意,我添加了注释来描述每个部分的作用)

#include "mod_foo.hpp"
#include "CApplication.hpp"

/* Custom definition to hold any configuration data we may need.
   At this stage we just use it to keep a copy of the CApplication
   object pointer. Later we will add more when we need specific custom
   configuration information. */
EXTERN_C_BLOCK_BEGIN
typedef struct
{
    void* vpCApplication;
} 
FOOCONFIG_t;
EXTERN_C_BLOCK_END

/* Forward reference to our custom function to save the FOOCONFIG_t* 
   configuration pointer with Apache. */
EXTERN_C_FUNC 
void foo_register_config_ptr( request_rec* inpRequest, FOOCONFIG_t* inpFooConfig );

/* Forward reference to our custom function to get the FOOCONFIG_t* 
   configuration pointer when we need it. */
EXTERN_C_FUNC 
FOOCONFIG_t* foo_get_config_ptr( request_rec* inpRequest );

/* Custom function to ensure our CApplication get's deleted at the
   end of the request cycle. */
EXTERN_C_FUNC
apr_status_t foo_delete_capplication_object( void* inPtr )
{
    if ( inPtr )
        delete ( CApplication* )inPtr;
	
    return OK;
}

/* Our custom handler (content generator) 
   */
EXTERN_C_FUNC
int foo_handler( request_rec* inpRequest )
{
    /* Create an instance of our application. */
    CApplication* pApp = new CApplication( inpRequest );
	
    if ( pApp == NULL )
	    return HTTP_SERVICE_UNAVAILABLE;
		    
    /* Register a C function to delete pApp
       at the end of the request cycle. */
    apr_pool_cleanup_register( 
        inpRequest->pool, 
        ( void* )pApp, 
        foo_delete_capplication_object, 
        apr_pool_cleanup_null 
    );
		
    /* Reserve a temporary memory block from the
       request pool to store data between hooks. */
    FOOCONFIG_t* pFooConfig = 
        ( FOOCONFIG_t* ) apr_palloc( 
            inpRequest->pool, sizeof( FOOCONFIG_t ) );
		
    /* Remember our application pointer for future calls. */
    pFooConfig->vpCApplication = ( void* )pApp;
		
    /* Register our config data structure for our module. */
    foo_register_config_ptr( inpRequest, pFooConfig );
		
    /* Run our application handler. */
    return pApp->RunHandler();
}

/* Apache callback to register our hooks.
   */
EXTERN_C_FUNC
void foo_hooks( apr_pool_t* inpPool )
{
    ap_hook_handler( foo_handler, NULL, NULL, APR_HOOK_MIDDLE );
}

/* Our standard module definition.
   */
EXTERN_C_BLOCK_BEGIN
module AP_MODULE_DECLARE_DATA foo_module =
{
    STANDARD20_MODULE_STUFF,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    foo_hooks
};
EXTERN_C_BLOCK_END

/* Custom function to register our FOOCONFIG_t* pointer with Apache
   for retrieval later as required. */
EXTERN_C_FUNC
void foo_register_capplication_ptr( request_rec* inpRequest, FOOCONFIG_t* inpPtr )
{
    ap_set_module_config( inpRequest->request_config, &foo_module, ( void* )inpPtr );
}

/* Custom function to retrieve our FOOCONFIG_t* pointer previously
   registered with Apache on this request cycle. */
EXTERN_C_FUNC
FOOCONFIG_t* foo_get_capplication_ptr( request_rec* inpRequest )
{
    FOOCONFIG_t* pReturnValue = NULL;
	
    if ( inpRequest != NULL )
    {
        pReturnValue = 
            ( FOOCONFIG_t* )ap_get_module_config( 
                inpRequest->request_config, &foo_module );
    }
	
    return pReturnValue;
}

如你所见,我们现在已经从 C 函数 foo_handler() 过渡到 C++ CApplication::RunHandler(),并且我们已经进入了 C++ 的世界。 在处理程序中,我们创建了应用程序的新实例。 为了确保我们的应用程序不会泄漏内存,一个 C 清理函数已注册到 request_rec->pool 的垃圾回收系统,该系统负责在请求周期结束时对我们的应用程序指针 pApp 调用 delete。

最后,我们从 request_rec->pool 预留了一小段内存来保存指向我们的应用程序配置数据结构的指针,然后将其注册到 Apache API。 虽然在本篇文章的这个阶段未使用,但这允许我们在处理程序完成后但在 request_rec->pool 被销毁之前,在其他 Apache 钩子中恢复指向我们的应用程序 pApp 的指针。 在后面的文章中,我们将看到这个恢复的指针对于处理在处理程序函数完成并返回后运行的 Apache 输出过滤器钩子非常有用。

结论

我们已经看到,从 Apache C 处理程序到 C++ 对象的控制转移非常简单。 在下一篇文章中,我们将研究将 Apache API 抽象成更明确的面向对象的一组对象的基础。

© . All rights reserved.