├── www
├── 1.txt
├── index.html
├── c.py
├── 手册.txt
└── index.py
├── LightCgiServer
├── README.md
├── .gitignore
├── LICENSE
├── LightCgiServer.h
├── tags
└── LightCgiServer.c
/www/1.txt:
--------------------------------------------------------------------------------
1 | hello world
2 |
--------------------------------------------------------------------------------
/LightCgiServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imyouxia/LightCgiServer/HEAD/LightCgiServer
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LightCgiServer
2 | ==============
3 |
4 | 使用Posix C 编写的轻量级CGI服务器。
5 |
6 | 编译:
7 |
8 | gcc -Wall -g LightCgiServer.c -o LightCgiServer
9 |
10 |
11 |
--------------------------------------------------------------------------------
/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Welcome!
5 |
6 |
7 | Welcome!
8 | If you are seeing this, it's because you've successfully built klange's Simple CGI Server!
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 | *.obj
5 | *.elf
6 |
7 | # Libraries
8 | *.lib
9 | *.a
10 |
11 | # Shared objects (inc. Windows DLLs)
12 | *.dll
13 | *.so
14 | *.so.*
15 | *.dylib
16 |
17 | # Executables
18 | *.exe
19 | *.out
20 | *.app
21 | *.i*86
22 | *.x86_64
23 | *.hex
24 |
--------------------------------------------------------------------------------
/www/c.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | print "Content-type:text/html\r\n\r\n"
4 | print ''
5 | print ''
6 | print 'Hello Word - First CGI Program'
7 | print ''
8 | print ''
9 | print 'Hello Word! This is my first CGI program
'
10 | print ''
11 | print ''
12 |
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 imyouxia
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/www/手册.txt:
--------------------------------------------------------------------------------
1 | 一、操作系统是Ubuntu下的操作步骤
2 | 1.net-snmp的安装
3 | (1)tar xzvf net-snmp-5.7.2.tar.gz
4 | (2)cd net-snmp-5.7.2
5 | (3)安装依赖环境
6 | sudo apt-get install libperl-dev
7 | (4)配置net-snmp
8 | ./configure –prefix=/usr/local/snmp –with-mib-modules=ucd-snmp/diskio
9 | (5)编译并安装
10 | make
11 | sudo make install
12 | (6)配置文件 snmpd.conf
13 | sudo cp EXAMPLE.conf /usr/local/snmp/share/snmp/snmpd.conf
14 | (7)sudo apt-get install snmpd
15 | (8)service snmp restart
16 |
17 | 2.libmysql的安装
18 | (1)安装mysql服务端:sudo apt-get install mysql-server
19 | (2)安装Mysql客户端:sudo apt-get install mysql-client
20 | (3)安装Mysql开发工具:sudo apt-get install libmysqlclient-dev
21 | (4)sudo ldconfig -v
22 |
23 | 3.cron定时任务
24 | vim /etc/crontab之后输入
25 | 0 1 * * * findtopo位置/findtopo
26 |
27 |
28 | 二、操作系统是Centos下的操作步骤
29 |
30 | 1.net-snmp的安装
31 | (1)tar xzvf net-snmp-5.7.2.tar.gz
32 | (2)cd net-snmp-5.7.2
33 | (3)配置net-snmp
34 | ./configure --prefix=/usr/local/snmp –with-mib-modules=ucd-snmp/diskio
35 | (4)编译并安装
36 | make
37 | make install
38 | (5)配置文件 snmpd.conf
39 | sudo cp EXAMPLE.conf /usr/local/snmp/share/snmp/snmpd.conf
40 | (6)service snmpd restart
41 |
42 | 2.libmysql的安装
43 | 64位系统:
44 | rpm -ivh mysql-connector-c-devel-6.1.1-1.linux_glibc2.5.x86_64.rpm
45 | rpm -ivh mysql-connector-c-shared-6.1.1-1.linux_glibc2.5.x86_64.rpm
46 | 32位系统:
47 | rpm -ivh mysql-connector-c-devel-6.1.1-1.linux_glibc2.5.i386.rpm
48 | rpm -ivh mysql-connector-c-shared-6.1.1-1.linux_glibc2.5.i386.rpm
49 |
50 | service mysql start
51 |
52 | 3.cron定时任务
53 | 1.安装crontab
54 | yum install vixie-cron
55 | yum install crontabs
56 |
57 | 2.设置cron开机启动
58 | service crond restart
59 | chkconfig –-level 35 crond on
60 |
61 | 0 1 * * * findtopo位置/findtopo
62 |
63 |
64 |
--------------------------------------------------------------------------------
/www/index.py:
--------------------------------------------------------------------------------
1 | import string,cgi,time
2 | from os import curdir, sep
3 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
4 |
5 | class MyHandler(BaseHTTPRequestHandler):
6 |
7 | def do_GET(self):
8 | try:
9 | if self.path.endswith(".html") or self.path.endswith(".txt"):
10 | f = open(curdir + sep + self.path) #self.path /index.html
11 | self.send_response(200)
12 | self.send_header('Content-type', 'text/html')
13 | self.end_headers()
14 | self.wfile.write(f.read())
15 | f.close()
16 | return
17 | if self.path.endswith(".py"):
18 | f = open(curdir + sep + self.path)
19 | self.send_response(200)
20 | self.send_header('Content-type', 'text/html')
21 | self.end_headers()
22 | self.wfile.write(f.read())
23 | f.close()
24 | return
25 | if self.path.endswith(".sth"): #dynamic
26 | self.send_response(200)
27 | self.send_header('Content-type', 'text/html')
28 | self.end_headers()
29 | self.wfile.write("today " + str(time.localtime()[7]))
30 | self.wfile.write("year " + str(time.localtime()[0]))
31 | return
32 |
33 | return
34 |
35 | except IOError:
36 | self.send_error(404,'File Not Found: %s' % self.path)
37 |
38 |
39 | def do_POST(self):
40 | global rootnode
41 | try:
42 | ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
43 | if ctype == 'multipart/form-data':
44 | query=cgi.parse_multipart(self.rfile, pdict)
45 | self.send_response(301)
46 |
47 | self.end_headers()
48 | upfilecontent = query.get('upfile')
49 | print "filecontent", upfilecontent[0]
50 | self.wfile.write("POST OK.
");
51 | self.wfile.write(upfilecontent[0]);
52 |
53 | except :
54 | pass
55 |
56 | def main():
57 | try:
58 | server = HTTPServer(('', 8080), MyHandler)
59 | print 'started httpserver...'
60 | server.serve_forever()
61 | except KeyboardInterrupt:
62 | print '^C received, shutting down server'
63 | server.socket.close()
64 |
65 | if __name__ == '__main__':
66 | main()
67 |
--------------------------------------------------------------------------------
/LightCgiServer.h:
--------------------------------------------------------------------------------
1 | #ifndef LightCgiServer_H_
2 | #define LightCgiServer_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | struct socket_request
21 | {
22 | int fd; //socket 文件描述符
23 | struct sockaddr_in remote_addr; //远程连接地址
24 | pthread_t thread; //线程
25 | };
26 |
27 | typedef struct _queue
28 | {
29 | void **buf;
30 | unsigned int size;
31 | unsigned int allSize;
32 | }queue_t;
33 |
34 |
35 | // Request Variables
36 | typedef struct _request_h
37 | {
38 | char* filename; //Filename was received(ie,/index.html)
39 | char* querystring; //Query String,URL Encoded
40 | int request_type; //Request type,GET = 0,POST = 1,HEAD = 2...
41 | char* _filename; //FileName relative to server
42 | char* ext; //Extension for requested file
43 | char* host; //Hostname for request
44 | char* http_version; //HTTP version used in request
45 | unsigned long c_length; //Content-Type,usually for POST
46 | char* c_type; //Content-Type,usually for POST
47 | char* c_cookie; //HTTP_COOKIE
48 | char* c_uagent; //User-Agent,for cgi
49 | char* c_referer; //Referer,for cgi
50 | }request_h;
51 |
52 | struct cgi_data
53 | {
54 | int fd; // 读描述符
55 | int fd2; // 写描述符
56 | int pid; // Process ID
57 | };
58 |
59 | #define PORT 80 //定义服务器默认端口号
60 | #define HEADER_SIZE 10240//request请求头的最大字节
61 | #define QUEUE_SIZE 1024 //队列个数
62 | #define CGI_POST 10240 //动态脚本传送的数据
63 | #define HTML_SIZE 10240 //HTML文本最大字节
64 | #define PAGES "www" //HTML文件目录
65 |
66 |
67 | void handleSignal(int sigNo);
68 | void disconnect(struct socket_request* socket,FILE *fd,request_h* request_header);
69 | queue_t* alloc_queue();
70 | void queue_append(queue_t* queue,void* value);
71 | unsigned int queue_size(queue_t* queue);
72 | void free_queue(queue_t* queue);
73 | void* queue_at(queue_t* queue,unsigned int id);
74 | void delete_queue(queue_t* queue);
75 | char from_hex(char c);
76 | void generic_response(FILE* fd,char* status,char* message);
77 | void* wait_pid(void* data);
78 | void unsupport(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header);
79 | int processHeader(struct socket_request* socket,queue_t* queue,FILE* fd,int* type_width,request_h* request_header);
80 | int request_file(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header);
81 | int set_env(struct socket_request* socket,queue_t* queue,request_h* request_header);
82 | int check_dir(FILE* fd,request_h* request_header,struct stat* Stats);
83 | int determine_mime(queue_t* queue,FILE* fd,FILE* content,request_h* request_header);
84 | void pipe_trans(queue_t* queue,FILE* fd,FILE* cgi_w,request_h* request_header);
85 | int read_header(struct socket_request* socket,queue_t* queue,FILE* fd,FILE* cgi_r,request_h* request_header,pthread_t* waitthread);
86 | int parse_html(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header);
87 | int readRequest(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header);
88 | void* handleRequest(void* socket);
89 |
90 | #endif
91 |
92 |
--------------------------------------------------------------------------------
/tags:
--------------------------------------------------------------------------------
1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
4 | !_TAG_PROGRAM_NAME Exuberant Ctags //
5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
6 | !_TAG_PROGRAM_VERSION 5.9~svn20110310 //
7 | CGI_POST LightCgiServer.h 62;" d
8 | HEADER_SIZE LightCgiServer.h 60;" d
9 | HTML_SIZE LightCgiServer.h 63;" d
10 | LightCgiServer_H_ LightCgiServer.h 2;" d
11 | PAGES LightCgiServer.h 64;" d
12 | PORT LightCgiServer.h 59;" d
13 | QUEUE_SIZE LightCgiServer.h 61;" d
14 | _filename LightCgiServer.h /^ char* _filename; \/\/FileName relative to server$/;" m struct:_request_h
15 | _queue LightCgiServer.h /^typedef struct _queue$/;" s
16 | _request_h LightCgiServer.h /^typedef struct _request_h$/;" s
17 | allSize LightCgiServer.h /^ unsigned int allSize;$/;" m struct:_queue
18 | alloc_queue LightCgiServer.c /^queue_t* alloc_queue()$/;" f
19 | buf LightCgiServer.h /^ void **buf;$/;" m struct:_queue
20 | c_cookie LightCgiServer.h /^ char* c_cookie; \/\/HTTP_COOKIE$/;" m struct:_request_h
21 | c_length LightCgiServer.h /^ unsigned long c_length; \/\/Content-Type,usually for POST$/;" m struct:_request_h
22 | c_referer LightCgiServer.h /^ char* c_referer; \/\/Referer,for cgi$/;" m struct:_request_h
23 | c_type LightCgiServer.h /^ char* c_type; \/\/Content-Type,usually for POST$/;" m struct:_request_h
24 | c_uagent LightCgiServer.h /^ char* c_uagent; \/\/User-Agent,for cgi$/;" m struct:_request_h
25 | cgi_data LightCgiServer.h /^struct cgi_data$/;" s
26 | check_dir LightCgiServer.c /^int check_dir(FILE* fd,request_h* request_header,struct stat* Stats)$/;" f
27 | delete_queue LightCgiServer.c /^void delete_queue(queue_t* queue)$/;" f
28 | determine_mime LightCgiServer.c /^int determine_mime(queue_t* queue,FILE* fd,FILE* content,request_h* request_header)$/;" f
29 | disconnect LightCgiServer.c /^void disconnect(struct socket_request *socket,FILE *fd,request_h* request_header)$/;" f
30 | ext LightCgiServer.h /^ char* ext; \/\/Extension for requested file$/;" m struct:_request_h
31 | fd LightCgiServer.h /^ int fd; \/\/ 读描述符$/;" m struct:cgi_data
32 | fd LightCgiServer.h /^ int fd; \/\/socket 文件描述符$/;" m struct:socket_request
33 | fd2 LightCgiServer.h /^ int fd2; \/\/ 写描述符$/;" m struct:cgi_data
34 | filename LightCgiServer.h /^ char* filename; \/\/Filename was received(ie,\/index.html)$/;" m struct:_request_h
35 | free_queue LightCgiServer.c /^void free_queue(queue_t* queue)$/;" f
36 | from_hex LightCgiServer.c /^char from_hex(char c)$/;" f
37 | generic_response LightCgiServer.c /^void generic_response(FILE* fd,char* status,char* message)$/;" f
38 | handleRequest LightCgiServer.c /^void *handleRequest(void *socket)$/;" f
39 | handleSignal LightCgiServer.c /^void handleSignal(int sigNo)$/;" f
40 | host LightCgiServer.h /^ char* host; \/\/Hostname for request$/;" m struct:_request_h
41 | http_version LightCgiServer.h /^ char* http_version; \/\/HTTP version used in request$/;" m struct:_request_h
42 | main LightCgiServer.c /^int main(int argc,char *argv[])$/;" f
43 | parse_html LightCgiServer.c /^int parse_html(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)$/;" f
44 | pid LightCgiServer.h /^ int pid; \/\/ Process ID$/;" m struct:cgi_data
45 | pipe_trans LightCgiServer.c /^void pipe_trans(queue_t* queue,FILE* fd,FILE* cgi_w,request_h* request_header)$/;" f
46 | port LightCgiServer.c /^int port; \/\/默认端口$/;" v
47 | processHeader LightCgiServer.c /^int processHeader(struct socket_request* socket,queue_t* queue,FILE* fd,int* type_width,request_h* request_header)$/;" f
48 | querystring LightCgiServer.h /^ char* querystring; \/\/Query String,URL Encoded$/;" m struct:_request_h
49 | queue_append LightCgiServer.c /^void queue_append(queue_t *queue,void *value)$/;" f
50 | queue_at LightCgiServer.c /^void *queue_at(queue_t* queue,unsigned int id)$/;" f
51 | queue_size LightCgiServer.c /^unsigned int queue_size(queue_t* queue)$/;" f
52 | queue_t LightCgiServer.h /^}queue_t;$/;" t typeref:struct:_queue
53 | readRequest LightCgiServer.c /^int readRequest(struct socket_request* socket,queue_t* queue,FILE *fd,request_h* request_header)$/;" f
54 | read_header LightCgiServer.c /^int read_header(struct socket_request* socket,queue_t* queue,FILE* fd,FILE* cgi_r,request_h* request_header,pthread_t* waitthread)$/;" f
55 | remote_addr LightCgiServer.h /^ struct sockaddr_in remote_addr; \/\/远程连接地址$/;" m struct:socket_request typeref:struct:socket_request::sockaddr_in
56 | request_file LightCgiServer.c /^int request_file(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)$/;" f
57 | request_h LightCgiServer.h /^}request_h;$/;" t typeref:struct:_request_h
58 | request_type LightCgiServer.h /^ int request_type; \/\/Request type,GET = 0,POST = 1,HEAD = 2...$/;" m struct:_request_h
59 | set_env LightCgiServer.c /^int set_env(struct socket_request* socket,queue_t* queue,request_h* request_header)$/;" f
60 | size LightCgiServer.h /^ unsigned int size;$/;" m struct:_queue
61 | socket_request LightCgiServer.h /^struct socket_request$/;" s
62 | sockfd LightCgiServer.c /^int sockfd; \/\/socket$/;" v
63 | thread LightCgiServer.h /^ pthread_t thread; \/\/线程$/;" m struct:socket_request
64 | unsupport LightCgiServer.c /^void unsupport(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)$/;" f
65 | wait_pid LightCgiServer.c /^void* wait_pid(void* data)$/;" f
66 |
--------------------------------------------------------------------------------
/LightCgiServer.c:
--------------------------------------------------------------------------------
1 | #include "LightCgiServer.h"
2 |
3 |
4 | int port; //默认端口
5 | int sockfd; //socket
6 |
7 | // SIGINT信号处理函数
8 | void handleSignal(int sigNo)
9 | {
10 | printf("Shutting down the Server!\n");
11 | //终止sock通信的读取和传送操作
12 | shutdown(sockfd,2);
13 | close(sockfd);
14 | exit(sigNo);
15 | }
16 |
17 | // 链接终止,释放内存
18 | void disconnect(struct socket_request *socket,FILE *fd,request_h* request_header)
19 | {
20 | struct socket_request *request = socket;
21 | if(fd)
22 | {
23 | fclose(fd);
24 | }
25 |
26 | // 终止读取和传送操作
27 | shutdown(request->fd,2);
28 |
29 | // 将子线程的状态设置为detached,则该线程运行结束后将自动释放所有资源
30 | if(request->thread)
31 | {
32 | pthread_detach(request->thread);
33 | }
34 |
35 | free(request_header);
36 | free(request);
37 |
38 | }
39 |
40 | // 将request header依次放到队列里,初始化队列
41 | queue_t* alloc_queue()
42 | {
43 | queue_t* queue = (queue_t*)malloc(sizeof(struct _queue));
44 | queue->buf = (void **)malloc(QUEUE_SIZE * sizeof(void *));
45 | queue->size = 0;
46 | queue->allSize = QUEUE_SIZE;
47 |
48 | return queue;
49 | }
50 |
51 | // 将请求添加到队列中
52 | void queue_append(queue_t *queue,void *value)
53 | {
54 | if(queue->size == queue->allSize)
55 | {
56 | queue->allSize = queue->allSize * 2; //如果队列满了,则2倍空间重新分配内存
57 | queue->buf = (void **)realloc(queue->buf,queue->allSize * sizeof(void*));
58 | }
59 | queue->buf[queue->size] = value;
60 | queue->size++;
61 | }
62 |
63 | // 目前队列里request headers的个数
64 | unsigned int queue_size(queue_t* queue)
65 | {
66 | return queue->size;
67 | }
68 |
69 | // 释放队列和队列里申请的内存
70 | void free_queue(queue_t* queue)
71 | {
72 | //free(queue->buf);
73 | free(queue);
74 | }
75 |
76 | // 返回队列里指定第id个request header
77 | void *queue_at(queue_t* queue,unsigned int id)
78 | {
79 | if(id >= queue->size)
80 | {
81 | return NULL;
82 | }
83 | return queue->buf[id];
84 |
85 | }
86 |
87 | // 释放队列内容
88 | void delete_queue(queue_t* queue)
89 | {
90 | unsigned int i;
91 | for(i = 0; i < queue_size(queue);++i)
92 | {
93 | free(queue_at(queue,i));
94 | }
95 |
96 | free_queue(queue);
97 | }
98 |
99 | // 将十六进制数,比如b转为对应的数11
100 | char from_hex(char c)
101 | {
102 | return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10;
103 | }
104 |
105 | // 将Response格式化输出到fd
106 | void generic_response(FILE* fd,char* status,char* message)
107 | {
108 | fprintf(fd,"HTTP/1.1 %s\r\n"
109 | "Content-Type: text/plain\r\n"
110 | "Content-Length: %d\r\n"
111 | "\r\n"
112 | "%s\r\n",status,strlen(message),message);
113 | }
114 |
115 | // 关闭管道并且等待子进程,防止产生僵尸进程
116 | void* wait_pid(void* data)
117 | {
118 | struct cgi_data* cgi_d = (struct cgi_data*)data;
119 | // 等待进程号为cgi->pid子进程完成,防止产生僵尸进程
120 | int status;
121 | waitpid(cgi_d->pid,&status,0);
122 |
123 | // 关闭管道
124 | close(cgi_d->fd);
125 | close(cgi_d->fd2);
126 | return NULL;
127 | }
128 |
129 | // 不支持的HTTP方法请求处理
130 | void unsupport(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)
131 | {
132 | generic_response(fd,"501 Not Implemented","Not implemented: The request type was not understood by the server.\n");
133 | delete_queue(queue);
134 | disconnect(socket,fd,request_header);
135 | }
136 |
137 | // 处理request header,判断请求类型
138 | int processHeader(struct socket_request* socket,queue_t* queue,FILE* fd,int* type_width,request_h* request_header)
139 | {
140 | unsigned int i;
141 | for(i = 0; i < queue_size(queue); ++i)
142 | {
143 | char *str = (char*)(queue_at(queue,i));
144 | //查找header里的:
145 | char* colon = strstr(str,": ");
146 | // 如果不存在: 且不为第一行,则处理请求方式
147 | if(!colon)
148 | {
149 | // 处理Reqest Line
150 | if(i > 0)
151 | {
152 | generic_response(fd,"400 Bad Request","Bad Request: A header line was missing colon.");
153 | delete_queue(queue);
154 | disconnect(socket,fd,request_header);
155 | return -1;
156 | }
157 | // 根据首字节,判断HTTP 请求方式,即GET,POST等等
158 | switch(str[0])
159 | {
160 | case 'G':
161 | if(strstr(str,"GET ") == str)
162 | {
163 | *type_width = 4;
164 | request_header->request_type = 1;
165 | }
166 | else
167 | {
168 | // 没有发现GET 类型,跳到不支持的类型处理函数,下同理
169 | unsupport(socket,queue,fd,request_header);
170 | return -1;
171 | }
172 | break;
173 | case 'P':
174 | if(strstr(str,"POST ") == str)
175 | {
176 | // POST 加上空格,为5个字节,向后移动5字节,下同
177 | *type_width = 5;
178 | request_header->request_type = 2;
179 | }
180 | else
181 | {
182 | unsupport(socket,queue,fd,request_header);
183 | return -1;
184 | }
185 | break;
186 | case 'H':
187 | if(strstr(str,"HEAD ") == str)
188 | {
189 | *type_width = 5;
190 | request_header->request_type = 3;
191 | }
192 | else
193 | {
194 | unsupport(socket,queue,fd,request_header);
195 | }
196 | break;
197 | default:
198 | unsupport(socket,queue,fd,request_header);
199 | return -1;
200 | //break;
201 | }
202 |
203 | // 向后移动字节
204 | request_header->filename = str + (*type_width);
205 |
206 | // 网站首页一般为 '\',其他为网址后的URI
207 | if(request_header->filename[0] == ' ' || request_header->filename[0] == '\r' || request_header->filename[0] == '\n')
208 | {
209 | generic_response(fd,"400 Bad Request","Bad Request: No File.\n");
210 | delete_queue(queue);
211 | disconnect(socket,fd,request_header);
212 | return -1;
213 | }
214 |
215 | // 判断HTTP的版本,有HTTP 1.0 和 HTTP1.1,现在多为1.1版本
216 | request_header->http_version = strstr(request_header->filename,"HTTP/");
217 | if(!(request_header->http_version))
218 | {
219 | // No Http Version
220 | generic_response(fd,"400 Bad Request","Bad Request: No HTTP Version.\n");
221 | delete_queue(queue);
222 | disconnect(socket,fd,request_header);
223 | return -1;
224 | }
225 |
226 | // 得到filename的值
227 | request_header->http_version[-1] = '\0';
228 | char *tmp;
229 | tmp = strstr(request_header->http_version,"\r\n");
230 | if(tmp)
231 | {
232 | tmp[0] = '\0';
233 | }
234 | tmp = strstr(request_header->http_version,"\n");
235 | if(tmp)
236 | {
237 | tmp[0] = '\0';
238 | }
239 |
240 | //获取查询的字符串,如http://xxx.com/?s=python
241 | request_header->querystring = strstr(request_header->filename,"?");
242 | if(request_header->querystring)
243 | {
244 | request_header->querystring++;
245 | request_header->querystring[-1] = '\0';
246 | }
247 | }
248 | else
249 | {
250 | // 如果第一行请求出现:,表示出错
251 | if(i == 0)
252 | {
253 | // Request Line 错误
254 | generic_response(fd,"400 Bad Request","Bad Request: First Line was not a Correct Request.\n");
255 | delete_queue(queue);
256 | disconnect(socket,fd,request_header);
257 | return -1;
258 | }
259 | // 处理header,指针移动向后移动两位,指向header各响应值
260 | colon[0] = '\0';
261 | colon = colon + 2;
262 |
263 | // 判断是否包含此请求类型
264 | if(strcmp(str,"Host") == 0)
265 | {
266 | request_header->host = colon;
267 | }
268 | else if(strcmp(str,"Content-Type") == 0)
269 | {
270 | // MIME-Type Message
271 | request_header->c_type = colon;
272 | }
273 | else if(strcmp(str,"Cookie") == 0)
274 | {
275 | request_header->c_cookie = colon;
276 | }
277 | else if(strcmp(str,"User-Agent") == 0)
278 | {
279 | request_header->c_uagent = colon;
280 | }
281 | else if(strcmp(str,"Content-Length") == 0)
282 | {
283 | request_header->c_length = atol(colon);
284 | }
285 | else if(strcmp(str,"Referer") == 0)
286 | {
287 | request_header->c_referer = colon;
288 | }
289 |
290 | }
291 |
292 | }
293 |
294 | // 如果HTTP请求类型不存在
295 | if(!(request_header->request_type))
296 | {
297 | unsupport(socket,queue,fd,request_header);
298 | return -1;
299 | }
300 | return 0;
301 | }
302 |
303 | // 解析文件和URL编码
304 | int request_file(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)
305 | {
306 | // 如果请求地址URI为空,或者包含' 空格等特殊字符,则请求失败
307 | //printf("%s\n %s\n",request_header->querystring,request_header->filename);
308 | if(!(request_header->filename) || strstr(request_header->filename,"'") || strstr(request_header->filename," ") || (request_header->querystring && strstr(request_header->querystring," ")))
309 | {
310 | generic_response(fd,"400 Bad Request","Bad Request: Filename was Error!");
311 | delete_queue(queue);
312 | disconnect(socket,fd,request_header);
313 | return -1;
314 | }
315 |
316 | request_header->_filename = calloc(sizeof(char) * (strlen(PAGES) + strlen(request_header->filename) + 2),1);
317 | // 连接pages + 文件名,strcat返回首地址
318 | strcat(request_header->_filename,PAGES);
319 | strcat(request_header->_filename,request_header->filename);
320 |
321 | // 如果文件名+目录里包含 % 字符,表示为中文,需要作URL解码
322 | if(strstr(request_header->_filename,"%"))
323 | {
324 | char buf[1024] = {0};
325 | char *pstr = request_header->_filename;
326 | char *pbuf = buf;
327 | while(*pstr)
328 | {
329 | if(*pstr == '%')
330 | {
331 | if(pstr[1] && pstr[2])
332 | {
333 | *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
334 | pstr += 2;
335 | }
336 | }
337 | else if(*pstr == '+')
338 | {
339 | *pbuf++ = ' ';
340 | }
341 | else
342 | {
343 | *pbuf++ = *pstr;
344 | }
345 | pstr++;
346 | }
347 | *pbuf = '\0';
348 | request_header->_filename = (char*)buf;
349 | }
350 | //printf("request_header->filename:%s\n",request_header->filename);
351 | // 获取文件后缀
352 | request_header->ext = request_header->filename + 1;
353 | // 循环得出最后的文件后缀开始
354 | while(strstr(request_header->ext + 1,"."))
355 | {
356 | request_header->ext = strstr(request_header->ext + 1,".");
357 | }
358 | if(request_header->ext == request_header->filename + 1)
359 | {
360 |
361 | request_header->ext = NULL;
362 | }
363 |
364 | return 0;
365 | }
366 |
367 | // 设置CGI环境变量
368 | int set_env(struct socket_request* socket,queue_t* queue,request_h* request_header)
369 | {
370 | if(!(request_header->host))
371 | {
372 | char hostname[1024];
373 | gethostname(hostname,sizeof(hostname));
374 | setenv("SERVER_NAME",hostname,1);
375 | setenv("HTTP_HOST",hostname,1);
376 | }
377 | else
378 | {
379 | setenv("SERVER_NAME",request_header->host,1);
380 | setenv("HTTP_HOST",request_header->host,1);
381 | }
382 | setenv("GATEWAY_INTERFACE","CGI/1.0",1);
383 | setenv("SERVER_PROTOCOL","HTTP/1.1",1);
384 | char c_port[20];
385 | sprintf(c_port,"%d",port);
386 | setenv("SERVER_PORT",c_port,1);
387 | // 设置请求类型
388 | if(request_header->request_type == 1)
389 | {
390 | setenv("REQUEST_METHOD","GET",1);
391 | }
392 | else if(request_header->request_type == 2)
393 | {
394 | setenv("REQUEST_METHOD","POST",1);
395 | }
396 | else if(request_header->request_type == 3)
397 | {
398 | setenv("REQUEST_METHOD","HEAD",1);
399 | }
400 | // URL中查询字符串,即问号后面那个
401 | if(request_header->querystring)
402 | {
403 | if(strlen(request_header->querystring))
404 | {
405 | setenv("QUERY_STRING",request_header->querystring,1);
406 | }
407 | else
408 | {
409 | setenv("QUERY_STRING","",1);
410 | }
411 | }
412 | // 去掉之前目录,获得单文件名字
413 | while(strstr(request_header->_filename,"/"))
414 | {
415 | request_header->_filename = strstr(request_header->_filename,"/") + 1;
416 | }
417 | request_header->_filename[-1] = '\0';
418 | char fullpath[1024 + strlen(request_header->_filename)];
419 | getcwd(fullpath,1023);
420 | strcat(fullpath,"/"PAGES"/");
421 | //fprintf(stderr,"%s\n",request_header->filename);
422 | strcat(fullpath,request_header->_filename);
423 | setenv("PATH_TRANSLATED",fullpath,1);
424 | setenv("SCRIPT_NAME",request_header->filename,1);
425 | setenv("SCRIPT_FILENAME",request_header->_filename,1);
426 | setenv("REDIRECT_STATUS","200",1);
427 | char c_length[100];
428 | c_length[0] = '\0';
429 | sprintf(c_length,"%lu",request_header->c_length);
430 | setenv("CONTENT_LENGTH",c_length,1);
431 | if(request_header->c_type)
432 | {
433 | setenv("CONTENT_TYPE",request_header->c_type,1);
434 | }
435 | // 获取远程客户端地址和主机名字
436 |
437 | struct hostent* client;
438 | client = gethostbyaddr((const char*)&socket->remote_addr.sin_addr.s_addr,sizeof(socket->remote_addr.sin_addr.s_addr),AF_INET);
439 | setenv("REMOTE_HOST",client->h_name,1);
440 | //printf("k%s\n",client->h_name);
441 |
442 | //printf("%s\n",request_header->_filename);
443 | setenv("REMOTE_ADDR",inet_ntoa(socket->remote_addr.sin_addr),1);
444 | // 设置Cookie
445 | if(request_header->c_cookie)
446 | {
447 | setenv("HTTP_COOKIE",request_header->c_cookie,1);
448 | }
449 | // 设置 USER_AGENT
450 | if(request_header->c_uagent)
451 | {
452 | setenv("HTTP_USER_AGENT",request_header->c_uagent,1);
453 | }
454 |
455 | // 设置 Referer
456 | if(request_header->c_referer)
457 | {
458 | setenv("HTTP_REFERER",request_header->c_referer,1);
459 | }
460 | char execute[1024];
461 | execute[0] = '\0';
462 | //sprintf(execute,"./%s",request_header->_filename);
463 | sprintf(execute,"%s",fullpath);
464 | // execlp 从PATH 环境变量中查找文件并执行,执行成功则不返回,否则返回-1
465 | execlp(execute,execute,(char*)0);
466 | // 如果执行失败,则继续下面操作
467 | fprintf(stderr,"[warn] Failed to execute CGI Script:%s?%s.\n",fullpath,request_header->querystring);
468 | // 回收内存
469 | delete_queue(queue);
470 | pthread_detach(socket->thread);
471 | free(socket);
472 |
473 | return -1;
474 | }
475 |
476 |
477 | // 判断_filename 是不是目录
478 | int check_dir(FILE* fd,request_h* request_header,struct stat* Stats)
479 | {
480 | if(request_header->_filename[strlen(request_header->_filename) - 1] != '/')
481 | {
482 | // 目录结尾无 '/'
483 | fprintf(fd,"HTTP/1.1 301 Moved Permanently\r\n");
484 | fprintf(fd,"Location: %s/\r\n",request_header->filename);
485 | fprintf(fd,"Content-Length: 0\r\n\r\n");
486 |
487 | return -1;
488 | }
489 | else
490 | {
491 | // 无默认文件,列出目录列表
492 | struct dirent **files = {0};
493 | int filecount = -1;
494 | filecount = scandir(request_header->_filename,&files,0,alphasort);
495 | // 打印目录列表,先发送HTTP Response
496 | fprintf(fd,"HTTP/1.1 200 OK\r\n");
497 | fprintf(fd,"Content-Type: text/html\r\n");
498 |
499 | // 为显示的HTML内容分配一些内存
500 | char *html = malloc(1024);
501 | html[0] = '\0';
502 | strcat(html,"Directory Listing");
503 | // 打印列表内容,并构造html
504 | unsigned int i;
505 | for(i = 0; i < filecount; ++i)
506 | {
507 | char fullname[strlen(request_header->_filename) + 1 + strlen(files[i]->d_name) + 1];
508 | sprintf(fullname,"%s/%s",request_header->_filename,files[i]->d_name);
509 | // 忽略目录下的目录
510 | if(stat(fullname,&(*Stats)) == 0 && S_ISDIR((*Stats).st_mode))
511 | {
512 | free(files[i]);
513 | continue;
514 | }
515 |
516 | char _file[2 * strlen(files[i]->d_name) + 64];
517 | sprintf(_file,"%s
\n",files[i]->d_name,files[i]->d_name);
518 | // 重新分配内存,将上述内容添加到末尾
519 | html = realloc(html,strlen(html) + strlen(_file) + 1);
520 | strcat(html,_file);
521 | free(files[i]);
522 | }
523 | free(files);
524 | html = realloc(html,strlen(html) + 64);
525 | strcat(html,"");
526 |
527 | // 发送Response
528 | fprintf(fd,"Content-Length: %d\r\n",(sizeof(char) * strlen(html)));
529 | fprintf(fd,"\r\n");
530 | fprintf(fd,"%s",html);
531 | free(html);
532 | }
533 | return 0;
534 | }
535 |
536 | // 确定MIME类型,根据请求类型发送Response
537 | int determine_mime(queue_t* queue,FILE* fd,FILE* content,request_h* request_header)
538 | {
539 | if(request_header->ext)
540 | {
541 | // 判断请求文件类型,对不同的请求,Response不同的值
542 | if(!strcmp(request_header->ext,".htm") || !strcmp(request_header->ext,".html"))
543 | {
544 | fprintf(fd,"Content-Type: text/html\r\n");
545 | }
546 | else if(!strcmp(request_header->ext,".css"))
547 | {
548 | fprintf(fd,"Content-Type: text/css\r\n");
549 | }
550 | else if(!strcmp(request_header->ext,".png"))
551 | {
552 | fprintf(fd,"Content-Type: image/png\r\n");
553 | }
554 | else if(!strcmp(request_header->ext,".jpg"))
555 | {
556 | fprintf(fd,"Content-Type: image/jpeg\r\n");
557 | }
558 | else if(!strcmp(request_header->ext,".gif"))
559 | {
560 | fprintf(fd,"Content-Type: image/gif\r\n");
561 | }
562 | else if(!strcmp(request_header->ext,".pdf"))
563 | {
564 | fprintf(fd,"Content-Type: application/pdf\r\n");
565 | }
566 | // HTML5里面的东西,好像是做缓存用的
567 | else if(!strcmp(request_header->ext,".manifest"))
568 | {
569 | fprintf(fd,"Content-Type: text/cache-manifest\r\n");
570 | }
571 | else
572 | {
573 | fprintf(fd,"Content-Type: text/unknown\r\n");
574 | }
575 | }
576 | else
577 | {
578 | fprintf(fd,"Content-Type: text/unknown\r\n");
579 | }
580 |
581 | // HEAD request,只需要读取headers
582 | if(request_header->request_type == 3)
583 | {
584 | fprintf(fd,"\r\n");
585 | fclose(content);
586 | fflush(fd);
587 | delete_queue(queue);
588 |
589 | return 1;
590 | }
591 |
592 | fseek((content),0,SEEK_END);
593 | long size = ftell(content);
594 | fseek((content),0,SEEK_SET);
595 |
596 | // 发送出去header后的文本长度
597 | fprintf(fd,"Content-Length: %ld\r\n",size);
598 | fprintf(fd,"\r\n");
599 |
600 | char buf[HTML_SIZE];
601 | while(!feof(content))
602 | {
603 | size_t n = fread(buf,1,HTML_SIZE - 1,content);
604 | fwrite(buf,1,n,fd);
605 | }
606 | fprintf(fd,"\r\n");
607 | fclose(content);
608 | return 0;
609 | }
610 |
611 | // 父进程读取客户端动态脚本传来的数据(Form表单数据),通过管道传入到子进程
612 | void pipe_trans(queue_t* queue,FILE* fd,FILE* cgi_w,request_h* request_header)
613 | {
614 | // 读取客户端数据,并通过管道传入到子进程,传输POST数据
615 | if(request_header->c_length > 0)
616 | {
617 | size_t total = 0;
618 | char buf[CGI_POST];
619 | while((total < request_header->c_length) && (!feof(fd)))
620 | {
621 | size_t left = request_header->c_length - total;
622 | if(left > CGI_POST)
623 | {
624 | // 请求太大
625 | left = CGI_POST;
626 | }
627 | size_t n = fread(buf,1,left,fd);
628 | total += n;
629 |
630 | // 向管道写入数据
631 | fwrite(buf,1,n,cgi_w);
632 | }
633 | }
634 |
635 | if(cgi_w)
636 | {
637 | fclose(cgi_w);
638 | }
639 |
640 | }
641 |
642 | // 子进程通过管道将数据传送过来,父进程解析HTTP头
643 | int read_header(struct socket_request* socket,queue_t* queue,FILE* fd,FILE* cgi_r,request_h* request_header,pthread_t* waitthread)
644 | {
645 | char buf[HEADER_SIZE];
646 | if(!cgi_r)
647 | {
648 | generic_response(fd,"500 Internal Server Error","Failed to execute CGI Script.\n");
649 | pthread_detach(*waitthread);
650 | fflush(fd);
651 | delete_queue(queue);
652 | return 1;
653 | }
654 | fprintf(fd,"HTTP/1.1 200 OK\r\n");
655 | unsigned int i = 0;
656 |
657 | // 读取子进程通过管道传输的数据,并写到socket中
658 | while(!feof(cgi_r))
659 | {
660 | char* in = fgets(buf,HEADER_SIZE - 1,cgi_r);
661 | if(!in)
662 | {
663 | fprintf(stderr,"[warn] Read nothing [%d on %p].\n",ferror(cgi_r),cgi_r);
664 | buf[0] = '\0';
665 | break;
666 | }
667 |
668 | if(!strcmp(in,"\r\n") || !strcmp(in,"\n"))
669 | {
670 | buf[0] = '\0';
671 | break;
672 | }
673 |
674 | if(!strcmp(in,": ") && !strcmp(in,"\r\n"))
675 | {
676 | fprintf(stderr,"[warn] Reuqest Line was too long or Error %zu.\n",strlen(buf));
677 | break;
678 | }
679 |
680 | fwrite(in,1,strlen(in),fd);
681 | ++i;
682 | }
683 | if(i < 1)
684 | {
685 | fprintf(stderr,"[warn] CGI Script didn't give us headers.\n");
686 | }
687 |
688 |
689 | if(feof(cgi_r))
690 | {
691 | fprintf(stderr,"[warn] The End of File,May be the Pipe is closed.\n");
692 | }
693 |
694 | // HEAD请求,只请求页面的首部
695 | if(request_header->request_type == 3)
696 | {
697 | fprintf(fd,"\r\n");
698 | pthread_detach(*waitthread);
699 | fflush(fd);
700 | delete_queue(queue);
701 | return 1;
702 | }
703 |
704 | int mode = 0;
705 | // 如果HTTP协议为HTTP/1.1,则设置Transfer-Encodingchunked
706 | // 这样我们可以分块发送,而不用一次全部发送
707 | if(!strcmp(request_header->http_version,"HTTP/1.1"))
708 | {
709 | fprintf(fd,"Transfer-Encoding: chunked\r\n");
710 | }
711 | else
712 | {
713 | // 如果不是HTTP/1.1,即为HTTP/1.0,
714 | // 则没实现长链接,Connection应设置为close
715 | fprintf(fd,"Connection: close\r\n\r\n");
716 | mode = 1;
717 | }
718 |
719 |
720 | if(strlen(buf) > 0)
721 | {
722 | fprintf(stderr,"[warn] Trying to dump remaing content.\n");
723 | // 其内容为一个chunk,用CRLF隔开,即\r\n
724 | // ASCII值打印
725 | fprintf(fd,"\r\n%zX\r\n",strlen(buf));
726 | fwrite(buf,1,strlen(buf),fd);
727 | }
728 |
729 | // 继续从子进程的CGI 应用程序读取数据
730 | // 如果为HTTP/1.1,则以chunks形式发送
731 | while(!feof(cgi_r))
732 | {
733 | size_t n_read = -1;
734 | n_read = fread(buf,1,HEADER_SIZE-1,cgi_r);
735 | if(n_read < 1)
736 | {
737 | fprintf(stderr,"[warn] Read nothing from CGI Application.\n");
738 | break;
739 | }
740 | // 如果为HTTP/1.1
741 | if(mode == 0)
742 | {
743 | fprintf(fd,"\r\n%zX\r\n",n_read);
744 | }
745 | fwrite(buf,1,n_read,fd);
746 | }
747 |
748 | if(mode == 0)
749 | {
750 | // 使用 0 字节长度的块结束chunked
751 | fprintf(fd,"\r\n0\r\n\r\n");
752 | }
753 |
754 | pthread_detach(*waitthread);
755 | if(cgi_r)
756 | {
757 | fclose(cgi_r);
758 | }
759 |
760 | // 如果是HTTP/1.1就保持长链接,不断开,只需要释放内存,继续while循环即可
761 | if(mode == 0)
762 | {
763 | fflush(fd);
764 | delete_queue(queue);
765 |
766 | return -1;
767 | }
768 | // 如果是HTTP/1.0,断开链接
769 | else
770 | {
771 | delete_queue(queue);
772 | disconnect(socket,fd,request_header);
773 | return -1;
774 | }
775 |
776 | }
777 |
778 | int parse_html(struct socket_request* socket,queue_t* queue,FILE* fd,request_h* request_header)
779 | {
780 | //printf("%s\n",request_header->_filename);
781 | FILE *content = fopen(request_header->_filename,"rb");
782 | // 如果打不开文件,显示404错误,或者也可能是403权限问题,这里用400表示
783 | if(!content)
784 | {
785 | generic_response(fd,"400 Bad Request","Bad Request: No File Or Forbidden.\n");
786 | fflush(fd);
787 | delete_queue(queue);
788 | // 此处。。。 free _filename
789 | // disconnect(socket,fd,request_header);
790 | // 此处有问题
791 | return 1;
792 | }
793 | else
794 | {
795 | struct stat Stats;
796 | // 判断文件是否可执行
797 | if(stat(request_header->_filename,&Stats) == 0 && (Stats.st_mode & S_IXOTH))
798 | {
799 | fclose(content);
800 |
801 | // 使用双向管道
802 | int pipe_r[2];
803 | int pipe_w[2];
804 | if(pipe(pipe_r) < 0)
805 | {
806 | fprintf(stderr,"Failed to create read pipe!\n");
807 | }
808 | if(pipe(pipe_w) < 0)
809 | {
810 | fprintf(stderr,"Failed to create write pipe!\n");
811 | }
812 | // 使用多进程,父子进程
813 | pid_t pid = 0;
814 | pid = fork();
815 |
816 | // 子进程
817 | if(pid == 0)
818 | {
819 | // 重定向
820 | dup2(pipe_r[0],STDIN_FILENO);
821 | dup2(pipe_w[1],STDOUT_FILENO);
822 | // 关闭
823 | close(pipe_r[1]);
824 | close(pipe_w[0]);
825 | // 已重定向,向STDOUT发送消息,即通过管道向父进程发送消息
826 | // 控制缓存的时间,即立即过期
827 | fprintf(stdout,"Expires: -1\r\n");
828 | // 进入www目录下
829 | char* dir = request_header->_filename;
830 | char wwwroot[1024];
831 | getcwd(wwwroot,1024);
832 | strcat(wwwroot,"/"PAGES);
833 | chdir(dir);
834 | // 设置DOCUMENT_ROOT 环境变量,嫌麻烦,没有统一处理,还得传参
835 | setenv("DOCUMENT_ROOT",wwwroot,1);
836 | int id = set_env(socket,queue,request_header);
837 | if(id == -1)
838 | {
839 | // 即子进程脚本没有执行
840 | return -1;
841 | }
842 | }
843 |
844 | // 父进程
845 | struct cgi_data* cgi_d = malloc(sizeof(struct cgi_data));
846 | cgi_d->pid = pid;
847 | // 待关闭
848 | cgi_d->fd = pipe_w[1];
849 | cgi_d->fd2 = pipe_r[0];
850 | pthread_t waitthread;
851 | // 创建一个线程,关闭父进程里的文件描述符,使其成为双向管道
852 | pthread_create(&waitthread,NULL,wait_pid,(void*)(cgi_d));
853 |
854 | // cgi_r 读取CGI 程序的输出,cgi_w映射到CGI程序的标准输入
855 | FILE* cgi_r = fdopen(pipe_w[0],"r");
856 | FILE* cgi_w = fdopen(pipe_r[1],"w");
857 |
858 | // 管道
859 | pipe_trans(queue,fd,cgi_w,request_header);
860 |
861 | // 读取header
862 | int id = read_header(socket,queue,fd,cgi_r,request_header,&waitthread);
863 | if(id == 1)
864 | {
865 | return 1;
866 | }
867 | else if(id == -1)
868 | {
869 | return -1;
870 | }
871 |
872 | }
873 | fprintf(fd,"HTTP/1.1 200 OK\r\n");
874 | }
875 | // 确定MIME类型
876 | if((determine_mime(queue,fd,content,request_header)) == 1)
877 | {
878 | return 1;
879 | }
880 | else
881 | {
882 | return 0;
883 | }
884 |
885 | return 0;
886 | }
887 |
888 | // 将 request headers 放到队列当中,直到客户端断开连接
889 | int readRequest(struct socket_request* socket,queue_t* queue,FILE *fd,request_h* request_header)
890 | {
891 | char buf[HEADER_SIZE];
892 | while(!feof(fd))
893 | {
894 | // 当读到一个换行符或EOF,结束读取
895 | char* in = fgets(buf,HEADER_SIZE - 2,fd);
896 | // 到达文件末尾
897 | if(!in)
898 | {
899 | break;
900 | }
901 |
902 | // 到达headers末尾
903 | if(!strcmp(in,"\r\n") || !strcmp(in,"\n"))
904 | {
905 | break;
906 | }
907 |
908 | // request line后面有个\n,判断是否存在request line
909 | if(!strstr(in,"\n"))
910 | {
911 | generic_response(fd,"400 Bad Request","Bad Request: Request Line was too long.\n");
912 | delete_queue(queue);
913 | disconnect(socket,fd,request_header);
914 | return -1;
915 | }
916 |
917 | char* request_line = malloc((strlen(buf)+1) * sizeof(char));
918 | strcpy(request_line,buf);
919 | // 将request line 存储到queue里
920 | //printf("%s\n",request_line);
921 | queue_append(queue,(void*)request_line);
922 | }
923 | // Socket无文件结束标志,如果出现这个表示客户端关闭连接
924 | if(feof(fd))
925 | {
926 | delete_queue(queue);
927 | disconnect(socket,fd,request_header);
928 | return -1;
929 | }
930 | return 0;
931 | }
932 |
933 | // 线程处理函数,处理每一个连接请求
934 | void *handleRequest(void *socket)
935 | {
936 | // GET POST 占的宽度
937 | int type_width = 0;
938 |
939 | request_h *request_header = (request_h*)malloc(sizeof(struct _request_h));
940 | request_header->filename = NULL;
941 | request_header->querystring = NULL;
942 | request_header->request_type = 0;
943 | request_header->_filename = NULL;
944 | request_header->ext = NULL;
945 | request_header->host = NULL;
946 | request_header->http_version = NULL;
947 | request_header->c_length = 0;
948 | request_header->c_type = NULL;
949 | request_header->c_cookie = NULL;
950 | request_header->c_uagent = NULL;
951 | request_header->c_referer = NULL;
952 |
953 | struct socket_request *request = (struct socket_request*)socket;
954 | // 将socket文件描述符转换为标准的文件描述符,因为socket描述符不能使用标准I/O fopen打开
955 | FILE *fd = fdopen(request->fd,"r+");
956 | if(!fd)
957 | {
958 | fprintf(stderr,"Transfer the Socket fd to File Error!\n");
959 | disconnect(request,fd,request_header);
960 | return NULL;
961 | }
962 |
963 | // 读取requests请求,直到客户端断开连接
964 | while(1)
965 | {
966 | queue_t *queue = alloc_queue();
967 |
968 | // 读取request请求
969 | if((readRequest(request,queue,fd,request_header)) == -1)
970 | {
971 | return NULL;
972 | }
973 | // 处理headers
974 | if ((processHeader(request,queue,fd,&type_width,request_header)) == -1)
975 | {
976 | return NULL;
977 | }
978 | //printf("%s\n%s\n%s\n",request_header->_filename,request_header->http_version,request_header->ext);
979 | // 解析文件和编码
980 | if((request_file(request,queue,fd,request_header)) == -1)
981 | {
982 | return NULL;
983 | }
984 |
985 | // 判断是否是目录
986 | struct stat Stats;
987 | if(stat(request_header->_filename,&Stats) == 0 && S_ISDIR(Stats.st_mode))
988 | {
989 | if(check_dir(fd,request_header,&Stats) == -1)
990 | {
991 | return NULL;
992 | }
993 | }
994 | else
995 | {
996 | // 解析HTML ,返回-1,表示错误,线程不在执行
997 | int id = parse_html(request,queue,fd,request_header);
998 | if(id == -1)
999 | {
1000 | return NULL;
1001 | }
1002 | // 返回1,表示长链接
1003 | else if(id == 1)
1004 | {
1005 | continue;
1006 | }
1007 |
1008 | }
1009 | }
1010 |
1011 | }
1012 |
1013 |
1014 | int main(int argc,char *argv[])
1015 | {
1016 | port = PORT;
1017 |
1018 | // 如果命令行参数个数大于1,即改变默认端口号,则修改默认端口号
1019 | if(argc > 1)
1020 | {
1021 | port = atoi(argv[1]);
1022 | }
1023 |
1024 | // 初始化TCP Socket
1025 | struct sockaddr_in addr;
1026 | if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
1027 | {
1028 | fprintf(stderr,"Create Socket Error!\n");
1029 | return -1;
1030 | }
1031 |
1032 | bzero(&addr,sizeof(addr));
1033 | addr.sin_family = AF_INET;
1034 | addr.sin_port = htons(port);
1035 | addr.sin_addr.s_addr = htonl(INADDR_ANY);
1036 |
1037 | // 设置socket关闭后,仍可继续重用该socket
1038 | int reuseaddr = 1;
1039 | if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&reuseaddr,sizeof(int)) < 0)
1040 | {
1041 | close(sockfd);
1042 | return -1;
1043 | }
1044 |
1045 | // Bind the socket
1046 | if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)
1047 | {
1048 | fprintf(stderr,"Failed to bind socket to the %d port!\n",port);
1049 | return -1;
1050 | }
1051 |
1052 | // 监听来自浏览器的请求
1053 | listen(sockfd,10);
1054 |
1055 | printf("The Cgi Server is Listening the %d port.\n",port);
1056 |
1057 | // 捕捉终端CTRL+C产生的SIGINT信号,使用我们自己的处理函数
1058 | signal(SIGINT,handleSignal);
1059 |
1060 | // 忽略SIGPIPE信号,否则会异常终止
1061 | signal(SIGPIPE,SIG_IGN);
1062 |
1063 | // 使用多线程,循环处理每一个accept请求
1064 | while(1)
1065 | {
1066 | struct socket_request *coming = calloc(sizeof(struct socket_request),1);
1067 | unsigned int len;
1068 | len = sizeof(coming->remote_addr);
1069 | coming->fd = accept(sockfd,(struct sockaddr*)&(coming->remote_addr),&len);
1070 | pthread_create(&(coming->thread),NULL,handleRequest,(void *)(coming));
1071 |
1072 | }
1073 |
1074 | }
1075 |
1076 |
--------------------------------------------------------------------------------