# This example library can be used to generate random http requests. Something like this could be used, for example, # to test an http parser. # To use this library, add the path to this file as a `--lib` argument. Take a look at use-http.pgen for an example that # uses this library to generate random http requests. # Generates an http HEAD request for the given host/path def head_request(host: String, path: String) = http_request(host, path, "HEAD", "", ""); # Generates an http OPTIONS request for the given host/path def options_request(host: String, path: String) = http_request(host, path, "OPTIONS", "", ""); # Generates an http GET request for the given host/path def get_request(host: String, path: String) = http_request(host, path, "GET", "", ""); # Generates an http DELETE request for the given host/path def delete_request(host: String, path: String) = http_request(host, path, "DELETE", "", ""); # Generates an http PUT request for the given host/path and body def put_request(host: String, path: String, body: String) = http_req_with_body(host, path, "PUT", "", body); # Generates an http PUT request for the given host/path and body def post_request(host: String, path: String, body: String) = http_req_with_body(host, path, "POST", "", body); # The most versatile way to generate an http request def http_request(host: String, path: String, req_method: String, headers: String, req_body: String) = concat( http_req_start(req_method, path), http_header("Host", host), concat( headers, connection_header(), accept_header(), user_agent_header(), repeat(uint(1, 4), random_header()) ), newline(), req_body ); # Generates an http request with a body. Ensures that the Content-Length header is set to the correct length for the body def http_req_with_body(host: String, path: String, req_method: String, headers: String, req_body: String) = req_body() { body -> http_request( host, path, req_method, concat( headers, # since we mapped the req_body argument, `body` will always refer to the same value in this scope, # so we can know that the content-length will match what is actually in the body later http_header("Content-Length", to_string(string_length(body))) ), # put another newline before the body concat(newline(), body) ) }; def newline() = "\r\n"; def http_req_start(req_method: String, path: String) = concat(req_method, " ", path, " HTTP/1.1", newline()); def http_header(key: String, value: String) = concat(key, ": ", value, newline()); def rand_mime_type() = select( "application/json", "text/plain", "text/html", "application/javascript" ); def accept_header() = http_header("Accept", rand_mime_type()); def connection_header() = http_header("Connection", select("keep-alive", "close")); def rand_user_agent() = select( "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1", "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)", "Googlebot/2.1 (+http://www.google.com/bot.html)", "curl/7.61.1" ); def user_agent_header() = http_header("User-Agent", rand_user_agent()); def capitalized_ascii_string() = concat( uppercase_ascii_string(1), lowercase_ascii_string(uint(1, 30)) ); def rand_header_key() = repeat_delimited(uint(1, 4), capitalized_ascii_string(), "-"); def rand_header_value() = alphanumeric_string(uint(1, 65)); def random_header() = http_header(rand_header_key(), rand_header_value());