转 w3c-libwww入门教程

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

 

【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@tom.com> 2004.7.20

    如果你 google 一下 libwww, 会发现三个不同的软件包: w3c-libwww,
perl-libwww, glibwww. 它们都是用来处理与 www 有关的各种协议的, 比如
http, ftp, news, gopher 等等. 其中 perl-libwww 是用于 perl 语言环境的,
glibwww 是 gnome 对 w3c-libwww 的一个简单的包装. w3c-libwww 是最古老的,
而且也可以说是最权威的, (假如存在所谓的权威的话 :)) 因为 w3c-libwww
的开发目标就是为 w3.org 发布的各种协议提供一个测试平台, 以评估各种
协议的可行性, 合理性, 兼容性, 可扩充性, 效率与安全等各方面的情况的.
因此其代码绝对值得一读. 但是初学者常常觉得这个函数库太庞杂, 抓任何一点
都会带出一大片, 找不到重点, 理不清头绪. 笔者希望本文能够对他们有所帮助.

===================================================================
??? w3c-libwww 是什么?
>>> Please visit http://www.w3.org/Library/

===================================================================
??? 如何搭建一个 w3c-libwww 的调试平台?
>>> 最好在 Linux 系统上, 把软件包解压, 然后
<cmd> ./configure --enable-shared=no --prefix=/home/me --with-ssl --with-zlib
--with-regex </cmd>
<cmd> make </cmd>
<cmd> make install </cmd>
这样会建立 /home/me/bin, /home/me/lib, /home/me/include 等目录. 你需要把
/home/me/bin 加入你的搜索路径, 以便系统能够找到 libwww-config. 这个配置
程序可能需要手工修改, 好在它非常简单, 对任何想学习 w3c-libwww 的人来说,
改这个 sh 程序不成问题.

===================================================================
??? 如何编译一个程序呢?
>>> 假如你的程序是 prog.c, 你可以这样编译:
<cmd> gcc -g -Wall -c -o prog.o `libwww-config --cflags` prog.c </cmd>
<cmd> gcc -g -o prog prog.o `libwww-config --libs` </cmd>
这样编译出来的程序是包含调试信息的 static 连接, 你可以对 w3c-libwww 的
库函数源代码进行调试.

===================================================================
??? 我能在 Win32 上建立这样的环境吗?
>>> 如果你有足够的钱购买 M$ 的开发工具, 我建议你关掉电脑出去好好享受生活.
如果你只能安装免费的 Cygwin, 那么恐怕不能对 w3c-libwww 的源代码进行调试了.
不过你还是可以用 dll 来做开发: 先用与 Linux 同样的方法在 Cygwin 上装一遍,
尽管这样装出来的 static 库问题很多, 几乎无法使用, 但是我们还是得到了
必要的头文件. 然后我们到源代码的 Library/src/windows 目录下面, 用
<cmd> dlltool -D wwwapp.dll -d wwwapp.def -l libwwwapp.dll.a </cmd>
生成所有必要 dll 的 import 库, (有几个 export 符号重复, 发现后注释掉.)
复制到目标 lib 下就可以了. 当然还要修改 libwww-config, 把所有的 wwwapp
之类的名字都改成 wwwapp.dll 这样的, 也就是把 static 连接都改成 shared
连接. 就可以了.

===================================================================
??? 那些 wwwapp.dll 在哪里啊?
>>> 从 http://www.w3.org 下载 w3c-libwww 的 Win32 发行包并安装. 然后把
其中的 dll 复制到你的某个搜索路径下面. 我就放在 gtk/2.0/bin 下面.

===================================================================
??? gtk+ 有一个 pkg-config 可以拿来用吗?
>>> 可以. 把下面这个文件放到 /lib/pkgconfig 下面就行了.
<file "/lib/pkgconfig/w3c-libwww.pc">
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
target=win32

Name: w3c-libwww
Description: w3c libwww (${target} target)
Version: 5.4.0
Requires:
Libs: -L${libdir} -lwwwxml.dll -lxmltok.dll -lxmlparse.dll -lwwwzip.dll -lwww
init.dll -lwwwapp.dll -lwwwhtml.dll -lwwwtelnt.dll -lwwwnews.dll -lwwwhttp.dl
l -lwwwmime.dll -lwwwgophe.dll -lwwwftp.dll -lwwwfile.dll -lwwwdir.dll -lwwwc
ache.dll
-lwwwstream.dll -lwwwmux -lwwwtrans.dll -lwwwcore.dll -lwwwutils.dll -lmd5 -L
/usr/lib -lz -lssl -lcrypto
Cflags: -I${includedir} -I${includedir}/w3c-libwww
</file>
你可以用 <cmd> pkg-config --list-all </cmd> 试试, 看能否列出 w3c-libwww.
当然, 如果你的 prefix 不同, 你可以修改.

===================================================================
??? 为什么 gcc 顽固地提示某些符号无法解决呢?
>>> 修改 libwww-config 或者 w3c-libwww.pc , 把其中的库列表用
-Wl,--start-group 和 -Wl,--end-group 括起来.

===================================================================
??? Cygwin 下的 gtk+ 开发需要使用 -mms-bitfields -mno-cygwin 选项,
w3c-libwww 需要吗?
>>> 为保持良好的可移植性, w3c-libwww 没有使用位域, 因此与 -mms-bitfields
选项无关, 也不强制要求使用 -mno-cygwin 选项, 但是考虑到与 gtk+ 的集成问题,
笔者推荐使用 -mno-cygwin .

===================================================================
??? Linux 下 <cmd> libwww-config --cflags </cmd> 还包含一个 -DHAVE_CONFIG_H,
这是必要的吗? 在 Cygwin 下情况如何?
>>> 在 Linux 下是必要的. 在 Cygwin 下则是*不能*要的. 而且你必须从源代码的
Library/src/windows 目录下面复制一份儿 config.h 到安装目录的
include/w3c-libwww/windows 下. 可能还需要注释掉下面这个配置项目:
<code "include/w3c-libwww/windows/config.h">
/* Define if you have the <direct.h> header file.  */
/*#define HAVE_DIRECT_H 1*/
</code>
然后, 你*必须*使用 -D_CONSOLE 或者 -D_WINDOWS 中的一个. 原因请阅读
include/w3c-libwww/wwwsys.h . 你可能还需要注释掉这个文件中这行代码:
<code "include/w3c-libwww/wwwsys.h">
/* #define MKDIR(a,b)      mkdir(a) */
</code>
你可能还需要从系统 include 目录下面复制一份儿 regex.h 到你的安装
include/w3c-libwww 目录下.

===================================================================
??? 如何知道我的程序使用了正确的 dll 呢?
>>> <cmd> cygcheck prog.exe </cmd>

===================================================================
??? 听说 w3c-libwww 使用 C 语言实现了许多 OO 风格的编程, 是吗?
>>> http://www.w3.org/Library/User/Style/

===================================================================
??? w3c-libwww 的文档不提供打包下载, 我必须在线阅读吗?
>>>
<cmd> wget -x -r -nc -nH -p -np --cut-dirs=2 http://www.w3.org/Library/User <
/cmd>

===================================================================
??? 给个程序试一试, 看看开发调试环境是否已经配置好.
>>>
<file "libinit.c">
/*
On Linux:
gcc -g -Wall -o libinit libinit.c `pkg-config --cflags --libs w3c-libwww`

On Cygwin:
gcc -c -g -Wall -mno-cygwin -D_CONSOLE -o libinit.o /
        `pkg-config --cflags w3c-libwww` libinit.c
gcc -g -mno-cygwin -o libinit.exe libinit.o `pkg-config --libs w3c-libwww`
*/
#include <WWWLib.h>

/* w3c-libwww 没有提供 Win32 下的缺省 Print 函数, 因此我们必须自己做 */
int printer(const char *fmt, va_list args)
{
        return vfprintf(stdout, fmt, args);
}

int main(int argc, char *argv[])
{
        /* Win32 下要使用 HTPrint() 就必须自己设置 callback */
        HTPrint_setCallback(printer);
        HTPrint("Hello w3c-libwww/n");

        HTLibInit("TestApp", "0.0.1");
        HTLibTerminate();
        return 0;
}
</file>
另外, Win32 下 HTTRACE() 无效.

===================================================================
??? 开发调试环境配置好了. 一个典型的 w3c-libwww 应用是个什么样子?
>>> 实现某个协议, 按照这个协议发送请求, 或者响应请求.
<file "req.c">
#include <WWWLib.h>
#include <WWWInit.h>

int printer(const char *fmt, va_list args)
{
        return vfprintf(stdout, fmt, args);
}

/* 实现某个协议的客户端代码, 通常要实现一个状态机 */
int my_client(SOCKET sock, HTRequest *req)
{
        HTNet *net = HTRequest_net(req);

        HTPrint("This's my_client/n");
        HTNet_delete(net, HT_OK);
        return HT_OK;
}

/* 实现某个协议的服务器端代码, 通常要实现一个状态机 */
int my_server(SOCKET sock, HTRequest *req)
{
        HTNet *net = HTRequest_net(req);

        HTPrint("This's my_server/n");
        HTNet_delete(net, HT_OK);
        return HT_OK;
}

int main(int argc, char *argv[])
{
        HTRequest *req;

        HTLibInit("ProtTest", "0.0.1");
        HTPrint_setCallback(printer);

        HTTransport_add("mytp", HT_TP_SINGLE, HTReader_new, HTWriter_new);
        /* 注册我们的协议 */
        HTProtocol_add("myprot", "mytp", 2008, NO, my_client, my_server);

        req = HTRequest_new();

        /* 发出一个按照我们协议的请求 */
        HTLoadAbsolute("myprot://localhost", req);
        HTPrint("/n");
        /* 响应一个按照我们协议的请求 */
        HTServeAbsolute("myprot://localhost", req);

        HTRequest_delete(req);

        HTLibTerminate();
        return 0;
}
</file>

===================================================================
??? 文档上说, 过滤器很重要. 过滤器是如何设置和被调用的?
>>>
<file "filter.c">
#include <WWWLib.h>
#include <WWWInit.h>

int printer(const char *fmt, va_list args)
{
        return vfprintf(stdout, fmt, args);
}

int my_client(SOCKET sock, HTRequest *req)
{
        HTNet *net = HTRequest_net(req);

        HTPrint("This's my_client/n");
        HTNet_delete(net, HT_OK); /* 造成后置过滤器被调用 */
        return HT_OK;
}

int my_server(SOCKET sock, HTRequest *req)
{
        HTNet *net = HTRequest_net(req);

        HTPrint("This's my_server/n");
        HTNet_delete(net, HT_OK); /* 造成后置过滤器被调用 */
        return HT_OK;
}

int my_before(HTRequest *req, void *param, int mode)
{
        HTPrint("This's my_before(%s)/n", (char *)param);
        return HT_OK;
}

int my_after(HTRequest *req, HTResponse *resp, void *param, int status)
{
        HTPrint("This's my_after(%s, %d)/n", (char *)param, status);
        return HT_OK;
}

int my_req_before(HTRequest *req, void *param, int mode)
{
        HTPrint("This's my_req_before(%s)/n", (char *)param);
        return HT_OK;
}

int my_req_after(HTRequest *req, HTResponse *resp, void *param, int status)
{
        HTPrint("This's my_req_after(%s, %d)/n", (char *)param, status);
        return HT_OK;
}

int main(int argc, char *argv[])
{
        HTRequest *req;

        HTLibInit("ProtTest", "0.0.1");
        HTPrint_setCallback(printer);

        HTTransport_add("mytp", HT_TP_SINGLE, HTReader_new, HTWriter_new);
        HTProtocol_add("myprot", "mytp", 2008, NO, my_client, my_server);
        /* 注册全局前置过滤器和后置过滤器 */
        HTNet_addBefore(my_before, NULL, "before-param", HT_FILTER_LAST);
        HTNet_addAfter(my_after, NULL, "after-param", HT_ALL, HT_FILTER_LAST);

        req = HTRequest_new();
        /* 注册请求前置过滤器和后置过滤器 */
        HTRequest_addBefore(req, my_req_before, NULL, "req_before_param",
                            HT_FILTER_LAST, NO);
        HTRequest_addAfter(req, my_req_after, NULL, "req_after_param", HT_ALL,
                           HT_FILTER_LAST, NO);

        HTLoadAbsolute("myprot://localhost", req);
        HTPrint("/n");
        HTServeAbsolute("myprot://localhost", req);

        HTRequest_delete(req);

        HTLibTerminate();
        return 0;
}
</file>

===================================================================
??? 任何具有 OO 风格的, 都必须处理事件. 请给个事件的例子好吗?
>>>
<file "timer.c">
#include <WWWLib.h>
#include <WWWInit.h>

int printer(const char *fmt, va_list args)
{
        return vfprintf(stdout, fmt, args);
}

int my_timer(HTTimer *tmr, void *param, HTEventType type)
{
        static int count = 0;

        HTPrint("I'm my_timer(%s) %d/n", (char *)param, count++);
        if (count >= 3)
                HTEventList_stopLoop();
        return HT_OK;
}

int main(int argc, char *argv[])
{
        HTTimer *timer;

        HTPrint_setCallback(printer);
        HTLibInit("TestApp", "0.0.1");
        HTEventInit();

        timer = HTTimer_new(NULL, my_timer, "my-timer", 2000, YES, YES);
        HTEventList_newLoop();
        HTPrint("app stopped/n");

        HTEventTerminate();
        HTLibTerminate();
        return 0;
}
</file>

===================================================================
??? 输入输出无疑是非常重要的. 请给个输出流的例子好吗?
>>>
<file "out_strm.c">
#include <WWWLib.h>
#include <WWWInit.h>
#include <WWWStream.h>

struct _HTStream {
        HTStreamClass *isa;
};

static int printer(const char *fmt, va_list pArgs)
{
        return vfprintf(stderr, fmt, pArgs);
}

int main(int argc, char *argv[])
{
        HTStream *out;

        HTPrint_setCallback(printer);
        HTLibInit("Test", "0.0.1");

        out = HTFWriter_new(NULL, stdout, YES);
        HTPrint("I'm %s/n", out->isa->name);
        (out->isa->put_string)(out, "Hello, stream/n");
        (out->isa->flush)(out);
        (out->isa->_free)(out);

        HTLibTerminate();
        return 0;
}
</file>

===================================================================
??? 请给个输入流的例子.
>>>
<file "in_strm.c">
#include <WWWLib.h>
#include <WWWInit.h>
#include <WWWStream.h>

struct _HTInputStream {
        HTInputStreamClass *isa;
};

int main(int argc, char *argv[])
{
        HTStream *out;
        HTInputStream *in;
        HTChannel *chnl;
        HTNet *innet;
        HTHost *host;
        FILE *fp;

        if (NULL == (fp = fopen(__FILE__, "rb")))
                return (fprintf(stderr, "Can't open source file/n"), 1);
        HTLibInit("Test", "0.0.1");

        host = HTHost_new("localhost", 0);
        innet = HTNet_new(host);
        out = HTFWriter_new(NULL, stdout, YES);
        HTNet_setReadStream(innet, out);
        HTHost_addNet(host, innet);

        chnl = HTChannel_new(INVSOC, fp, YES);

        in = HTANSIReader_new(host, chnl, NULL, 0);
        (in->isa->read)(in);
        (in->isa->close)(in);

        HTChannel_delete(chnl, HT_OK);

        HTLibTerminate();
        fclose(fp);
        return 0;
}
</file>

===================================================================
??? 我怎么没看到 write 啊? 读入的东西是怎么跑到输出上去的呢?
>>> w3c-libwww 认为, 没有无缘无故的读, 也没有无缘无故的写. 因此你必须
在读之前设置好输出, 然后在 (in->isa->read)(in) 的时候, 会找到你所设置
的输出, 并写到这个输出里面. 调用方只管事前设置就行了, 无需事中干预.
参见 Library/src/HTANSI.c!HTANSIReader_read .

===================================================================
??? 这些事前设置好像很乱啊.
>>> 那是为了循序渐进, 每次引入几个概念以便读者逐步认识. 如果不是自己
开发新协议, 而只是应用 w3c-ilbwww 的话, 可以简单一些.
<file "sload.c">
/* CAUTION: For Cygwin Win32 ONLY !!! */
#include <WWWLib.h>
#include <WWWInit.h>

int terminate_handler(HTRequest * request, HTResponse * response,
                      void * param, int status)
{
        return (HTEventList_stopLoop(), HT_OK);
}

