A mirror for tinyhttpd(Tinyhttpd非官方镜像,Fork 自sourceForge,仅供学习)
测试 CGI 时需要本机安装 PERL,同时安装 perl-cgi
Compile for Linux
To compile for Linux:
1) Comment out the #include <pthread.h> line.
2) Comment out the line that defines the variable newthread.
3) Comment out the two lines that run pthread_create().
4) Uncomment the line that runs accept_request().
5) Remove -lsocket from the Makefile.
void error_die(const char *); // 异常信息写到perror并退出
int get_line(int, char *, int); // 读取request headers的一行,把回车换行等情况都统一为换行符结束
void cat(int, FILE *); // 读取server上的一个文件,写到client socket
void serve_file(int, const char *); // 调用响应头并调用cat函数,将server上的文件发给client
void headers(int, const char *); // 构造200 OK的响应头部,写到套接字
void bad_request(int); // 返回给客户端一个400 BAD REQUEST响应报文
void not_found(int); // 返回给客户端一个404 NOT FOUND响应报文
void cannot_execute(int); // 返回给客户端一个500 Internal Server Error响应报文,主要处理发生在执行 CGI 程序时出现的错误
void unimplemented(int); // 返回给客户端一个501 Method Not Implemented响应报文,表明httpd服务器不支持该方法
int startup(u_short *); // 建立HTTP服务,包括创建套接字、绑定端口、监听客户端等
void *accept_request(void *); // 处理server监听到的client socket的一个HTTP请求,在这里体现了服务器处理请求的流程
void execute_cgi(int, const char *, const char *, const char *); // 执行CGI脚本程序,核心执行函数建议源码阅读顺序:
main -> startup -> accept_request -> execute_cgi,通晓主要工作流程后,再仔细把每个函数的源码看一看。
整体执行流程图(对应博客)如下:
-
【setup函数】服务器启动,在指定端口或随机选取端口绑定 httpd 服务。
-
【main函数死循环】收到一个 HTTP 请求报文时(其实就是 listen 的端口 accpet 的时候),派生一个线程运行 accept_request 函数。
-
【accept_request函数】取出 HTTP 请求报文的请求行中的 method (GET 或 POST) 和 url。
- 对于 GET 方法,如果有携带参数,则 query_string 指针指向 url 中 ? 后面的 GET 参数。
- 格式化 url 到 path 数组,path 表示浏览器请求的服务器文件路径(在 tinyhttpd 中服务器文件位于 htdocs 文件夹下)。当 url 以 / 结尾,或 url 是个目录,则默认在 path 中加上 index.html,表示访问主页。
- 如果文件路径合法,对于无参数的 GET 请求,直接输出服务器文件到浏览器,即用 HTTP 格式写到套接字上,跳到流程 10。其他情况(带参数 GET、POST 方式,url 为可执行文件),则调用 excute_cgi 函数执行 cgi 脚本。
-
【excute_cgi函数】读取整个 HTTP 请求头并丢弃,如果是 POST 则找出 Content-Length 的值并放到环境变量中(后续 POST 请求使用)。然后,把 HTTP 200 状态码写到套接字。建立两个管道,cgi_input 和 cgi_output,并 fork 一个子进程。
- 在子进程中,把 STDOUT 重定向到 cgi_output 的写入端,把 STDIN 重定向到 cgi_input 的读取端,关闭 cgi_input 的写入端 和 cgi_output 的读取端。然后,设置 request_method 环境变量,GET 的话设置 query_string 环境变量,POST 的话设置 content_length 环境变量,这些环境变量都是为了给 cgi 脚本调用,接着调用 execl 运行 cgi 程序。
- 在父进程中,关闭 cgi_input 的读取端和 cgi_output 的写入端。如果 POST 的话,把 POST 数据写入 cgi_input,已被重定向到 STDIN,读取 cgi_output 管道的输出到客户端,该管道输入是 STDOUT。接着关闭所有管道,等待子进程结束。这一部分比较乱,见“httpd 执行流程图”的管道流向状态图。
-
关闭与浏览器的连接,完成了一次 HTTP 请求与响应,因为 HTTP 是无连接的。
以下内容来自源作者:
This software is copyright 1999 by J. David Blackstone. Permission is granted to redistribute and modify this software under the terms of the GNU General Public License, available at http://www.gnu.org/ .
If you use this software or examine the code, I would appreciate knowing and would be overjoyed to hear about it at [email protected] .
This software is not production quality. It comes with no warranty of any kind, not even an implied warranty of fitness for a particular purpose. I am not responsible for the damage that will likely result if you use this software on your computer system.
I wrote this webserver for an assignment in my networking class in 1999. We were told that at a bare minimum the server had to serve pages, and told that we would get extra credit for doing "extras." Perl had introduced me to a whole lot of UNIX functionality (I learned sockets and fork from Perl!), and O'Reilly's lion book on UNIX system calls plus O'Reilly's books on CGI and writing web clients in Perl got me thinking and I realized I could make my webserver support CGI with little trouble.
Now, if you're a member of the Apache core group, you might not be impressed. But my professor was blown over. Try the color.cgi sample script and type in "chartreuse." Made me seem smarter than I am, at any rate. :)
Apache it's not. But I do hope that this program is a good educational tool for those interested in http/socket programming, as well as UNIX system calls. (There's some textbook uses of pipes, environment variables, forks, and so on.)
One last thing: if you look at my webserver or (are you out of mind?!?) use it, I would just be overjoyed to hear about it. Please email me. I probably won't really be releasing major updates, but if I help you learn something, I'd love to know!
Happy hacking!
J. David Blackstone
