解析 tcpdump 捕获的 HTTP 响应 - 实体为空,但 header 之后有数据
Parsing HTTP response captured by tcpdump - entity is null, but there is data after the header
我正在尝试从 tcpdump 捕获的 .pcap 文件中解析 HTTP 响应消息,使用 pkts.io 解析捕获文件并使用 Apache httpcommons 解析消息。
在解析捕获文件时,我将作为消息一部分的每个数据包的有效负载(通过 Packet.getPayload()
、doc 获得)附加到 byte[] data
.
如果我打印 new String(data, "UTF-8")
,我得到这个:
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 10 Apr 2015 04:00:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=300
Vary: Accept-Encoding
Content-Encoding: gzip
1dd
��������������S�n�0��+X_���
��q�b�a���������Ȓf�q��G�K�I��=���������χ/�rg�f�d"kʌ\�+1l���P
]�\^�@r�{�k��;pģ�7�=t� `C+5qg�
...
当我尝试解析 HTTP 消息(下面的代码)时,我得到了所有 headers 没问题,但是 resp.getEntity()
returns null
.
SessionInputBufferImpl inBuffer = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), packet.getData().length);
InputStream inStream = new ByteArrayInputStream(packet.getData());
inBuffer.bind(inStream);
DefaultHttpResponseParser respParser = new DefaultHttpResponseParser(inBuffer);
HttpResponse resp = (HttpResponse) respParser.parse();
从这里我可以去哪里尝试以文本形式获取响应body?
获取实体主体时,您需要同时查看传输编码和内容编码,并进行适当的解码。参见 section 4 "Transfer Codings" of RFC 7230。
查看 类 中的 HttpComponents,例如 ChunkedInputStream(用于分块传输编码)并查找可以解压缩 gzip 文本的代码(用于 gzip 内容编码)。
我无法让 HttpResponse.getEntity()
工作,所以我不得不自己解析响应。这是我拼凑的代码。它遍历包含整个响应内容的 byte[]
,寻找分隔 header 字段和 body 的空行,并复制之后的所有内容:
private byte[] getContent(byte[] message) {
int start = -1;
byte[] content = null;
for (int i = 0; i < message.length; ++i) {
if (start >= 0) {
content[i-start] = message[i];
continue;
}
System.out.print((char)message[i]);
if (message[i] == (byte) 13 && message[i+1]==(byte)10 && message[i+2] == (byte) 13 && message[i+3]==(byte)10 ) { //CR
start = i+4;
content = new byte[message.length-(i+4)];
i += 3;
}
}
return content;
}
然后,如果响应有 Transfer-Encoding: chunked
和 Content-Encoding: gzip
,我使用 ChunkedInputStream
(来自 HttpComponents)和 GZIPInputStream
来自 java.util
来获取实际返回内容。
byte[] content = getContent(packet.getData());
if (content.length > 0) {
InputStream byteIS = new ByteArrayInputStream(content);
SessionInputBufferImpl contentBuf = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), content.length);
contentBuf.bind(byteIS);
ChunkedInputStream chunkedIS = new ChunkedInputStream(contentBuf);
GZIPInputStream gzipIS = new GZIPInputStream(chunkedIS);
while (gzipIS.available() != 0) {
byte[] buf = new byte[128];
gzipIS.read(buf);
contentBuilder.append(new String(buf, "UTF-8"));
}
gzipIS.close();
String contentString = contentBuilder.toString();
}
我正在尝试从 tcpdump 捕获的 .pcap 文件中解析 HTTP 响应消息,使用 pkts.io 解析捕获文件并使用 Apache httpcommons 解析消息。
在解析捕获文件时,我将作为消息一部分的每个数据包的有效负载(通过 Packet.getPayload()
、doc 获得)附加到 byte[] data
.
如果我打印 new String(data, "UTF-8")
,我得到这个:
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 10 Apr 2015 04:00:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=300
Vary: Accept-Encoding
Content-Encoding: gzip
1dd
��������������S�n�0��+X_���
��q�b�a���������Ȓf�q��G�K�I��=���������χ/�rg�f�d"kʌ\�+1l���P
]�\^�@r�{�k��;pģ�7�=t� `C+5qg�
...
当我尝试解析 HTTP 消息(下面的代码)时,我得到了所有 headers 没问题,但是 resp.getEntity()
returns null
.
SessionInputBufferImpl inBuffer = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), packet.getData().length);
InputStream inStream = new ByteArrayInputStream(packet.getData());
inBuffer.bind(inStream);
DefaultHttpResponseParser respParser = new DefaultHttpResponseParser(inBuffer);
HttpResponse resp = (HttpResponse) respParser.parse();
从这里我可以去哪里尝试以文本形式获取响应body?
获取实体主体时,您需要同时查看传输编码和内容编码,并进行适当的解码。参见 section 4 "Transfer Codings" of RFC 7230。
查看 类 中的 HttpComponents,例如 ChunkedInputStream(用于分块传输编码)并查找可以解压缩 gzip 文本的代码(用于 gzip 内容编码)。
我无法让 HttpResponse.getEntity()
工作,所以我不得不自己解析响应。这是我拼凑的代码。它遍历包含整个响应内容的 byte[]
,寻找分隔 header 字段和 body 的空行,并复制之后的所有内容:
private byte[] getContent(byte[] message) {
int start = -1;
byte[] content = null;
for (int i = 0; i < message.length; ++i) {
if (start >= 0) {
content[i-start] = message[i];
continue;
}
System.out.print((char)message[i]);
if (message[i] == (byte) 13 && message[i+1]==(byte)10 && message[i+2] == (byte) 13 && message[i+3]==(byte)10 ) { //CR
start = i+4;
content = new byte[message.length-(i+4)];
i += 3;
}
}
return content;
}
然后,如果响应有 Transfer-Encoding: chunked
和 Content-Encoding: gzip
,我使用 ChunkedInputStream
(来自 HttpComponents)和 GZIPInputStream
来自 java.util
来获取实际返回内容。
byte[] content = getContent(packet.getData());
if (content.length > 0) {
InputStream byteIS = new ByteArrayInputStream(content);
SessionInputBufferImpl contentBuf = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), content.length);
contentBuf.bind(byteIS);
ChunkedInputStream chunkedIS = new ChunkedInputStream(contentBuf);
GZIPInputStream gzipIS = new GZIPInputStream(chunkedIS);
while (gzipIS.available() != 0) {
byte[] buf = new byte[128];
gzipIS.read(buf);
contentBuilder.append(new String(buf, "UTF-8"));
}
gzipIS.close();
String contentString = contentBuilder.toString();
}