int main(int argc, char *argv[])
{
        char *              url = NULL;
        HTRequest *         request = HTRequest_new();

        HTLibInit("Simple load file", "0.0.1");
        HTTransport_add("local", HT_TP_SINGLE, HTANSIReader_new,
                        HTANSIWriter_new);
        HTProtocol_add("file", "local", 0, YES, HTLoadFile, NULL);
        HTEventInit();
        HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);

        url = HTGetCurrentDirectoryURL();
        HTSACat(&url, __FILE__);
        if (HTLoadToFile/*!HTLoadFile*/(url, request, "CON") == YES)
                HTEventList_loop(request);
        HT_FREE(url);

        HTRequest_delete(request);
        HTEventTerminate();
        HTLibTerminate();
        return 0;
}
</file>

===================================================================
??? 这回连 read 也看不到了.
>>> 参见 Library/src/HTFile.c!HTLoadFile 和 HTHost.c!HTHost_read .

===================================================================
??? 从 HTLoadToFile 到 HTLoadFile 又发生了什么呢?
>>> 按照下列顺序去读 Library/src 下的源代码:
HTAccess.c!HTLoadToFile(url, request, filename)
HTAccess.c!HTLoadAbsolute(url, request)
HTReqMan.c!HTLoad(request, recursive)
HTNet.c!HTNet_newClient(request)
HTProt.c!HTProtocol_find(request, access)
HTProt.c!HTProtocol_client(protocol) 就是 HTLoadFile 了.
最后的调用语句是这样的: (*(cbf))(INVSOC, request) .

===================================================================
??? HTNet_newServer(request) 和 HTNet_newClient(request) 主要干什么?
>>> 首先 HTNet_executeBeforeAll(request), 然后 create_object() 创建一个
空的 HTNet, 设置好 preemptive, protocol, transport, request, 同时也
HTRequest_setNet(request, me), 建立 request 和 net 的双向互指关系.
然后就 (*(cbf))(INVSOC, request), 调用服务(或客户)回调函数.

===================================================================
??? 为什么要做的这么麻烦啊?
>>> 比如小学生做应用题, 通常会列出一排算式, 都是具体数字, 每一步得一个
结果, 实实在在. 但这只是算术, 很初级的东西. 最明显的局限是"可移植性"
和"可重用性"太低. 高级一点的就是代数. 用常数和未知数取代具体数字,
在不知道其具体内容的情况下进行运算. 写程序也是这样. 初学者总是习惯于调用
具体的函数, 比如为 file:// 写一个 HTNet_newFileClient, 为 http:// 写一个
HTNet_newHttpClient, 或者把协议类型作为参数传进来, 然后用 switch 分别
调用 HTLoadFile, HTLoadHttp. 如果有一天要增加一个 newprot:// , 那么这些
代码就都要作相应改动. 这就相当于"算术"的水平. 高级一点的就使用函数指针.
不管这个函数的具体内容, HTNet_newClient 只管在适当的环境下以适当的方式
进行调用就行了. 就像对未知数进行"代数"运算一样. 这样的程序抽象层次更高,
适用性更广. 增改协议的时候, 不需要改动 HTNet_newClient. 类似的技术今天
已经应用得相当普遍. 比如 C++ 的抽象类, Java 和 Gtk+ 的 Interface 等等.

===================================================================
??? 我如何建立一个服务呢?
>>> 有一个 Library/Examples/listen.c 改写如下:
<file "listen.c">
#include <WWWLib.h>
#include <WWWInit.h>

int global_after(HTRequest *req, HTResponse *resp, void *param, int status)
{
        return (HTEventList_stopLoop(), HT_OK);
}

int main(int argc, char *argv[])
{
        HTRequest *req = HTRequest_new();
        HTStream *out;

        HTLibInit("Simple Listener", "0.0.1");
        HTEventInit();
        HTNet_addAfter(global_after, NULL, NULL, HT_ALL, HT_FILTER_LAST);
        HTTransport_add("tcp", HT_TP_SINGLE, HTReader_new, HTWriter_new);
        /* 注意端口号是 2004 (任意), 服务回调函数是 HTLoadSocket */
        HTProtocol_add("noop", "tcp", 2004, NO, NULL, HTLoadSocket);

        HTRequest_setOutputFormat(req, WWW_RAW);
        out = HTFWriter_new(req, stdout, YES);
        HTRequest_setOutputStream(req, out);

        HTServeAbsolute("noop://localhost", req);
        HTEventList_newLoop();

        HTRequest_delete(req);
        HTEventTerminate();
        HTLibTerminate();
        return 0;
}
</file>
执行 listen.exe , 然后从浏览器上访问 http://localhost:2004 , 就可以从
控制台看到浏览器发给服务器的请求的全部内容. 用 telnet://localhost:2004
连接, 则可以看到从 telnet 终端输入的内容都显示在控制台上.

===================================================================
??? 看起来关键是服务回调函数 HTLoadSocket , 它是干什么的?
>>> 参见 Library/src/HTSocket.c . 先做一个 HTHost_listen, 然后进入
SocketEvent, 若是 RAW_BEGIN, 则 HTHost_accept, 进入 RAW_NEED_STREAM.
如是 RAW_NEED_STREAM, 则把 request 的 outputStream 设置为 net 的
readStream , 并设置已连接, 进入 RAW_READ. 若是 RAW_READ, 则进行
HTHost_read.

===================================================================
??? 我能做一个 echo 吗?
>>>
<file "secho.c">
#include <WWWLib.h>
#include <WWWInit.h>

int global_after(HTRequest *req, HTResponse *resp, void *param, int status)
{
        HTEventList_stopLoop();
        return HT_OK;
}

typedef enum _EchoState {
        ECHO_ERROR = -2,
        ECHO_OK = -1,
        ECHO_BEGIN = 0,
        ECHO_NEED_STREAM,
        ECHO_READ
} EchoState;

typedef struct _echo_info {
        EchoState state;
        HTNet *net;
        HTRequest *request;
} echo_info;

static int EchoCleanup(HTRequest *request, int status)
{
        HTNet *net = HTRequest_net(request);
        echo_info *echo = (echo_info *)HTNet_context(net);

        if (status == HT_INTERRUPTED) {
                (void)0;
        } else if (status == HT_TIMEOUT) {
                (void)0;
        }
        HTNet_delete(net, HT_ERROR);
        HT_FREE(echo);
        return YES;
}

static int EchoEvent(SOCKET soc, void *pVoid, HTEventType type);

int HTServEcho(SOCKET soc, HTRequest *request)
{
        echo_info *echo;
        HTNet *net = HTRequest_net(request);
        char *url;

        if (NULL == (echo = (echo_info *)HT_CALLOC(1, sizeof(echo_info))))
                HT_OUTOFMEM("HTServEcho");
        echo->state = ECHO_BEGIN;
        echo->net = net;
        echo->request = request;
        HTNet_setContext(net, echo);
        HTNet_setEventCallback(net, EchoEvent);
        HTNet_setEventParam(net, echo);

        url = HTAnchor_physical(HTRequest_anchor(request));
        if (HTHost_listen(NULL, net, url) == HT_ERROR)
                /* HTNet_execute(net, HTEvent_CLOSE) */
                return EchoEvent(soc, echo, HTEvent_CLOSE);
        /* HTNet_start(net) */
        return EchoEvent(soc, echo, HTEvent_BEGIN);
}

static int EchoEvent(SOCKET soc, void *pVoid, HTEventType type)
{
        echo_info *echo = (echo_info *)pVoid;
        int status = HT_ERROR;
        HTNet *net = echo->net;
        HTRequest *request = echo->request;
        HTHost *host = HTNet_host(net);

        if (type == HTEvent_BEGIN) {
                echo->state = ECHO_BEGIN;
        } else if (type == HTEvent_CLOSE) {
                EchoCleanup(request, HT_INTERRUPTED);
                return HT_OK;
        } else if (type == HTEvent_TIMEOUT) {
                HTRequest_addError(request, ERR_FATAL, NO, HTERR_TIME_OUT,
                                   NULL, 0, "HTServEcho");
                EchoCleanup(request, HT_TIMEOUT);
                return HT_OK;
        } else if (type == HTEvent_END) {
                EchoCleanup(request, HT_OK);
                return HT_OK;
        }

        while (1) {
                switch (echo->state) {
                case ECHO_BEGIN:
                        status = HTHost_accept(host, net, NULL);
                        host = HTNet_host(net);
                        if (status == HT_OK) {
                                echo->state = ECHO_NEED_STREAM;
                        } else if (status == HT_WOULD_BLOCK
                                   || status == HT_PENDING) {
                                return HT_OK;
                        } else {
                                echo->state = ECHO_ERROR;
                        }
                        break;
                case ECHO_NEED_STREAM:
                        HTNet_setReadStream(net,
                            (HTStream *)HTNet_getOutput(net, NULL, 0));
                        HTRequest_setOutputConnected(request, YES);
                        echo->state = ECHO_READ;
                        break;
                case ECHO_READ:
                        status = HTHost_read(host, net);
                        if (status == HT_WOULD_BLOCK)
                                return HT_OK;
                        else if (status == HT_CLOSED)
                                echo->state = ECHO_OK;
                        else
                                echo->state = ECHO_ERROR;
                        break;
                case ECHO_OK:
                        EchoCleanup(request, HT_OK);
                        return HT_OK;
                        break;
                case ECHO_ERROR:
                        EchoCleanup(request, HT_ERROR);
                        return HT_OK;
                        break;
                default:
                        HTDEBUGBREAK("Bad echo state %d/n" _ echo->state);
                }
        }
        return HT_OK;
}

int main(int argc, char *argv[])
{
        HTRequest *req;

        HTLibInit("Simply Echo", "0.0.1");
        HTEventInit();
        HTNet_addAfter(global_after, NULL, NULL, HT_ALL, HT_FILTER_LAST);
        HTTransport_add("tcp", HT_TP_SINGLE, HTReader_new, HTWriter_new);
        HTProtocol_add("noop", "tcp", 2004, NO, NULL, HTServEcho);

        req = HTRequest_new();
        HTRequest_setOutputFormat(req, WWW_RAW);

        HTServeAbsolute("noop://localhost", req);
        HTEventList_newLoop();

        HTRequest_delete(req);
        HTEventTerminate();
        HTLibTerminate();
        return 0;
}
</file>
这个程序在 Win32/Cygwin 上编译后, 运行. 用 telnet 连接本机端口 2004,
就可以看到 echo 的效果了. 但是在 linux 上编译后, 只能 echo 一下,
包括其本身的源码 Library/Example/listen.c 也是这样. 原因不详.

===================================================================
??? 事件究竟是在什么地方被执行的?
>>>
<code "HTEvtLst.c!AsyncWindowProc(hwnd, wMsg, wParam, lParam)">
    if (uMsg == WM_TIMER) {
        HTTimer_dispatch((HTTimer *)wParam);
        return (0);
    }
    /* dispatch() means (*event->cbf)(s, event->param, type); */
    if (HTEventList_dispatch((int)sock, type, now) != HT_OK)
        HTEndLoop = -1;
</code>
另一方面:
<code "HTEvtLst.c!HTEventList_loop(NULL)">
    /* Don't leave this loop until we leave the application */
    while (!HTEndLoop) {
        if (active_sockets == 0)
            continue;

        /* There were active sockets. Determine which fd sets they were in */
        for (s = 0 ; s <= maxfds ; s++) {
            if (FD_ISSET(s, &texceptset))
                if ((status = EventOrder_add(s, HTEvent_OOB, now)) != HT_OK)
                    goto stop_loop;
            if (FD_ISSET(s, &twriteset))
                if ((status = EventOrder_add(s, HTEvent_WRITE, now)) != HT_OK)
                    goto stop_loop;
            if (FD_ISSET(s, &treadset))
                if ((status = EventOrder_add(s, HTEvent_READ, now)) != HT_OK)
                    goto stop_loop;
        }
        /* execute() means (*event->cbf)(s, event->param, type); */
        if ((status = EventOrder_executeAndDelete()) != HT_OK) break;
    };
</code>

===================================================================
??? secho 只能接受一个连接, 我如何做一个真正的服务器呢?
>>> 从 4.0 版到 5.0 版, w3c-libwww 曾经有个短命的 MiniServer 子项目.
到 5.1 版就被放弃了. 由于现在的 5.4 版与 5.0 版在 API 上已经发生了巨大的
变化, 因此这个 MiniServer 的源代码已经没有什么参考价值了. w3c-libwww
可能是出于 "只做一件事情, 力图做到最好" 的考虑, 放弃了对服务器框架的支持.

===================================================================
??? 用 w3c-libwww 来开发客户端, 有哪些典型的应用呢?
>>> 你自己去看文档吧, 有很多好的例子. 我能说的就到此为止了.
本文附录有一些随手摘录的笔记, 既不正式, 也不完全, 聊作参考吧.

===================================================================
附: 本文档例子程序在 Win32/Cygwin 平台上的 Makefile,
<file "Makefile">
all: libinit.exe req.exe filter.exe timer.exe out_strm.exe in_strm.exe /
        sload.exe listen.exe secho.exe

.SUFFIXES:
.SUFFIXES: .exe .o .c

.o.exe:
        gcc -g -mno-cygwin -o $@ $< `pkg-config --libs w3c-libwww`

.c.o:
        gcc -c -g -Wall -mno-cygwin -D_CONSOLE -o $@ /
                `pkg-config --cflags w3c-libwww` $<

clean:
        @rm -f *.exe *.o

.PHONY: all
</file>

===================================================================
??? WWWLib.h 包括哪些内容?
>>>
<code "WWWLib.h">
#include "wwwsys.h"
#include "WWWUtil.h"
#include "WWWCore.h"
</code>

===================================================================
??? WWWUtil.h 包括哪些内容?
>>>
<code "WWWUtil.h">
#include "wwwsys.h"
#include "HTUtils.h"
#include "HTArray.h"
#include "HTAssoc.h"
#include "HTAtom.h"
#include "HTChunk.h"
#include "HTList.h"
#include "HTMemory.h"
#include "HTString.h"
#include "HTUU.h"
</code>

===================================================================
??? libwww 是如何处理 HTPrint 的?
>>> 用户可以设置自己的方式。对 Win32 平台,则是“必须”设置自己的方式。
<code "HTUtils.h">
typedef int HTPrintCallback(const char * fmt, va_list pArgs);

extern void HTPrint_setCallback(HTPrintCallback * pCall);
extern HTPrintCallback * HTPrint_getCallback(void);

extern int HTPrint(const char * fmt, ...);
</code>

<code "HTTrace.c">
PRIVATE HTPrintCallback * PHTPrintCallback = NULL;

PUBLIC void HTPrint_setCallback (HTPrintCallback * pCall)
{
    PHTPrintCallback = pCall;
}

PUBLIC HTPrintCallback * HTPrint_getCallback (void)
{
    return PHTPrintCallback;
}

PUBLIC int HTPrint (const char * fmt, ...)
{
    va_list pArgs;
    va_start(pArgs, fmt);
    if (PHTPrintCallback)
        return (*PHTPrintCallback)(fmt, pArgs);
#ifdef WWW_WIN_WINDOW
    return (0);  /* 对于 Win32 平台,必须由用户设置回调函数。*/
#else
    return (vfprintf(stdout, fmt, pArgs));
#endif
}
</code>

===================================================================
??? libwww 是如何处理 HTTRACE 的?
>>> 注意 HTTRACE 与 HTPrint 有本质的不同。HTTRACE 是一个宏,可以被定义为
像 HTPrint 一样的函数 HTTrace,也可以被定义为根本什么也没有。而且 HTTRACE
在 Win32 平台上实际没有实现,虽然理论上并没有障碍。
在其他平台上,函数 HTTrace 的实现与 HTPrint 类似,只是增加了一个
WWW_TraceFlag。以选择不同的 trace 范畴。
<code "HTUtils.h">
#ifdef HTDEBUG
#ifdef WWW_WIN_DLL
extern int *            WWW_TraceFlag;   /* In DLLs, we need the indirection*/
#define WWWTRACE        (*WWW_TraceFlag) /* 但实际上,这个变量既没有被实例化*/
                                         /* 也没有被 export,因此根本没用。*/
#else
extern unsigned int     WWW_TraceFlag;       /* Global flag for all W3 trace*/
#define WWWTRACE        (WWW_TraceFlag)  /* 在 HTTrace.c 中被实例化。*/
#endif /* WWW_WIN_DLL */
#else
#define WWWTRACE        0                /* 非调试版屏蔽一切 trace。*/
#endif /* HTDEBUG */

typedef enum _HTTraceFlags {
    SHOW_UTIL_TRACE     = 0x1,
    SHOW_APP_TRACE      = 0x2,
    ....
    SHOW_ALL_TRACE      = (int) 0xFFFFFFFF
} HTTraceFlags;

