Lighttpd1.4.20源码分析之状态机(3)返回response_410
Lighttpd1.4.20源码分析之状态机(3)返回response
好久没顾这个了,最近比较清闲,重新拾掇一下,有始有终。
回到正题,前一篇介绍完了请求的处理,先面lighttpd将会把处理的结果返回给客户端。状态机进入CON_STATE_RESPONST_START。在这个状态中,服务器主要的工作在函数connection_handle_write_prepare。这个函数不算复杂,主要是根据客户端请求的method来设置response的headers,其实就是设置“Content-Length”的值。下面是函数代码,做了一些删减:
1 static int connection_handle_write_prepare(server * srv, connection * con)
2 {
3 if (con->mode == DIRECT)
4 {
5 /*
6 * static files
7 */
8 switch (con->request.http_method)
9 {
10 case HTTP_METHOD_GET:
11 case HTTP_METHOD_POST:
12 case HTTP_METHOD_HEAD:
13 case HTTP_METHOD_PUT:
14 case HTTP_METHOD_MKCOL:
15 case HTTP_METHOD_DELETE:
16 case HTTP_METHOD_COPY:
17 case HTTP_METHOD_MOVE:
18 case HTTP_METHOD_PROPFIND:
19 case HTTP_METHOD_PROPPATCH:
20 case HTTP_METHOD_LOCK:
21 case HTTP_METHOD_UNLOCK:
22 break;
23 case HTTP_METHOD_OPTIONS:
24 /*
25 * 400 is coming from the request-parser BEFORE uri.path is set
26 * 403 is from the response handler when noone else catched it
27 * */
28 if ((!con->http_status || con->http_status == 200)
29 && con->uri.path->used && con->uri.path->ptr[0] != '*')
30 {
31 response_header_insert(srv, con, CONST_STR_LEN("Allow"),
32 CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
33
34 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
35 con->parsed_response &= ~HTTP_CONTENT_LENGTH;
36
37 con->http_status = 200;
38 con->file_finished = 1;
39
40 chunkqueue_reset(con->write_queue);
41 }
42 break;
43 default:
44 switch (con->http_status)
45 {
46 case 400: /* bad request */
47 case 414: /* overload request header */
48 case 505: /* unknown protocol */
49 case 207: /* this was webdav */
50 break;
51 default:
52 con->http_status = 501;
53 break;
54 }
55 break;
56 }
57 }
58
59 if (con->http_status == 0)
60 {
61 con->http_status = 403;
62 }
63
64 switch (con->http_status)
65 {
66 case 204: /* class: header only */
67 case 205:
68 case 304:
69 /*
70 * disable chunked encoding again as we have no body
71 */
72 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
73 con->parsed_response &= ~HTTP_CONTENT_LENGTH;
74 chunkqueue_reset(con->write_queue);
75
76 con->file_finished = 1;
77 break;
78 default: /* class: header + body */
79 if (con->mode != DIRECT)
80 break;
81
82 /*
83 * only custom body for 4xx and 5xx
84 */
85 if (con->http_status < 400 || con->http_status >= 600)
86 break;
87
88 con->file_finished = 0;
89 buffer_reset(con->physical.path);
90
91 /*
92 * try to send static errorfile
93 */
94 if (!buffer_is_empty(con->conf.errorfile_prefix))
95 {
96 //设置对应的错误提示文件
97 }
98
99 if (!con->file_finished)
100 {
101 //没有对应的错误提示文件,设置默认错误提示。
102 }
103 break;
104 }
105
106 if (con->file_finished)
107 {
108 /*
109 * we have all the content and chunked encoding is not used, set a 110 * content-length
111 */
112 if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 113 (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)
114 {
115 off_t qlen = chunkqueue_length(con->write_queue); 116 /**
117 * The Content-Length header only can be sent if we have content: 118 * - HEAD doesn't have a content-body (but have a content-length) 119 * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
120 *
121 * Otherwise generate a Content-Length header as chunked encoding is not
122 * available
123 */
124 if ((con->http_status >= 100 && con->http_status < 200) || 125 con->http_status == 204 || con->http_status == 304)
126 {
127 data_string *ds;
128 /*
129 * no Content-Body, no Content-Length
*/ 130
131 if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "Content-Length")))
132 {
133 buffer_reset(ds->value); /* Headers with empty values 134 * are ignored for output */ 135 }
136 }
137 else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) 138 {
139 /*
140 * qlen = 0 is important for Redirects (301, ...) as they MAY 141 * have a content. Browsers are waiting for a Content otherwise
142 */
143 buffer_copy_off_t(srv->tmp_buf, qlen); 144
, CONST_STR_LEN("Content-Length"), 145 response_header_overwrite(srv, con
CONST_BUF_LEN(srv->tmp_buf));
146 }
147 }
148 }
149 else
150 {
151 /**
152 * the file isn't finished yet, but we have all headers 153 *
154 * to get keep-alive we either need:
155 * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or 156 * - Transfer-Encoding: chunked (HTTP/1.1)
157 */
158
159 if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) && 160 ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0))
161 {
162 con->keep_alive = 0;
163 }
164
165 /**
166 * if the backend sent a Connection: close, follow the wish 167 *
168 * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
169 * will close the connection. That's fine. We can always decide the close
170 * the connection
171 *
172 * FIXME: to be nice we should remove the Connection: ...
173 */
->parsed_response & HTTP_CONNECTION) 174 if (con
175 {
176 /*
177 * a subrequest disable keep-alive although the client wanted it
178 */
179 if (con->keep_alive && !con->response.keep_alive) 180 {
181 con->keep_alive = 0;
182 }
183 }
184 }
185
186 if (con->request.http_method == HTTP_METHOD_HEAD) 187 {
188 /**
189 * a HEAD request has the same as a GET 190 * without the content
191 */
192 con->file_finished = 1;
193
194 chunkqueue_reset(con->write_queue); 195 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
196 }
197
198 http_response_write_header(srv, con);
199
200 return 0;
201 }