http: Store request/response data there, not in the conversation

The host, request method, request URI, and response code are
information that are local to a request/response pair. Storing
them in the conversation data struct means that we only have access
to one set of values at any one point.

Currently they are updated every time a packet is dissected,
which is fine for sequential processing but causes unexpected
behavior when scrolling the window upwards, going directly
to a packet, or filtering, among other out of order behavior.

Store the values in the per packet data, and create the
file scoped data only on the first pass. The conversation
level data will have access to the final http_req_res_t
struct, which is useful for connections that Upgrade to a
different dissector.

Also, when a response code is in the Informational 1xx category,
that means it is an interim response and the next response could
be for the same request. (This affects 100 Continue, 103 Early
Hints, etc.)

Fix #16753.
This commit is contained in:
John Thacker 2022-09-29 17:26:12 -04:00 committed by AndersBroman
parent 1293f15897
commit 891716800b
3 changed files with 114 additions and 68 deletions

View File

@ -404,10 +404,9 @@ static int
dissect_grpc(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data) dissect_grpc(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
{ {
int ret; int ret;
http_conv_t* http_conv; http_req_res_t* curr_req_res;
tvbuff_t* real_data_tvb; tvbuff_t* real_data_tvb;
grpc_context_info_t grpc_ctx = { 0 }; grpc_context_info_t grpc_ctx = { 0 };
conversation_t* conv = find_or_create_conversation(pinfo);
http_message_info_t* http_msg_info = (http_message_info_t*)data; http_message_info_t* http_msg_info = (http_message_info_t*)data;
gboolean is_grpc_web_text = g_str_has_prefix(pinfo->match_string, "application/grpc-web-text"); gboolean is_grpc_web_text = g_str_has_prefix(pinfo->match_string, "application/grpc-web-text");
@ -429,10 +428,10 @@ dissect_grpc(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
grpc_ctx.encoding = http2_get_header_value(pinfo, HTTP2_HEADER_GRPC_ENCODING, FALSE); grpc_ctx.encoding = http2_get_header_value(pinfo, HTTP2_HEADER_GRPC_ENCODING, FALSE);
} }
else if (proto_is_frame_protocol(pinfo->layers, "http")) { else if (proto_is_frame_protocol(pinfo->layers, "http")) {
http_conv = (http_conv_t*)conversation_get_proto_data(conv, proto_http); curr_req_res = (http_req_res_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, 0);
DISSECTOR_ASSERT_HINT(http_conv && http_msg_info, "Unexpected error: HTTP conversation or HTTP message info not available."); DISSECTOR_ASSERT_HINT(curr_req_res && http_msg_info, "Unexpected error: HTTP request/reply or HTTP message info not available.");
grpc_ctx.is_request = (http_msg_info->type == HTTP_REQUEST); grpc_ctx.is_request = (http_msg_info->type == HTTP_REQUEST);
grpc_ctx.path = http_conv->request_uri; grpc_ctx.path = curr_req_res->request_uri;
grpc_ctx.content_type = pinfo->match_string; /* only for grpc-web(-text) over http1.1 */ grpc_ctx.content_type = pinfo->match_string; /* only for grpc-web(-text) over http1.1 */
if (http_msg_info->data) { if (http_msg_info->data) {
grpc_ctx.encoding = (const gchar*)wmem_map_lookup((wmem_map_t *)http_msg_info->data, HTTP2_HEADER_GRPC_ENCODING); grpc_ctx.encoding = (const gchar*)wmem_map_lookup((wmem_map_t *)http_msg_info->data, HTTP2_HEADER_GRPC_ENCODING);

View File

@ -289,8 +289,8 @@ static range_t *http_tcp_range = NULL;
static range_t *http_sctp_range = NULL; static range_t *http_sctp_range = NULL;
static range_t *http_tls_range = NULL; static range_t *http_tls_range = NULL;
typedef void (*ReqRespDissector)(tvbuff_t*, proto_tree*, int, const guchar*, typedef void (*ReqRespDissector)(packet_info*, tvbuff_t*, proto_tree*, int, const guchar*,
const guchar*, http_conv_t *); const guchar*, http_conv_t *, http_req_res_t *);
/** /**
* Transfer codings from * Transfer codings from
@ -1037,7 +1037,8 @@ get_http_conversation_data(packet_info *pinfo, conversation_t **conversation)
* create a new http_req_res_t and add it to the conversation. * create a new http_req_res_t and add it to the conversation.
* @return the new allocated object which is already added to the linked list * @return the new allocated object which is already added to the linked list
*/ */
static http_req_res_t* push_req_res(http_conv_t *conv_data) static http_req_res_t*
push_req_res(http_conv_t *conv_data)
{ {
http_req_res_t *req_res = wmem_new0(wmem_file_scope(), http_req_res_t); http_req_res_t *req_res = wmem_new0(wmem_file_scope(), http_req_res_t);
nstime_set_unset(&(req_res->req_ts)); nstime_set_unset(&(req_res->req_ts));
@ -1057,7 +1058,8 @@ static http_req_res_t* push_req_res(http_conv_t *conv_data)
/** /**
* push a request frame number and its time stamp to the conversation data. * push a request frame number and its time stamp to the conversation data.
*/ */
static void push_req(http_conv_t *conv_data, packet_info *pinfo) static http_req_res_t*
push_req(http_conv_t *conv_data, packet_info *pinfo)
{ {
/* a request will always create a new http_req_res_t object */ /* a request will always create a new http_req_res_t object */
http_req_res_t *req_res = push_req_res(conv_data); http_req_res_t *req_res = push_req_res(conv_data);
@ -1065,26 +1067,45 @@ static void push_req(http_conv_t *conv_data, packet_info *pinfo)
req_res->req_framenum = pinfo->num; req_res->req_framenum = pinfo->num;
req_res->req_ts = pinfo->abs_ts; req_res->req_ts = pinfo->abs_ts;
/* XXX: Using the same proto key for the frame doesn't work well
* with HTTP 1.1 pipelining, or other situations where more
* than one request can appear in a frame.
*/
p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res); p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res);
return req_res;
} }
/** /**
* push a response frame number to the conversation data. * push a response frame number to the conversation data.
*/ */
static void push_res(http_conv_t *conv_data, packet_info *pinfo) static http_req_res_t*
push_res(http_conv_t *conv_data, packet_info *pinfo)
{ {
/* a response will create a new http_req_res_t object: if no /* a response will create a new http_req_res_t object: if no
object exists, or if one exists for another response. In object exists, or if the most recent one is already for
both cases the corresponding request was not a different response. (Exception: If the previous response
code was in the Informational 1xx category, then it was
an interim response, and this response could be for the same
request.) In both cases the corresponding request was not
detected/included in the conversation. In all other cases detected/included in the conversation. In all other cases
the http_req_res_t object created by the request is the http_req_res_t object created by the request is
used. */ used. */
/* XXX: This finds the only most recent request and doesn't support
* HTTP 1.1 pipelining.
*/
http_req_res_t *req_res = conv_data->req_res_tail; http_req_res_t *req_res = conv_data->req_res_tail;
if (!req_res || req_res->res_framenum > 0) { if (!req_res || (req_res->res_framenum > 0 && req_res->response_code >= 200)) {
req_res = push_req_res(conv_data); req_res = push_req_res(conv_data);
} }
req_res->res_framenum = pinfo->num; req_res->res_framenum = pinfo->num;
/* XXX: Using the same proto key for the frame doesn't work well
* with HTTP 1.1 pipelining, or other situations where more
* than one request can appear in a frame.
*/
p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res); p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res);
return req_res;
} }
/* /*
@ -1134,6 +1155,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
wmem_map_t *chunk_map = NULL; wmem_map_t *chunk_map = NULL;
conversation_t *conversation; conversation_t *conversation;
http_req_res_t *curr = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, 0);
conversation = find_or_create_conversation(pinfo); conversation = find_or_create_conversation(pinfo);
if (cmp_address(&pinfo->src, conversation_key_addr1(conversation->key_ptr)) == 0 && pinfo->srcport == conversation_key_port1(conversation->key_ptr)) { if (cmp_address(&pinfo->src, conversation_key_addr1(conversation->key_ptr)) == 0 && pinfo->srcport == conversation_key_port1(conversation->key_ptr)) {
@ -1172,7 +1194,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* actually HTTP (even if what we have here is part of a file being * actually HTTP (even if what we have here is part of a file being
* transferred over HTTP). * transferred over HTTP).
*/ */
if (conv_data->request_uri) if (conv_data->req_res_tail)
have_seen_http = TRUE; have_seen_http = TRUE;
/* /*
@ -1270,14 +1292,27 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
try_desegment_body = (http_desegment_body && !end_of_stream); try_desegment_body = (http_desegment_body && !end_of_stream);
if (try_desegment_body && http_type == HTTP_RESPONSE) { if (try_desegment_body && http_type == HTTP_RESPONSE) {
/* /*
* conv_data->response_code is not yet set, so extract * The response_code is not yet set, so extract
* the response code from the current line. * the response code from the current line.
*/ */
gint response_code = parse_http_status_code(firstline, firstline + first_linelen); gint response_code = parse_http_status_code(firstline, firstline + first_linelen);
if ((g_strcmp0(conv_data->request_method, "HEAD") == 0 || /*
* On a second pass, we should have already associated
* the response with the request. On a first sequential
* pass, we haven't done so yet (as we don't know if we
* need more data), so get the request method from the
* most recent request, if it exists.
*/
char* request_method = NULL;
if (curr) {
request_method = curr->request_method;
} else if (!PINFO_FD_VISITED(pinfo) && conv_data->req_res_tail) {
request_method = conv_data->req_res_tail->request_method;
}
if ((g_strcmp0(request_method, "HEAD") == 0 ||
(response_code / 100 == 2 && (response_code / 100 == 2 &&
(g_strcmp0(conv_data->request_method, "CONNECT") == 0 || (g_strcmp0(request_method, "CONNECT") == 0 ||
g_strcmp0(conv_data->request_method, "SSTP_DUPLEX_POST") == 0)) || g_strcmp0(request_method, "SSTP_DUPLEX_POST") == 0)) ||
response_code / 100 == 1 || response_code / 100 == 1 ||
response_code == 204 || response_code == 204 ||
response_code == 304)) { response_code == 304)) {
@ -1477,9 +1512,17 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
offset, next_offset - offset, ett_http_request, &hdr_item, text); offset, next_offset - offset, ett_http_request, &hdr_item, text);
expert_add_info_format(pinfo, hdr_item, &ei_http_chat, "%s", text); expert_add_info_format(pinfo, hdr_item, &ei_http_chat, "%s", text);
if (!PINFO_FD_VISITED(pinfo)) {
if (http_type == HTTP_REQUEST) {
curr = push_req(conv_data, pinfo);
curr->request_method = wmem_strdup(wmem_file_scope(), stat_info->request_method);
} else if (http_type == HTTP_RESPONSE) {
curr = push_res(conv_data, pinfo);
}
}
if (reqresp_dissector) { if (reqresp_dissector) {
reqresp_dissector(tvb, req_tree, offset, line, reqresp_dissector(pinfo, tvb, req_tree, offset, line,
lineend, conv_data); lineend, conv_data, curr);
} }
} else { } else {
/* /*
@ -1497,7 +1540,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
if ((g_ascii_strncasecmp(stat_info->request_uri, "http://", 7) == 0) || if ((g_ascii_strncasecmp(stat_info->request_uri, "http://", 7) == 0) ||
(g_ascii_strncasecmp(stat_info->request_uri, "https://", 8) == 0) || (g_ascii_strncasecmp(stat_info->request_uri, "https://", 8) == 0) ||
(g_ascii_strncasecmp(conv_data->request_method, "CONNECT", 7) == 0)) { (g_ascii_strncasecmp(stat_info->request_method, "CONNECT", 7) == 0)) {
uri = wmem_strdup(wmem_packet_scope(), stat_info->request_uri); uri = wmem_strdup(wmem_packet_scope(), stat_info->request_uri);
} }
else { else {
@ -1506,7 +1549,9 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
g_strstrip(wmem_strdup(wmem_packet_scope(), stat_info->http_host)), stat_info->request_uri); g_strstrip(wmem_strdup(wmem_packet_scope(), stat_info->http_host)), stat_info->request_uri);
} }
stat_info->full_uri = wmem_strdup(wmem_packet_scope(), uri); stat_info->full_uri = wmem_strdup(wmem_packet_scope(), uri);
conv_data->full_uri = wmem_strdup(wmem_file_scope(), uri); if (!PINFO_FD_VISITED(pinfo) && curr) {
curr->full_uri = wmem_strdup(wmem_file_scope(), uri);
}
if (tree) { if (tree) {
e_ti = proto_tree_add_string(http_tree, e_ti = proto_tree_add_string(http_tree,
hf_http_request_full_uri, tvb, 0, hf_http_request_full_uri, tvb, 0,
@ -1517,17 +1562,8 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
} }
} }
if (!PINFO_FD_VISITED(pinfo)) {
if (http_type == HTTP_REQUEST) {
push_req(conv_data, pinfo);
} else if (http_type == HTTP_RESPONSE) {
push_res(conv_data, pinfo);
}
}
if (tree) { if (tree) {
proto_item *pi; proto_item *pi;
http_req_res_t *curr = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, 0);
http_req_res_t *prev = curr ? curr->prev : NULL; http_req_res_t *prev = curr ? curr->prev : NULL;
http_req_res_t *next = curr ? curr->next : NULL; http_req_res_t *next = curr ? curr->next : NULL;
@ -1580,13 +1616,8 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* /*
* add the request URI to the response to allow filtering responses filtered by URI * add the request URI to the response to allow filtering responses filtered by URI
*/ */
if (conv_data && (conv_data->full_uri || conv_data->request_uri)) { if (curr && curr->request_uri) {
if (conv_data->full_uri) { pi = proto_tree_add_string(http_tree, hf_http_response_for_uri, tvb, 0, 0, curr->full_uri ? curr->full_uri : curr->request_uri);
pi = proto_tree_add_string(http_tree, hf_http_response_for_uri, tvb, 0, 0, conv_data->full_uri);
}
else {
pi = proto_tree_add_string(http_tree, hf_http_response_for_uri, tvb, 0, 0, conv_data->request_uri);
}
proto_item_set_generated(pi); proto_item_set_generated(pi);
} }
@ -1902,10 +1933,12 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* Data and not a complete object? * Data and not a complete object?
*/ */
if(have_tap_listener(http_eo_tap)) { if(have_tap_listener(http_eo_tap)) {
eo_info = wmem_new(wmem_packet_scope(), http_eo_t); eo_info = wmem_new0(wmem_packet_scope(), http_eo_t);
eo_info->hostname = conv_data->http_host; if (curr) {
eo_info->filename = conv_data->request_uri; eo_info->hostname = curr->http_host;
eo_info->filename = curr->request_uri;
}
eo_info->content_type = headers.content_type; eo_info->content_type = headers.content_type;
eo_info->payload_len = tvb_captured_length(next_tvb); eo_info->payload_len = tvb_captured_length(next_tvb);
eo_info->payload_data = tvb_get_ptr(next_tvb, 0, eo_info->payload_len); eo_info->payload_data = tvb_get_ptr(next_tvb, 0, eo_info->payload_len);
@ -2023,7 +2056,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
} }
/* Detect protocol changes after receiving full response headers. */ /* Detect protocol changes after receiving full response headers. */
if (conv_data->request_method && http_type == HTTP_RESPONSE && pinfo->desegment_offset <= 0 && pinfo->desegment_len <= 0) { if (http_type == HTTP_RESPONSE && curr && pinfo->desegment_offset <= 0 && pinfo->desegment_len <= 0) {
dissector_handle_t next_handle = NULL; dissector_handle_t next_handle = NULL;
gboolean server_acked = FALSE; gboolean server_acked = FALSE;
@ -2031,7 +2064,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* SSTP uses a special request method (instead of the Upgrade * SSTP uses a special request method (instead of the Upgrade
* header) and expects a 200 response to set up the session. * header) and expects a 200 response to set up the session.
*/ */
if (strcmp(conv_data->request_method, "SSTP_DUPLEX_POST") == 0 && conv_data->response_code == 200) { if (g_strcmp0(curr->request_method, "SSTP_DUPLEX_POST") == 0 && curr->response_code == 200) {
next_handle = sstp_handle; next_handle = sstp_handle;
server_acked = TRUE; server_acked = TRUE;
} }
@ -2040,7 +2073,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* An HTTP/1.1 upgrade only proceeds if the server responds * An HTTP/1.1 upgrade only proceeds if the server responds
* with 101 Switching Protocols. See RFC 7230 Section 6.7. * with 101 Switching Protocols. See RFC 7230 Section 6.7.
*/ */
if (headers.upgrade && conv_data->response_code == 101) { if (headers.upgrade && curr->response_code == 101) {
next_handle = dissector_get_string_handle(upgrade_subdissector_table, headers.upgrade); next_handle = dissector_get_string_handle(upgrade_subdissector_table, headers.upgrade);
if (!next_handle) { if (!next_handle) {
char *slash_pos = strchr(headers.upgrade, '/'); char *slash_pos = strchr(headers.upgrade, '/');
@ -2073,9 +2106,9 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* protocol version into a sub-tree. * protocol version into a sub-tree.
*/ */
static void static void
basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset, basic_request_dissector(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
const guchar *line, const guchar *lineend, int offset, const guchar *line, const guchar *lineend,
http_conv_t *conv_data) http_conv_t *conv_data _U_, http_req_res_t *curr)
{ {
const guchar *next_token; const guchar *next_token;
const gchar *request_uri; const gchar *request_uri;
@ -2104,8 +2137,9 @@ basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
/* Save the request URI for various later uses */ /* Save the request URI for various later uses */
request_uri = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tokenlen, ENC_ASCII); request_uri = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tokenlen, ENC_ASCII);
stat_info->request_uri = wmem_strdup(wmem_packet_scope(), request_uri); stat_info->request_uri = wmem_strdup(wmem_packet_scope(), request_uri);
conv_data->request_uri = wmem_strdup(wmem_file_scope(), request_uri); if (!PINFO_FD_VISITED(pinfo) && curr) {
curr->request_uri = wmem_strdup(wmem_file_scope(), request_uri);
}
tj = proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen, request_uri); tj = proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen, request_uri);
if (( query_str = strchr(request_uri, '?')) != NULL) { if (( query_str = strchr(request_uri, '?')) != NULL) {
if (strlen(query_str) > 1) { if (strlen(query_str) > 1) {
@ -2167,9 +2201,9 @@ parse_http_status_code(const guchar *line, const guchar *lineend)
} }
static void static void
basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset, basic_response_dissector(packet_info *pinfo _U_, tvbuff_t *tvb, proto_tree *tree,
const guchar *line, const guchar *lineend, int offset, const guchar *line, const guchar *lineend,
http_conv_t *conv_data _U_) http_conv_t *conv_data _U_, http_req_res_t *curr)
{ {
const guchar *next_token; const guchar *next_token;
int tokenlen; int tokenlen;
@ -2201,8 +2235,11 @@ basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
memcpy(response_code_chars, line, 3); memcpy(response_code_chars, line, 3);
response_code_chars[3] = '\0'; response_code_chars[3] = '\0';
stat_info->response_code = conv_data->response_code = stat_info->response_code =
(guint)strtoul(response_code_chars, NULL, 10); (guint)strtoul(response_code_chars, NULL, 10);
if (curr) {
curr->response_code = stat_info->response_code;
}
proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3, proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3,
stat_info->response_code); stat_info->response_code);
@ -2598,7 +2635,7 @@ http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
addresses_equal(&conv_data->server_addr, &pinfo->src); addresses_equal(&conv_data->server_addr, &pinfo->src);
/* Grab the destination port number from the request URI to find the right subdissector */ /* Grab the destination port number from the request URI to find the right subdissector */
strings = wmem_strsplit(wmem_packet_scope(), conv_data->request_uri, ":", 2); strings = wmem_strsplit(wmem_packet_scope(), conv_data->req_res_tail->request_uri, ":", 2);
if(strings[0] != NULL && strings[1] != NULL) { if(strings[0] != NULL && strings[1] != NULL) {
/* /*
@ -2671,7 +2708,7 @@ http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
static int static int
is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type, is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
ReqRespDissector *reqresp_dissector, ReqRespDissector *reqresp_dissector,
http_conv_t *conv_data) http_conv_t *conv_data _U_)
{ {
int isHttpRequestOrReply = FALSE; int isHttpRequestOrReply = FALSE;
@ -2847,7 +2884,6 @@ is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
*reqresp_dissector = basic_request_dissector; *reqresp_dissector = basic_request_dissector;
stat_info->request_method = wmem_strndup(wmem_packet_scope(), data, indx); stat_info->request_method = wmem_strndup(wmem_packet_scope(), data, indx);
conv_data->request_method = wmem_strndup(wmem_file_scope(), data, indx);
} }
@ -3119,6 +3155,7 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
int i; int i;
int* hf_id; int* hf_id;
tap_credential_t* auth; tap_credential_t* auth;
http_req_res_t *curr_req_res = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, 0);
len = next_offset - offset; len = next_offset - offset;
line_end_offset = offset + linelen; line_end_offset = offset + linelen;
@ -3414,7 +3451,9 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
case HDR_HOST: case HDR_HOST:
stat_info->http_host = wmem_strndup(wmem_packet_scope(), value, value_len); stat_info->http_host = wmem_strndup(wmem_packet_scope(), value, value_len);
conv_data->http_host = wmem_strndup(wmem_file_scope(), value, value_len); if (!PINFO_FD_VISITED(pinfo) && curr_req_res) {
curr_req_res->http_host = wmem_strndup(wmem_file_scope(), value, value_len);
}
break; break;
case HDR_UPGRADE: case HDR_UPGRADE:
@ -3470,9 +3509,9 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
break; break;
case HDR_LOCATION: case HDR_LOCATION:
if (conv_data->request_uri){ if (curr_req_res && curr_req_res->request_uri){
stat_info->location_target = wmem_strndup(wmem_packet_scope(), value, value_len); stat_info->location_target = wmem_strndup(wmem_packet_scope(), value, value_len);
stat_info->location_base_uri = wmem_strdup(wmem_packet_scope(), conv_data->full_uri); stat_info->location_base_uri = wmem_strdup(wmem_packet_scope(), curr_req_res->full_uri);
} }
break; break;
case HDR_HTTP2_SETTINGS: case HDR_HTTP2_SETTINGS:
@ -3842,11 +3881,13 @@ dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
* Check if this is proxied connection and if so, hand of dissection to the * Check if this is proxied connection and if so, hand of dissection to the
* payload-dissector. * payload-dissector.
* Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */ * Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
http_req_res_t *curr_req_res = conv_data->req_res_tail;
if(pinfo->num >= conv_data->startframe && if(pinfo->num >= conv_data->startframe &&
conv_data->response_code == 200 && curr_req_res &&
conv_data->request_method && curr_req_res->response_code == 200 &&
strncmp(conv_data->request_method, "CONNECT", 7) == 0 && curr_req_res->request_method &&
conv_data->request_uri) { strncmp(curr_req_res->request_method, "CONNECT", 7) == 0 &&
curr_req_res->request_uri) {
if (conv_data->startframe == 0 && !PINFO_FD_VISITED(pinfo)) { if (conv_data->startframe == 0 && !PINFO_FD_VISITED(pinfo)) {
conv_data->startframe = pinfo->num; conv_data->startframe = pinfo->num;
conv_data->startoffset = 0; conv_data->startoffset = 0;

View File

@ -49,6 +49,11 @@ typedef struct _http_req_res_t {
guint32 res_framenum; guint32 res_framenum;
/** timestamp of the request */ /** timestamp of the request */
nstime_t req_ts; nstime_t req_ts;
guint response_code;
gchar *request_method;
gchar *http_host;
gchar *request_uri;
gchar *full_uri;
/** pointer to the next element in the linked list, NULL for the tail node */ /** pointer to the next element in the linked list, NULL for the tail node */
struct _http_req_res_t *next; struct _http_req_res_t *next;
/** pointer to the previous element in the linked list, NULL for the head node */ /** pointer to the previous element in the linked list, NULL for the head node */
@ -57,12 +62,7 @@ typedef struct _http_req_res_t {
/** Conversation data of a HTTP connection. */ /** Conversation data of a HTTP connection. */
typedef struct _http_conv_t { typedef struct _http_conv_t {
guint response_code;
guint32 req_res_num; /**< The number of requests in the conversation. */ guint32 req_res_num; /**< The number of requests in the conversation. */
gchar *http_host;
gchar *request_method;
gchar *request_uri;
gchar *full_uri;
/* Used to speed up desegmenting of chunked Transfer-Encoding. */ /* Used to speed up desegmenting of chunked Transfer-Encoding. */
wmem_map_t *chunk_offsets_fwd; wmem_map_t *chunk_offsets_fwd;
@ -80,6 +80,12 @@ typedef struct _http_conv_t {
address server_addr; address server_addr;
/** the tail node of req_res */ /** the tail node of req_res */
http_req_res_t *req_res_tail; http_req_res_t *req_res_tail;
/** Information from the last request or response can
* be found in the tail node. It is only sensible to look
* at on the first (sequential) pass, or after startframe /
* startoffset on connections that have proxied/tunneled/Upgraded.
*/
} http_conv_t; } http_conv_t;
typedef enum _http_type { typedef enum _http_type {