#define UTIL_TRACE      (WWWTRACE & SHOW_UTIL_TRACE)
#define APP_TRACE       (WWWTRACE & SHOW_APP_TRACE)
....
#define ALL_TRACE       (WWWTRACE & SHOW_ALL_TRACE)

typedef int HTTraceCallback(const char * fmt, va_list pArgs);
extern void HTTrace_setCallback(HTTraceCallback * pCall);
extern HTTraceCallback * HTTrace_getCallback(void);

#ifdef HTDEBUG
#undef _
#define _ ,
/* 这里的 TYPE 就是 APP_TRACE 之类,即 (WWWTRACE & SHOW_APP_TRACE) 之类。*/
#define HTTRACE(TYPE, FMT) /
        do { if (TYPE) HTTrace(FMT); } while (0);
extern int HTTrace(const char * fmt, ...);
#else
#define HTTRACE(TYPE, FMT)              /* empty */
#endif /* HTDEBUG */

typedef int HTTraceDataCallback(char * data, size_t len, char * fmt,
                                va_list pArgs);
extern void HTTraceData_setCallback(HTTraceDataCallback * pCall);
extern HTTraceDataCallback * HTTraceData_getCallback(void);

#ifdef HTDEBUG
#define HTTRACEDATA(DATA, LEN, FMT) HTTraceData((DATA), (LEN), FMT)
extern int HTTraceData(char * data, size_t len, char * fmt, ...);
#else
#define HTTRACEDATA(DATA, LEN, FMT)     /* empty */
#endif /* HTDEBUG */
</code>

<code "HTTrace.c">
#if WWWTRACE_MODE == WWWTRACE_FILE
PUBLIC FILE *WWWTrace = NULL;
#endif

#ifndef WWW_WIN_DLL
PUBLIC unsigned int WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */
#endif

PRIVATE HTTraceCallback * PHTTraceCallback = NULL;
PRIVATE HTTraceDataCallback * PHTTraceDataCallback = NULL;

/* ---------------------------------------------------------------------- */

PUBLIC void HTTrace_setCallback (HTTraceCallback * pCall)
{
    PHTTraceCallback = pCall;
}

PUBLIC HTTraceCallback * HTTrace_getCallback (void)
{
    return PHTTraceCallback;
}

PUBLIC int HTTrace (const char * fmt, ...)
{
    va_list pArgs;
    va_start(pArgs, fmt);
    if (PHTTraceCallback)
        return (*PHTTraceCallback)(fmt, pArgs);
#ifdef WWW_WIN_WINDOW
    return (0);
#else
    return (vfprintf(stderr, fmt, pArgs));
#endif
}

PUBLIC void HTTraceData_setCallback (HTTraceDataCallback * pCall)
{
    PHTTraceDataCallback = pCall;
}

PUBLIC HTTraceDataCallback * HTTraceData_getCallback (void)
{
    return PHTTraceDataCallback;
}

PUBLIC int HTTraceData (char * data, size_t len, char * fmt, ...)
{
    va_list pArgs;
    va_start(pArgs, fmt);
    if (PHTTraceDataCallback)
        return (*PHTTraceDataCallback)(data, len, fmt, pArgs);
    return (0); /* 必须由用户定义回调函数 */
}
</code>

===================================================================
??? libwww 是如何处理 HTArray 的?
>>> HTArray 是个存储 (void *) 的数组,可以自动扩展。
<code "HTArray.h" impl="HTArray.c">
/* 这个结构也可以放在 HTArray.c 当中,做成 private。
   相应的几个宏改成函数。参见 HTChunk。
*/
typedef struct {
    int         size;           /* In numbers of elements       */
    int         growby;         /* Allocation unit in elements  */
    int         allocated;      /* Current size of *data        */
    void **     data;           /* Pointer to malloced area or 0 */
} HTArray;

extern HTArray * HTArray_new (int grow);
extern BOOL HTArray_delete (HTArray * array);
extern BOOL HTArray_clear (HTArray * array);
extern BOOL HTArray_addObject (HTArray * array, void * object);

/* 如果有数据,则返回该数据,并准备访问下一个数据 */
#define HTArray_firstObject(me, dp) /
        ((me) && ((dp)=(me)->data) ? *(dp)++ : NULL)
#define HTArray_nextObject(me, dp) /
        ((me) && (dp) ? *(dp)++ : NULL)

typedef int HTComparer (const void * a, const void * b);
extern BOOL HTArray_sort (HTArray * array, HTComparer * comp);
#define HTArray_data(me)        ((me) ? (me)->data : NULL)
#define HTArray_size(me)        ((me) ? (me)->size : -1)
</code>

===================================================================
??? libwww 如何处理 HTList?
>>> HTList 是个单向链表,其数据域为 void * object。
<code "HTList.h" impl="HTList.c">
typedef struct _HTList HTList;

struct _HTList {
  void * object;
  HTList * next;
};

extern HTList * HTList_new      (void);
extern BOOL     HTList_delete   (HTList *me);
extern BOOL HTList_addObject (HTList *me, void *newObject);
extern BOOL HTList_appendObject (HTList * me, void * newObject);
extern HTList * HTList_addList (HTList * me, void * newObject);
extern HTList * HTList_appendList (HTList * me, void * newObject);
extern BOOL     HTList_removeObject             (HTList * me, void * oldObject);
extern BOOL     HTList_quickRemoveElement       (HTList * me, HTList * last);
extern BOOL     HTList_removeObjectAll          (HTList * me, void * oldObject);
extern void *   HTList_removeLastObject         (HTList * me);
extern void *   HTList_removeFirstObject        (HTList * me);
/* NULL 和 me->next==NULL 都被视为空链表 */
#define         HTList_isEmpty(me)              (me ? me->next == NULL : YES)
extern int      HTList_count                    (HTList *me);
extern int      HTList_indexOf   (HTList * me, void * object);
extern int      HTList_indexOfElement (HTList * me, HTList * element);
extern void *   HTList_objectAt  (HTList * me, int position);
extern HTList * HTList_elementOf (HTList * me, void * object, HTList ** pLast);
#define         HTList_objectOf(me)             (me ? me->object: NULL)
#define         HTList_lastObject(me) /
                ((me) && (me)->next ? (me)->next->object : NULL)
extern void * HTList_firstObject  (HTList * me);
#define         HTList_nextObject(me) /
                ((me) && ((me) = (me)->next) ? (me)->object : NULL)
extern BOOL HTList_insertionSort(HTList * list, HTComparer * comp);
#define HTList_free(x)  HT_FREE(x)
</code>

===================================================================
??? libwww 如何处理 HTAssocList ?
>>> HTAssocList 就是 HTList,只是其数据域为 HTAssoc。
<code "HTAssoc.h" impl="HTAssoc.c">
typedef HTList HTAssocList;

typedef struct {
    char * name;
    char * value;
} HTAssoc;

extern HTAssocList * HTAssocList_new (void);
extern BOOL          HTAssocList_delete (HTAssocList * alist);
extern BOOL HTAssocList_addObject (
        HTAssocList *   alist,
        const char *    name,
        const char *    value);
extern BOOL HTAssocList_replaceObject (
        HTAssocList *   list,
        const char *    name,
        const char *    value);
extern BOOL HTAssocList_removeObject (
        HTAssocList *   list,
        const char *    name);
extern char * HTAssocList_findObject (
        HTAssocList *   alist,
        const char *    name);
extern char * HTAssocList_findObjectExact (
        HTAssocList *   alist,
        const char *    name);
extern char * HTAssocList_findObjectCaseSensitive (
        HTAssocList *   list,
        const char *    name);
extern char * HTAssocList_findObjectCaseSensitiveExact (
        HTAssocList *   list,
        const char *    name);
#define HTAssoc_name(me)        ((me) ? (me)->name : NULL)
#define HTAssoc_value(me)       ((me) ? (me)->value : NULL)
#define HTAssocList_nextObject(me) /
        ((me) && ((me) = (me)->next) ? (me)->object : NULL)
</code>

===================================================================
??? libwww 如何处理 HTString?
>>>
<code "HTString.h" impl="HTString.c">
#define StrAllocCopy(dest, src) HTSACopy (&(dest), src)
#define StrAllocCat(dest, src)  HTSACat  (&(dest), src)
extern char * HTSACopy (char **dest, const char *src);
extern char * HTSACat  (char **dest, const char *src);
extern char * StrAllocMCopy (char ** dest, ...);
extern char * StrAllocMCat (char ** dest, ...);
extern int strcasecomp  (const char *a, const char *b);
extern int strncasecomp (const char *a, const char *b, int n);
extern int tailcomp(const char * s1, const char * s2);
extern int tailcasecomp(const char * s1, const char * s2);
extern char * HTStrMatch        (const char * tmpl, const char * name);
extern char * HTStrCaseMatch    (const char * tmpl, const char * name);
extern char * HTStrCaseStr (char * s1, char * s2);
extern char * HTStrip (char * s);
</code>

