]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/http/message_fuzz.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / test / beast / http / message_fuzz.hpp
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
11 #define BOOST_BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
12
13 #include <boost/beast/core/ostream.hpp>
14 #include <boost/beast/http/detail/rfc7230.hpp>
15 #include <cstdint>
16 #include <random>
17 #include <string>
18
19 namespace boost {
20 namespace beast {
21 namespace http {
22
23 template<class = void>
24 std::string
25 escaped_string(string_view s)
26 {
27 std::string out;
28 out.reserve(s.size());
29 for(char c : s)
30 {
31 if(c == '\r')
32 out.append("\\r");
33 else if(c == '\n')
34 out.append("\\n");
35 else if(c == '\t')
36 out.append("\\t");
37 else
38 out.append(&c, 1);
39 }
40 return out;
41 }
42
43 // Produces random HTTP messages
44 //
45 template<class = void>
46 class message_fuzz_t
47 {
48 std::mt19937 rng_;
49
50 static
51 std::string
52 to_hex(std::size_t v)
53 {
54 if(! v)
55 return "0";
56 std::string s;
57 while(v > 0)
58 {
59 s.insert(s.begin(),
60 "0123456789abcdef"[v&0xf]);
61 v >>= 4;
62 }
63 return s;
64 }
65
66 public:
67 template<class UInt = std::size_t>
68 UInt
69 rand(std::size_t n)
70 {
71 return static_cast<UInt>(
72 std::uniform_int_distribution<
73 std::size_t>{0, n-1}(rng_));
74 }
75
76 std::string
77 method()
78 {
79 #if 0
80 // All IANA registered methods
81 static char const* const list[39] = {
82 "ACL", "BASELINE-CONTROL", "BIND", "CHECKIN", "CHECKOUT", "CONNECT",
83 "COPY", "DELETE", "GET", "HEAD", "LABEL", "LINK", "LOCK", "MERGE",
84 "MKACTIVITY", "MKCALENDAR", "MKCOL", "MKREDIRECTREF", "MKWORKSPACE",
85 "MOVE", "OPTIONS", "ORDERPATCH", "PATCH", "POST", "PRI", "PROPFIND",
86 "PROPPATCH", "PUT", "REBIND", "REPORT", "SEARCH", "TRACE", "UNBIND",
87 "UNCHECKOUT", "UNLINK", "UNLOCK", "UPDATE", "UPDATEREDIRECTREF",
88 "VERSION-CONTROL"
89 };
90 return list[rand(39)];
91 #else
92 // methods parsed by nodejs-http-parser
93 static char const* const list[33] = {
94 "ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "HEAD", "GET",
95 "LINK", "LOCK", "MERGE", "MKCOL", "MKCALENDAR", "MKACTIVITY", "M-SEARCH",
96 "MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND", "PROPPATCH",
97 "PURGE", "PUT", "REBIND", "REPORT", "SEARCH", "SUBSCRIBE", "TRACE",
98 "UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE"
99 };
100 return list[rand(33)];
101 #endif
102 }
103
104 std::string
105 scheme()
106 {
107 static char const* const list[241] = {
108 "aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs",
109 "aim", "appdata", "apt", "attachment", "aw", "barion", "beshare", "bitcoin",
110 "blob", "bolo", "callto", "cap", "chrome", "chrome-extension", "cid",
111 "coap", "coaps", "com-eventbrite-attendee", "content", "crid", "cvs",
112 "data", "dav", "dict", "dis", "dlna-playcontainer", "dlna-playsingle",
113 "dns", "dntp", "dtn", "dvb", "ed2k", "example", "facetime", "fax", "feed",
114 "feedready", "file", "filesystem", "finger", "fish", "ftp", "geo", "gg",
115 "git", "gizmoproject", "go", "gopher", "gtalk", "h323", "ham", "hcp",
116 "http", "https", "iax", "icap", "icon", "im", "imap", "info", "iotdisco",
117 "ipn", "ipp", "ipps", "irc", "irc6", "ircs", "iris", "iris.beep",
118 "iris.lwz", "iris.xpc", "iris.xpcs", "isostore", "itms", "jabber", "jar",
119 "jms", "keyparc", "lastfm", "ldap", "ldaps", "magnet", "mailserver",
120 "mailto", "maps", "market", "message", "mid", "mms",
121 "modem", "ms-access", "ms-drive-to", "ms-enrollment", "ms-excel",
122 "ms-getoffice", "ms-help", "ms-infopath", "ms-media-stream-id", "ms-project",
123 "ms-powerpoint", "ms-publisher", "ms-search-repair",
124 "ms-secondary-screen-controller", "ms-secondary-screen-setup",
125 "ms-settings", "ms-settings-airplanemode", "ms-settings-bluetooth",
126 "ms-settings-camera", "ms-settings-cellular", "ms-settings-cloudstorage",
127 "ms-settings-emailandaccounts", "ms-settings-language", "ms-settings-location",
128 "ms-settings-lock", "ms-settings-nfctransactions", "ms-settings-notifications",
129 "ms-settings-power", "ms-settings-privacy", "ms-settings-proximity",
130 "ms-settings-screenrotation", "ms-settings-wifi", "ms-settings-workplace",
131 "ms-spd", "ms-transit-to", "ms-visio", "ms-walk-to", "ms-word", "msnim",
132 "msrp", "msrps", "mtqp", "mumble", "mupdate", "mvn", "news", "nfs", "ni",
133 "nih", "nntp", "notes", "oid", "opaquelocktoken", "pack", "palm", "paparazzi",
134 "pkcs11", "platform", "pop", "pres", "prospero", "proxy", "psyc", "query",
135 "redis", "rediss", "reload", "res", "target", "rmi", "rsync", "rtmfp",
136 "rtmp", "rtsp", "rtsps", "rtspu", "secondlife", "service", "session", "sftp",
137 "sgn", "shttp", "sieve", "sip", "sips", "skype", "smb", "sms", "smtp",
138 "snews", "snmp", "soap.beep", "soap.beeps", "soldat", "spotify", "ssh",
139 "steam", "stun", "stuns", "submit", "svn", "tag", "teamspeak", "tel",
140 "teliaeid", "telnet", "tftp", "things", "thismessage", "tip", "tn3270",
141 "tool", "turn", "turns", "tv", "udp", "unreal", "urn", "ut2004", "v-event",
142 "vemmi", "ventrilo", "videotex", "vnc", "view-source", "wais", "webcal",
143 "wpid", "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire",
144 "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r",
145 "z39.50s:"
146 };
147 return list[rand(241)];
148 }
149
150 std::string
151 pchar()
152 {
153 if(rand(4))
154 return std::string(1,
155 "0123456789"
156 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
157 "abcdefghijklmnopqrstuvwxyz"
158 ":@&=+$,"[rand(69)]);
159 std::string s = "%";
160 s += "0123456789abcdef"[rand(16)];
161 s += "0123456789abcdef"[rand(16)];
162 return s;
163 }
164
165 char
166 uric()
167 {
168 return 'a';
169 }
170
171 char
172 uric_no_slash()
173 {
174 return 'a';
175 }
176
177 std::string
178 param()
179 {
180 std::string s;
181 while(rand(2))
182 s += pchar();
183 return s;
184 }
185
186 std::string
187 query()
188 {
189 std::string s;
190 while(rand(2))
191 s += uric();
192 return s;
193 }
194
195 std::string
196 userinfo()
197 {
198 std::string s;
199 while(rand(2))
200 s += "a";
201 return s;
202 }
203
204 /* authority = server | reg_name
205
206 reg_name = 1*( unreserved | escaped | "$" | "," |
207 ";" | ":" | "@" | "&" | "=" | "+" )
208
209 server = [ [ userinfo "@" ] hostport ]
210 userinfo = *( unreserved | escaped |
211 ";" | ":" | "&" | "=" | "+" | "$" | "," )
212
213 hostport = host [ ":" port ]
214 host = hostname | IPv4address
215 hostname = *( domainlabel "." ) toplabel [ "." ]
216 domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
217 toplabel = alpha | alpha *( alphanum | "-" ) alphanum
218 IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
219 port = *digit
220 */
221 std::string
222 server()
223 {
224 std::string s;
225 if(rand(2))
226 s += userinfo() + "@";
227 return s;
228 }
229
230 std::string
231 reg_name()
232 {
233 std::string s;
234 s = "a";
235 while(rand(2))
236 s += "a";
237 return s;
238 }
239
240 std::string
241 authority()
242 {
243 if(rand(2))
244 return server();
245 return reg_name();
246 }
247
248 std::string
249 opaque_part()
250 {
251 std::string s;
252 s += uric_no_slash();
253 while(rand(2))
254 s += uric();
255 return s;
256 }
257
258 /* abs_path = "/" path_segments
259 path_segments = segment *( "/" segment )
260 segment = *pchar *( ";" param )
261 param = *pchar
262 pchar = unreserved | escaped |
263 ":" | "@" | "&" | "=" | "+" | "$" | ","
264 */
265 std::string
266 abs_path()
267 {
268 std::string s = "/";
269 for(;;)
270 {
271 while(rand(2))
272 s += pchar();
273 while(rand(2))
274 s += ";" + param();
275 if(rand(2))
276 break;
277 s.append("/");
278 }
279 return s;
280 }
281
282 /* net_path = "//" authority [ abs_path ]
283 */
284 std::string
285 net_path()
286 {
287 std::string s = "//";
288 s += authority();
289 if(rand(2))
290 s += abs_path();
291 return s;
292 }
293
294 /* absoluteURI = scheme ":" ( hier_part | opaque_part )
295 scheme = alpha *( alpha | digit | "+" | "-" | "." )
296 hier_part = ( net_path | abs_path ) [ "?" query ]
297 abs_path = "/" path_segments
298 query = *uric
299 opaque_part = uric_no_slash *uric
300 */
301 std::string
302 abs_uri()
303 {
304 std::string s;
305 s = scheme() + ":";
306 if(rand(2))
307 {
308 if(rand(2))
309 s += net_path();
310 else
311 s += abs_path();
312 if(rand(2))
313 s += "?" + query();
314 }
315 else
316 {
317 s += opaque_part();
318 }
319 return s;
320 }
321
322 std::string
323 target()
324 {
325 //switch(rand(4))
326 switch(1)
327 {
328 case 0: return abs_uri();
329 case 1: return abs_path();
330 case 2: return authority();
331 default:
332 case 3: break;
333 }
334 return "*";
335 }
336
337 std::string
338 token()
339 {
340 static char constexpr valid[78] =
341 "!#$%&\'*+-." "0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
342 "UVWXYZ^_`a" "bcdefghijk" "lmnopqrstu" "vwxyz|~";
343 std::string s;
344 s.append(1, valid[rand(77)]);
345 while(rand(4))
346 s.append(1, valid[rand(77)]);
347 return s;
348 }
349
350 #if 0
351 std::string
352 target()
353 {
354 static char constexpr alpha[63] =
355 "0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
356 "UVWXYZabcd" "efghijklmn" "opqrstuvwx" "yz";
357 std::string s;
358 s = "/";
359 while(rand(4))
360 s.append(1, alpha[rand(62)]);
361 return s;
362 }
363 #endif
364
365 std::string
366 field()
367 { static char const* const list[289] =
368 {
369 "A-IM",
370 "Accept", "Accept-Additions", "Accept-Charset", "Accept-Datetime", "Accept-Encoding",
371 "Accept-Features", "Accept-Language", "Accept-Patch", "Accept-Ranges", "Age", "Allow",
372 "ALPN", "Also-Control", "Alt-Svc", "Alt-Used", "Alternate-Recipient", "Alternates",
373 "Apply-To-Redirect-Ref", "Approved", "Archive", "Archived-At", "Article-Names",
374 "Article-Updates", "Authentication-Info", "Authentication-Results", "Authorization",
375 "Auto-Submitted", "Autoforwarded", "Autosubmitted", "Base", "Bcc", "Body", "C-Ext",
376 "C-Man", "C-Opt", "C-PEP", "C-PEP-Info", "Cache-Control",
377 "CalDAV-Timezones", "Cc", "Close", "Comments", /*"Connection",*/ "Content-Alternative",
378 "Content-Base", "Content-Description", "Content-Disposition", "Content-Duration",
379 "Content-Encoding", "Content-features", "Content-ID", "Content-Identifier",
380 "Content-Language", /*"Content-Length",*/ "Content-Location", "Content-MD5",
381 "Content-Range", "Content-Return", "Content-Script-Type", "Content-Style-Type",
382 "Content-Transfer-Encoding", "Content-Type", "Content-Version", "Control", "Conversion",
383 "Conversion-With-Loss", "Cookie", "Cookie2", "DASL", "DAV", "DL-Expansion-History", "Date",
384 "Date-Received", "Default-Style", "Deferred-Delivery", "Delivery-Date", "Delta-Base",
385 "Depth", "Derived-From", "Destination", "Differential-ID", "Digest",
386 "Discarded-X400-IPMS-Extensions", "Discarded-X400-MTS-Extensions", "Disclose-Recipients",
387 "Disposition-Notification-Options", "Disposition-Notification-To", "Distribution",
388 "DKIM-Signature", "Downgraded-Bcc", "Downgraded-Cc", "Downgraded-Disposition-Notification-To",
389 "Downgraded-Final-Recipient", "Downgraded-From", "Downgraded-In-Reply-To",
390 "Downgraded-Mail-From", "Downgraded-Message-Id", "Downgraded-Original-Recipient",
391 "Downgraded-Rcpt-To", "Downgraded-References", "Downgraded-Reply-To", "Downgraded-Resent-Bcc",
392 "Downgraded-Resent-Cc", "Downgraded-Resent-From", "Downgraded-Resent-Reply-To",
393 "Downgraded-Resent-Sender", "Downgraded-Resent-To", "Downgraded-Return-Path",
394 "Downgraded-Sender", "Downgraded-To", "Encoding", "Encrypted", "ETag", "Expect",
395 "Expires", "Expiry-Date", "Ext", "Followup-To", "Forwarded", "From",
396 "Generate-Delivery-Report", "GetProfile", "Hobareg", "Host", "HTTP2-Settings", "IM", "If",
397 "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Schedule-Tag-Match",
398 "If-Unmodified-Since", "Importance", "In-Reply-To", "Incomplete-Copy", "Injection-Date",
399 "Injection-Info", "Keep-Alive", "Keywords", "Label", "Language", "Last-Modified",
400 "Latest-Delivery-Time", "Lines", "Link", "List-Archive", "List-Help", "List-ID",
401 "List-Owner", "List-Post", "List-Subscribe", "List-Unsubscribe", "Location", "Lock-Token",
402 "Man", "Max-Forwards", "Memento-Datetime", "Message-Context", "Message-ID", "Message-Type",
403 "Meter", "MIME-Version", "MMHS-Exempted-Address", "MMHS-Extended-Authorisation-Info",
404 "MMHS-Subject-Indicator-Codes", "MMHS-Handling-Instructions", "MMHS-Message-Instructions",
405 "MMHS-Codress-Message-Indicator", "MMHS-Originator-Reference", "MMHS-Primary-Precedence",
406 "MMHS-Copy-Precedence", "MMHS-Message-Type", "MMHS-Other-Recipients-Indicator-To",
407 "MMHS-Other-Recipients-Indicator-CC", "MMHS-Acp127-Message-Identifier", "MMHS-Originator-PLAD",
408 "MT-Priority", "Negotiate", "Newsgroups", "NNTP-Posting-Date", "NNTP-Posting-Host",
409 "Obsoletes", "Opt", "Ordering-Type", "Organization", "Origin",
410 "Original-Encoded-Information-Types", "Original-From", "Original-Message-ID",
411 "Original-Recipient", "Original-Sender", "Originator-Return-Address", "Original-Subject",
412 "Overwrite", "P3P", "Path", "PEP", "PICS-Label", "Pep-Info", "Position", "Posting-Version",
413 "Pragma", "Prefer", "Preference-Applied", "Prevent-NonDelivery-Report", "Priority",
414 "ProfileObject", "Protocol", "Protocol-Info", "Protocol-Query", "Protocol-Request",
415 "Proxy-Authenticate", "Proxy-Authentication-Info", "Proxy-Authorization", "Proxy-Features",
416 "Proxy-Instruction", "Public", "Public-Key-Pins", "Public-Key-Pins-Report-Only", "Range",
417 "Received", "Received-SPF", "Redirect-Ref", "References", "Referer", "Relay-Version",
418 "Reply-By", "Reply-To", "Require-Recipient-Valid-Since", "Resent-Bcc", "Resent-Cc",
419 "Resent-Date", "Resent-From", "Resent-Message-ID", "Resent-Reply-To", "Resent-Sender",
420 "Resent-To", "Retry-After", "Return-Path", "Safe", "Schedule-Reply", "Schedule-Tag",
421 "Sec-WebSocket-Accept", "Sec-WebSocket-Extensions", "Sec-WebSocket-Key",
422 "Sec-WebSocket-Protocol", "Sec-WebSocket-Version", "Security-Scheme", "See-Also", "Sender",
423 "Sensitivity", "Server", "Set-Cookie", "Set-Cookie2",
424 "SetProfile", "SLUG", "SoapAction", "Solicitation", "Status-URI", "Strict-Transport-Security",
425 "Subject", "Summary", "Supersedes", "Surrogate-Capability", "Surrogate-Control", "TCN",
426 "TE", "Timeout", "To", "Trailer", /*"Transfer-Encoding",*/ "URI", /*"Upgrade",*/ "User-Agent",
427 "Variant-Vary", "Vary", "VBR-Info", "Via", "WWW-Authenticate", "Want-Digest", "Warning",
428 "X400-Content-Identifier", "X400-Content-Return", "X400-Content-Type", "X400-MTS-Identifier",
429 "X400-Originator", "X400-Received", "X400-Recipients", "X400-Trace", "X-Frame-Options", "Xref"
430 };
431 return list[rand(289)];
432 }
433
434 std::string
435 text()
436 {
437 std::string s;
438 while(rand(3))
439 {
440 for(;;)
441 {
442 char c = rand<char>(256);
443 if(detail::is_text(c))
444 {
445 s.append(1, c);
446 break;
447 }
448 }
449 }
450 return s;
451 }
452
453 std::string
454 value()
455 {
456 std::string s;
457 while(rand(3))
458 {
459 if(rand(5))
460 {
461 s.append(text());
462 }
463 else
464 {
465 // LWS
466 if(! rand(4))
467 s.append("\r\n");
468 s.append(1, rand(2) ? ' ' : '\t');
469 while(rand(2))
470 s.append(1, rand(2) ? ' ' : '\t');
471 }
472 }
473 return s;
474 }
475
476 template<class DynamicBuffer>
477 void
478 fields(DynamicBuffer& db)
479 {
480 auto os = ostream(db);
481 while(rand(6))
482 os <<
483 field() <<
484 (rand(4) ? ": " : ":") <<
485 value() <<
486 "\r\n";
487 }
488
489 template<class DynamicBuffer>
490 void
491 body(DynamicBuffer& db)
492 {
493 if(! rand(4))
494 {
495 ostream(db) <<
496 "Content-Length: 0\r\n\r\n";
497 return;
498 }
499 if(rand(2))
500 {
501 auto const len = rand(500);
502 ostream(db) <<
503 "Content-Length: " << len << "\r\n\r\n";
504 auto mb = db.prepare(len);
505 for(auto it = net::buffer_sequence_begin(mb);
506 it != net::buffer_sequence_end(mb);
507 ++it)
508 {
509 net::mutable_buffer b = *it;
510 auto p = static_cast<char*>(b.data());
511 auto n = b.size();
512 while(n--)
513 *p++ = static_cast<char>(32 + rand(26+26+10+6));
514 }
515 db.commit(len);
516 }
517 else
518 {
519 auto len = rand(500);
520 ostream(db) <<
521 "Transfer-Encoding: chunked\r\n\r\n";
522 while(len > 0)
523 {
524 auto n = (std::min)(1 + rand(300), len);
525 len -= n;
526 ostream(db) <<
527 to_hex(n) << "\r\n";
528 auto mb = db.prepare(n);
529 for(auto it = net::buffer_sequence_begin(mb);
530 it != net::buffer_sequence_end(mb);
531 ++it)
532 {
533 net::mutable_buffer b = *it;
534 auto p = static_cast<char*>(b.data());
535 auto m = b.size();
536 while(m--)
537 *p++ = static_cast<char>(32 + rand(26+26+10+6));
538 }
539 db.commit(n);
540 ostream(db) << "\r\n";
541 }
542 ostream(db) << "0\r\n\r\n";
543 }
544 }
545
546 template<class DynamicBuffer>
547 void
548 request(DynamicBuffer& db)
549 {
550 ostream(db) <<
551 method() << " " << target() << " HTTP/1.1\r\n";
552 fields(db);
553 body(db);
554 }
555
556 template<class DynamicBuffer>
557 void
558 response(DynamicBuffer& db)
559 {
560 ostream(db) <<
561 "HTTP/1." <<
562 (rand(2) ? "0" : "1") << " " <<
563 (100 + rand(401)) << " " <<
564 token() <<
565 "\r\n";
566 fields(db);
567 body(db);
568 ostream(db) << "\r\n";
569 }
570 };
571
572 using message_fuzz = message_fuzz_t<>;
573
574 template<class Good, class Bad>
575 void
576 chunkExtensionsTest(
577 Good const& good, Bad const& bad)
578 {
579 good("");
580 good(";x");
581 good(";x;y");
582 good(";x=y");
583 good(";x;y=z");
584 good(" ;x");
585 good("\t;x");
586 good(" \t;x");
587 good("\t ;x");
588 good(" ; x");
589 good(" ;\tx");
590 good("\t ; \tx");
591 good(";x= y");
592 good(" ;x= y");
593 good(" ; x= y");
594 good(R"(;x="\"")");
595 good(R"(;x="\\")");
596 good(R"(;x;y=z;z="\"";p="\\";q="1\"2\\")");
597
598 bad(" ");
599 bad(";");
600 bad("=");
601 bad(" ;");
602 bad("; ");
603 bad(" ; ");
604 bad(" ; x ");
605 bad(";x =");
606 bad(";x = ");
607 bad(";x==");
608 }
609
610 } // http
611 } // beast
612 } // boost
613
614 #endif