【libwww介绍】
官方网站:http://www.w3.org/Library/
更多信息:http://www.w3.org/Library/User/
运行平台:Unix/Linux,Windows
以下资料来源:http://zh.wikipedia.org/wiki/Libwww
简介:
Libwww 是一个高度模组化用户端的网页存取API ,用C语言写成,可在 Unix 和 Windows 上运行。 It can be used for both large and small applications including: browsers/editors, robots and batch tools. There are pluggable modules provided with Libwww which include complete HTTP/1.1 with caching, pipelining, POST, Digest Authentication, deflate, etc. The purpose of libwww is to serve as a testbed for protocol experiments. 蒂姆·伯纳斯-李 在 1992 年十一月创造出了 Libwww,用於展示网际网路的潜能。使用 Libwww 的应用程式,如被广泛使用的命令列文字浏览器 Lynx 及 Mosaic web browser 即是用 Libwww 所写成的。 Libwww 目前为一开放原始码程式,并於日前移至 W3C 管理。基於其为开放原始码的特性,任何人都能为 Libwww 付出一点心力,这也确保了 Libwww 能一直进步,成为更有用的软体。
以下文章来源:
http://bbs.nju.edu.cn/bbsanc?path=/groups/GROUP_3/CPlusPlus/D74D7D299/M.1090339010.A
w3c-libwww入门教程
丁建华 <jhding> 2004.7.20<br><br> 如果你 google 一下 libwww, 会发现三个不同的软件包: w3c-libwww,<br>perl-libwww, glibwww. 它们都是用来处理与 www 有关的各种协议的, 比如<br>http, ftp, news, gopher 等等. 其中 perl-libwww 是用于 perl 语言环境的,<br>glibwww 是 gnome 对 w3c-libwww 的一个简单的包装. w3c-libwww 是最古老的,<br>而且也可以说是最权威的, (假如存在所谓的权威的话 :)) 因为 w3c-libwww<br>的开发目标就是为 w3.org 发布的各种协议提供一个测试平台, 以评估各种<br>协议的可行性, 合理性, 兼容性, 可扩充性, 效率与安全等各方面的情况的.<br>因此其代码绝对值得一读. 但是初学者常常觉得这个函数库太庞杂, 抓任何一点<br>都会带出一大片, 找不到重点, 理不清头绪. 笔者希望本文能够对他们有所帮助. <br><br>===================================================================<br>??? w3c-libwww 是什么?<br>>>> Please visit <a href="http://www.w3.org/Library/" target="_blank">http://www.w3.org/Library/</a><br><br>===================================================================<br>??? 如何搭建一个 w3c-libwww 的调试平台?<br>>>> 最好在 Linux 系统上, 把软件包解压, 然后<br><cmd> ./configure --enable-shared=no --prefix=/home/me --with-ssl --with-zlib<br> --with-regex </cmd><br><cmd> make </cmd><br><cmd> make install </cmd><br>这样会建立 /home/me/bin, /home/me/lib, /home/me/include 等目录. 你需要把<br>/home/me/bin 加入你的搜索路径, 以便系统能够找到 libwww-config. 这个配置<br>程序可能需要手工修改, 好在它非常简单, 对任何想学习 w3c-libwww 的人来说,<br>改这个 sh 程序不成问题.<br><br>===================================================================<br>??? 如何编译一个程序呢?<br>>>> 假如你的程序是 prog.c, 你可以这样编译:<br><cmd> gcc -g -Wall -c -o prog.o `libwww-config --cflags` prog.c </cmd><br><cmd> gcc -g -o prog prog.o `libwww-config --libs` </cmd><br>这样编译出来的程序是包含调试信息的 static 连接, 你可以对 w3c-libwww 的<br>库函数源代码进行调试.<br><br>===================================================================<br>??? 我能在 Win32 上建立这样的环境吗?<br>>>> 如果你有足够的钱购买 M$ 的开发工具, 我建议你关掉电脑出去好好享受生活.<br>如果你只能安装免费的 Cygwin, 那么恐怕不能对 w3c-libwww 的源代码进行调试了.<br>不过你还是可以用 dll 来做开发: 先用与 Linux 同样的方法在 Cygwin 上装一遍,<br>尽管这样装出来的 static 库问题很多, 几乎无法使用, 但是我们还是得到了<br>必要的头文件. 然后我们到源代码的 Library/src/windows 目录下面, 用<br><cmd> dlltool -D wwwapp.dll -d wwwapp.def -l libwwwapp.dll.a </cmd><br>生成所有必要 dll 的 import 库, (有几个 export 符号重复, 发现后注释掉.)<br>复制到目标 lib 下就可以了. 当然还要修改 libwww-config, 把所有的 wwwapp <br>之类的名字都改成 wwwapp.dll 这样的, 也就是把 static 连接都改成 shared <br>连接. 就可以了.<br><br>===================================================================<br>??? 那些 wwwapp.dll 在哪里啊?<br>>>> 从 <a href="http://www.w3.org/" target="_blank">http://www.w3.org</a> 下载 w3c-libwww 的 Win32 发行包并安装. 然后把<br>其中的 dll 复制到你的某个搜索路径下面. 我就放在 gtk/2.0/bin 下面.<br><br>===================================================================<br>??? gtk+ 有一个 pkg-config 可以拿来用吗?<br>>>> 可以. 把下面这个文件放到 /lib/pkgconfig 下面就行了.<br><file><br>prefix=/usr/local<br>exec_prefix=${prefix}<br>libdir=${exec_prefix}/lib<br>includedir=${prefix}/include<br>target=win32<br><br>Name: w3c-libwww<br>Description: w3c libwww (${target} target)<br>Version: 5.4.0<br>Requires: <br>Libs: -L${libdir} -lwwwxml.dll -lxmltok.dll -lxmlparse.dll -lwwwzip.dll -lwww<br>init.dll -lwwwapp.dll -lwwwhtml.dll -lwwwtelnt.dll -lwwwnews.dll -lwwwhttp.dl<br>l -lwwwmime.dll -lwwwgophe.dll -lwwwftp.dll -lwwwfile.dll -lwwwdir.dll -lwwwc<br>ache.dll <br>-lwwwstream.dll -lwwwmux -lwwwtrans.dll -lwwwcore.dll -lwwwutils.dll -lmd5 -L<br>/usr/lib -lz -lssl -lcrypto<br>Cflags: -I${includedir} -I${includedir}/w3c-libwww<br></file><br>你可以用 <cmd> pkg-config --list-all </cmd> 试试, 看能否列出 w3c-libwww.<br>当然, 如果你的 prefix 不同, 你可以修改.<br><br>===================================================================<br>??? 为什么 gcc 顽固地提示某些符号无法解决呢?<br>>>> 修改 libwww-config 或者 w3c-libwww.pc , 把其中的库列表用<br>-Wl,--start-group 和 -Wl,--end-group 括起来.<br><br>===================================================================<br>??? Cygwin 下的 gtk+ 开发需要使用 -mms-bitfields -mno-cygwin 选项,<br>w3c-libwww 需要吗?<br>>>> 为保持良好的可移植性, w3c-libwww 没有使用位域, 因此与 -mms-bitfields <br>选项无关, 也不强制要求使用 -mno-cygwin 选项, 但是考虑到与 gtk+ 的集成问题,<br>笔者推荐使用 -mno-cygwin .<br><br>===================================================================<br>??? Linux 下 <cmd> libwww-config --cflags </cmd> 还包含一个 -DHAVE_CONFIG_H,<br>这是必要的吗? 在 Cygwin 下情况如何?<br>>>> 在 Linux 下是必要的. 在 Cygwin 下则是*不能*要的. 而且你必须从源代码的<br>Library/src/windows 目录下面复制一份儿 config.h 到安装目录的 <br>include/w3c-libwww/windows 下. 可能还需要注释掉下面这个配置项目:<br><code><br>/* Define if you have the <direct.h> header file. */<br>/*#define HAVE_DIRECT_H 1*/<br></direct.h></code><br>然后, 你*必须*使用 -D_CONSOLE 或者 -D_WINDOWS 中的一个. 原因请阅读<br>include/w3c-libwww/wwwsys.h . 你可能还需要注释掉这个文件中这行代码:<br><code><br>/* #define MKDIR(a,b) mkdir(a) */<br></code><br>你可能还需要从系统 include 目录下面复制一份儿 regex.h 到你的安装<br>include/w3c-libwww 目录下.<br><br>===================================================================<br>??? 如何知道我的程序使用了正确的 dll 呢?<br>>>> <cmd> cygcheck prog.exe </cmd><br><br>===================================================================<br>??? 听说 w3c-libwww 使用 C 语言实现了许多 OO 风格的编程, 是吗?<br>>>> <a href="http://www.w3.org/Library/User/Style/" target="_blank">http://www.w3.org/Library/User/Style/</a><br><br>===================================================================<br>??? w3c-libwww 的文档不提供打包下载, 我必须在线阅读吗?<br>>>><br><cmd> wget -x -r -nc -nH -p -np --cut-dirs=2 <a href="http://www.w3.org/Library/User" target="_blank">http://www.w3.org/Library/User</a> /cmd><br><br>===================================================================<br>??? 给个程序试一试, 看看开发调试环境是否已经配置好.<br>>>><br><file><br>/*<br>On Linux:<br>gcc -g -Wall -o libinit libinit.c `pkg-config --cflags --libs w3c-libwww`<br><br>On Cygwin:<br>gcc -c -g -Wall -mno-cygwin -D_CONSOLE -o libinit.o /<br> `pkg-config --cflags w3c-libwww` libinit.c<br>gcc -g -mno-cygwin -o libinit.exe libinit.o `pkg-config --libs w3c-libwww`<br>*/<br>#include <wwwlib.h><br><br>/* w3c-libwww 没有提供 Win32 下的缺省 Print 函数, 因此我们必须自己做 */<br>int printer(const char *fmt, va_list args)<br>{<br> return vfprintf(stdout, fmt, args);<br>}<br><br>int main(int argc, char *argv[])<br>{<br> /* Win32 下要使用 HTPrint() 就必须自己设置 callback */<br> HTPrint_setCallback(printer);<br> HTPrint("Hello w3c-libwww/n");<br><br> HTLibInit("TestApp", "0.0.1");<br> HTLibTerminate();<br> return 0;<br>}<br></wwwlib.h></file><br>另外, Win32 下 HTTRACE() 无效.<br><br>===================================================================<br>??? 开发调试环境配置好了. 一个典型的 w3c-libwww 应用是个什么样子?<br>>>> 实现某个协议, 按照这个协议发送请求, 或者响应请求.<br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int printer(const char *fmt, va_list args)<br>{<br> return vfprintf(stdout, fmt, args);<br>}<br><br>/* 实现某个协议的客户端代码, 通常要实现一个状态机 */<br>int my_client(SOCKET sock, HTRequest *req)<br>{<br> HTNet *net = HTRequest_net(req);<br><br> HTPrint("This's my_client/n");<br> HTNet_delete(net, HT_OK);<br> return HT_OK;<br>}<br><br>/* 实现某个协议的服务器端代码, 通常要实现一个状态机 */<br>int my_server(SOCKET sock, HTRequest *req)<br>{<br> HTNet *net = HTRequest_net(req);<br><br> HTPrint("This's my_server/n");<br> HTNet_delete(net, HT_OK);<br> return HT_OK;<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTRequest *req;<br><br> HTLibInit("ProtTest", "0.0.1");<br> HTPrint_setCallback(printer);<br><br> HTTransport_add("mytp", HT_TP_SINGLE, HTReader_new, HTWriter_new);<br> /* 注册我们的协议 */<br> HTProtocol_add("myprot", "mytp", 2008, NO, my_client, my_server);<br><br> req = HTRequest_new();<br><br> /* 发出一个按照我们协议的请求 */<br> HTLoadAbsolute("myprot://localhost", req);<br> HTPrint("/n");<br> /* 响应一个按照我们协议的请求 */<br> HTServeAbsolute("myprot://localhost", req);<br><br> HTRequest_delete(req);<br><br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 文档上说, 过滤器很重要. 过滤器是如何设置和被调用的?<br>>>><br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int printer(const char *fmt, va_list args)<br>{<br> return vfprintf(stdout, fmt, args);<br>}<br><br>int my_client(SOCKET sock, HTRequest *req)<br>{<br> HTNet *net = HTRequest_net(req);<br><br> HTPrint("This's my_client/n");<br> HTNet_delete(net, HT_OK); /* 造成后置过滤器被调用 */<br> return HT_OK;<br>}<br><br>int my_server(SOCKET sock, HTRequest *req)<br>{<br> HTNet *net = HTRequest_net(req);<br><br> HTPrint("This's my_server/n");<br> HTNet_delete(net, HT_OK); /* 造成后置过滤器被调用 */<br> return HT_OK;<br>}<br><br>int my_before(HTRequest *req, void *param, int mode)<br>{<br> HTPrint("This's my_before(%s)/n", (char *)param);<br> return HT_OK;<br>}<br><br>int my_after(HTRequest *req, HTResponse *resp, void *param, int status)<br>{<br> HTPrint("This's my_after(%s, %d)/n", (char *)param, status);<br> return HT_OK;<br>}<br><br>int my_req_before(HTRequest *req, void *param, int mode)<br>{<br> HTPrint("This's my_req_before(%s)/n", (char *)param);<br> return HT_OK;<br>}<br><br>int my_req_after(HTRequest *req, HTResponse *resp, void *param, int status)<br>{<br> HTPrint("This's my_req_after(%s, %d)/n", (char *)param, status);<br> return HT_OK;<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTRequest *req;<br><br> HTLibInit("ProtTest", "0.0.1");<br> HTPrint_setCallback(printer);<br><br> HTTransport_add("mytp", HT_TP_SINGLE, HTReader_new, HTWriter_new);<br> HTProtocol_add("myprot", "mytp", 2008, NO, my_client, my_server);<br> /* 注册全局前置过滤器和后置过滤器 */<br> HTNet_addBefore(my_before, NULL, "before-param", HT_FILTER_LAST);<br> HTNet_addAfter(my_after, NULL, "after-param", HT_ALL, HT_FILTER_LAST);<br><br> req = HTRequest_new();<br> /* 注册请求前置过滤器和后置过滤器 */<br> HTRequest_addBefore(req, my_req_before, NULL, "req_before_param",<br> HT_FILTER_LAST, NO);<br> HTRequest_addAfter(req, my_req_after, NULL, "req_after_param", HT_ALL,<br> HT_FILTER_LAST, NO);<br><br> HTLoadAbsolute("myprot://localhost", req);<br> HTPrint("/n");<br> HTServeAbsolute("myprot://localhost", req);<br><br> HTRequest_delete(req);<br><br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 任何具有 OO 风格的, 都必须处理事件. 请给个事件的例子好吗?<br>>>><br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int printer(const char *fmt, va_list args)<br>{<br> return vfprintf(stdout, fmt, args);<br>}<br><br>int my_timer(HTTimer *tmr, void *param, HTEventType type)<br>{<br> static int count = 0;<br><br> HTPrint("I'm my_timer(%s) %d/n", (char *)param, count++);<br> if (count >= 3)<br> HTEventList_stopLoop();<br> return HT_OK;<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTTimer *timer;<br><br> HTPrint_setCallback(printer);<br> HTLibInit("TestApp", "0.0.1");<br> HTEventInit();<br><br> timer = HTTimer_new(NULL, my_timer, "my-timer", 2000, YES, YES);<br> HTEventList_newLoop();<br> HTPrint("app stopped/n");<br><br> HTEventTerminate();<br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 输入输出无疑是非常重要的. 请给个输出流的例子好吗?<br>>>><br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br>#include <wwwstream.h><br><br>struct _HTStream {<br> HTStreamClass *isa;<br>};<br><br>static int printer(const char *fmt, va_list pArgs)<br>{<br> return vfprintf(stderr, fmt, pArgs);<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTStream *out;<br><br> HTPrint_setCallback(printer);<br> HTLibInit("Test", "0.0.1");<br><br> out = HTFWriter_new(NULL, stdout, YES);<br> HTPrint("I'm %s/n", out->isa->name);<br> (out->isa->put_string)(out, "Hello, stream/n");<br> (out->isa->flush)(out);<br> (out->isa->_free)(out);<br><br> HTLibTerminate();<br> return 0;<br>}<br></wwwstream.h></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 请给个输入流的例子.<br>>>><br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br>#include <wwwstream.h><br><br>struct _HTInputStream {<br> HTInputStreamClass *isa;<br>};<br><br>int main(int argc, char *argv[])<br>{<br> HTStream *out;<br> HTInputStream *in;<br> HTChannel *chnl;<br> HTNet *innet;<br> HTHost *host;<br> FILE *fp;<br><br> if (NULL == (fp = fopen(__FILE__, "rb")))<br> return (fprintf(stderr, "Can't open source file/n"), 1);<br> HTLibInit("Test", "0.0.1");<br><br> host = HTHost_new("localhost", 0);<br> innet = HTNet_new(host);<br> out = HTFWriter_new(NULL, stdout, YES);<br> HTNet_setReadStream(innet, out);<br> HTHost_addNet(host, innet);<br><br> chnl = HTChannel_new(INVSOC, fp, YES);<br><br> in = HTANSIReader_new(host, chnl, NULL, 0);<br> (in->isa->read)(in);<br> (in->isa->close)(in);<br><br> HTChannel_delete(chnl, HT_OK);<br><br> HTLibTerminate();<br> fclose(fp);<br> return 0;<br>}<br></wwwstream.h></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 我怎么没看到 write 啊? 读入的东西是怎么跑到输出上去的呢?<br>>>> w3c-libwww 认为, 没有无缘无故的读, 也没有无缘无故的写. 因此你必须<br>在读之前设置好输出, 然后在 (in->isa->read)(in) 的时候, 会找到你所设置<br>的输出, 并写到这个输出里面. 调用方只管事前设置就行了, 无需事中干预.<br>参见 Library/src/HTANSI.c!HTANSIReader_read .<br><br>===================================================================<br>??? 这些事前设置好像很乱啊.<br>>>> 那是为了循序渐进, 每次引入几个概念以便读者逐步认识. 如果不是自己<br>开发新协议, 而只是应用 w3c-ilbwww 的话, 可以简单一些.<br><file><br>/* CAUTION: For Cygwin Win32 ONLY !!! */<br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int terminate_handler(HTRequest * request, HTResponse * response,<br> void * param, int status)<br>{<br> return (HTEventList_stopLoop(), HT_OK);<br>}<br><br>int main(int argc, char *argv[])<br>{<br> char * url = NULL;<br> HTRequest * request = HTRequest_new();<br><br> HTLibInit("Simple load file", "0.0.1");<br> HTTransport_add("local", HT_TP_SINGLE, HTANSIReader_new, <br> HTANSIWriter_new);<br> HTProtocol_add("file", "local", 0, YES, HTLoadFile, NULL);<br> HTEventInit();<br> HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);<br><br> url = HTGetCurrentDirectoryURL();<br> HTSACat(&url, __FILE__);<br> if (HTLoadToFile/*!HTLoadFile*/(url, request, "CON") == YES)<br> HTEventList_loop(request);<br> HT_FREE(url);<br><br> HTRequest_delete(request);<br> HTEventTerminate();<br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br><br>===================================================================<br>??? 这回连 read 也看不到了.<br>>>> 参见 Library/src/HTFile.c!HTLoadFile 和 HTHost.c!HTHost_read .<br><br>===================================================================<br>??? 从 HTLoadToFile 到 HTLoadFile 又发生了什么呢?<br>>>> 按照下列顺序去读 Library/src 下的源代码:<br>HTAccess.c!HTLoadToFile(url, request, filename)<br>HTAccess.c!HTLoadAbsolute(url, request)<br>HTReqMan.c!HTLoad(request, recursive)<br>HTNet.c!HTNet_newClient(request)<br>HTProt.c!HTProtocol_find(request, access)<br>HTProt.c!HTProtocol_client(protocol) 就是 HTLoadFile 了. <br>最后的调用语句是这样的: (*(cbf))(INVSOC, request) .<br><br>===================================================================<br>??? HTNet_newServer(request) 和 HTNet_newClient(request) 主要干什么?<br>>>> 首先 HTNet_executeBeforeAll(request), 然后 create_object() 创建一个<br>空的 HTNet, 设置好 preemptive, protocol, transport, request, 同时也<br>HTRequest_setNet(request, me), 建立 request 和 net 的双向互指关系.<br>然后就 (*(cbf))(INVSOC, request), 调用服务(或客户)回调函数.<br><br>===================================================================<br>??? 为什么要做的这么麻烦啊?<br>>>> 比如小学生做应用题, 通常会列出一排算式, 都是具体数字, 每一步得一个<br>结果, 实实在在. 但这只是算术, 很初级的东西. 最明显的局限是"可移植性"<br>和"可重用性"太低. 高级一点的就是代数. 用常数和未知数取代具体数字,<br>在不知道其具体内容的情况下进行运算. 写程序也是这样. 初学者总是习惯于调用<br>具体的函数, 比如为 file:// 写一个 HTNet_newFileClient, 为 http:// 写一个<br>HTNet_newHttpClient, 或者把协议类型作为参数传进来, 然后用 switch 分别<br>调用 HTLoadFile, HTLoadHttp. 如果有一天要增加一个 newprot:// , 那么这些<br>代码就都要作相应改动. 这就相当于"算术"的水平. 高级一点的就使用函数指针.<br>不管这个函数的具体内容, HTNet_newClient 只管在适当的环境下以适当的方式<br>进行调用就行了. 就像对未知数进行"代数"运算一样. 这样的程序抽象层次更高, <br>适用性更广. 增改协议的时候, 不需要改动 HTNet_newClient. 类似的技术今天<br>已经应用得相当普遍. 比如 C++ 的抽象类, Java 和 Gtk+ 的 Interface 等等.<br><br>===================================================================<br>??? 我如何建立一个服务呢?<br>>>> 有一个 Library/Examples/listen.c 改写如下:<br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int global_after(HTRequest *req, HTResponse *resp, void *param, int status)<br>{<br> return (HTEventList_stopLoop(), HT_OK);<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTRequest *req = HTRequest_new();<br> HTStream *out;<br><br> HTLibInit("Simple Listener", "0.0.1");<br> HTEventInit();<br> HTNet_addAfter(global_after, NULL, NULL, HT_ALL, HT_FILTER_LAST);<br> HTTransport_add("tcp", HT_TP_SINGLE, HTReader_new, HTWriter_new);<br> /* 注意端口号是 2004 (任意), 服务回调函数是 HTLoadSocket */<br> HTProtocol_add("noop", "tcp", 2004, NO, NULL, HTLoadSocket);<br><br> HTRequest_setOutputFormat(req, WWW_RAW);<br> out = HTFWriter_new(req, stdout, YES);<br> HTRequest_setOutputStream(req, out);<br><br> HTServeAbsolute("noop://localhost", req);<br> HTEventList_newLoop();<br><br> HTRequest_delete(req);<br> HTEventTerminate();<br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br>执行 listen.exe , 然后从浏览器上访问 <a href="http://localhost:2004/" target="_blank">http://localhost:2004</a> , 就可以从<br>控制台看到浏览器发给服务器的请求的全部内容. 用 telnet://localhost:2004<br>连接, 则可以看到从 telnet 终端输入的内容都显示在控制台上.<br><br>===================================================================<br>??? 看起来关键是服务回调函数 HTLoadSocket , 它是干什么的?<br>>>> 参见 Library/src/HTSocket.c . 先做一个 HTHost_listen, 然后进入<br>SocketEvent, 若是 RAW_BEGIN, 则 HTHost_accept, 进入 RAW_NEED_STREAM.<br>如是 RAW_NEED_STREAM, 则把 request 的 outputStream 设置为 net 的<br>readStream , 并设置已连接, 进入 RAW_READ. 若是 RAW_READ, 则进行<br>HTHost_read.<br><br>===================================================================<br>??? 我能做一个 echo 吗?<br>>>> <br><file><br>#include <wwwlib.h><br>#include <wwwinit.h><br><br>int global_after(HTRequest *req, HTResponse *resp, void *param, int status)<br>{<br> HTEventList_stopLoop();<br> return HT_OK;<br>}<br><br>typedef enum _EchoState {<br> ECHO_ERROR = -2,<br> ECHO_OK = -1,<br> ECHO_BEGIN = 0,<br> ECHO_NEED_STREAM,<br> ECHO_READ<br>} EchoState;<br><br>typedef struct _echo_info {<br> EchoState state;<br> HTNet *net;<br> HTRequest *request;<br>} echo_info;<br><br>static int EchoCleanup(HTRequest *request, int status)<br>{<br> HTNet *net = HTRequest_net(request);<br> echo_info *echo = (echo_info *)HTNet_context(net);<br><br> if (status == HT_INTERRUPTED) {<br> (void)0;<br> } else if (status == HT_TIMEOUT) {<br> (void)0;<br> }<br> HTNet_delete(net, HT_ERROR);<br> HT_FREE(echo);<br> return YES;<br>}<br><br>static int EchoEvent(SOCKET soc, void *pVoid, HTEventType type);<br><br>int HTServEcho(SOCKET soc, HTRequest *request)<br>{<br> echo_info *echo;<br> HTNet *net = HTRequest_net(request);<br> char *url;<br><br> if (NULL == (echo = (echo_info *)HT_CALLOC(1, sizeof(echo_info))))<br> HT_OUTOFMEM("HTServEcho");<br> echo->state = ECHO_BEGIN;<br> echo->net = net;<br> echo->request = request;<br> HTNet_setContext(net, echo);<br> HTNet_setEventCallback(net, EchoEvent);<br> HTNet_setEventParam(net, echo);<br><br> url = HTAnchor_physical(HTRequest_anchor(request));<br> if (HTHost_listen(NULL, net, url) == HT_ERROR)<br> /* HTNet_execute(net, HTEvent_CLOSE) */<br> return EchoEvent(soc, echo, HTEvent_CLOSE);<br> /* HTNet_start(net) */<br> return EchoEvent(soc, echo, HTEvent_BEGIN);<br>}<br><br>static int EchoEvent(SOCKET soc, void *pVoid, HTEventType type)<br>{<br> echo_info *echo = (echo_info *)pVoid;<br> int status = HT_ERROR;<br> HTNet *net = echo->net;<br> HTRequest *request = echo->request;<br> HTHost *host = HTNet_host(net);<br><br> if (type == HTEvent_BEGIN) {<br> echo->state = ECHO_BEGIN;<br> } else if (type == HTEvent_CLOSE) {<br> EchoCleanup(request, HT_INTERRUPTED);<br> return HT_OK;<br> } else if (type == HTEvent_TIMEOUT) {<br> HTRequest_addError(request, ERR_FATAL, NO, HTERR_TIME_OUT,<br> NULL, 0, "HTServEcho");<br> EchoCleanup(request, HT_TIMEOUT);<br> return HT_OK;<br> } else if (type == HTEvent_END) {<br> EchoCleanup(request, HT_OK);<br> return HT_OK;<br> }<br><br> while (1) {<br> switch (echo->state) {<br> case ECHO_BEGIN:<br> status = HTHost_accept(host, net, NULL);<br> host = HTNet_host(net);<br> if (status == HT_OK) {<br> echo->state = ECHO_NEED_STREAM;<br> } else if (status == HT_WOULD_BLOCK<br> || status == HT_PENDING) {<br> return HT_OK;<br> } else {<br> echo->state = ECHO_ERROR;<br> }<br> break;<br> case ECHO_NEED_STREAM:<br> HTNet_setReadStream(net, <br> (HTStream *)HTNet_getOutput(net, NULL, 0));<br> HTRequest_setOutputConnected(request, YES);<br> echo->state = ECHO_READ;<br> break;<br> case ECHO_READ:<br> status = HTHost_read(host, net);<br> if (status == HT_WOULD_BLOCK)<br> return HT_OK;<br> else if (status == HT_CLOSED)<br> echo->state = ECHO_OK;<br> else<br> echo->state = ECHO_ERROR;<br> break;<br> case ECHO_OK:<br> EchoCleanup(request, HT_OK);<br> return HT_OK;<br> break;<br> case ECHO_ERROR:<br> EchoCleanup(request, HT_ERROR);<br> return HT_OK;<br> break;<br> default:<br> HTDEBUGBREAK("Bad echo state %d/n" _ echo->state);<br> }<br> }<br> return HT_OK;<br>}<br><br>int main(int argc, char *argv[])<br>{<br> HTRequest *req;<br><br> HTLibInit("Simply Echo", "0.0.1");<br> HTEventInit();<br> HTNet_addAfter(global_after, NULL, NULL, HT_ALL, HT_FILTER_LAST);<br> HTTransport_add("tcp", HT_TP_SINGLE, HTReader_new, HTWriter_new);<br> HTProtocol_add("noop", "tcp", 2004, NO, NULL, HTServEcho);<br><br> req = HTRequest_new();<br> HTRequest_setOutputFormat(req, WWW_RAW);<br><br> HTServeAbsolute("noop://localhost", req);<br> HTEventList_newLoop();<br><br> HTRequest_delete(req);<br> HTEventTerminate();<br> HTLibTerminate();<br> return 0;<br>}<br></wwwinit.h></wwwlib.h></file><br>这个程序在 Win32/Cygwin 上编译后, 运行. 用 telnet 连接本机端口 2004,<br>就可以看到 echo 的效果了. 但是在 linux 上编译后, 只能 echo 一下,<br>包括其本身的源码 Library/Example/listen.c 也是这样. 原因不详.<br><br>===================================================================<br>??? 事件究竟是在什么地方被执行的?<br>>>><br><code wmsg wparam lparam><br> if (uMsg == WM_TIMER) {<br> HTTimer_dispatch((HTTimer *)wParam);<br> return (0);<br> }<br> /* dispatch() means (*event->cbf)(s, event->param, type); */<br> if (HTEventList_dispatch((int)sock, type, now) != HT_OK)<br> HTEndLoop = -1;<br></code><br>另一方面:<br><code><br> /* Don't leave this loop until we leave the application */<br> while (!HTEndLoop) {<br> if (active_sockets == 0)<br> continue;<br><br> /* There were active sockets. Determine which fd sets they were in */<br> for (s = 0 ; s if (FD_ISSET(s, &texceptset))<br> if ((status = EventOrder_add(s, HTEvent_OOB, now)) != HT_OK)<br> goto stop_loop;<br> if (FD_ISSET(s, &twriteset))<br> if ((status = EventOrder_add(s, HTEvent_WRITE, now)) != HT_OK)<br> goto stop_loop;<br> if (FD_ISSET(s, &treadset))<br> if ((status = EventOrder_add(s, HTEvent_READ, now)) != HT_OK)<br> goto stop_loop;<br> }<br> /* execute() means (*event->cbf)(s, event->param, type); */<br> if ((status = EventOrder_executeAndDelete()) != HT_OK) break;<br> };<br></code><br><br>===================================================================<br>??? secho 只能接受一个连接, 我如何做一个真正的服务器呢?<br>>>> 从 4.0 版到 5.0 版, w3c-libwww 曾经有个短命的 MiniServer 子项目.<br>到 5.1 版就被放弃了. 由于现在的 5.4 版与 5.0 版在 API 上已经发生了巨大的<br>变化, 因此这个 MiniServer 的源代码已经没有什么参考价值了. w3c-libwww<br>可能是出于 "只做一件事情, 力图做到最好" 的考虑, 放弃了对服务器框架的支持.<br><br>===================================================================<br>??? 用 w3c-libwww 来开发客户端, 有哪些典型的应用呢?<br>>>> 你自己去看文档吧, 有很多好的例子. 我能说的就到此为止了.<br>本文附录有一些随手摘录的笔记, 既不正式, 也不完全, 聊作参考吧.<br><br>===================================================================<br>附: 本文档例子程序在 Win32/Cygwin 平台上的 Makefile, <br><file><br>all: libinit.exe req.exe filter.exe timer.exe out_strm.exe in_strm.exe /<br> sload.exe listen.exe secho.exe<br><br>.SUFFIXES:<br>.SUFFIXES: .exe .o .c<br><br>.o.exe:<br> gcc -g -mno-cygwin -o $@ $<br>.c.o:<br> gcc -c -g -Wall -mno-cygwin -D_CONSOLE -o $@ /<br> `pkg-config --cflags w3c-libwww` $<br>clean:<br> @rm -f *.exe *.o<br><br>.PHONY: all<br></file><br><br>===================================================================<br>??? WWWLib.h 包括哪些内容?<br>>>><br><code><br>#include "wwwsys.h"<br>#include "WWWUtil.h"<br>#include "WWWCore.h"<br></code><br><br>===================================================================<br>??? WWWUtil.h 包括哪些内容?<br>>>><br><code><br>#include "wwwsys.h"<br>#include "HTUtils.h"<br>#include "HTArray.h"<br>#include "HTAssoc.h"<br>#include "HTAtom.h"<br>#include "HTChunk.h"<br>#include "HTList.h"<br>#include "HTMemory.h"<br>#include "HTString.h"<br>#include "HTUU.h"<br></code><br><br>===================================================================<br>??? libwww 是如何处理 HTPrint 的?<br>>>> 用户可以设置自己的方式。对 Win32 平台,则是“必须”设置自己的方式。<br><code><br>typedef int HTPrintCallback(const char * fmt, va_list pArgs);<br><br>extern void HTPrint_setCallback(HTPrintCallback * pCall);<br>extern HTPrintCallback * HTPrint_getCallback(void);<br><br>extern int HTPrint(const char * fmt, ...);<br></code><br><br><code><br>PRIVATE HTPrintCallback * PHTPrintCallback = NULL;<br><br>PUBLIC void HTPrint_setCallback (HTPrintCallback * pCall)<br>{<br> PHTPrintCallback = pCall;<br>}<br><br>PUBLIC HTPrintCallback * HTPrint_getCallback (void)<br>{<br> return PHTPrintCallback;<br>}<br><br>PUBLIC int HTPrint (const char * fmt, ...)<br>{<br> va_list pArgs;<br> va_start(pArgs, fmt);<br> if (PHTPrintCallback)<br> return (*PHTPrintCallback)(fmt, pArgs);<br>#ifdef WWW_WIN_WINDOW<br> return (0); /* 对于 Win32 平台,必须由用户设置回调函数。*/<br>#else<br> return (vfprintf(stdout, fmt, pArgs));<br>#endif<br>}<br></code><br><br>===================================================================<br>??? libwww 是如何处理 HTTRACE 的?<br>>>> 注意 HTTRACE 与 HTPrint 有本质的不同。HTTRACE 是一个宏,可以被定义为<br>像 HTPrint 一样的函数 HTTrace,也可以被定义为根本什么也没有。而且 HTTRACE<br>在 Win32 平台上实际没有实现,虽然理论上并没有障碍。<br>在其他平台上,函数 HTTrace 的实现与 HTPrint 类似,只是增加了一个 <br>WWW_TraceFlag。以选择不同的 trace 范畴。<br><code><br>#ifdef HTDEBUG<br>#ifdef WWW_WIN_DLL<br>extern int * WWW_TraceFlag; /* In DLLs, we need the indirection*/<br>#define WWWTRACE (*WWW_TraceFlag) /* 但实际上,这个变量既没有被实例化*/<br> /* 也没有被 export,因此根本没用。*/<br>#else<br>extern unsigned int WWW_TraceFlag; /* Global flag for all W3 trace*/<br>#define WWWTRACE (WWW_TraceFlag) /* 在 HTTrace.c 中被实例化。*/<br>#endif /* WWW_WIN_DLL */<br>#else<br>#define WWWTRACE 0 /* 非调试版屏蔽一切 trace。*/<br>#endif /* HTDEBUG */<br><br>typedef enum _HTTraceFlags {<br> SHOW_UTIL_TRACE = 0x1,<br> SHOW_APP_TRACE = 0x2,<br> ....<br> SHOW_ALL_TRACE = (int) 0xFFFFFFFF<br>} HTTraceFlags;<br><br>#define UTIL_TRACE (WWWTRACE & SHOW_UTIL_TRACE)<br>#define APP_TRACE (WWWTRACE & SHOW_APP_TRACE)<br>....<br>#define ALL_TRACE (WWWTRACE & SHOW_ALL_TRACE)<br><br>typedef int HTTraceCallback(const char * fmt, va_list pArgs);<br>extern void HTTrace_setCallback(HTTraceCallback * pCall);<br>extern HTTraceCallback * HTTrace_getCallback(void);<br><br>#ifdef HTDEBUG<br>#undef _<br>#define _ ,<br>/* 这里的 TYPE 就是 APP_TRACE 之类,即 (WWWTRACE & SHOW_APP_TRACE) 之类。*/<br>#define HTTRACE(TYPE, FMT) /<br> do { if (TYPE) HTTrace(FMT); } while (0);<br>extern int HTTrace(const char * fmt, ...);<br>#else<br>#define HTTRACE(TYPE, FMT) /* empty */<br>#endif /* HTDEBUG */<br><br>typedef int HTTraceDataCallback(char * data, size_t len, char * fmt, <br> va_list pArgs);<br>extern void HTTraceData_setCallback(HTTraceDataCallback * pCall);<br>extern HTTraceDataCallback * HTTraceData_getCallback(void);<br><br>#ifdef HTDEBUG<br>#define HTTRACEDATA(DATA, LEN, FMT) HTTraceData((DATA), (LEN), FMT)<br>extern int HTTraceData(char * data, size_t len, char * fmt, ...);<br>#else<br>#define HTTRACEDATA(DATA, LEN, FMT) /* empty */<br>#endif /* HTDEBUG */<br></code><br><br><code><br>#if WWWTRACE_MODE == WWWTRACE_FILE<br>PUBLIC FILE *WWWTrace = NULL;<br>#endif<br><br>#ifndef WWW_WIN_DLL<br>PUBLIC unsigned int WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */<br>#endif<br><br>PRIVATE HTTraceCallback * PHTTraceCallback = NULL;<br>PRIVATE HTTraceDataCallback * PHTTraceDataCallback = NULL;<br><br>/* ---------------------------------------------------------------------- */<br><br>PUBLIC void HTTrace_setCallback (HTTraceCallback * pCall)<br>{<br> PHTTraceCallback = pCall;<br>}<br><br>PUBLIC HTTraceCallback * HTTrace_getCallback (void)<br>{<br> return PHTTraceCallback;<br>}<br><br>PUBLIC int HTTrace (const char * fmt, ...)<br>{<br> va_list pArgs;<br> va_start(pArgs, fmt);<br> if (PHTTraceCallback)<br> return (*PHTTraceCallback)(fmt, pArgs);<br>#ifdef WWW_WIN_WINDOW<br> return (0);<br>#else<br> return (vfprintf(stderr, fmt, pArgs));<br>#endif<br>}<br><br>PUBLIC void HTTraceData_setCallback (HTTraceDataCallback * pCall)<br>{<br> PHTTraceDataCallback = pCall;<br>}<br><br>PUBLIC HTTraceDataCallback * HTTraceData_getCallback (void)<br>{<br> return PHTTraceDataCallback;<br>}<br><br>PUBLIC int HTTraceData (char * data, size_t len, char * fmt, ...)<br>{<br> va_list pArgs;<br> va_start(pArgs, fmt);<br> if (PHTTraceDataCallback)<br> return (*PHTTraceDataCallback)(data, len, fmt, pArgs);<br> return (0); /* 必须由用户定义回调函数 */<br>}<br></code><br><br>===================================================================<br>??? libwww 是如何处理 HTArray 的?<br>>>> HTArray 是个存储 (void *) 的数组,可以自动扩展。<br><code impl="HTArray.c"><br>/* 这个结构也可以放在 HTArray.c 当中,做成 private。<br> 相应的几个宏改成函数。参见 HTChunk。<br>*/<br>typedef struct {<br> int size; /* In numbers of elements */<br> int growby; /* Allocation unit in elements */<br> int allocated; /* Current size of *data */<br> void ** data; /* Pointer to malloced area or 0 */<br>} HTArray;<br><br>extern HTArray * HTArray_new (int grow);<br>extern BOOL HTArray_delete (HTArray * array);<br>extern BOOL HTArray_clear (HTArray * array);<br>extern BOOL HTArray_addObject (HTArray * array, void * object);<br><br>/* 如果有数据,则返回该数据,并准备访问下一个数据 */<br>#define HTArray_firstObject(me, dp) /<br> ((me) && ((dp)=(me)->data) ? *(dp)++ : NULL)<br>#define HTArray_nextObject(me, dp) /<br> ((me) && (dp) ? *(dp)++ : NULL)<br><br>typedef int HTComparer (const void * a, const void * b);<br>extern BOOL HTArray_sort (HTArray * array, HTComparer * comp);<br>#define HTArray_data(me) ((me) ? (me)->data : NULL)<br>#define HTArray_size(me) ((me) ? (me)->size : -1)<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTList?<br>>>> HTList 是个单向链表,其数据域为 void * object。<br><code impl="HTList.c"><br>typedef struct _HTList HTList;<br><br>struct _HTList {<br> void * object;<br> HTList * next;<br>};<br><br>extern HTList * HTList_new (void);<br>extern BOOL HTList_delete (HTList *me);<br>extern BOOL HTList_addObject (HTList *me, void *newObject);<br>extern BOOL HTList_appendObject (HTList * me, void * newObject);<br>extern HTList * HTList_addList (HTList * me, void * newObject);<br>extern HTList * HTList_appendList (HTList * me, void * newObject);<br>extern BOOL HTList_removeObject (HTList * me, void * oldObject);<br>extern BOOL HTList_quickRemoveElement (HTList * me, HTList * last);<br>extern BOOL HTList_removeObjectAll (HTList * me, void * oldObject);<br>extern void * HTList_removeLastObject (HTList * me);<br>extern void * HTList_removeFirstObject (HTList * me);<br>/* NULL 和 me->next==NULL 都被视为空链表 */<br>#define HTList_isEmpty(me) (me ? me->next == NULL : YES)<br>extern int HTList_count (HTList *me);<br>extern int HTList_indexOf (HTList * me, void * object);<br>extern int HTList_indexOfElement (HTList * me, HTList * element);<br>extern void * HTList_objectAt (HTList * me, int position);<br>extern HTList * HTList_elementOf (HTList * me, void * object, HTList ** pLast);<br>#define HTList_objectOf(me) (me ? me->object: NULL)<br>#define HTList_lastObject(me) /<br> ((me) && (me)->next ? (me)->next->object : NULL)<br>extern void * HTList_firstObject (HTList * me);<br>#define HTList_nextObject(me) /<br> ((me) && ((me) = (me)->next) ? (me)->object : NULL)<br>extern BOOL HTList_insertionSort(HTList * list, HTComparer * comp);<br>#define HTList_free(x) HT_FREE(x)<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTAssocList ?<br>>>> HTAssocList 就是 HTList,只是其数据域为 HTAssoc。<br><code impl="HTAssoc.c"><br>typedef HTList HTAssocList;<br><br>typedef struct {<br> char * name;<br> char * value;<br>} HTAssoc;<br><br>extern HTAssocList * HTAssocList_new (void);<br>extern BOOL HTAssocList_delete (HTAssocList * alist);<br>extern BOOL HTAssocList_addObject (<br> HTAssocList * alist,<br> const char * name,<br> const char * value);<br>extern BOOL HTAssocList_replaceObject (<br> HTAssocList * list,<br> const char * name,<br> const char * value);<br>extern BOOL HTAssocList_removeObject (<br> HTAssocList * list,<br> const char * name);<br>extern char * HTAssocList_findObject (<br> HTAssocList * alist,<br> const char * name);<br>extern char * HTAssocList_findObjectExact (<br> HTAssocList * alist,<br> const char * name);<br>extern char * HTAssocList_findObjectCaseSensitive (<br> HTAssocList * list,<br> const char * name);<br>extern char * HTAssocList_findObjectCaseSensitiveExact (<br> HTAssocList * list,<br> const char * name);<br>#define HTAssoc_name(me) ((me) ? (me)->name : NULL)<br>#define HTAssoc_value(me) ((me) ? (me)->value : NULL)<br>#define HTAssocList_nextObject(me) /<br> ((me) && ((me) = (me)->next) ? (me)->object : NULL)<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTString?<br>>>> <br><code impl="HTString.c"><br>#define StrAllocCopy(dest, src) HTSACopy (&(dest), src)<br>#define StrAllocCat(dest, src) HTSACat (&(dest), src)<br>extern char * HTSACopy (char **dest, const char *src);<br>extern char * HTSACat (char **dest, const char *src);<br>extern char * StrAllocMCopy (char ** dest, ...);<br>extern char * StrAllocMCat (char ** dest, ...);<br>extern int strcasecomp (const char *a, const char *b);<br>extern int strncasecomp (const char *a, const char *b, int n);<br>extern int tailcomp(const char * s1, const char * s2);<br>extern int tailcasecomp(const char * s1, const char * s2);<br>extern char * HTStrMatch (const char * tmpl, const char * name);<br>extern char * HTStrCaseMatch (const char * tmpl, const char * name);<br>extern char * HTStrCaseStr (char * s1, char * s2);<br>extern char * HTStrip (char * s);<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTAtom?<br>>>> HTAtom 是个散列表,所谓的 atom 在这里就是单元的内存地址。<br><code impl="HTAtom.c"><br>typedef struct _HTAtom HTAtom;<br>struct _HTAtom {<br> HTAtom * next;<br> char * name;<br>}; /* struct _HTAtom */<br><br>extern HTAtom * HTAtom_for (const char * string);<br>extern HTAtom * HTAtom_caseFor (const char * string);<br>#define HTAtom_name(a) ((a) ? (a)->name : NULL)<br>extern HTList * HTAtom_templateMatches (const char * templ);<br>extern void HTAtom_deleteAll (void);<br></code><br><br><code><br>PRIVATE HTAtom * hash_table[HT_XL_HASH_SIZE];<br>PRIVATE BOOL initialised = NO;<br>/* 在 HTAtom_for 和 HTAtom_casefor 中, 先计算 hash,然后在<br>hash_table 中 strcmp,strcasecomp,若有就返回该单元的内存地址,<br>若没有就加入一个新单元,并返回其地址。<br>*/<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTChunk?<br>>>> <br><code impl="HTChunk.c"><br>typedef struct _HTChunk HTChunk;<br><br>extern HTChunk * HTChunk_new (int growby);<br>extern void HTChunk_delete (HTChunk * ch);<br>extern void HTChunk_clear (HTChunk * ch);<br>extern void HTChunk_ensure (HTChunk * ch, int extra_size);<br>extern void HTChunk_putc (HTChunk * ch, char c);<br>extern void HTChunk_puts (HTChunk * ch, const char *str);<br>extern void HTChunk_putb (HTChunk * ch, const char *block, int len);<br>extern char * HTChunk_data (HTChunk * ch);<br>extern int HTChunk_size (HTChunk * ch);<br>extern BOOL HTChunk_truncate (HTChunk * ch, int size);<br>extern BOOL HTChunk_setSize (HTChunk * ch, int size);<br>extern void HTChunk_terminate (HTChunk * ch);<br>extern HTChunk * HTChunk_fromCString (char * str, int grow);<br>extern char * HTChunk_toCString (HTChunk * ch);<br>extern HTChunk * HTChunk_fromBuffer (char * buf, int buflen, int size, int gr<br>ow);<br></code><br><br><code><br>struct _HTChunk {<br> int size; /* In bytes */<br> int growby; /* Allocation unit in bytes */<br> int allocated; /* Current size of *data */<br> char * data; /* Pointer to malloced area or 0 */<br>}; <br>/* Free a chunk but keep the data <br>*/<br>PUBLIC char * HTChunk_toCString (HTChunk * ch)<br>{<br> char * ret = 0;<br> if (ch) {<br> ret = ch->data;<br> HT_FREE(ch);<br> }<br> return ret;<br>}<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTMemory?<br>>>> <br><code impl="HTMemory.c"><br>extern void* HTMemory_malloc(size_t size);<br>extern void* HTMemory_calloc(size_t count, size_t size);<br>extern void* HTMemory_realloc(void * ptr, size_t size);<br>extern void HTMemory_free(void* ptr);<br><br>#define HT_MALLOC(size) HTMemory_malloc((size))<br>#define HT_CALLOC(count, size) HTMemory_calloc((count), (size))<br>#define HT_REALLOC(ptr, size) HTMemory_realloc((ptr), (size))<br>#define HT_FREE(pointer) {HTMemory_free((pointer));((pointer))=NULL;}<br><br>/* 可以注册多个内存清理函数,出现短缺就进行清理 */<br>typedef void HTMemoryCallback(size_t size);<br>extern BOOL HTMemoryCall_add (HTMemoryCallback * cbf);<br>extern BOOL HTMemoryCall_delete (HTMemoryCallback * cbf);<br>extern BOOL HTMemoryCall_deleteAll (void);<br><br>/* 可以设置一个内存不足无法继续时的必要清理函数,清理之后就 abort() */<br>typedef void HTMemory_exitCallback(char *name, char *file, unsigned long line);<br>extern void HTMemory_setExit(HTMemory_exitCallback * pExit);<br>extern HTMemory_exitCallback * HTMemory_exit(void);<br><br>#define outofmem(file, name) HT_OUTOFMEM(name)<br>#define HT_OUTOFMEM(name) HTMemory_outofmem((name), __FILE__, __LINE__)<br>extern void HTMemory_outofmem(char * name, char * file, unsigned long line);<br></code><br><br><code><br>PRIVATE HTList * HTMemCall = NULL; /* List of memory freers */<br>PRIVATE HTMemory_exitCallback * PExit = NULL; /* panic and exit function */<br>PRIVATE size_t LastAllocSize = 0; /* size of last allocation */ <br><br>PUBLIC void * HTMemory_malloc (size_t size)<br>{<br> void * ptr;<br> ptr = malloc(LastAllocSize = size);<br> if (ptr != NULL) return ptr;<br> /* 出现短缺 */<br> if (HTMemCall) {<br> HTMemoryCallback * pres;<br> while ((pres = (HTMemoryCallback *) HTList_nextObject(HTMemCall))) {<br> HTTRACE(MEM_TRACE, "Mem Calling. %p (size %d)/n" _ (void*)pres _ <br>size);<br> (*pres)(size); /* 清理 */<br> if ((ptr = malloc(size)) != NULL) return ptr; /* 重试 */<br> }<br> }<br> HTTRACE(MEM_TRACE, "Memory.... Couldn't allocate %d bytes/n" _ size);<br> return NULL;<br>}<br><br>PUBLIC void HTMemory_outofmem (char * name, char * file, unsigned long line)<br>{<br> if (PExit) /* 如果注册了必要清理函数,就进行必要清理 */<br> (*PExit)(name, file, line);<br> HTTRACE(ALL_TRACE, "%s:%ld failed allocation for /"%s/" (%ld bytes)./nPro<br>gram aborted./n" _<br> file _ line _ name _ LastAllocSize);<br> abort();<br>}<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTUU?<br>>>> <br><code impl="HTUU.c"><br>extern int HTUU_encode (unsigned char * bufin, unsigned int nbytes,<br> char * bufcoded);<br>extern int HTUU_decode (char * bufcoded, unsigned char * bufplain,<br> int outbufsize);<br></code><br><br>===================================================================<br>??? WWWCore.h 包括哪些内容?<br>>>><br><code><br>#include "wwwsys.h"<br>#include "HTLib.h"<br>#include "HTReq.h"<br>#include "HTMethod.h"<br>#include "HTAnchor.h"<br>#include "HTLink.h"<br>#include "HTParse.h"<br>#include "HTEscape.h"<br>#include "HTUTree.h"<br>#include "HTWWWStr.h"<br>#include "HTUser.h"<br>#include "HTEvent.h"<br>#include "HTMemLog.h"<br>#include "HTError.h"<br>#include "HTAlert.h"<br>#include "HTFormat.h"<br>#include "HTStream.h"<br>#include "HTStruct.h"<br>#include "HTNoFree.h"<br>#include "HTIOStream.h"<br>#include "HTDNS.h"<br>#include "HTHost.h"<br>#include "HTNet.h"<br>#include "HTInet.h"<br>#include "HTTrans.h"<br>#include "HTProt.h"<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTInet?<br>>>> 获取网络配置的一些函数,在 HTUserProfile 中有运用。<br><code impl="HTInet.c"><br>extern char * HTErrnoString (int errnum);<br>extern int HTInetStatus (int errnum, char * where);<br>extern unsigned int HTCardinal (int * pstatus,<br> char ** pp,<br> unsigned int max_value);<br>extern const char * HTInetString (struct sockaddr_in * sin);<br>extern int HTParseInet (HTHost * host, char * hostname, HTRequest * request);<br>extern time_t HTGetTimeZoneOffset (void);<br>extern ms_t HTGetTimeInMillis (void);<br>extern char * HTGetHostName (void);<br>extern char * HTGetMailAddress (void);<br>extern char * HTGetNewsServer (void);<br>extern char * HTGetTmpFileName (const char * dir);<br>#ifdef WWWLIB_SIG<br>extern void HTSetSignal (void);<br>#endif<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTUserProfile?<br>>>> <br><code impl="HTUser.c"><br>typedef struct _HTUserProfile HTUserProfile;<br><br>extern HTUserProfile * HTUserProfile_new (const char * name, void * context);<br>extern BOOL HTUserProfile_localize (HTUserProfile * up); /* 填缺省值 */<br>extern BOOL HTUserProfile_delete (HTUserProfile * up);<br></code><br><br><code><br>struct _HTUserProfile {<br> char * user; /* name, set in HTUserProfile_new(name, context) */<br> /* 但是这个字段实际上没有任何用处! */<br><br> char * fqdn; /* Fully qualified domain name */<br>extern char * HTUserProfile_fqdn (HTUserProfile * up);<br>extern BOOL HTUserProfile_setFqdn (HTUserProfile * up, const char * fqdn);<br><br> char * email; /* Email address of current user */<br>extern char * HTUserProfile_email (HTUserProfile * up);<br>extern BOOL HTUserProfile_setEmail (HTUserProfile * up, const char * email);<br><br> char * news; /* The news server to use */<br>extern char * HTUserProfile_news (HTUserProfile * host);<br>extern BOOL HTUserProfile_setNews (HTUserProfile * host, const char * news);<br><br> char * tmp; /* Location for temporary files */<br>extern char * HTUserProfile_tmp (HTUserProfile * host);<br>extern BOOL HTUserProfile_setTmp (HTUserProfile * host, const char * tmp);<br><br> time_t timezone; /* Time zone in seconds */<br>extern time_t HTUserProfile_timezone (HTUserProfile * up);<br>extern BOOL HTUserProfile_setTimezone (HTUserProfile * up, time_t timezone);<br><br> void * context; /* Application specific */<br>extern void * HTUserProfile_context (HTUserProfile * up);<br>extern BOOL HTUserProfile_setContext (HTUserProfile * up, void * context);<br>};<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTLib?<br>>>> 注意,实际上 HTLibInit 干的事儿很少,HTLibTerminate 倒是干的很多。<br><code impl="HTLib.c"><br>extern BOOL HTLibInit (const char * AppName, const char * AppVersion);<br>extern BOOL HTLibTerminate (void);<br></code><br><br><code><br>PRIVATE char * HTAppName = NULL; /* Application name: please supply */<br>extern const char * HTLib_appName (void);<br>extern BOOL HTLib_setAppName (const char * name);<br><br>PRIVATE char * HTAppVersion = NULL; /* Application version: please supply */<br>extern const char * HTLib_appVersion (void);<br>extern BOOL HTLib_setAppVersion (const char * version);<br><br>PRIVATE char * HTLibName = "libwww";<br>extern const char * HTLib_name (void);<br><br>PRIVATE char * HTLibVersion = W3C_VERSION;<br>extern const char * HTLib_version (void);<br><br>PRIVATE BOOL HTSecure = NO; /* Can we access local file system? */<br>extern BOOL HTLib_secure (void);<br>extern void HTLib_setSecure (BOOL mode);<br><br>PRIVATE BOOL initialized = NO;<br>extern BOOL HTLib_isInitialized (void);<br><br>PRIVATE HTUserProfile * UserProfile = NULL; /* Default user profile */<br>extern HTUserProfile * HTLib_userProfile (void);<br>extern BOOL HTLib_setUserProfile (HTUserProfile * up);<br><br>PUBLIC BOOL HTLibInit (const char * AppName, const char * AppVersion)<br>{<br> HTTRACE(CORE_TRACE, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE/n");<br><br> /* Set the application name and version */<br> HTLib_setAppName(AppName);<br> HTLib_setAppVersion(AppVersion);<br><br> /* Initialize the timezone */<br>#ifdef HAVE_TZSET<br> tzset();<br>#endif<br><br> /* Create a default user profile and initialize it */<br> UserProfile = HTUserProfile_new(HT_DEFAULT_USER, NULL);<br> HTUserProfile_localize(UserProfile);<br><br>#ifdef WWWLIB_SIG<br> /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting<br> ** to a port where we should get `connection refused'. We ignore this <br> ** using the following function call<br> */<br> HTSetSignal(); /* Set signals in library */<br>#endif<br><br> initialized = YES;<br> return YES;<br>}<br><br>PUBLIC BOOL HTLibTerminate (void)<br>{<br> HTTRACE(CORE_TRACE, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE/n");<br><br> /* 这八个单元是有全局结构的,应该对它们的初始化予以关注 */<br> HTNet_killAll();<br> HTHost_deleteAll(); /* Delete remaining hosts */<br> HTChannel_deleteAll(); /* Delete remaining channels */<br> HTAtom_deleteAll(); /* Remove the atoms */<br> HTDNS_deleteAll(); /* Remove the DNS host cache */<br> HTAnchor_deleteAll(NULL); /* Delete anchors and drop hyperdocs */<br> HTProtocol_deleteAll(); /* Remove bindings between access and protocols */<br> HTUTree_deleteAll(); /* Delete all URL Trees */<br><br> HT_FREE(HTAppName); /* Freed thanks to Wade Ogden <wade> */<br> HT_FREE(HTAppVersion);<br> HTUserProfile_delete(UserProfile); /* Free our default User profile */<br><br> initialized = NO;<br> return YES;<br>}<br></wade></code><br><br>===================================================================<br>??? libwww 如何处理 HTRequest?<br>>>> HTRequest 涉及三个文件,HTReq.h HTReqMan.h HTReqMan.c。<br><code impl="HTReqMan.c"><br>struct _HTRequest {<br> BOOL internal; /* Does the app knows about this one? */<br>extern BOOL HTRequest_setInternal (HTRequest * request, BOOL mode);<br>extern BOOL HTRequest_internal (HTRequest * request);<br><br> time_t date; /* Time stamp when the request was issued */<br>extern time_t HTRequest_date (HTRequest * request);<br>extern BOOL HTRequest_setDate (HTRequest * request, time_t date);<br><br> HTMethod method;<br>extern void HTRequest_setMethod (HTRequest *request, HTMethod method);<br>extern HTMethod HTRequest_method (HTRequest *request);<br><br> BOOL flush; /* Should we flush immediately */<br>extern BOOL HTRequest_setFlush (HTRequest * me, BOOL mode);<br>extern BOOL HTRequest_flush (HTRequest * me);<br><br> HTPriority priority; /* Priority for this request */<br>extern HTPriority HTRequest_priority (HTRequest * request);<br>extern BOOL HTRequest_setPriority (HTRequest * request, HTPriority priority);<br><br>#ifdef HT_EXT<br> char * messageBody;<br>extern BOOL HTRequest_setMessageBody (HTRequest * request, const char * body);<br>extern BOOL HTRequest_deleteMessageBody (HTRequest * request);<br>extern char * HTRequest_messageBody (HTRequest * request);<br><br> long int messageBodyLength;<br>extern BOOL HTRequest_setMessageBodyLength (HTRequest * request, long int len<br>gth);<br>extern long int HTRequest_messageBodyLength (HTRequest * request);<br><br> HTFormat messageBodyFormat;<br>extern BOOL HTRequest_setMessageBodyFormat (HTRequest * request, HTFormat for<br>mat);<br>extern HTFormat HTRequest_messageBodyFormat (HTRequest * request);<br>#endif<br> HTUserProfile * userprofile;<br>extern BOOL HTRequest_setUserProfile (HTRequest * request, HTUserProfile * up);<br>extern HTUserProfile * HTRequest_userProfile (HTRequest * request);<br><br> HTNet * net; /* Information about socket etc. */<br>extern HTNet * HTRequest_net (HTRequest * request);<br>extern BOOL HTRequest_setNet (HTRequest * request, HTNet * net);<br><br> HTResponse * response;<br>extern HTResponse * HTRequest_response (HTRequest * request);<br>extern BOOL HTRequest_setResponse (HTRequest * request, HTResponse * response);<br><br> HTList * error_stack; /* List of errors */<br>extern HTList * HTRequest_error (HTRequest * request);<br>extern void HTRequest_setError (HTRequest * request, HTList * list);<br>extern void HTRequest_deleteAllErrors (HTRequest * request);<br>extern BOOL HTRequest_addError (HTRequest * request,<br> HTSeverity severity,<br> BOOL ignore,<br> int element,<br> void * par,<br> unsigned int length,<br> char * where);<br>extern BOOL HTRequest_addSystemError (HTRequest * request,<br> HTSeverity severity,<br> int errornumber,<br> BOOL ignore,<br> char * syscall);<br><br> int retrys; /* Number of automatic reloads */<br>extern int HTRequest_retrys (HTRequest * request);<br>extern BOOL HTRequest_addRetry (HTRequest * request); /* increase by 1 */<br>extern BOOL HTRequest_doRetry (HTRequest *request); /* if needed */<br><br> int max_forwards;<br>extern BOOL HTRequest_setMaxForwards (HTRequest * request, int maxforwards);<br>extern int HTRequest_maxForwards (HTRequest * request);<br><br> int AAretrys; /* Number of authentication retries */<br>extern int HTRequest_AAretrys (HTRequest * request);<br>extern BOOL HTRequest_addAARetry (HTRequest * request);<br><br> BOOL preemptive;<br>extern void HTRequest_setPreemptive (HTRequest *request, BOOL mode);<br>extern BOOL HTRequest_preemptive (HTRequest *request);<br><br> BOOL ContentNegotiation;<br>extern void HTRequest_setNegotiation (HTRequest *request, BOOL mode);<br>extern BOOL HTRequest_negotiation (HTRequest *request);<br><br> HTPreconditions preconditions;<br>extern void HTRequest_setPreconditions (HTRequest * me, HTPreconditions mode);<br>extern HTPreconditions HTRequest_preconditions (HTRequest * me);<br><br> HTGnHd GenMask;<br>extern void HTRequest_setGnHd (HTRequest *request, HTGnHd gnhd);<br>extern void HTRequest_addGnHd (HTRequest *request, HTGnHd gnhd);<br>extern HTGnHd HTRequest_gnHd (HTRequest *request);<br><br> HTRsHd ResponseMask;<br>extern void HTRequest_setRsHd (HTRequest * request, HTRsHd rshd);<br>extern void HTRequest_addRsHd (HTRequest * request, HTRsHd rshd);<br>extern HTRsHd HTRequest_rsHd (HTRequest * request);<br><br> HTRqHd RequestMask;<br>extern void HTRequest_setRqHd (HTRequest *request, HTRqHd rqhd);<br>extern void HTRequest_addRqHd (HTRequest *request, HTRqHd rqhd);<br>extern HTRqHd HTRequest_rqHd (HTRequest *request);<br><br> HTEnHd EntityMask;<br>extern void HTRequest_setEnHd (HTRequest *request, HTEnHd enhd);<br>extern void HTRequest_addEnHd (HTRequest *request, HTEnHd enhd);<br>extern HTEnHd HTRequest_enHd (HTRequest *request);<br><br> HTMIMEParseSet * parseSet;<br> BOOL pars_local;<br>extern void HTRequest_setMIMEParseSet (HTRequest *request,<br> HTMIMEParseSet * parseSet, BOOL local);<br>extern HTMIMEParseSet * HTRequest_MIMEParseSet (HTRequest *request,<br> BOOL * pLocal);<br><br> HTList * conversions;<br> BOOL conv_local;<br>extern void HTRequest_setConversion (HTRequest *request, HTList *type, BOOL o<br>verride);<br>extern HTList * HTRequest_conversion (HTRequest *request);<br><br> HTList * encodings;<br> BOOL enc_local;<br>extern void HTRequest_setEncoding (HTRequest *request, HTList *enc, BOOL over<br>ride);<br>extern HTList * HTRequest_encoding (HTRequest *request);<br><br> HTList * tes;<br> BOOL te_local;<br>extern void HTRequest_setTransfer (HTRequest *request, HTList *te, BOOL overr<br>ide);<br>extern HTList * HTRequest_transfer (HTRequest *request);<br><br> HTList * languages;<br> BOOL lang_local;<br>extern void HTRequest_setLanguage (HTRequest *request, HTList *lang, BOOL ove<br>rride);<br>extern HTList * HTRequest_language (HTRequest *request);<br><br> HTList * charsets;<br> BOOL char_local;<br>extern void HTRequest_setCharset (HTRequest *request, HTList *charset, BOOL o<br>verride);<br>extern HTList * HTRequest_charset (HTRequest *request);<br><br> HTList * befores;<br> BOOL befores_local;<br>extern BOOL HTRequest_addBefore (HTRequest * request, HTNetBefore * filter,<br> const char * tmplate, void * param,<br> HTFilterOrder order, BOOL override);<br>extern HTList * HTRequest_before (HTRequest * request, BOOL * override);<br>extern BOOL HTRequest_deleteBefore (HTRequest * request, HTNetBefore * filter);<br>extern BOOL HTRequest_deleteBeforeAll (HTRequest * request);<br><br> HTList * afters;<br> BOOL afters_local;<br>extern BOOL HTRequest_addAfter (HTRequest * request, HTNetAfter * filter,<br> const char * tmplate, void * param,<br> int status, HTFilterOrder order,<br> BOOL override);<br>extern HTList * HTRequest_after (HTRequest * request, BOOL * override);<br>extern BOOL HTRequest_deleteAfter (HTRequest * request, HTNetAfter * filter);<br>extern BOOL HTRequest_deleteAfterStatus (HTRequest * request, int status);<br>extern BOOL HTRequest_deleteAfterAll (HTRequest * request);<br><br> char * proxy;<br>extern BOOL HTRequest_setProxy (HTRequest * request, const char * proxy);<br>extern char * HTRequest_proxy (HTRequest * request);<br>extern BOOL HTRequest_deleteProxy (HTRequest * request); /* free(me->proxy) */<br><br> BOOL full_uri;<br>extern void HTRequest_setFullURI (HTRequest *request, BOOL mode);<br>extern BOOL HTRequest_fullURI (HTRequest *request);<br><br> HTReload reload;<br>extern void HTRequest_setReloadMode (HTRequest *request, HTReload mode);<br>extern HTReload HTRequest_reloadMode (HTRequest *request);<br><br> HTAssocList * cache_control;<br>extern BOOL HTRequest_addCacheControl (HTRequest * request,<br> char * token, char *value);<br>extern BOOL HTRequest_deleteCacheControlAll (HTRequest * request);<br>extern HTAssocList * HTRequest_cacheControl (HTRequest * request);<br><br> char * default_put_name;<br>extern char * HTRequest_defaultPutName (HTRequest * me);<br>extern BOOL HTRequest_setDefaultPutName (HTRequest * me, char * name);<br>extern BOOL HTRequest_deleteDefaultPutName (HTRequest * me);<br><br> HTAssocList * byte_ranges;<br>extern BOOL HTRequest_addRange (HTRequest * request,<br> char * unit, char * range);<br>extern BOOL HTRequest_deleteRangeAll (HTRequest * request);<br>extern HTAssocList * HTRequest_range (HTRequest * request);<br><br> HTAssocList * connection;<br>extern BOOL HTRequest_addConnection (HTRequest * request,<br> char * token, char * value);<br>extern BOOL HTRequest_deleteConnection (HTRequest * request);<br>extern HTAssocList * HTRequest_connection (HTRequest * request);<br><br> HTAssocList * expect;<br>extern BOOL HTRequest_addExpect (HTRequest * me,<br> char * token, char * value);<br>extern BOOL HTRequest_deleteExpect (HTRequest * me);<br>extern HTAssocList * HTRequest_expect (HTRequest * me);<br><br> char * realm; /* Current realm */<br>extern BOOL HTRequest_setRealm (HTRequest * request, char * realm);<br>extern const char * HTRequest_realm (HTRequest * request);<br>extern BOOL HTRequest_deleteRealm (HTRequest * me);<br><br> HTAssocList * credentials; /* Credentials received by server */<br>extern BOOL HTRequest_addCredentials (HTRequest * request,<br> char * token, char * value);<br>extern BOOL HTRequest_deleteCredentialsAll (HTRequest * request);<br>extern HTAssocList * HTRequest_credentials (HTRequest * request);<br><br> HTAssocList * extra_headers;<br>extern BOOL HTRequest_addExtraHeader (HTRequest * request,<br> char * token, char * value);<br>extern HTAssocList * HTRequest_extraHeader (HTRequest * request);<br>extern BOOL HTRequest_deleteExtraHeaderAll (HTRequest * request);<br><br> HTList * generators;<br> BOOL gens_local;<br>extern void HTRequest_setGenerator (HTRequest *request, HTList *gens,<br> BOOL override);<br>extern HTList * HTRequest_generator (HTRequest *request, BOOL *override);<br><br> HTAssocList * mandatory; /* 有实现而无声明 */<br>PUBLIC BOOL HTRequest_addMandatory (HTRequest * me,<br> char * token, char * value)<br>PUBLIC HTAssocList * HTRequest_mandatory (HTRequest * me)<br>PUBLIC BOOL HTRequest_deleteMandatoryAll (HTRequest * me)<br><br> HTAssocList * optional; /* 有实现而无声明 */<br>PUBLIC BOOL HTRequest_addOptional (HTRequest * me,<br> char * token, char * value)<br>PUBLIC HTAssocList * HTRequest_optional (HTRequest * me)<br>PUBLIC BOOL HTRequest_deleteOptionalAll (HTRequest * me)<br><br> HTParentAnchor * anchor; /* The Client anchor for this request */<br> HTChildAnchor * childAnchor; /* For element within the object */<br>extern void HTRequest_setAnchor (HTRequest *request, HTAnchor *anchor);<br>extern HTParentAnchor * HTRequest_anchor (HTRequest *request);<br>extern HTChildAnchor * HTRequest_childAnchor (HTRequest * request);<br><br> HTParentAnchor * parentAnchor; /* For referer field */<br>extern void HTRequest_setParent (HTRequest *request, HTParentAnchor *parent);<br>extern HTParentAnchor * HTRequest_parent (HTRequest *request);<br><br> HTStream * output_stream; <br> HTStream * orig_output_stream; <br>extern void HTRequest_setOutputStream (HTRequest *request, HTStream *output);<br>extern HTStream *HTRequest_outputStream (HTRequest *request);<br><br> HTFormat output_format;<br>extern void HTRequest_setOutputFormat (HTRequest *request, HTFormat format);<br>extern HTFormat HTRequest_outputFormat (HTRequest *request);<br><br> BOOL connected;<br>extern void HTRequest_setOutputConnected (HTRequest * request, BOOL mode);<br>extern BOOL HTRequest_outputConnected (HTRequest * request);<br><br> HTStream * debug_stream;<br> HTStream * orig_debug_stream;<br>extern void HTRequest_setDebugStream (HTRequest *request, HTStream *debug);<br>extern HTStream *HTRequest_debugStream (HTRequest *request);<br><br> HTFormat debug_format;<br>extern void HTRequest_setDebugFormat (HTRequest *request, HTFormat format);<br>extern HTFormat HTRequest_debugFormat (HTRequest *request);<br><br> HTStream * input_stream; <br>extern void HTRequest_setInputStream (HTRequest * request, HTStream * input);<br>extern HTStream *HTRequest_inputStream (HTRequest * request);<br><br> HTFormat input_format;<br> HTPostCallback * PostCallback;<br>typedef int HTPostCallback (HTRequest * request, HTStream * target);<br>extern void HTRequest_setPostCallback (HTRequest * request, HTPostCallback * <br>cbf);<br>extern HTPostCallback * HTRequest_postCallback (HTRequest * request);<br><br> HTRequestCallback * callback;<br>typedef int HTRequestCallback (HTRequest * request, void *param);<br>extern void HTRequest_setCallback (HTRequest *request, HTRequestCallback *cb);<br>extern HTRequestCallback *HTRequest_callback (HTRequest *request);<br><br> void * context;<br>extern void HTRequest_setContext (HTRequest *request, void *context);<br>extern void *HTRequest_context (HTRequest *request);<br><br> HTRequest * source; /* Source for request or itself */<br>extern BOOL HTRequest_isPostWeb (HTRequest * request);<br>extern BOOL HTRequest_setSource (HTRequest * request, HTRequest * source);<br>extern HTRequest * HTRequest_source (HTRequest * request);<br><br> HTParentAnchor * source_anchor; /* Source anchor or itself */<br>extern BOOL HTRequest_setEntityAnchor (HTRequest * request, HTParentAnchor * <br>anchor);<br>extern HTParentAnchor * HTRequest_entityAnchor (HTRequest * request);<br><br> HTRequest * mainDestination; /* For the typical case */<br> HTList * destinations; /* List of related requests */<br> int destRequests; /* Number of destination requests */<br> int destStreams; /* Number of destination streams */<br>PUBLIC BOOL HTRequest_addDestination (HTRequest * src, HTRequest * dest)<br>PUBLIC BOOL HTRequest_removeDestination (HTRequest * dest)<br>PUBLIC BOOL HTRequest_destinationsReady (HTRequest * me)<br>PUBLIC BOOL HTRequest_linkDestination (HTRequest *dest)<br>PUBLIC BOOL HTRequest_unlinkDestination (HTRequest *dest)<br>PUBLIC BOOL HTRequest_removePostWeb (HTRequest *me)<br>PUBLIC BOOL HTRequest_killPostWeb (HTRequest *me)<br>};<br><br>extern BOOL HTRequest_addDestination (HTRequest * src, HTRequest * dest);<br>extern BOOL HTRequest_removeDestination (HTRequest * dest);<br>extern BOOL HTRequest_destinationsReady (HTRequest * me);<br><br>extern BOOL HTRequest_linkDestination (HTRequest * dest);<br>extern BOOL HTRequest_unlinkDestination (HTRequest * dest);<br><br>extern BOOL HTRequest_removePostWeb (HTRequest * me);<br>extern BOOL HTRequest_killPostWeb (HTRequest * me);<br><br>#define HTRequest_mainDestination(me) /<br> ((me) && (me)->source ? (me)->source->mainDestination : NULL)<br>#define HTRequest_isDestination(me) /<br> ((me) && (me)->source && (me) != (me)->source)<br>#define HTRequest_isMainDestination(me) /<br> ((me) && (me)->source && /<br> (me) == (me)->source->mainDestination)<br>#define HTRequest_isSource(me) /<br> ((me) && (me)->source && (me) == (me)->source)<br></code><br><br><code impl="HTReqMan.c"><br>typedef long HTRequestID;<br>typedef struct _HTRequest HTRequest;<br>extern HTRequest * HTRequest_new (void);<br>extern BOOL HTRequest_clear (HTRequest * me);<br>extern HTRequest * HTRequest_dup (HTRequest * src);<br>extern HTRequest * HTRequest_dupInternal (HTRequest * src);<br>extern void HTRequest_delete (HTRequest * request);<br><br>/* 调用 HTNet_newClient(req) / HTNet_newServer(req) */<br>extern BOOL HTLoad (HTRequest * request, BOOL recursive);<br>extern BOOL HTServe(HTRequest * request, BOOL recursive);<br><br>/* 调用 HTHost_forceFlush(host) */<br>extern int HTRequest_forceFlush (HTRequest * request);<br><br>/* 调用相应的 HTNet_* 函数 */<br>extern BOOL HTRequest_kill(HTRequest * request);<br>extern long HTRequest_bodyRead (HTRequest * request);<br>extern long HTRequest_bodyWritten (HTRequest * request);<br>extern long HTRequest_bytesRead (HTRequest * request);<br>extern long HTRequest_bytesWritten (HTRequest * request);<br></code><br><br><code><br>PRIVATE int HTMaxRetry = HT_MAX_RELOADS;<br>extern BOOL HTRequest_setMaxRetry (int newmax);<br>extern int HTRequest_maxRetry (void);<br><br>struct _HTStream {<br> HTStreamClass * isa;<br> /* ... */<br>};<br><br>PUBLIC BOOL HTLoad (HTRequest * me, BOOL recursive)<br>{<br> if (!me || !me->anchor) {<br> HTTRACE(CORE_TRACE, "Load Start.. Bad argument/n");<br> return NO;<br> }<br><br> /* Make sure that we don't carry over any old physical address */<br> if (!recursive) HTAnchor_clearPhysical(me->anchor);<br><br> /* Set the default method if not already done */<br> if (me->method == METHOD_INVALID) me->method = METHOD_GET;<br><br> /* Should we keep the error stack or not? */<br> if (!recursive && me->error_stack) {<br> HTError_deleteAll(me->error_stack);<br> me->error_stack = NULL;<br> }<br><br> /* Delete any old Response Object */<br> if (me->response) {<br> HTResponse_delete(me->response);<br> me->response = NULL;<br> }<br><br> /*<br> ** We set the start point of handling a request to here.<br> ** This time will be used by the cache<br> */<br> HTRequest_setDate(me, time(NULL));<br><br> /* Now start the Net Manager */<br> return HTNet_newClient(me);<br>}<br><br>PUBLIC BOOL HTServe (HTRequest * me, BOOL recursive)<br>{<br> if (!me || !me->anchor) {<br> HTTRACE(CORE_TRACE, "Serve Start. Bad argument/n");<br> return NO;<br> }<br><br> /* Make sure that we don't carry over any old physical address */<br> if (!recursive) HTAnchor_clearPhysical(me->anchor);<br><br> /* Should we keep the error stack or not? */<br> if (!recursive && me->error_stack) {<br> HTError_deleteAll(me->error_stack);<br> me->error_stack = NULL;<br> }<br><br> /* Delete any old Response Object */<br> if (me->response) {<br> HTResponse_delete(me->response);<br> me->response = NULL;<br> }<br><br> /* Now start the Net Manager */<br> return HTNet_newServer(me);<br>}<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTNet?<br>>>> 有三个文件:HTNetMan.h HTNet.h HTNet.c<br><code><br>struct _HTNet {<br> int hash; /* Hash value */<br><br> /* Link to other objects */<br> HTRequest * request; /* Link to request object */<br>extern BOOL HTNet_setRequest (HTNet * net, HTRequest * request);<br>extern HTRequest * HTNet_request (HTNet * net);<br><br> HTHost * host; /* What we know about the remote host */<br>extern BOOL HTNet_setHost (HTNet * net, HTHost * host);<br>extern HTHost * HTNet_host (HTNet * net);<br>extern BOOL HTNet_setSocket (HTNet * net, SOCKET sockfd);<br>extern SOCKET HTNet_socket (HTNet * net); /* net->host->channel's socket */<br>extern BOOL HTNet_persistent (HTNet * net); /* host's isPersistent */<br>extern BOOL HTNet_setPersistent (HTNet * net,<br> BOOL persistent,<br> HTTransportMode mode);<br>extern BOOL HTNet_setChannel (HTNet * net, HTChannel * channel);<br>extern HTChannel * HTNet_channel (HTNet * net);<br>extern BOOL HTNet_setDns (HTNet * net, HTdns * dns); /* host->dns */<br>extern HTdns * HTNet_dns (HTNet * net);<br><br> HTProtocol * protocol; /* Protocol to this request */<br>extern BOOL HTNet_setProtocol (HTNet * net, HTProtocol * protocol);<br>extern HTProtocol * HTNet_protocol (HTNet * net);<br><br> HTTransport * transport; /* Transport for this request */<br>extern BOOL HTNet_setTransport (HTNet * net, HTTransport * tp);<br>extern HTTransport * HTNet_transport (HTNet * net);<br><br> int session;<br><br> /* For progress notifications */<br> BOOL countRawBytes; /* If we should count raw bytes */<br>extern BOOL HTNet_setRawBytesCount (HTNet * net, BOOL mode);<br>extern BOOL HTNet_rawBytesCount (HTNet * net);<br><br> long bytesRead; /* Bytes in body */<br> long headerBytesRead; /* Bytes read in header */<br> long bytesWritten; /* Bytes written to network */<br> long headerBytesWritten; /* Bytes written in header */<br><br> time_t connecttime; /* Used on multihomed hosts */<br> BOOL preemptive; /* Eff result from Request and Protocol */<br>extern BOOL HTNet_preemptive (HTNet * net);<br><br> HTEvent event; /* NOTE: This is *NOT* a pointer */<br>extern HTEvent * HTNet_event (HTNet * net);<br>extern BOOL HTNet_setEventParam (HTNet * net, void * eventParam);<br>extern void * HTNet_eventParam (HTNet * net);<br>extern BOOL HTNet_setEventCallback(HTNet * net, HTEventCallback * cbf);<br>extern HTEventCallback * HTNet_eventCallback(HTNet * net);<br>extern HTPriority HTNet_priority (HTNet * net); /* event.priority */<br>extern BOOL HTNet_setPriority (HTNet * net, HTPriority priority);<br>extern BOOL HTNet_execute (HTNet * net, HTEventType type); <br> /* (*(net->event.cbf))(HTNet_socket(net), net->event.param, type); */<br>extern BOOL HTNet_start (HTNet * net);<br> /* (*(me->event.cbf))(HTNet_socket(me), me->event.param, HTEvent_BEGIN); */<br><br> HTStream * readStream; /* host's input stream puts data here */<br>extern HTStream * HTNet_readStream(HTNet * net);<br>extern BOOL HTNet_setReadStream (HTNet * net, HTStream * stream);<br><br> /* User specific stuff */<br> void * context; /* Protocol Specific context */<br>extern BOOL HTNet_setContext (HTNet * net, void * context);<br>extern void * HTNet_context (HTNet * net);<br><br> /* Eric's sleezoid cheat - should go to extra pipeline object */<br> HTEventType registeredFor;<br>};<br><br>extern SOCKET HTNet_socket(HTNet * me);<br><br>#define HTNet_setBytesRead(me,l) ((me) ? (me->bytesRead=(l)) : -1)<br>#define HTNet_bytesRead(me) ((me) ? (me)->bytesRead : -1)<br>#define HTNet_addBytesRead(me,l) ((me) ? (me->bytesRead+=(l)) : -1)<br><br>#define HTNet_setHeaderBytesRead(me,l) ((me) ? (me->headerBytesRead=(l)) :-1)<br>#define HTNet_headerBytesRead(me) ((me) ? (me)->headerBytesRead : -1)<br>#define HTNet_addHeaderBytesRead(me,l) ((me) ? (me->headerBytesRead+=(l)) <br><font color="#808080">: -1)<br></font><br>#define HTNet_setBytesWritten(me,l) ((me) ? (me->bytesWritten=(l)) :-1)<br>#define HTNet_bytesWritten(me) ((me) ? (me)->bytesWritten : -1)<br>#define HTNet_addBytesWritten(me,l) ((me) ? (me->bytesWritten+=(l)) : -1)<br><br>#define HTNet_setHeaderBytesWritten(me,l) ((me) ? (me->headerBytesWritten=(l)<br>) :-1)<br>#define HTNet_headerBytesWritten(me) ((me) ? /<br> ((me)->headerBytesWritten==0 ? /<br> HTNet_bytesWritten(me) : /<br> (me)->headerBytesWritten) : -1)<br>#define HTNet_addHeaderBytesWritten(me,l) ((me) ? (me->headerBytesWritten+=(l<br>)) : -1)<br><br>extern BOOL HTNet_setEventParam(HTNet * net, void * eventParam);<br>extern void* HTNet_eventParam(HTNet * net);<br>extern BOOL HTNet_setEventCallback(HTNet * net, HTEventCallback * cbf);<br>extern HTEventCallback * HTNet_eventCallback(HTNet * net);<br>extern BOOL HTNet_setEventPriority(HTNet * net, HTPriority priority);<br>extern HTPriority HTNet_eventPriority(HTNet * net);<br></code><br><br><code impl="HTNet.c"><br>typedef struct _HTNet HTNet;<br><br>typedef int HTNetBefore (HTRequest * request, void * param, int mode);<br>extern BOOL HTNetCall_addBefore (HTList * list, HTNetBefore * before,<br> const char * tmplate, void * param,<br> HTFilterOrder order);<br>extern BOOL HTNetCall_deleteBefore (HTList * list, HTNetBefore * before);<br>extern BOOL HTNetCall_deleteBeforeAll (HTList * list);<br>extern int HTNetCall_executeBefore (HTList * list, HTRequest * request);<br><br>typedef int HTNetAfter (HTRequest * request, HTResponse * response,<br> void * param, int status);<br>extern BOOL HTNetCall_addAfter (HTList * list, HTNetAfter * after,<br> const char * tmplate, void * param,<br> int status, HTFilterOrder order);<br>extern BOOL HTNetCall_deleteAfter (HTList * list, HTNetAfter * after);<br>extern BOOL HTNetCall_deleteAfterStatus (HTList * list, int status);<br>extern BOOL HTNetCall_deleteAfterAll (HTList * list);<br>extern int HTNetCall_executeAfter (HTList * list, HTRequest * request,<br> int status);<br><br>extern HTList *HTNet_activeQueue (void);<br>extern BOOL HTNet_idle (void);<br>extern BOOL HTNet_idle (void);<br><br><br>extern HTList *HTNet_pendingQueue (void);<br><br>extern BOOL HTNet_newClient (HTRequest * request);<br>extern BOOL HTNet_newServer (HTRequest * request);<br>extern HTNet * HTNet_new (HTHost * host);<br>extern HTNet * HTNet_dup (HTNet * src);<br>extern BOOL HTNet_deleteDup (HTNet * dup);<br><br>extern BOOL HTNet_delete (HTNet * me, int status);<br>extern BOOL HTNet_wait (HTNet *net);<br><br>extern BOOL HTNet_killPipe (HTNet * net);<br>extern BOOL HTNet_kill (HTNet * me);<br>extern BOOL HTNet_killAll (void);<br><br>extern HTOutputStream * HTNet_getOutput (HTNet * me, void * param, int mode);<br></code><br><br><code><br>typedef struct _BeforeFilter {<br> HTNetBefore * before; /* Filter function */<br> char * tmplate; /* URL template for when to call filter */<br> int order; /* Relative execution order */<br> void * param; /* Local context */<br>} BeforeFilter;<br><br>typedef struct _AfterFilter {<br> HTNetAfter * after; /* Filter function */<br> char * tmplate; /* URL template for when to call filter */<br> int order; /* Relative execution order */<br> void * param; /* Local context */<br> int status; /* Status of load for when to call filter */<br>} AfterFilter;<br><br>struct _HTStream {<br> const HTStreamClass * isa;<br> /* ... */<br>};<br><br>struct _HTInputStream {<br> const HTInputStreamClass * isa;<br> /* ... */<br>};<br><br>typedef struct _HTFilterEvent {<br> HTRequest * request;<br> int status;<br> HTTimer * timer;<br>} HTFilterEvent;<br><br>PRIVATE HTList * HTBefore = NULL; /* List of global BEFORE filters */<br>extern BOOL HTNet_setBefore (HTList * list);<br>extern HTList * HTNet_before (void);<br>extern BOOL HTNet_addBefore (HTNetBefore * before, const char * tmplate,<br> void * param, HTFilterOrder order);<br>extern BOOL HTNet_deleteBefore (HTNetBefore * before);<br>extern int HTNet_executeBeforeAll (HTRequest * request);<br><br>PRIVATE HTList * HTAfter = NULL; /* List of global AFTER filters */<br>extern BOOL HTNet_setAfter (HTList * list);<br>extern HTList * HTNet_after (void);<br>extern BOOL HTNet_addAfter (HTNetAfter * after, const char * tmplate,<br> void * param, int status,<br> HTFilterOrder order);<br>extern BOOL HTNet_deleteAfter (HTNetAfter * after);<br>extern BOOL HTNet_deleteAfterStatus (int status);<br>extern int HTNet_executeAfterAll (HTRequest * request, int status);<br><br>PRIVATE int MaxActive = HT_MAX_SOCKETS; /* Max active requests */<br>extern BOOL HTNet_setMaxSocket (int newmax);<br>extern int HTNet_maxSocket (void);<br><br>PRIVATE int Active = 0; /* Counts open sockets */<br>extern void HTNet_increaseSocket (void);<br>extern void HTNet_decreaseSocket (void);<br>extern int HTNet_availableSockets (void);<br><br>PRIVATE int Persistent = 0; /* Counts persistent sockets */<br>extern void HTNet_increasePersistentSocket (void);<br>extern void HTNet_decreasePersistentSocket (void);<br>extern int HTNet_availablePersistentSockets (void);<br><br>PRIVATE HTList ** NetTable = NULL; /* List of net objects */<br>extern BOOL HTNet_deleteAll (void);<br><br>PRIVATE int HTNetCount = 0; /* Counting elements in table */<br>extern BOOL HTNet_isIdle (void); /* HTNetCount > 0 */<br>extern BOOL HTNet_isEmpty (void); /* HTNetCount extern int HTNet_count (void);<br><br>/* get and call Protocol_server(INVSOC, request) */<br>PUBLIC BOOL HTNet_newServer (HTRequest * request)<br>{<br> HTParentAnchor * anchor = HTRequest_anchor(request);<br> HTNet * me = NULL;<br> HTProtocol * protocol;<br> HTTransport * tp = NULL; /* added JTD:5/28/96 */<br> char * physical = NULL;<br> int status;<br> HTProtCallback * cbf;<br><br> if (!request) return NO;<br><br> /*<br> ** First we do all the "BEFORE" callbacks in order to see if we are to<br> ** continue with this request or not. If we receive a callback status<br> ** that is NOT HT_OK then jump directly to the after callbacks and return<br> */<br> if ((status = HTNet_executeBeforeAll(request)) != HT_OK) {<br><br> /*<br> ** If in non-blocking mode then return here and call AFTER<br> ** filters from a timer event handler. As Olga Antropova<br> ** points out, otherwise, the stack can grow if new requests<br> ** are started directly from the after filters <br> */<br> if (HTEvent_isCallbacksRegistered() && !HTRequest_preemptive(request))<br> createAfterFilterEvent(request, status);<br> else<br> HTNet_executeAfterAll(request, status);<br> return YES;<br> }<br><br> /*<br> ** If no translation was provided by the filters then use the anchor<br> ** address directly<br> */<br> if (!(physical = HTAnchor_physical(anchor))) {<br> char * addr = HTAnchor_address((HTAnchor *) anchor);<br> HTTRACE(CORE_TRACE, "Net Object.. Using default address/n");<br> HTAnchor_setPhysical(anchor, addr);<br> physical = HTAnchor_physical(anchor);<br> HT_FREE(addr);<br> }<br><br> /* Find a protocol object for this access scheme */<br> {<br> char * access = HTParse(physical, "", PARSE_ACCESS); <br> if ((protocol = HTProtocol_find(request, access)) == NULL) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO PROTOCOL Object found for UR<br>I scheme `%s/'/n" _ access);<br> HT_FREE(access);<br> return NO;<br> }<br> if (!(cbf = HTProtocol_server(protocol))) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO SERVER HANDLER for URI schem<br>e `%s/'/n" _ access);<br> HT_FREE(access);<br> HT_FREE(me);<br> return NO;<br> }<br> HT_FREE(access);<br> }<br><br> /* Find a transport object for this protocol */<br> if ((tp = HTTransport_find(request, HTProtocol_transport(protocol))) == N<br>ULL) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO TRANSPORT found for protocol `%s<br>/'/n" _ HTProtocol_name(protocol));<br> return NO;<br> }<br><br> /* Create new net object and bind to request object */<br> if ((me = create_object()) == NULL) return NO;<br> me->preemptive = (HTProtocol_preemptive(protocol) || HTRequest_preemptive<br>(request));<br> HTNet_setEventPriority(me, HTRequest_priority(request));<br> me->protocol = protocol;<br> me->transport = tp; /* added - JTD:5/28/96 */<br> me->request = request;<br> HTRequest_setNet(request, me);<br><br> /* Start the server request */<br> HTTRACE(CORE_TRACE, "Net Object.. starting SERVER request %p and net obje<br>ct %p/n" _ request _ me);<br> (*(cbf))(INVSOC, request);<br> return YES;<br>}<br><br>/* HTNet_newClient<br>** ---------------<br>** Create a new HTNet object as a new request to be handled. If we have<br>** more than MaxActive connections already then put this into the<br>** pending queue, else start the request by calling the call back<br>** function registered with this access method. <br>** Returns YES if OK, else NO<br>*/<br>/* get and call Protocol_client(INVSOC, request) */<br>PUBLIC BOOL HTNet_newClient (HTRequest * request)<br>{<br> HTParentAnchor * anchor = HTRequest_anchor(request);<br> HTNet * me = NULL;<br> HTProtocol * protocol = NULL;<br> HTTransport * tp = NULL;<br> char * physical = NULL;<br> int status;<br> HTProtCallback * cbf;<br><br> if (!request) return NO;<br><br> /*<br> ** First we do all the "BEFORE" callbacks in order to see if we are to<br> ** continue with this request or not. If we receive a callback status<br> ** that is NOT HT_OK then jump directly to the after callbacks and return<br> */<br> if ((status = HTNet_executeBeforeAll(request)) != HT_OK) {<br><br> /*<br> ** If in non-blocking mode then return here and call AFTER<br> ** filters from a timer event handler. As Olga Antropova<br> ** points out, otherwise, the stack can grow if new requests<br> ** are started directly from the after filters <br> */<br> if (HTEvent_isCallbacksRegistered() && !HTRequest_preemptive(request))<br> createAfterFilterEvent(request, status);<br> else<br> HTNet_executeAfterAll(request, status);<br> return YES;<br> }<br><br> /*<br> ** If no translation was provided by the filters then use the anchor<br> ** address directly<br> */<br> if (!(physical = HTAnchor_physical(anchor))) {<br> char * addr = HTAnchor_address((HTAnchor *) anchor);<br> HTTRACE(CORE_TRACE, "Net Object.. Using default address/n");<br> HTAnchor_setPhysical(anchor, addr);<br> physical = HTAnchor_physical(anchor);<br> HT_FREE(addr);<br> }<br><br> /* Find a protocol object for this access scheme */<br> {<br> char * proxy = HTRequest_proxy(request);<br> char * access = HTParse(proxy ? proxy : physical, "", PARSE_ACCESS); <br><br> if ((protocol = HTProtocol_find(request, access)) == NULL) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO PROTOCOL Object found for UR<br>I scheme `%s/'/n" _ access);<br> HT_FREE(access);<br> return NO;<br> }<br> if (!(cbf = HTProtocol_client(protocol))) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO CLIENT HANDLER for URI schem<br>e `%s/'/n" _ access);<br> HT_FREE(access);<br> HT_FREE(me);<br> return NO;<br> }<br> HT_FREE(access);<br> }<br><br> /* Find a transport object for this protocol */<br> tp = HTTransport_find(request, HTProtocol_transport(protocol));<br> if (tp == NULL) {<br> HTTRACE(CORE_TRACE, "Net Object.. NO TRANSPORT found for protocol `%s<br>/'/n" _ HTProtocol_name(protocol));<br> return NO;<br> }<br><br> /* Create new net object and bind it to the request object */<br> if ((me = create_object()) == NULL) return NO;<br> me->preemptive = (HTProtocol_preemptive(protocol) || HTRequest_preemptive<br>(request));<br>#if 0<br> me->priority = HTRequest_priority(request);<br>#endif<br> HTNet_setEventPriority(me, HTRequest_priority(request));<br> me->protocol = protocol;<br> me->transport = tp;<br> me->request = request;<br> HTRequest_setNet(request, me);<br><br> /* Increase the number of retrys for this download */<br> HTRequest_addRetry(request);<br><br> /*<br> ** Check if we can start the request, else put it into pending queue<br> ** If so then call the call back function associated with the anchor.<br> ** We use the INVSOC as we don't have a valid socket yet!<br> */<br> HTTRACE(CORE_TRACE, "Net Object.. starting request %p (retry=%d) with net<br> object %p/n" _ <br> request _ HTRequest_retrys(request) _ me);<br> (*(cbf))(INVSOC, request);<br> return YES;<br>}<br><br>PUBLIC BOOL HTNet_clear (HTNet * net)<br>{<br> if (net) {<br> net->host->channel = NULL;<br> net->readStream = NULL;<br> net->bytesRead = 0;<br> net->headerBytesRead = 0;<br> net->bytesWritten = 0;<br> net->headerBytesWritten = 0;<br> return YES;<br> }<br> return NO;<br>}<br><br>/* Set (*Transport->output_new)(...) to Host's Channel and return it */<br>PUBLIC HTOutputStream * HTNet_getOutput (HTNet * me, void * param, int mode)<br>{<br> if (me && me->host && me->host->channel && me->transport) {<br> HTTransport * tp = me->transport;<br> HTChannel * ch = me->host->channel;<br> HTOutputStream * output = (*tp->output_new)(me->host, ch, param, mode);<br> HTChannel_setOutput(ch, output);<br> return output;<br> }<br> HTTRACE(CORE_TRACE, "Host Object.. Can't create output stream/n");<br> return NULL;<br>}<br></code><br><br>===================================================================<br>??? libwww 如何处理 HTProtocol?<br>>>> <br><code impl="HTProt.c"><br>typedef struct _HTProtocol HTProtocol;<br>typedef u_short HTProtocolId;<br><br>typedef int HTProtCallback (SOCKET, HTRequest *);<br>extern BOOL HTProtocol_add (const char * name,<br> const char * transport,<br> HTProtocolId port,<br> BOOL preemptive,<br> HTProtCallback * client,<br> HTProtCallback * server);<br>extern BOOL HTProtocol_delete (const char * name);<br>extern BOOL HTProtocol_deleteAll (void);<br>extern HTProtocol * HTProtocol_find (HTRequest * request, const char * access);<br></code><br><br><code><br>struct _HTProtocol {<br> char * name; /* Name of this protocol access scheme */<br>extern const char * HTProtocol_name (HTProtocol * protocol);<br><br> char * transport; /* Name of the transport */<br>extern BOOL HTProtocol_setTransport (HTProtocol * protoccol,<br> const char * transport);<br>extern const char * HTProtocol_transport (HTProtocol * protocol);<br><br> HTProtocolId id; /* Default port for this protocol */<br>extern HTProtocolId HTProtocol_id (HTProtocol * protocol);<br><br> BOOL preemptive;<br>extern BOOL HTProtocol_preemptive (HTProtocol * protocol);<br><br> HTProtCallback * client;<br>extern HTProtCallback * HTProtocol_client (HTProtocol * protocol);<br><br> HTProtCallback * server;<br>extern HTProtCallback * HTProtocol_server (HTProtocol * protocol);<br>};<br><br>PRIVATE HTList * protocols = NULL; /* List of registered protocols */<br></code><br><br><the-end></the-end><br></cmd></jhding>