===================================================================
??? libwww 如何处理 HTAtom?
>>> HTAtom 是个散列表,所谓的 atom 在这里就是单元的内存地址。
<code "HTAtom.h" impl="HTAtom.c">
typedef struct _HTAtom HTAtom;
struct _HTAtom {
        HTAtom *        next;
        char *          name;
}; /* struct _HTAtom */

extern HTAtom * HTAtom_for      (const char * string);
extern HTAtom * HTAtom_caseFor  (const char * string);
#define HTAtom_name(a) ((a) ? (a)->name : NULL)
extern HTList * HTAtom_templateMatches (const char * templ);
extern void HTAtom_deleteAll (void);
</code>

<code "HTAtom.c">
PRIVATE HTAtom * hash_table[HT_XL_HASH_SIZE];
PRIVATE BOOL initialised = NO;
/* 在 HTAtom_for 和 HTAtom_casefor 中, 先计算 hash,然后在
hash_table 中 strcmp,strcasecomp,若有就返回该单元的内存地址,
若没有就加入一个新单元,并返回其地址。
*/
</code>

===================================================================
??? libwww 如何处理 HTChunk?
>>>
<code "HTChunk.h" impl="HTChunk.c">
typedef struct _HTChunk HTChunk;

extern HTChunk * HTChunk_new (int growby);
extern void HTChunk_delete (HTChunk * ch);
extern void HTChunk_clear (HTChunk * ch);
extern void HTChunk_ensure (HTChunk * ch, int extra_size);
extern void HTChunk_putc (HTChunk * ch, char c);
extern void HTChunk_puts (HTChunk * ch, const char *str);
extern void HTChunk_putb (HTChunk * ch, const char *block, int len);
extern char * HTChunk_data (HTChunk * ch);
extern int HTChunk_size (HTChunk * ch);
extern BOOL HTChunk_truncate (HTChunk * ch, int size);
extern BOOL HTChunk_setSize (HTChunk * ch, int size);
extern void HTChunk_terminate (HTChunk * ch);
extern HTChunk * HTChunk_fromCString    (char * str, int grow);
extern char * HTChunk_toCString         (HTChunk * ch);
extern HTChunk * HTChunk_fromBuffer (char * buf, int buflen, int size, int gr
ow);
</code>

<code "HTChunk.c">
struct _HTChunk {
    int         size;           /* In bytes                     */
    int         growby;         /* Allocation unit in bytes     */
    int         allocated;      /* Current size of *data        */
    char *      data;           /* Pointer to malloced area or 0 */
};     
/*      Free a chunk but keep the data
*/
PUBLIC char * HTChunk_toCString (HTChunk * ch)
{
    char * ret = 0;
    if (ch) {
        ret = ch->data;
        HT_FREE(ch);
    }
    return ret;
}
</code>

===================================================================
??? libwww 如何处理 HTMemory?
>>>
<code "HTMemory.h" impl="HTMemory.c">
extern void* HTMemory_malloc(size_t size);
extern void* HTMemory_calloc(size_t count, size_t size);
extern void* HTMemory_realloc(void * ptr, size_t size);
extern void HTMemory_free(void* ptr);

#define HT_MALLOC(size)         HTMemory_malloc((size))
#define HT_CALLOC(count, size)  HTMemory_calloc((count), (size))
#define HT_REALLOC(ptr, size)   HTMemory_realloc((ptr), (size))
#define HT_FREE(pointer)        {HTMemory_free((pointer));((pointer))=NULL;}

/* 可以注册多个内存清理函数,出现短缺就进行清理 */
typedef void HTMemoryCallback(size_t size);
extern BOOL HTMemoryCall_add (HTMemoryCallback * cbf);
extern BOOL HTMemoryCall_delete (HTMemoryCallback * cbf);
extern BOOL HTMemoryCall_deleteAll (void);

/* 可以设置一个内存不足无法继续时的必要清理函数,清理之后就 abort() */
typedef void HTMemory_exitCallback(char *name, char *file, unsigned long line);
extern void HTMemory_setExit(HTMemory_exitCallback * pExit);
extern HTMemory_exitCallback * HTMemory_exit(void);

#define outofmem(file, name)    HT_OUTOFMEM(name)
#define HT_OUTOFMEM(name)       HTMemory_outofmem((name), __FILE__, __LINE__)
extern void HTMemory_outofmem(char * name, char * file, unsigned long line);
</code>

<code "HTMemory.c">
PRIVATE HTList * HTMemCall = NULL;                  /* List of memory freers */
PRIVATE HTMemory_exitCallback * PExit = NULL;     /* panic and exit function */
PRIVATE size_t LastAllocSize = 0;                 /* size of last allocation */

PUBLIC void * HTMemory_malloc (size_t size)
{
    void * ptr;
    ptr = malloc(LastAllocSize = size);
    if (ptr != NULL) return ptr;
    /* 出现短缺 */
    if (HTMemCall) {
        HTMemoryCallback * pres;
        while ((pres = (HTMemoryCallback *) HTList_nextObject(HTMemCall))) {
            HTTRACE(MEM_TRACE, "Mem Calling. %p (size %d)/n" _ (void*)pres _
size);
            (*pres)(size);  /* 清理 */
            if ((ptr = malloc(size)) != NULL) return ptr;  /* 重试 */
        }
    }
    HTTRACE(MEM_TRACE, "Memory.... Couldn't allocate %d bytes/n" _ size);
    return NULL;
}

PUBLIC void HTMemory_outofmem (char * name, char * file, unsigned long line)
{
    if (PExit)  /* 如果注册了必要清理函数,就进行必要清理 */
        (*PExit)(name, file, line);
    HTTRACE(ALL_TRACE, "%s:%ld failed allocation for /"%s/" (%ld bytes)./nPro
gram aborted./n" _
            file _ line _ name _ LastAllocSize);
    abort();
}
</code>

===================================================================
??? libwww 如何处理 HTUU?
>>>
<code "HTUU.h" impl="HTUU.c">
extern int HTUU_encode (unsigned char * bufin, unsigned int nbytes,
                        char * bufcoded);
extern int HTUU_decode (char * bufcoded, unsigned char * bufplain,
                        int outbufsize);
</code>

===================================================================
??? WWWCore.h 包括哪些内容?
>>>
<code "WWWCore.h">
#include "wwwsys.h"
#include "HTLib.h"
#include "HTReq.h"
#include "HTMethod.h"
#include "HTAnchor.h"
#include "HTLink.h"
#include "HTParse.h"
#include "HTEscape.h"
#include "HTUTree.h"
#include "HTWWWStr.h"
#include "HTUser.h"
#include "HTEvent.h"
#include "HTMemLog.h"
#include "HTError.h"
#include "HTAlert.h"
#include "HTFormat.h"
#include "HTStream.h"
#include "HTStruct.h"
#include "HTNoFree.h"
#include "HTIOStream.h"
#include "HTDNS.h"
#include "HTHost.h"
#include "HTNet.h"
#include "HTInet.h"
#include "HTTrans.h"
#include "HTProt.h"
</code>

===================================================================
??? libwww 如何处理 HTInet?
>>> 获取网络配置的一些函数,在 HTUserProfile 中有运用。
<code "HTInet.h" impl="HTInet.c">
extern char * HTErrnoString     (int errnum);
extern int HTInetStatus         (int errnum, char * where);
extern unsigned int HTCardinal (int *           pstatus,
                                char **         pp,
                                unsigned int    max_value);
extern const char * HTInetString (struct sockaddr_in * sin);
extern int HTParseInet (HTHost * host, char * hostname, HTRequest * request);
extern time_t HTGetTimeZoneOffset (void);
extern ms_t HTGetTimeInMillis (void);
extern char * HTGetHostName (void);
extern char * HTGetMailAddress (void);
extern char * HTGetNewsServer (void);
extern char * HTGetTmpFileName (const char * dir);
#ifdef WWWLIB_SIG
extern void HTSetSignal (void);
#endif
</code>

