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