您的位置:首页 > 理论基础 > 计算机网络

Symbian编程总结-网络与通信-使用CEComFilter捕获系统HTTP请求

2009-04-23 10:43 681 查看
本文章由杨芹勍原创,如需转载请注明作者及出处,否则保留追究法律责任的权利!

一、前言

在IE浏览器中,如果想捕获浏览器的HTTP请求,可以通过BHO或者“异步可插协议”技术实现,类似于“迅雷”之类的下载软件,当用户点击一个下载链接会自动弹出。在Symbian OS中有一种技术与“异步可插协议”非常类似,Symbian OS会在HTTP请求中每一步处理过程都通知用户代码,本文将介绍这种技术的实现,并在文章的最后提供在手机上实现下载软件的具体思路。

二、核心ECOM接口类CEComFilter

从类名可以看出,CEComFilter是一个ECOM接口类(关于ECOM方面的编程总结,我会在后面的章节陆续放出),以下列出CEComFilter类的关键代码(SDK中文件cecomfilter.h内):

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

1

const

TUid KUidFilterPluginInterface

=

{

0x101F446D

};

2

class

CEComFilter :

public

CBase

3

{

4

public

:

5

static

CEComFilter

*

InstallFilterL(RHTTPSession aSession,

const

TUid aEComFilterUid)

6

{

7

TAny

*

filterPlugin

=

REComSession::CreateImplementationL(aEComFilterUid, _FOFF(CEComFilter,iEcomDtorID),

&

aSession);

8

return

REINTERPRET_CAST(CEComFilter

*

, filterPlugin);

9

}

10

11

static

CEComFilter

*

InstallFilterL(RHTTPSession aSession,

const

TDesC8

&

aEComFilterDataType)

12

{

13

TEComResolverParams resolverParams;

14

resolverParams.SetDataType(aEComFilterDataType);

15

16

//

This will leave if the plugin is not found

17

TAny

*

filterPlugin

=

REComSession::CreateImplementationL(KUidFilterPluginInterface,

18

_FOFF(CEComFilter,iEcomDtorID),

19

&

aSession, resolverParams);

20

return

REINTERPRET_CAST(CEComFilter

*

, filterPlugin);

21

}

22

23

~

CEComFilter()

24

{

25

REComSession::DestroyedImplementation(iEcomDtorID);

26

}

27

28

private

:

29

TUid iEcomDtorID;

30

};
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

通过代码我们可以分析出以下结论:

第1行,CEComFilter这个ECOM接口类的接口UID(interface_uid)为0x101F446D;

第5行、第11行,该接口提供了能够获得“ECOM实现(指实现了ECOM接口的类)”的两个工厂方法:InstallFilterL的两个重载函数。第一个函数将“ECOM实现”的“实现UID(implementation_uid)”传给默认ECOM决议者,第二个函数将提示参数传给默认ECOM决议者。
注意:两个工厂方法都会将RHTTPSession http会话的指针通过ECOM决议者创建“ECOM实现”时传入“ECOM实现”的构造函数。

系统创建了HTTP会话后,会遍历所有实现了CEComFilter接口的ECOM实现UID(implementation_uid),使用工 厂方法将ECOM实现实例化,同时传入HTTP会话(RHTTPSession);这样,我们的CEComFilter的实现就能够针对此HTTP会话进 行相关监控。

在此,系统只知道interface_uid,如何通过interface_uid知道有哪些implementation_uid的实现呢?很简单,使用如下函数即可获得:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

class

REComSession  :

public

RSessionBase
{
...
IMPORT_C

static

void

ListImplementationsL(TUid aInterfaceUid, RImplInfoPtrArray

&

aImplInfoArray);
...
}
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

具体流程如下(模拟实现):



三、如何实现CEComFilter接口

实现CEComFilter,其实就是实现一个普通的ECOM接口,步骤非常简单,在此不再说明具体步骤。重点在第5步:如何对传入的RHTTPSession进行监控。

SDK中关于RHTTPSession::FilterCollection()方法的解释:

Accessor for the filter collection. Note that the filter collection can't be edited after the first transaction has been created.

注意:如果已经在RHTTPSession上创建了RHTTPTransaction,则不能对Filter Collection进行修改。

此方法返回类型RHTTPFilterCollection,使用RHTTPFilterCollection::AddFilterL的重载函数向RHTTPSession的监视器队列中添加“监视器”,用于捕获HTTP请求信息:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

IMPORT_C

void

AddFilterL(MHTTPFilter

&

aFilter, THTTPEvent aEvent, RStringF aHeader, TInt aStatusCode, TInt aPosition, RStringF aName);
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