===================================================================
??? libwww 如何处理 HTUserProfile?
>>>
<code "HTUser.h" impl="HTUser.c">
typedef struct _HTUserProfile HTUserProfile;

extern HTUserProfile * HTUserProfile_new (const char * name, void * context);
extern BOOL HTUserProfile_localize (HTUserProfile * up); /* 填缺省值 */
extern BOOL HTUserProfile_delete (HTUserProfile * up);
</code>

<code "HTUser.c">
struct _HTUserProfile {
    char *      user; /* name, set in HTUserProfile_new(name, context) */
    /* 但是这个字段实际上没有任何用处! */

    char *      fqdn;                         /* Fully qualified domain name */
extern char * HTUserProfile_fqdn (HTUserProfile * up);
extern BOOL HTUserProfile_setFqdn (HTUserProfile * up, const char * fqdn);

    char *      email;                      /* Email address of current user */
extern char * HTUserProfile_email (HTUserProfile * up);
extern BOOL HTUserProfile_setEmail (HTUserProfile * up, const char * email);

    char *      news;                              /* The news server to use */
extern char * HTUserProfile_news (HTUserProfile * host);
extern BOOL HTUserProfile_setNews (HTUserProfile * host, const char * news);

    char *      tmp;                         /* Location for temporary files */
extern char * HTUserProfile_tmp (HTUserProfile * host);
extern BOOL HTUserProfile_setTmp (HTUserProfile * host, const char * tmp);

    time_t      timezone;                            /* Time zone in seconds */
extern time_t HTUserProfile_timezone (HTUserProfile * up);
extern BOOL HTUserProfile_setTimezone (HTUserProfile * up, time_t timezone);

    void *      context;                             /* Application specific */
extern void * HTUserProfile_context (HTUserProfile * up);
extern BOOL HTUserProfile_setContext (HTUserProfile * up, void * context);
};
</code>

===================================================================
??? libwww 如何处理 HTLib?
>>> 注意,实际上 HTLibInit 干的事儿很少,HTLibTerminate 倒是干的很多。
<code "HTLib.h" impl="HTLib.c">
extern BOOL HTLibInit (const char * AppName, const char * AppVersion);
extern BOOL HTLibTerminate (void);
</code>

<code "HTLib.c">
PRIVATE char * HTAppName = NULL;          /* Application name: please supply */
extern const char * HTLib_appName (void);
extern BOOL HTLib_setAppName (const char * name);

PRIVATE char * HTAppVersion = NULL;    /* Application version: please supply */
extern const char * HTLib_appVersion (void);
extern BOOL HTLib_setAppVersion (const char * version);

PRIVATE char * HTLibName = "libwww";
extern const char * HTLib_name (void);

PRIVATE char * HTLibVersion = W3C_VERSION;
extern const char * HTLib_version (void);

PRIVATE BOOL   HTSecure = NO;            /* Can we access local file system? */
extern BOOL HTLib_secure (void);
extern void HTLib_setSecure (BOOL mode);

PRIVATE BOOL   initialized = NO;
extern BOOL HTLib_isInitialized (void);

PRIVATE HTUserProfile * UserProfile = NULL;          /* Default user profile */
extern HTUserProfile * HTLib_userProfile (void);
extern BOOL HTLib_setUserProfile (HTUserProfile * up);

