mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 09:38:19 +00:00
142 lines
3.4 KiB
JavaScript
142 lines
3.4 KiB
JavaScript
# $Id:$
|
|
|
|
enum ExpectBody {
|
|
BODY_EXPECTED,
|
|
BODY_NOT_EXPECTED,
|
|
BODY_MAYBE,
|
|
};
|
|
|
|
enum DeliveryMode {
|
|
UNKNOWN_DELIVERY_MODE,
|
|
CONTENT_LENGTH,
|
|
CHUNKED,
|
|
MULTIPART,
|
|
};
|
|
|
|
## token = 1*<any CHAR except CTLs or separators>
|
|
## separators = "(" | ")" | "<" | ">" | "@"
|
|
## | "," | ";" | ":" | "\" | <">
|
|
## | "/" | "[" | "]" | "?" | "="
|
|
## | "{" | "}" | SP | HT
|
|
## reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
|
|
## "$" | ","
|
|
|
|
type HTTP_TOKEN = RE/[^()<>@,;:\\"\/\[\]?={} \t]+/;
|
|
type HTTP_WS = RE/[ \t]*/;
|
|
type HTTP_URI = RE/[[:alnum:][:punct:]]+/;
|
|
|
|
type HTTP_PDU(is_orig: bool) = case is_orig of {
|
|
true -> request: HTTP_Request;
|
|
false -> reply: HTTP_Reply;
|
|
};
|
|
|
|
type HTTP_Request = record {
|
|
request: HTTP_RequestLine;
|
|
msg: HTTP_Message(BODY_MAYBE);
|
|
};
|
|
|
|
function expect_reply_body(reply_status: int): ExpectBody
|
|
%{
|
|
// TODO: check if the request is "HEAD"
|
|
if ( (reply_status >= 100 && reply_status < 200) ||
|
|
reply_status == 204 || reply_status == 304 )
|
|
return BODY_NOT_EXPECTED;
|
|
return BODY_EXPECTED;
|
|
%}
|
|
|
|
type HTTP_Reply = record {
|
|
reply: HTTP_ReplyLine;
|
|
msg: HTTP_Message(expect_reply_body(reply.status.stat_num));
|
|
};
|
|
|
|
type HTTP_RequestLine = record {
|
|
method: HTTP_TOKEN;
|
|
: HTTP_WS;
|
|
uri: HTTP_URI;
|
|
: HTTP_WS;
|
|
version: HTTP_Version;
|
|
} &oneline;
|
|
|
|
type HTTP_ReplyLine = record {
|
|
version: HTTP_Version;
|
|
: HTTP_WS;
|
|
status: HTTP_Status;
|
|
: HTTP_WS;
|
|
reason: bytestring &restofdata;
|
|
} &oneline;
|
|
|
|
type HTTP_Status = record {
|
|
stat_str: RE/[0-9]{3}/;
|
|
} &let {
|
|
stat_num: int = bytestring_to_int(stat_str, 10);
|
|
};
|
|
|
|
type HTTP_Version = record {
|
|
: "HTTP/";
|
|
vers_str: RE/[0-9]+\.[0-9]+/;
|
|
} &let {
|
|
vers_num: double = bytestring_to_double(vers_str);
|
|
};
|
|
|
|
type HTTP_Headers = HTTP_Header[] &until($input.length() == 0);
|
|
|
|
type HTTP_Message(expect_body: ExpectBody) = record {
|
|
headers: HTTP_Headers;
|
|
body_or_not: case expect_body of {
|
|
BODY_NOT_EXPECTED -> none: empty;
|
|
default -> body: HTTP_Body(expect_body);
|
|
};
|
|
};
|
|
|
|
# Multi-line headers are supported by allowing header names to be
|
|
# empty.
|
|
#
|
|
type HTTP_HEADER_NAME = RE/|([^: \t]+:)/;
|
|
type HTTP_Header = record {
|
|
name: HTTP_HEADER_NAME &transient;
|
|
: HTTP_WS;
|
|
value: bytestring &restofdata &transient;
|
|
} &oneline;
|
|
|
|
type MIME_Line = record {
|
|
line: bytestring &restofdata &transient;
|
|
} &oneline;
|
|
|
|
type MIME_Lines = MIME_Line[]
|
|
&until($context.flow.is_end_of_multipart($input));
|
|
|
|
# TODO: parse multipart message according to MIME
|
|
type HTTP_Body(expect_body: ExpectBody) =
|
|
case $context.flow.delivery_mode() of {
|
|
|
|
CONTENT_LENGTH -> body: bytestring
|
|
&length = $context.flow.content_length(),
|
|
&chunked;
|
|
|
|
CHUNKED -> chunks: HTTP_Chunks;
|
|
|
|
MULTIPART -> multipart: MIME_Lines;
|
|
|
|
default -> unknown: HTTP_UnknownBody(expect_body);
|
|
};
|
|
|
|
type HTTP_UnknownBody(expect_body: ExpectBody) = case expect_body of {
|
|
BODY_MAYBE, BODY_NOT_EXPECTED -> maybenot: empty;
|
|
BODY_EXPECTED -> rest: bytestring &restofflow &chunked;
|
|
};
|
|
|
|
type HTTP_Chunks = record {
|
|
chunks: HTTP_Chunk[] &until($element.chunk_length == 0);
|
|
headers: HTTP_Headers;
|
|
};
|
|
|
|
type HTTP_Chunk = record {
|
|
length_line: bytestring &oneline;
|
|
data: bytestring &length = chunk_length &chunked;
|
|
opt_crlf: case chunk_length of {
|
|
0 -> none: empty;
|
|
default -> crlf: bytestring &oneline &check(trailing_crlf == "");
|
|
};
|
|
} &let {
|
|
chunk_length: int = bytestring_to_int(length_line, 16);
|
|
};
|