参数说明:

aFilter:类型为MHTTPFilter的引用,MHTTPFilter的定义为:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

1

class

MHTTPFilter

2

{

3

public

:

4

IMPORT_C

virtual

void

MHFUnload(RHTTPSession aSession, THTTPFilterHandle aHandle);

5

IMPORT_C

virtual

void

MHFLoad(RHTTPSession aSession, THTTPFilterHandle aHandle);

6

IMPORT_C

virtual

void

MHFRunL(RHTTPTransaction aTransaction,

const

THTTPEvent

&

aEvent);

7

IMPORT_C

virtual

void

MHFSessionRunL(

const

THTTPSessionEvent

&

aEvent);

8

IMPORT_C

virtual

TInt MHFRunError(TInt aError, RHTTPTransaction aTransaction,

const

THTTPEvent

&

aEvent);

9

IMPORT_C

virtual

TInt MHFSessionRunError(TInt aError,

const

THTTPSessionEvent

&

aEvent);

10

};
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

看到这里大家肯定会想起MHTTPTransactionCallback类,此类用在 RHTTPSession::OpenTransactionL中,为HTTP请求的回调,我们使用 RHTTPSession::OpenTransactionL打开一个连接后,往往会在MHFRunL方法中获取HTTP返回的字节、检查 StatusCode、检查HTTP头信息等。而MHTTPFilter也提供MHFRunL方法,我们可以再此方法中对系统任意一个HTTP请求进行捕 获,做相应的检查和处理;
另外,MHTTPFilter类中的方法都不是纯虚函数,我们的类中可以有选择的进行继承;

aEvent:监视器所监视的HTTP请求事件类型,可以监视所有时间或者只针对Transaction Event、Session Event进行监视,具体请参看SDK中“THTTPEvent”类的文档;

aHeaders:HTTP接收到指定的头将触发事件;

aStatusCode:HTTP接收到指定的状态码将触发事件;

aPosition:监视器所在“位置”,在RHTTPSession完成一个HTTP请求时,会分为几个步骤:处理协议、处理缓存、处理状态 码、处理UA等,aPosition所代表的“位置”指的就是把监视器插入哪个步骤中进行监视,具体数值及详细解释请参看 MHTTPFilter::TPositions枚举值的说明;

aName:自定义的监视器的名字。

根据以上分析,我们可以通过实现CEComFilter接口完成一个Demo:只要系统提交了HTTP进行Url的请求,就弹出一个全局消息框,显示HTTP所请求的Url地址。

四、实现CEComFilter接口

完整源代码请点击此处下载

1、实现接口的类名叫CFelixHttpFilter,定义如下:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

1

class

CFelixHttpFilter:

public

CEComFilter,

private

MHTTPFilter

2

{

3

public

:

4

~

CFelixHttpFilter();

5

static

CFelixHttpFilter

*

NewL(TAny

*

aHttpSession);

6

static

CFelixHttpFilter

*

NewLC(TAny

*

aHttpSession);

7

8

public

:

9

//

MHTTPFilter

10

void

MHFUnload(RHTTPSession aSession, THTTPFilterHandle aHandle);

11

void

MHFLoad(RHTTPSession aSession, THTTPFilterHandle aHandle);

12

void

MHFRunL(RHTTPTransaction aTransaction,

const

THTTPEvent

&

aEvent);

13

14

private

:

15

CFelixHttpFilter();

16

void

ConstructL(TAny

*

aHttpSession);

17

18

private

:

19

RStringF iFilterName;

20

};

21
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

2、关键类代码实现如下:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

1

_LIT8(KFilterName,

"

FelixFilter

"

);

2

3

CFelixHttpFilter::

~

CFelixHttpFilter()

4

{

5

iFilterName.Close();

6

}

7

8

CFelixHttpFilter

*

CFelixHttpFilter::NewLC(TAny

*

aHttpSession)

9

{

10

CFelixHttpFilter

*

self

=

new

(ELeave) CFelixHttpFilter();

11

CleanupStack::PushL(self);

12

self

->

ConstructL(aHttpSession);

13

return

self;

14

}

15

16

CFelixHttpFilter

*

CFelixHttpFilter::NewL(TAny

*

aHttpSession)

17

{

18

CFelixHttpFilter

*

self

=

CFelixHttpFilter::NewLC(aHttpSession);

19

CleanupStack::Pop();

//

self;

20

return

self;

21

}

22

23

void

CFelixHttpFilter::ConstructL(TAny

*

aHttpSession)

24

