Kaynağa Gözat

support "chunk-extension" and "trailer" in HTTP 1.1 "Chunked Transfer Coding"

Peter Huber 2 yıl önce
ebeveyn
işleme
f929cb46e5
1 değiştirilmiş dosya ile 64 ekleme ve 5 silme
  1. 64 5
      src/civetweb.c

+ 64 - 5
src/civetweb.c

@@ -6672,6 +6672,22 @@ mg_read(struct mg_connection *conn, void *buf, size_t len)
 					if (mg_read_inner(conn, lenbuf + i, 1) != 1) {
 						lenbuf[i] = 0;
 					}
+					if ((i > 0) && (lenbuf[i] == ';'))
+					{
+						// chunk extension --> skip chars until next CR
+						//
+						// RFC 2616, 3.6.1 Chunked Transfer Coding
+					    // (https://www.rfc-editor.org/rfc/rfc2616#page-25)
+						//
+						// chunk          = chunk-size [ chunk-extension ] CRLF
+						//                  chunk-data CRLF
+						// ...
+						// chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+						do
+							++conn->content_len;
+						while (mg_read_inner(conn, lenbuf + i, 1) == 1 &&
+							   lenbuf[i] != '\r');
+					}
 					if ((i > 0) && (lenbuf[i] == '\r')
 					    && (lenbuf[i - 1] != '\r')) {
 						continue;
@@ -6697,13 +6713,56 @@ mg_read(struct mg_connection *conn, void *buf, size_t len)
 					conn->is_chunked = 2;
 					return -1;
 				}
-				if (chunkSize == 0) {
+				if (conn->is_chunked == 3) {
 					/* try discarding trailer for keep-alive */
-					conn->content_len += 2;
-					if ((mg_read_inner(conn, lenbuf, 2) == 2)
-					    && (lenbuf[0] == '\r') && (lenbuf[1] == '\n')) {
-						conn->is_chunked = 4;
+
+					// We found the last chunk (length 0) including the
+					// CRLF that terminates that chunk. Now follows a possibly
+					// empty trailer and a final CRLF.
+					//
+					// see RFC 2616, 3.6.1 Chunked Transfer Coding
+					// (https://www.rfc-editor.org/rfc/rfc2616#page-25)
+					//
+					// Chunked-Body   = *chunk
+					// 	                last-chunk
+					// 	                trailer
+					// 	                CRLF
+					// ...
+					// last-chunk     = 1*("0") [ chunk-extension ] CRLF
+					// ...
+					// trailer        = *(entity-header CRLF)
+
+					int crlf_count = 2;  // one CRLF already determined
+
+					while (crlf_count < 4 && conn->is_chunked == 3) {
+						++conn->content_len;
+						if (mg_read_inner(conn, lenbuf, 1) == 1) {
+							if ((crlf_count == 0 || crlf_count == 2)) {
+								if (lenbuf[0] == '\r')
+									++crlf_count;
+								else
+									crlf_count = 0;
+							}
+							else {
+								// previous character was a CR
+								// --> next character must be LF
+
+								if (lenbuf[0] == '\n')
+									++crlf_count;
+								else
+									conn->is_chunked = 2;
+							}
+						}
+						else
+							// premature end of trailer
+							conn->is_chunked = 2;
 					}
+
+					if (conn->is_chunked == 2)
+						return -1;
+					else
+						conn->is_chunked = 4;
+
 					break;
 				}