1. 程式人生 > >ttp響應chunked格式分析

ttp響應chunked格式分析

計數器 decimal 記錄 nco amp bytes 正文 tle 十六進制

有的時候服務器生成HTTP回應是無法確定信息大小的,這時用Content-Length就無法事先寫入長度,而需要實時生成消息長度,這時服務器一般采用Chunked編碼。

在進行Chunked編碼傳輸時,在回復消息的頭部有transfer-coding並定義為Chunked,表示將用Chunked編碼傳輸內容。

Chunked編碼使用若幹個Chunk串連而成,由一個標明長度為0的chunk標示結束。每個Chunk分為頭部和正文兩部分,頭部內容指定下一段正文的字符總數(十六進制的數字)和數量單位(一般不寫),正文部分就是指定長度的實際內容,兩部分之間用回車換行(CRLF)隔開。在最後一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通常可以直接忽略)。

我們來模擬一下數據結構:
[Chunk大小][回車][Chunk數據體][回車][Chunk大小][回車][Chunk數據體][回車][0][回車][footer內容(有的話)][回車]

註意chunk-size是以十六進制的ASCII碼表示的,比如86AE(實際的十六進制應該是:38366165),計算成長度應該是:34478,表示從回車之後有連續的34478字節的數據。
跟蹤了www.yahoo.com的返回數據,發現在chunk-size中,還會多一些空格。可能是固定長度為7個字節,不滿7個字節的,就以空格補足,空格的ASCII碼是0x20。

解碼流程:
對chunked編碼進行解碼的目的是將分塊的chunk-data整合恢復成一塊作為報文體,同時記錄此塊體的長度。
RFC2616中附帶的解碼流程如下:(偽代碼)
length := 0 //長度計數器置0
read chunk-size, chunk-extension (if any) and CRLF //讀取chunk-size, chunk-extension
//和CRLF
while(chunk-size > 0 ) { //表明不是last-chunk
read chunk-data and CRLF //讀chunk-size大小的chunk-data,skip CRLF
append chunk-data to entity-body //將此塊chunk-data追加到entity-body後
read chunk-size and CRLF //讀取新chunk的chunk-size 和 CRLF
}
read entity-header //entity-header的格式為name:valueCRLF,如果為空即只有CRLF
while (entity-header not empty) //即,不是只有CRLF的空行
{
append entity-header to existing header fields
read entity-header
}
Content-Length:=length //將整個解碼流程結束後計算得到的新報文體length
//作為Content-Length域的值寫入報文中
Remove "chunked" from Transfer-Encoding //同時從Transfer-Encoding中域值去除chunked這個標記

Sample

Encoded response

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1A
and this is the second one
0

same as above, raw bytes in hex

0000-000F   48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d   HTTP/1.1 200 OK.
0010-001F   0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74   .Content-Type: t
0020-002F   65 78 74 2f 70 6c 61 69 6e 0d 0a 54 72 61 6e 73   ext/plain..Trans
0030-003F   66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 68   fer-Encoding: ch
0040-004F   75 6e 6b 65 64 0d 0a 0d 0a 32 35 0d 0a 54 68 69   unked....25..Thi
0050-005F   73 20 69 73 20 74 68 65 20 64 61 74 61 20 69 6e   s is the data in
0060-006F   20 74 68 65 20 66 69 72 73 74 20 63 68 75 6e 6b    the first chunk
0070-007F   0d 0a 0d 0a 31 41 0d 0a 61 6e 64 20 74 68 69 73   ....1A..and this
0080-008F   20 69 73 20 74 68 65 20 73 65 63 6f 6e 64 20 6f    is the second o
0090-009F   6e 65 0d 0a 30 0d 0a 0d 0a                        ne..0....

same as above, in Java code

public static final byte[] CHUNKED_RESPONSE;
static {		 
	StringBuilder sb = new StringBuilder();
	sb.append("HTTP/1.1 200 OK/r/n");
	sb.append("Content-Type: text/plain/r/n");
	sb.append("Transfer-Encoding: chunked/r/n/r/n");
	sb.append("25/r/n");		
	sb.append("This is the data in the first chunk/r/n"); // 37 bytes of payload
			// (conveniently consisting of ASCII characters only)
	sb.append("/r/n1A/r/n");
	sb.append("and this is the second one"); // 26 bytes of payload
			// (conveniently consisting of ASCII characters only)
	sb.append("/r/n0/r/n/r/n");
	CHUNKED_RESPONSE = sb.toString().getBytes(java.nio.charset.Charset.forName("US-ASCII"));
}

Decoded data

This is the data in the first chunk
and this is the second one

基本上checked的編碼方式。

ttp響應chunked格式分析