Я пытаюсь проанализировать сообщение ответа HTTP из файла.pcap, захваченного tcpdump, с помощью pkts.io, чтобы проанализировать файл захвата и HTTP-объекты Apache для синтаксического анализа сообщения.
При анализе файла захвата я добавляю полезную нагрузку каждого пакета (полученного с помощью 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-сообщение (код ниже), я получаю все заголовки в порядке, но resp.getEntity()
возвращает значение 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();
Куда я могу пойти отсюда, чтобы попытаться получить тело ответа как текст?
Когда вы получаете тело сущности, вам нужно посмотреть как кодирование передачи, так и кодирование содержимого, и выполнить соответствующее декодирование. См. Раздел 4 "Передача кодов" RFC 7230.
Посмотрите на классы в HttpComponents, такие как ChunkedInputStream (для chunked Transfer-Encoding) и найдите код, который может un-gzip gzipped text (для gzip Content-Encoding).
Мне не удалось заставить HttpResponse.getEntity()
работать, поэтому мне пришлось самому разобрать ответ. Вот код, который я бросил вместе. Он просматривает byte[]
содержащий весь контент ответа, ищущий пустую строку, разделяющую поля заголовка и тело, и копирует все после этого:
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();
}
InputStream
возвращаемыйsomeHttpResponse.getEntity().getContent()
, если сущность не была нулевой.)Content-Encoding: gzip
и1dd
, он искажен, так как между полями заголовка и телом должна быть пустая строка (CRLF). Если это так, то не следует ожидать, что он будет разбираться, хотя HttpComponents должен указывать на ошибку. Если у него есть пустая строка, вы должны получить объект и, если HttpComponents не ип-куска и распаковывать его для вас, вам нужно подключить материал таким образом , что он делает.