已经有一个月没有更新博客了,一方面是因为平时太忙了,另一方面是想积攒一些干货进行分享。最近主要是做了一些开源项目的源码分析工作,有c项目也有python项目,想提升一下内功,今天分享一下tinyhttpd源码分析的成果。tinyhttpd是一个非常轻量型的http服务器,c代码500行左右,可以帮助我们了解http服务器运行的实质。在分析之前,我们先说一下http报文。(我的新书《Python爬虫开发与项目实战》出版了,大家可以看一下样章)
一.http请求
http请求由三部分组成,分别是:起始行、消息报头、请求正文
1
2
3
4
5
6
|
Request Line<
CRLF
>
Header-Name: header-value<
CRLF
>
Header-Name: header-value<
CRLF
>
//一个或多个,均以<
CRLF
>结尾
<
CRLF
>
body//请求正文
|
1、起始行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:
1
|
Method Request-URI HTTP-Version CRLF
|
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。
2、请求方法(所有方法全为大写)有多种,各个方法的解释如下:
- GET 请求获取Request-URI所标识的资源
- POST 在Request-URI所标识的资源后附加新的数据
- HEAD 请求获取由Request-URI所标识的资源的响应消息报头
- PUT 请求服务器存储一个资源,并用Request-URI作为其标识
- DELETE 请求服务器删除Request-URI所标识的资源
- TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
- CONNECT 保留将来使用
- OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
应用举例:
GET方法:在浏览器的地址栏中输入网址的方式访问网页时,浏览器采用GET方法向服务器获取资源,eg:
1
|
GET /form.html HTTP/1.1 (CRLF)
|
POST方法要求被请求服务器接受附在请求后面的数据,常用于提交表单。eg:
1
2
3
4
5
6
7
8
9
|
POST /reg.jsp HTTP/ (CRLF)
Accept:image/gif,image/x-xbit,... (CRLF)
...
HOST:www.guet.edu.cn (CRLF)
Content-Length:22 (CRLF)
Connection:Keep-Alive (CRLF)
Cache-Control:no-cache (CRLF)
(CRLF) //该CRLF表示消息报头已经结束,在此之前为消息报头
user=jeffrey&pwd=1234 //此行以下为提交的数据
|
二.tinyhttpd源码分析
tinyhttpd总共包含以下函数:
1
2
3
4
5
6
7
8
9
10
11
12
|
void
accept_request(
int
);
//处理从套接字上监听到的一个 HTTP 请求
void
bad_request(
int
);
//返回给客户端这是个错误请求,400响应码
void
cat(
int
,
FILE
*);
//读取服务器上某个文件写到 socket 套接字
void
cannot_execute(
int
);
//处理发生在执行 cgi 程序时出现的错误
void
error_die(
const
char
*);
//把错误信息写到 perror
void
execute_cgi(
int
,
const
char
*,
const
char
*,
const
char
*);
//运行cgi脚本,这个非常重要,涉及动态解析
int
get_line(
int
,
char
*,
int
);
//读取一行HTTP报文
void
headers(
int
,
const
char
*);
//返回HTTP响应头
void
not_found(
int
);
//返回找不到请求文件
void
serve_file(
int
,
const
char
*);
//调用 cat 把服务器文件内容返回给浏览器。
int
startup(u_short *);
//开启http服务,包括绑定端口,监听,开启线程处理链接
void
unimplemented(
int
);
//返回给浏览器表明收到的 HTTP 请求所用的 method 不被支持。
|
建议源码阅读顺序: main -> startup -> accept_request -> execute_cgi
按照以上顺序,看一下浏览器和tinyhttpd交互的整个流程:
三.注释版源码
注释版源码已经放到github上了,以后所有的源码分析都会上传github上。由于tinyhttpd源码较少,下面将完整的代码贴出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|