PUBLIC BOOL HTLibInit (const char * AppName, const char * AppVersion)
{
    HTTRACE(CORE_TRACE, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE/n");

    /* Set the application name and version */
    HTLib_setAppName(AppName);
    HTLib_setAppVersion(AppVersion);

    /* Initialize the timezone */
#ifdef HAVE_TZSET
    tzset();
#endif

    /* Create a default user profile and initialize it */
    UserProfile = HTUserProfile_new(HT_DEFAULT_USER, NULL);
    HTUserProfile_localize(UserProfile);

#ifdef WWWLIB_SIG
    /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting
    ** to a port where we should get `connection refused'. We ignore this
    ** using the following function call
    */
    HTSetSignal();                                 /* Set signals in library */
#endif

    initialized = YES;
    return YES;
}

PUBLIC BOOL HTLibTerminate (void)
{
    HTTRACE(CORE_TRACE, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE/n");

    /* 这八个单元是有全局结构的,应该对它们的初始化予以关注 */
    HTNet_killAll();
    HTHost_deleteAll();         /* Delete remaining hosts */
    HTChannel_deleteAll();                      /* Delete remaining channels */
    HTAtom_deleteAll();                                  /* Remove the atoms */
    HTDNS_deleteAll();                          /* Remove the DNS host cache */
    HTAnchor_deleteAll(NULL);           /* Delete anchors and drop hyperdocs */
    HTProtocol_deleteAll();  /* Remove bindings between access and protocols */
    HTUTree_deleteAll();                             /* Delete all URL Trees */

    HT_FREE(HTAppName);         /* Freed thanks to Wade Ogden <wade@ebt.com> */
    HT_FREE(HTAppVersion);
    HTUserProfile_delete(UserProfile);      /* Free our default User profile */

    initialized = NO;
    return YES;
}
</code>

===================================================================
??? libwww 如何处理 HTRequest?
>>> HTRequest 涉及三个文件,HTReq.h HTReqMan.h HTReqMan.c。
<code "HTReqMan.h" impl="HTReqMan.c">
struct _HTRequest {
    BOOL                internal;      /* Does the app knows about this one? */
extern BOOL HTRequest_setInternal (HTRequest * request, BOOL mode);
extern BOOL HTRequest_internal (HTRequest * request);

    time_t              date;      /* Time stamp when the request was issued */
extern time_t HTRequest_date  (HTRequest * request);
extern BOOL HTRequest_setDate (HTRequest * request, time_t date);

    HTMethod            method;
extern void HTRequest_setMethod (HTRequest *request, HTMethod method);
extern HTMethod HTRequest_method (HTRequest *request);

    BOOL                flush;                /* Should we flush immediately */
extern BOOL HTRequest_setFlush (HTRequest * me, BOOL mode);
extern BOOL HTRequest_flush (HTRequest * me);

    HTPriority          priority;               /* Priority for this request */
extern HTPriority HTRequest_priority (HTRequest * request);
extern BOOL HTRequest_setPriority (HTRequest * request, HTPriority priority);

#ifdef HT_EXT
    char *             messageBody;
extern BOOL HTRequest_setMessageBody (HTRequest * request, const char * body);
extern BOOL HTRequest_deleteMessageBody (HTRequest * request);
extern char * HTRequest_messageBody (HTRequest * request);

    long int           messageBodyLength;
extern BOOL HTRequest_setMessageBodyLength (HTRequest * request, long int len
gth);
extern long int HTRequest_messageBodyLength (HTRequest * request);

    HTFormat           messageBodyFormat;
extern BOOL HTRequest_setMessageBodyFormat (HTRequest * request, HTFormat for
mat);
extern HTFormat HTRequest_messageBodyFormat (HTRequest * request);
#endif
    HTUserProfile *     userprofile;
extern BOOL HTRequest_setUserProfile (HTRequest * request, HTUserProfile * up);
extern HTUserProfile * HTRequest_userProfile (HTRequest * request);

    HTNet *             net;                /* Information about socket etc. */
extern HTNet * HTRequest_net (HTRequest * request);
extern BOOL HTRequest_setNet (HTRequest * request, HTNet * net);

    HTResponse *        response;
extern HTResponse * HTRequest_response (HTRequest * request);
extern BOOL HTRequest_setResponse (HTRequest * request, HTResponse * response);

    HTList *            error_stack;                       /* List of errors */
extern HTList * HTRequest_error (HTRequest * request);
extern void HTRequest_setError  (HTRequest * request, HTList * list);
extern void HTRequest_deleteAllErrors (HTRequest * request);
extern BOOL HTRequest_addError (HTRequest *     request,
                                HTSeverity      severity,
                                BOOL            ignore,
                                int             element,
                                void *          par,
                                unsigned int    length,
                                char *          where);
extern BOOL HTRequest_addSystemError (HTRequest *       request,
                                      HTSeverity        severity,
                                      int               errornumber,
                                      BOOL              ignore,
                                      char *            syscall);

    int                 retrys;               /* Number of automatic reloads */
extern int HTRequest_retrys (HTRequest * request);
extern BOOL HTRequest_addRetry (HTRequest * request); /* increase by 1 */
extern BOOL HTRequest_doRetry (HTRequest *request); /* if needed */

    int                 max_forwards;
extern BOOL HTRequest_setMaxForwards (HTRequest * request, int maxforwards);
extern int HTRequest_maxForwards (HTRequest * request);

    int                 AAretrys;      /* Number of authentication retries */
extern int HTRequest_AAretrys (HTRequest * request);
extern BOOL HTRequest_addAARetry (HTRequest * request);

    BOOL                preemptive;
extern void HTRequest_setPreemptive (HTRequest *request, BOOL mode);
extern BOOL HTRequest_preemptive (HTRequest *request);

    BOOL                ContentNegotiation;
extern void HTRequest_setNegotiation (HTRequest *request, BOOL mode);
extern BOOL HTRequest_negotiation (HTRequest *request);

    HTPreconditions     preconditions;
extern void HTRequest_setPreconditions (HTRequest * me, HTPreconditions mode);
extern HTPreconditions HTRequest_preconditions (HTRequest * me);

    HTGnHd              GenMask;
extern void HTRequest_setGnHd (HTRequest *request, HTGnHd gnhd);
extern void HTRequest_addGnHd (HTRequest *request, HTGnHd gnhd);
extern HTGnHd HTRequest_gnHd (HTRequest *request);

    HTRsHd              ResponseMask;
extern void HTRequest_setRsHd (HTRequest * request, HTRsHd rshd);
extern void HTRequest_addRsHd (HTRequest * request, HTRsHd rshd);
extern HTRsHd HTRequest_rsHd (HTRequest * request);

    HTRqHd              RequestMask;
extern void HTRequest_setRqHd (HTRequest *request, HTRqHd rqhd);
extern void HTRequest_addRqHd (HTRequest *request, HTRqHd rqhd);
extern HTRqHd HTRequest_rqHd (HTRequest *request);

    HTEnHd              EntityMask;
extern void HTRequest_setEnHd (HTRequest *request, HTEnHd enhd);
extern void HTRequest_addEnHd (HTRequest *request, HTEnHd enhd);
extern HTEnHd HTRequest_enHd (HTRequest *request);

    HTMIMEParseSet *    parseSet;
    BOOL                pars_local;
extern void HTRequest_setMIMEParseSet (HTRequest *request,
                                       HTMIMEParseSet * parseSet, BOOL local);
extern HTMIMEParseSet * HTRequest_MIMEParseSet (HTRequest *request,
                                              BOOL * pLocal);

    HTList *            conversions;
    BOOL                conv_local;
extern void HTRequest_setConversion (HTRequest *request, HTList *type, BOOL o
verride);
extern HTList * HTRequest_conversion (HTRequest *request);

    HTList *            encodings;
    BOOL                enc_local;
extern void HTRequest_setEncoding (HTRequest *request, HTList *enc, BOOL over
ride);
extern HTList * HTRequest_encoding (HTRequest *request);

    HTList *            tes;
    BOOL                te_local;
extern void HTRequest_setTransfer (HTRequest *request, HTList *te, BOOL overr
ide);
extern HTList * HTRequest_transfer (HTRequest *request);

    HTList *            languages;
    BOOL                lang_local;
extern void HTRequest_setLanguage (HTRequest *request, HTList *lang, BOOL ove
rride);
extern HTList * HTRequest_language (HTRequest *request);

    HTList *            charsets;
    BOOL                char_local;
extern void HTRequest_setCharset (HTRequest *request, HTList *charset, BOOL o
verride);
extern HTList * HTRequest_charset (HTRequest *request);

    HTList *            befores;
    BOOL                befores_local;
extern BOOL HTRequest_addBefore (HTRequest * request, HTNetBefore * filter,
                                 const char * tmplate, void * param,
                                 HTFilterOrder order, BOOL override);
extern HTList * HTRequest_before (HTRequest * request, BOOL * override);
extern BOOL HTRequest_deleteBefore (HTRequest * request, HTNetBefore * filter);
extern BOOL HTRequest_deleteBeforeAll (HTRequest * request);

    HTList *            afters;
    BOOL                afters_local;
extern BOOL HTRequest_addAfter (HTRequest * request, HTNetAfter * filter,
                                const char * tmplate, void * param,
                                int status, HTFilterOrder order,
                                BOOL override);
extern HTList * HTRequest_after (HTRequest * request, BOOL * override);
extern BOOL HTRequest_deleteAfter (HTRequest * request, HTNetAfter * filter);
extern BOOL HTRequest_deleteAfterStatus (HTRequest * request, int status);
extern BOOL HTRequest_deleteAfterAll (HTRequest * request);

    char *              proxy;
extern BOOL HTRequest_setProxy    (HTRequest * request, const char * proxy);
extern char * HTRequest_proxy     (HTRequest * request);
extern BOOL HTRequest_deleteProxy (HTRequest * request); /* free(me->proxy) */

    BOOL                full_uri;
extern void HTRequest_setFullURI (HTRequest *request, BOOL mode);
extern BOOL HTRequest_fullURI (HTRequest *request);

    HTReload            reload;
extern void HTRequest_setReloadMode (HTRequest *request, HTReload mode);
extern HTReload HTRequest_reloadMode (HTRequest *request);

    HTAssocList *       cache_control;
extern BOOL HTRequest_addCacheControl        (HTRequest * request,
                                              char * token, char *value);
extern BOOL HTRequest_deleteCacheControlAll  (HTRequest * request);
extern HTAssocList * HTRequest_cacheControl  (HTRequest * request);

    char *              default_put_name;
extern char * HTRequest_defaultPutName (HTRequest * me);
extern BOOL HTRequest_setDefaultPutName (HTRequest * me, char * name);
extern BOOL HTRequest_deleteDefaultPutName (HTRequest * me);

    HTAssocList *       byte_ranges;
extern BOOL HTRequest_addRange       (HTRequest * request,
                                      char * unit, char * range);
extern BOOL HTRequest_deleteRangeAll (HTRequest * request);
extern HTAssocList * HTRequest_range (HTRequest * request);

    HTAssocList *       connection;
extern BOOL HTRequest_addConnection        (HTRequest * request,
                                            char * token, char * value);
extern BOOL HTRequest_deleteConnection     (HTRequest * request);
extern HTAssocList * HTRequest_connection  (HTRequest * request);

    HTAssocList *       expect;
extern BOOL HTRequest_addExpect (HTRequest * me,
                                 char * token, char * value);
extern BOOL HTRequest_deleteExpect (HTRequest * me);
extern HTAssocList * HTRequest_expect (HTRequest * me);

    char *              realm;                              /* Current realm */
extern BOOL HTRequest_setRealm (HTRequest * request, char * realm);
extern const char * HTRequest_realm (HTRequest * request);
extern BOOL HTRequest_deleteRealm (HTRequest * me);

    HTAssocList *       credentials;       /* Credentials received by server */
extern BOOL HTRequest_addCredentials       (HTRequest * request,
                                            char * token, char * value);
extern BOOL HTRequest_deleteCredentialsAll (HTRequest * request);
extern HTAssocList * HTRequest_credentials (HTRequest * request);

    HTAssocList *       extra_headers;
extern BOOL HTRequest_addExtraHeader       (HTRequest * request,
                                            char * token, char * value);
extern HTAssocList * HTRequest_extraHeader (HTRequest * request);
extern BOOL HTRequest_deleteExtraHeaderAll (HTRequest * request);

    HTList *            generators;
    BOOL                gens_local;
extern void HTRequest_setGenerator (HTRequest *request, HTList *gens,
                                    BOOL override);
extern HTList * HTRequest_generator (HTRequest *request, BOOL *override);

    HTAssocList *       mandatory; /* 有实现而无声明 */
PUBLIC BOOL HTRequest_addMandatory (HTRequest * me,
                                    char * token, char * value)
PUBLIC HTAssocList * HTRequest_mandatory (HTRequest * me)
PUBLIC BOOL HTRequest_deleteMandatoryAll (HTRequest * me)

    HTAssocList *       optional; /* 有实现而无声明 */
PUBLIC BOOL HTRequest_addOptional (HTRequest * me,
                                   char * token, char * value)
PUBLIC HTAssocList * HTRequest_optional (HTRequest * me)
PUBLIC BOOL HTRequest_deleteOptionalAll (HTRequest * me)

    HTParentAnchor *    anchor;        /* The Client anchor for this request */
    HTChildAnchor *     childAnchor;        /* For element within the object */
extern void HTRequest_setAnchor (HTRequest *request, HTAnchor *anchor);
extern HTParentAnchor * HTRequest_anchor (HTRequest *reques

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值