2 * Routines handling protocols with a request/response line, headers,
3 * a blank line, and an optional body.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/strutil.h>
20 #include <wsutil/strtoi.h>
22 #include <epan/req_resp_hdrs.h>
25 * Optionally do reassembly of the request/response line, headers, and body.
28 req_resp_hdrs_do_reassembly(tvbuff_t
*tvb
, const int offset
, packet_info
*pinfo
,
29 const bool desegment_headers
, const bool desegment_body
,
30 bool desegment_until_fin
, int *last_chunk_offset
,
31 dissector_table_t streaming_subdissector_table
, dissector_handle_t
*streaming_chunk_handle
)
33 int next_offset
= offset
;
35 int length_remaining
, reported_length_remaining
;
39 bool content_length_found
= false;
40 bool content_type_found
= false;
41 bool chunked_encoding
= false;
43 char *content_type
= NULL
;
44 dissector_handle_t streaming_handle
= NULL
;
45 bool streaming_chunk_mode
= false;
47 DISSECTOR_ASSERT_HINT((streaming_subdissector_table
&& streaming_chunk_handle
)
48 || (streaming_subdissector_table
== NULL
&& streaming_chunk_handle
== NULL
),
49 "The streaming_subdissector_table and streaming_chunk_handle arguments must "
50 "be both given or both NULL.");
52 /* Check whether the first line is the beginning of a chunk.
53 * If it is the beginning of a chunk, we assume we are working
54 * in streaming chunk mode. The headers of HTTP request or response
55 * and at least one chunk should have been dissected in the previous
56 * packets and now we are processing subsequent chunks.
58 if (desegment_body
&& streaming_subdissector_table
59 && starts_with_chunk_size(tvb
, offset
, pinfo
)) {
60 streaming_chunk_mode
= true;
64 * Do header desegmentation if we've been told to.
66 * RFC 2616 defines HTTP messages as being either of the
67 * Request or the Response type
68 * (HTTP-message = Request | Response).
69 * Request and Response are defined as:
70 * Request = Request-Line
73 * | entity-header ) CRLF)
76 * Response = Status-Line
79 * | entity-header ) CRLF)
82 * that's why we can always assume two consecutive line
83 * endings (we allow CR, LF, or CRLF, as some clients
84 * or servers might not use a full CRLF) to mark the end
85 * of the headers. The worst thing that would happen
86 * otherwise would be the packet not being desegmented
87 * or being interpreted as only headers.
89 * RFC 2326 says RTSP works the same way; RFC 3261 says SIP
94 * If header desegmentation is activated, check that all
95 * headers are in this tvbuff (search for an empty line
96 * marking end of headers) or request one more byte (we
97 * don't know how many bytes we'll need, so we just ask
100 * If tvb starts with chunk size, then we just ignore headers parsing.
102 if (!streaming_chunk_mode
103 && desegment_headers
&& pinfo
->can_desegment
) {
105 next_offset_sav
= next_offset
;
107 reported_length_remaining
=
108 tvb_reported_length_remaining(tvb
, next_offset
);
111 * Request one more byte if there're no
112 * bytes left in the reported data (if there're
113 * bytes left in the reported data, but not in
114 * the available data, requesting more bytes
115 * won't help, as those bytes weren't captured).
117 if (reported_length_remaining
< 1) {
118 pinfo
->desegment_offset
= offset
;
119 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
123 length_remaining
= tvb_captured_length_remaining(tvb
,
127 * Request one more byte if we cannot find a
128 * header (i.e. a line end).
130 linelen
= tvb_find_line_end(tvb
, next_offset
,
131 length_remaining
, &next_offset
, true);
133 length_remaining
>= reported_length_remaining
) {
135 * Not enough data; ask for one more
138 pinfo
->desegment_offset
= offset
;
139 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
145 * We found the end of the headers.
151 * Is this a Content-Length or Transfer-Encoding
152 * header? If not, it either means that we are in
153 * a different header line, or that we are
154 * at the end of the headers, or that there
155 * isn't enough data; the two latter cases
156 * have already been handled above.
158 if (desegment_body
) {
159 /* Optimization to avoid fetching the whole (potentially very long)
160 * line and doing expensive string comparisons if the first
161 * character doesn't match. Shaves about 20% off the load time of
162 * one of my sample files that's HTTP-alike. */
163 unsigned char first_byte
= tvb_get_uint8(tvb
, next_offset_sav
);
164 if (! (first_byte
== 'c' || first_byte
== 'C' ||
165 first_byte
== 't' || first_byte
== 'T')) {
170 * Check if we've found Content-Length.
172 line
= tvb_get_string_enc(pinfo
->pool
, tvb
, next_offset_sav
, linelen
, ENC_UTF_8
|ENC_NA
);
173 if (g_ascii_strncasecmp(line
, "Content-Length:", 15) == 0) {
174 /* SSTP sets 2^64 as length, but does not really have such a
175 * large payload. Since the current tvb APIs are limited to
176 * 2^31-1 bytes, ignore large values we cannot handle. */
177 header_val
= g_strstrip(line
+ 15);
178 if (ws_strtoi32(header_val
, NULL
, &content_length
) && content_length
>= 0)
179 content_length_found
= true;
180 } else if (g_ascii_strncasecmp(line
, "Content-Type:", 13) == 0) {
181 content_type_found
= true;
182 content_type
= line
+13;
183 while (*content_type
== ' ') {
186 g_strchomp(content_type
);
187 if (streaming_subdissector_table
) {
188 streaming_handle
= dissector_get_string_handle(streaming_subdissector_table
, content_type
);
190 } else if (g_ascii_strncasecmp( line
, "Transfer-Encoding:", 18) == 0) {
192 * Find out if this Transfer-Encoding is
193 * chunked. It should be, since the
194 * other types aren't really used, but
195 * RFC 7230 defines some.
196 * (RFC 3261 says "chunked" MUST NOT be
197 * used for SIP, and RFCs 2326 and 7826
198 * say the same for RTSP, but handle it
204 header_val
= line
+18;
206 len
= (unsigned) strlen(header_val
);
207 /* Skip white space */
208 while (p
< header_val
+ len
&&
209 (*p
== ' ' || *p
== '\t'))
211 if (p
<= header_val
+ len
) {
212 if (g_ascii_strncasecmp(p
, "chunked", 7)
215 * Don't bother looking
222 chunked_encoding
= true;
230 if (streaming_chunk_mode
) {
231 /* the tvb starts with chunk size without HTTP headers */
232 chunked_encoding
= true;
233 } else if (desegment_body
&& chunked_encoding
&& streaming_handle
&& streaming_chunk_handle
) {
234 streaming_chunk_mode
= true;
235 *streaming_chunk_handle
= streaming_handle
;
239 * The above loop ends when we reached the end of the headers, so
240 * there should be content_length bytes after the 4 terminating bytes
241 * and next_offset points to after the end of the headers.
243 * XXX: If desegment_headers is false but desegment_body is true,
244 * then for HTTP Responses we will always set to DESEGMENT_UNTIL_FIN,
245 * which is probably not what we want.
247 if (desegment_body
) {
248 if (chunked_encoding
) {
250 * This data is chunked, so we need to keep pulling
251 * data until we reach the end of the stream, or a
254 * But if streaming_chunk_mode is true,
255 * we will just pull one more chunk if the end of
256 * this tvb is in middle of a chunk. Because we want
257 * to dissect chunks with subdissector as soon as
261 * This doesn't bother with trailing headers; I don't
262 * think they are really used, and we'd have to use
263 * is_http_request_or_reply() to determine if it was
264 * a trailing header, or the start of a new response.
266 bool done_chunking
= false;
267 if (last_chunk_offset
!= NULL
&& *last_chunk_offset
) {
268 next_offset
= offset
+ *last_chunk_offset
;
271 while (!done_chunking
) {
272 unsigned chunk_size
= 0;
273 int chunk_offset
= 0;
274 char *chunk_string
= NULL
;
277 reported_length_remaining
=
278 tvb_reported_length_remaining(tvb
,
281 if (reported_length_remaining
== 0 && streaming_chunk_mode
) {
285 if (reported_length_remaining
< 1) {
286 pinfo
->desegment_offset
= offset
;
287 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
291 length_remaining
= tvb_captured_length_remaining(tvb
,
294 linelen
= tvb_find_line_end(tvb
, next_offset
,
295 length_remaining
, &chunk_offset
, true);
299 reported_length_remaining
) {
300 pinfo
->desegment_offset
= offset
;
301 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
305 /* We have a line with the chunk size in it.*/
307 /* Save off the offset so we can skip this work next time.
308 * Use a relative offset, because we might call this
309 * with a different offset with a reassembled tvb.
311 if (last_chunk_offset
!= NULL
) {
312 *last_chunk_offset
= next_offset
- offset
;
315 chunk_string
= tvb_get_string_enc(pinfo
->pool
, tvb
, next_offset
,
320 * We don't care about the extensions (including optional
321 * BWS, see RFC 9112 7.1.1)
323 if ((c
= strpbrk(c
, "; \t"))) {
327 if (!ws_hexstrtou32(chunk_string
, NULL
, &chunk_size
)) {
328 /* We couldn't get the chunk size,
333 if (chunk_size
> 1U<<31) {
334 /* Chunk size is unreasonable. */
335 /* XXX What /is/ reasonable? */
339 if (chunk_size
== 0) {
341 * This is the last chunk. Let's pull in the
344 linelen
= tvb_find_line_end(tvb
,
345 chunk_offset
, length_remaining
, &chunk_offset
, true);
349 reported_length_remaining
) {
350 pinfo
->desegment_offset
= offset
;
351 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
355 pinfo
->desegment_offset
= chunk_offset
;
356 pinfo
->desegment_len
= 0;
357 done_chunking
= true;
360 * Skip to the next chunk if we
363 if (reported_length_remaining
>
366 next_offset
= chunk_offset
370 * Fetch this chunk, plus the
373 if (streaming_chunk_mode
) {
374 int size_remaining
= chunk_size
+ linelen
+ 4 - reported_length_remaining
;
375 if (size_remaining
== 0) {
378 pinfo
->desegment_offset
= offset
;
379 pinfo
->desegment_len
= size_remaining
;
383 pinfo
->desegment_offset
= offset
;
384 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
391 } else if (content_length_found
) {
392 if (content_length
>= 128*1024) { /* MS-RPCH stipulate that the content-length must be between 128K and 2G */
394 if (content_type_found
&&
395 strncmp(content_type
, "application/rpc", 15) == 0) {
396 /* It looks like a RPC_IN_DATA request or a RPC_OUT_DATA response
397 * in which the content-length is meaningless
401 /* Following sizeof will return the length of the string + \0 we need to not count it*/
402 tmp
= tvb_get_string_enc(pinfo
->pool
, tvb
, 0, sizeof("RPC_OUT_DATA") - 1, ENC_ASCII
);
403 if ((strncmp(tmp
, "RPC_IN_DATA", sizeof("RPC_IN_DATA") - 1) == 0) ||
404 (strncmp(tmp
, "RPC_OUT_DATA", sizeof("RPC_OUT_DATA") - 1) == 0)) {
408 /* next_offset has been set to the end of the headers */
409 if (!tvb_bytes_exist(tvb
, next_offset
, content_length
)) {
410 length_remaining
= tvb_captured_length_remaining(tvb
,
412 reported_length_remaining
=
413 tvb_reported_length_remaining(tvb
, next_offset
);
414 if (length_remaining
< reported_length_remaining
) {
416 * It's a waste of time asking for more
417 * data, because that data wasn't captured.
421 if (length_remaining
== -1)
422 length_remaining
= 0;
423 pinfo
->desegment_offset
= offset
;
424 pinfo
->desegment_len
=
425 content_length
- length_remaining
;
428 } else if (desegment_until_fin
&& pinfo
->can_desegment
) {
430 * No Content-Length nor Transfer-Encoding headers are
431 * found. For HTTP requests, there is definitely no
432 * body (case 6 of RFC 7230, Section 3.3.3.). For HTTP
433 * responses, the message body length runs until the end
434 * of the connection (case 7).
436 * Protocols like RTSP treat absence of Content-Length
437 * as 0, so do not request more segments either.
439 length_remaining
= tvb_captured_length_remaining(tvb
, next_offset
);
440 reported_length_remaining
= tvb_reported_length_remaining(tvb
, next_offset
);
441 if (length_remaining
< reported_length_remaining
) {
443 * It's a waste of time asking for more
444 * data, because that data wasn't captured.
449 pinfo
->desegment_offset
= offset
;
450 pinfo
->desegment_len
= DESEGMENT_UNTIL_FIN
;
458 * No further desegmentation needed.
464 * Editor modelines - https://www.wireshark.org/tools/modelines.html
469 * indent-tabs-mode: t
472 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
473 * :indentSize=8:tabSize=8:noTabs=false: