Backport lighttpd trunk里的100-Continue实现到lighttpd-1.4.16
之前提到为了在lighttpd实现对客户端的CA认证,需要使用一个针对1.4.16版本的补丁。
前些天在服务测试的时候发现lighttpd的稳定版本在处理100-Continue时,仅仅做返回417处理。从而导致有些客户端,如CURL工作不正常的问题。
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
/* HTTP 2616 8.2.3
* Expect: 100-continue
*
* -> (10.1.1) 100 (read content, process request, send final status-code)
* -> (10.4.18) 417 (close)
*
* (not handled at all yet, we always send 417 here)
*
* What has to be added ?
* 1. handling of chunked request body
* 2. out-of-order sending from the HTTP/1.1 100 Continue
* header
*
*/
con->http_status = 417;
con->keep_alive = 0;
array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
BUG Tracker上开发人员声称要等到1.5.x才能解决这个问题。我到trunk中看了一下,发现相关代码已经在仓库中了,索性就做了以下backport。发现1.4.x到1.5版本基本框架变化不是太大,只是很多函数和状态机state的命令做了不小的调整。所以只要在发现request header中有Expect: 100-continue时,返回100 status,并且继续等待客户端POST就行了:
diff -urN lighttpd-1.4.16.orig/src/connections.c lighttpd-1.4.16.new/src/connections.c
--- lighttpd-1.4.16.orig/src/connections.c 2007-06-15 23:30:34.000000000 +0800
+++ lighttpd-1.4.16.new/src/connections.c 2008-12-14 15:35:38.000000000 +0800
@@ -579,6 +579,15 @@
switch(network_write_chunkqueue(srv, con, con->write_queue)) {
case 0:
if (con->file_finished) {
+ if ( con->http_status == 100 ) {
+ /* send out the 100 Continue header and handle the request as normal
+ * afterwards */
+ con->http_status = 0;
+
+ /* cleanup send chunkqueue's. */
+ chunkqueue_reset( con->write_queue );
+ connection_set_state(srv, con, CON_STATE_REQUEST_START);
+ }
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
joblist_append(srv, con);
}
@@ -1448,6 +1467,10 @@
con->http_status = con->error_handler_saved_status;
}
+ if ( array_get_element( con->request.headers, "Expect" ) ) {
+ con->http_status = 100;
+ }
+
if (con->http_status == 0) con->http_status = 200;
/* we have something to send, go on */
diff -urN lighttpd-1.4.16.orig/src/request.c lighttpd-1.4.16.new/src/request.c
--- lighttpd-1.4.16.orig/src/request.c 2007-06-15 22:08:32.000000000 +0800
+++ lighttpd-1.4.16.new/src/request.c 2008-12-14 15:35:31.000000000 +0800
@@ -877,26 +877,27 @@
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
- /* HTTP 2616 8.2.3
- * Expect: 100-continue
- *
- * -> (10.1.1) 100 (read content, process request, send final status-code)
- * -> (10.4.18) 417 (close)
- *
- * (not handled at all yet, we always send 417 here)
- *
- * What has to be added ?
- * 1. handling of chunked request body
- * 2. out-of-order sending from the HTTP/1.1 100 Continue
- * header
- *
- */
+ /* HTTP 2616 8.2.3
+ * Expect: 100-continue
+ *
+ * -> (10.1.1) 100 (read content, process request, send final status-code)
+ * -> (10.4.18) 417 (close)
+ *
+ *
+ */
+
+ if (0 != buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
+ /* we only support 100-continue */
+ con->http_status = 417;
+ return 0;
+ }
+
+ if (con->request.http_version != HTTP_VERSION_1_1) {
+ /* only HTTP/1.1 clients can send us this header */
+ con->http_status = 417;
+ return 0;
+ }
- con->http_status = 417;
- con->keep_alive = 0;
-
- array_insert_unique(con->request.headers, (data_unset *)ds);
- return 0;
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
if (!con->request.http_host) {
con->request.http_host = ds->value;
需要解决相同问题的童鞋可以参考一下。