Разбор HTTP-ответа, захваченного tcpdump - Entity имеет значение null, но после заголовка есть данные

1

Я пытаюсь проанализировать сообщение ответа 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();

Куда я могу пойти отсюда, чтобы попытаться получить тело ответа как текст?

Теги:
apache-httpcomponents
pcap

2 ответа

1
Лучший ответ

Когда вы получаете тело сущности, вам нужно посмотреть как кодирование передачи, так и кодирование содержимого, и выполнить соответствующее декодирование. См. Раздел 4 "Передача кодов" RFC 7230.

Посмотрите на классы в HttpComponents, такие как ChunkedInputStream (для chunked Transfer-Encoding) и найдите код, который может un-gzip gzipped text (для gzip Content-Encoding).

  • 0
    Оба из них относятся только к содержанию сообщения, хотя, нет? (Т.е. я хотел бы обернуть InputStream возвращаемый someHttpResponse.getEntity().getContent() , если сущность не была нулевой.)
  • 0
    Если в HTTP-ответе действительно нет пустой строки между Content-Encoding: gzip и 1dd , он искажен, так как между полями заголовка и телом должна быть пустая строка (CRLF). Если это так, то не следует ожидать, что он будет разбираться, хотя HttpComponents должен указывать на ошибку. Если у него есть пустая строка, вы должны получить объект и, если HttpComponents не ип-куска и распаковывать его для вас, вам нужно подключить материал таким образом , что он делает.
Показать ещё 6 комментариев
2

Мне не удалось заставить 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();
}
  • 0
    Спасибо за это. Настолько хромает, что не понятно, как легко подготовить тело, используя DefaultHttpResponseParser.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню