Backport lighttpd trunk里的100-Continue实现到lighttpd-1.4.16

December 14, 2008 at 4:03 pm (protocols)

之前提到为了在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;

需要解决相同问题的童鞋可以参考一下。

Permalink Leave a Comment

Follow

Get every new post delivered to your Inbox.