{

25

RHTTPSession

&

httpSession

=

*

(reinterpret_cast

<

RHTTPSession

*>

(aHttpSession));

26

27

iFilterName

=

httpSession.StringPool().OpenFStringL(KFilterName);

28

CleanupClosePushL(iFilterName);

29

30

httpSession.FilterCollection().AddFilterL(

*

this

, THTTPEvent::EAnyTransactionEvent, RStringF(), KAnyStatusCode, EClientFilters, iFilterName);

31

CleanupStack::Pop(

&

iFilterName);

32

}

33

34

void

CFelixHttpFilter::MHFUnload(RHTTPSession aSession, THTTPFilterHandle aHandle)

35

{

36

delete

this

;

37

}

38

39

void

CFelixHttpFilter::MHFRunL(RHTTPTransaction aTransaction,

const

THTTPEvent

&

aEvent)

40

{

41

if

(aEvent

==

THTTPEvent::ESubmit)

42

{

43

//

在此处拦截到请求的Url

44

const

TDesC8

&

url

=

aTransaction.Request().URI().UriDes();

45

TBuf

<

KMaxFileName

>

url16;

46

url16.Copy(url);

47

48

//

效果:将url打印到屏幕上

49

CEikonEnv::Static()

->

InfoWinL(url16, KNullDesC16);

50

}

51

}

52

53

const

TImplementationProxy kImplementationTable[]

=

54

{

55

IMPLEMENTATION_PROXY_ENTRY(

0xA00133E9

, CFelixHttpFilter::NewL)

56

};

57

58

EXPORT_C

const

TImplementationProxy

*

ImplementationGroupProxy(TInt

&

aTableCount)

59

{

60

aTableCount

=

sizeof

(kImplementationTable)

/

sizeof

(TImplementationProxy);

61

return

kImplementationTable;

62

}

63
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

注意,代码第55行中的0xA00133E9是我们ECOM实现的implementation_uid。

3、我们的程序UID3为0xA00133E8,ECOM资源文件名:A00133E8.rss,内容如下:

<

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ 
>

1

RESOURCE REGISTRY_INFO filterinfo

2

{

3

dll_uid

=

_UID3;

4

interfaces

=

5

{

6

INTERFACE_INFO

7

{

8

interface_uid

=

0x101F446D

;

9

implementations

=

10

{

11

IMPLEMENTATION_INFO

12

{

13

implementation_uid

=

0xA00133E9

;

14

version_no

=

1

;

15

display_name

=

"

Felix Filter

"

;

16

default_data

=

"

HTTP/+FELIXFILTER

"

;

17

opaque_data

=

""

;

18

}

19

};

20

}

21

};

22

}

23
< 本插件原作者为 Steve Dunn,汉化刘建成. http://www.tvwz.com.cn >

以上资源文件第16行,default_data的作用:

HTTP监视器能够“主动的”加载或者“被动的”加载,这取决于你资源文件中IMPLEMENTATION_INFO小节中的“default_data”字段(以上代码第16行)所设定的值,有如下三个加载选项被支持:

HTTP/+FELIXFILTER:监视器总是能自动加载

HTTP/-FELIXFILTER:监视器不会加载,用户只能手动的加载它

HTTP/FELIXFILTER:除非用户从监视器集合中移除,监视器都会加载

五、如何实现手机下载软件

基本概念都已经清楚,现在我们来想想如何实现手机上的迅雷。根据以下流程可以容易的做到:

按照以上步骤,实现CEComFilter接口,生成基于多态dll的plugin;

重写MHTTPFilter::MHFRunL方法;

因为要做下载软件不可能在MHFRunL方法中简单地通过判断Url来判断文件类型,必须通过判断服务器返回的MIME类型是否为所支持下载文件 类型的MIME,因此得判断aEvent是否为“服务器端Headers返回”的状态,来获取返回头的“Content-Type”字段;

判断MHFRunL方法中的aEvent是否为EGotResponseHeaders;

通过aTransaction.Response().GetHeaderCollection()获取字段“Content-Type”的值,通过“自定义字符串池(将在以后章节介绍)”的技术加快MIME的匹配对比;

如果服务器返回的MIME类型满足下载工具支持的类型,则弹出全局询问框,询问用户是否通过下载工具下载;

用户选择“是”,则将aTransaction.Cancel(),获取请求的Url,启动下载程序并将Url发送过去;

用户选择“否”,什么事都不做。

六、参考文献

how to get your filter loaded automatically

Writing an HTTP filter plugin

本文章由杨芹勍原创,如需转载请注明作者及出处,否则保留追究法律责任的权利!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