25namespace proto_fuzzer {
31constexpr std::uint32_t kDefaultBackpressureBufferBytes = 2048;
36constexpr std::uint32_t kMinBackpressureBufferBytes = 2048;
37constexpr std::uint32_t kMaxBackpressureBufferBytes = 4096;
38constexpr std::uint32_t kMaxDrainBytesPerIteration = 1024;
39constexpr std::uint32_t kHaproxyConnectBufferBytes = 2048;
40constexpr std::uint32_t kHaproxyConnectDrainBytes = 48;
41constexpr std::uint32_t kMqttProbeBufferBytes = 2048;
42constexpr std::uint32_t kMqttProbeDrainBytes = 1024;
43constexpr std::uint32_t kSmtpProbeBufferBytes = 2048;
44constexpr std::uint32_t kSmtpProbeDrainBytes = 1024;
49constexpr std::uint64_t kMaxLocalPortRange = 16;
50constexpr std::size_t kGopherTlsPeerKeyHostBytes = 10163;
55constexpr char kDefaultIpfsCid[] =
"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi";
56constexpr char kDefaultIpnsName[] =
"k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8";
61template <
typename RepeatedField>
62void TrimRepeated(RepeatedField* field, std::size_t limit) {
63 const std::size_t size =
static_cast<std::size_t
>(field->size());
65 field->DeleteSubrange(
static_cast<int>(limit),
static_cast<int>(size - limit));
71void TrimMetadata(std::string* value) {
82void CanonicalizeTlsAuthority(curl::fuzzer::proto::Scenario* scenario) {
83 const std::string& host_path = scenario->host_path();
84 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
85 if (suffix_start == std::string::npos) {
86 scenario->set_host_path(
"tls.test/");
89 scenario->set_host_path(
"tls.test" + host_path.substr(suffix_start));
95void CanonicalizeHttp3Authority(curl::fuzzer::proto::Scenario* scenario) {
96 const std::string& host_path = scenario->host_path();
97 if (!scenario->http3_plan().use_h1_connect_udp_proxy() || host_path.empty() || host_path.front() !=
'[') {
98 CanonicalizeTlsAuthority(scenario);
101 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
102 scenario->set_host_path(std::string(
"[::1]") +
103 (suffix_start == std::string::npos ?
"/" : host_path.substr(suffix_start)));
110void CanonicalizeAltSvcAuthority(curl::fuzzer::proto::Scenario* scenario) {
111 const std::string& host_path = scenario->host_path();
112 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
113 if (suffix_start == std::string::npos) {
114 scenario->set_host_path(
"altsvc-origin.test/");
117 scenario->set_host_path(
"altsvc-origin.test" + host_path.substr(suffix_start));
122void CanonicalizeTlsCertificateChain(curl::fuzzer::proto::Scenario* scenario) {
123 switch (scenario->tls_certificate_chain()) {
124 case curl::fuzzer::proto::TLS_CERTIFICATE_CHAIN_DEFAULT_EC:
125 case curl::fuzzer::proto::TLS_CERTIFICATE_CHAIN_ALL_KEY_TYPES:
128 scenario->clear_tls_certificate_chain();
135void CanonicalizeTlsGroupProfile(curl::fuzzer::proto::Scenario* scenario) {
136 switch (scenario->tls_group_profile()) {
137 case curl::fuzzer::proto::TLS_GROUP_X25519:
138 case curl::fuzzer::proto::TLS_GROUP_PROVIDER_DEFAULT:
141 scenario->clear_tls_group_profile();
148void CanonicalizeTlsClientCredentialProfile(curl::fuzzer::proto::Scenario* scenario) {
149 switch (scenario->tls_client_credential_profile()) {
150 case curl::fuzzer::proto::TLS_CLIENT_CREDENTIAL_NONE:
151 case curl::fuzzer::proto::TLS_CLIENT_CREDENTIAL_MALFORMED_PKCS12:
152 case curl::fuzzer::proto::TLS_CLIENT_CREDENTIAL_ENGINE_DEV_NULL:
153 case curl::fuzzer::proto::TLS_CLIENT_CREDENTIAL_DEFAULT_PROVIDER_DEV_NULL:
154 case curl::fuzzer::proto::TLS_CLIENT_CREDENTIAL_UNLOADED_PROVIDER_DEV_NULL:
157 scenario->clear_tls_client_credential_profile();
163void CanonicalizeTlsHandshakeProfile(curl::fuzzer::proto::Scenario* scenario) {
164 switch (scenario->tls_handshake_profile()) {
165 case curl::fuzzer::proto::TLS_HANDSHAKE_DEFAULT:
166 case curl::fuzzer::proto::TLS_HANDSHAKE_OPENSSL_CLOSE_NOTIFY:
167 case curl::fuzzer::proto::TLS_HANDSHAKE_OPENSSL_HELLO_REQUEST:
170 scenario->clear_tls_handshake_profile();
178void CanonicalizeGopherProbeMode(curl::fuzzer::proto::Scenario* scenario) {
179 switch (scenario->gopher_probe_mode()) {
180 case curl::fuzzer::proto::GOPHER_PROBE_DEFAULT:
181 case curl::fuzzer::proto::GOPHER_PROBE_PARTIAL_WRITE_NO_TIMEOUT:
182 case curl::fuzzer::proto::GOPHER_PROBE_SEND_TIMEOUT:
183 case curl::fuzzer::proto::GOPHER_PROBE_TLS_SESSION_KEY_LIMIT:
186 scenario->clear_gopher_probe_mode();
193void CanonicalizeRtspProbeMode(curl::fuzzer::proto::Scenario* scenario) {
194 switch (scenario->rtsp_probe_mode()) {
195 case curl::fuzzer::proto::RTSP_PROBE_DEFAULT:
196 case curl::fuzzer::proto::RTSP_PROBE_CROSS_ORIGIN_REUSE:
197 case curl::fuzzer::proto::RTSP_PROBE_SPLIT_INVALID_RTP_WRITE_FAILURE:
200 scenario->clear_rtsp_probe_mode();
208void CanonicalizeMqttProbeMode(curl::fuzzer::proto::Scenario* scenario) {
209 switch (scenario->mqtt_probe_mode()) {
210 case curl::fuzzer::proto::MQTT_PROBE_DEFAULT:
211 case curl::fuzzer::proto::MQTT_PROBE_SEND_BACKPRESSURE:
212 case curl::fuzzer::proto::MQTT_PROBE_OVERSIZED_USERNAME:
213 case curl::fuzzer::proto::MQTT_PROBE_OVERSIZED_PASSWORD:
216 scenario->clear_mqtt_probe_mode();
223void CanonicalizeSmtpProbeMode(curl::fuzzer::proto::Scenario* scenario) {
224 switch (scenario->smtp_probe_mode()) {
225 case curl::fuzzer::proto::SMTP_PROBE_DEFAULT:
226 case curl::fuzzer::proto::SMTP_PROBE_STARTTLS_TRY:
227 case curl::fuzzer::proto::SMTP_PROBE_STARTTLS_REQUIRE:
228 case curl::fuzzer::proto::SMTP_PROBE_STARTTLS_FILTER_ALLOCATION_FAILURE:
229 case curl::fuzzer::proto::SMTP_PROBE_SEND_BACKPRESSURE:
232 scenario->clear_smtp_probe_mode();
241void CanonicalizeH2ProxyOriginAuthority(curl::fuzzer::proto::Scenario* scenario) {
242 const std::string& host_path = scenario->host_path();
243 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
244 if (suffix_start == std::string::npos) {
245 scenario->set_host_path(
"origin.test/");
248 scenario->set_host_path(
"origin.test" + host_path.substr(suffix_start));
254void CanonicalizeSocksAuthority(curl::fuzzer::proto::Scenario* scenario) {
255 const std::string& host_path = scenario->host_path();
256 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
257 const auto mode = scenario->socks_proxy_mode();
258 const bool resolve_at_proxy =
259 mode == curl::fuzzer::proto::SOCKS_PROXY_SOCKS4A || mode == curl::fuzzer::proto::SOCKS_PROXY_SOCKS5_HOSTNAME;
260 const char* host = resolve_at_proxy ?
"socks.test" :
"localhost";
261 if (suffix_start == std::string::npos) {
262 scenario->set_host_path(std::string(host) +
"/");
265 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
273void CanonicalizeHttpTransportAuthority(curl::fuzzer::proto::Scenario* scenario) {
274 const std::string& host_path = scenario->host_path();
275 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
276 if (suffix_start == std::string::npos) {
277 scenario->set_host_path(
"transport.test/");
280 scenario->set_host_path(
"transport.test" + host_path.substr(suffix_start));
285void CanonicalizeProxySocketOptionAuthority(curl::fuzzer::proto::Scenario* scenario) {
287 switch (scenario->proxy_socket_option_mode()) {
288 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_HOSTNAME:
289 host =
"service.proxy.test";
291 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV4_CIDR:
294 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV6_CIDR:
297 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_ENV_HTTP_PROXY:
298 host =
"proxy-origin.test";
300 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_LOOPBACK_INTERFACE_KEEPALIVE:
301 host =
"resolve.test";
303 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_DEFAULT:
308 const std::string& host_path = scenario->host_path();
309 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
310 scenario->set_host_path(std::string(host) +
311 (suffix_start == std::string::npos ?
"/" : host_path.substr(suffix_start)));
319void CanonicalizeResolverAuthority(curl::fuzzer::proto::Scenario* scenario) {
320 const std::string& host_path = scenario->host_path();
321 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
322 const char* host =
"localhost";
323 switch (scenario->resolver_mode()) {
324 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_POSITIVE:
325 host =
"resolver-positive.test";
327 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_NEGATIVE:
328 host =
"resolver-negative.test";
330 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_LINK_LOCAL:
331 host =
"resolver-link-local.test";
333 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_PARTIAL:
334 host =
"resolver-partial.test";
336 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_QUEUED_CANCEL:
337 host =
"resolver-queued-cancel.test";
339 case curl::fuzzer::proto::RESOLVER_MODE_UNIX_SOCKET:
340 host =
"resolver-unix.test";
342 case curl::fuzzer::proto::RESOLVER_MODE_GLOBAL_LIFECYCLE:
345 case curl::fuzzer::proto::RESOLVER_MODE_DEFAULT:
350 : ((scenario->happy_eyeballs() || !scenario->resolve_entries().empty()) ?
"resolve.test" :
"localhost");
353 if (suffix_start == std::string::npos) {
354 scenario->set_host_path(std::string(host) +
"/");
357 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
360bool IsThreadedResolverMode(curl::fuzzer::proto::ResolverMode mode) {
361 return mode == curl::fuzzer::proto::RESOLVER_MODE_THREADED_POSITIVE ||
362 mode == curl::fuzzer::proto::RESOLVER_MODE_THREADED_NEGATIVE ||
363 mode == curl::fuzzer::proto::RESOLVER_MODE_THREADED_LINK_LOCAL ||
364 mode == curl::fuzzer::proto::RESOLVER_MODE_THREADED_PARTIAL ||
365 mode == curl::fuzzer::proto::RESOLVER_MODE_THREADED_QUEUED_CANCEL;
374void CanonicalizeTftpAuthority(curl::fuzzer::proto::Scenario* scenario) {
375 const std::string& host_path = scenario->host_path();
376 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
377 if (suffix_start == std::string::npos) {
378 scenario->set_host_path(
"tftp.test/file");
381 scenario->set_host_path(
"tftp.test" + host_path.substr(suffix_start));
390void CanonicalizeFtpAuthority(curl::fuzzer::proto::Scenario* scenario) {
391 const std::string& host_path = scenario->host_path();
392 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
393 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_FTPS ?
"tls.test" :
"ftp.test";
394 if (suffix_start == std::string::npos) {
395 scenario->set_host_path(std::string(host) +
"/file");
398 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
409void CanonicalizeSmtpAuthority(curl::fuzzer::proto::Scenario* scenario) {
410 const std::string& host_path = scenario->host_path();
411 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
412 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_SMTPS ?
"tls.test" :
"smtp.test";
413 if (suffix_start == std::string::npos) {
414 scenario->set_host_path(std::string(host) +
"/client.test");
417 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
430void CanonicalizeImapAuthority(curl::fuzzer::proto::Scenario* scenario) {
431 const std::string& host_path = scenario->host_path();
432 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
433 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_IMAPS ?
"tls.test" :
"imap.test";
434 const std::size_t authority_end = suffix_start == std::string::npos ? host_path.size() : suffix_start;
435 const bool retain_default_port = scenario->scheme() == curl::fuzzer::proto::SCHEME_IMAP && authority_end >= 3 &&
436 host_path.compare(authority_end - 3, 3,
":80") == 0;
437 const std::string authority = std::string(host) + (retain_default_port ?
":80" :
"");
438 if (suffix_start == std::string::npos) {
439 scenario->set_host_path(authority +
"/INBOX");
442 scenario->set_host_path(authority + host_path.substr(suffix_start));
450void CanonicalizePop3Authority(curl::fuzzer::proto::Scenario* scenario) {
451 const std::string& host_path = scenario->host_path();
452 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
453 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_POP3S ?
"tls.test" :
"pop3.test";
454 if (suffix_start == std::string::npos) {
455 scenario->set_host_path(std::string(host) +
"/1");
458 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
468void CanonicalizeMqttAuthority(curl::fuzzer::proto::Scenario* scenario) {
469 const std::string& host_path = scenario->host_path();
470 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
471 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_MQTTS ?
"tls.test" :
"mqtt.test";
472 if (suffix_start == std::string::npos) {
473 scenario->set_host_path(std::string(host) +
"/topic");
476 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
485void CanonicalizeDictAuthority(curl::fuzzer::proto::Scenario* scenario) {
486 const std::string& host_path = scenario->host_path();
487 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
488 if (suffix_start == std::string::npos) {
489 scenario->set_host_path(
"dict.test/d:word");
492 std::string canonical =
"dict.test" + host_path.substr(suffix_start);
496 scenario->set_host_path(canonical);
507void CanonicalizeLdapAuthority(curl::fuzzer::proto::Scenario* scenario) {
508 const std::string& host_path = scenario->host_path();
509 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
510 const char* host = scenario->scheme() == curl::fuzzer::proto::SCHEME_LDAPS ?
"tls.test" :
"ldap.test";
511 if (suffix_start == std::string::npos) {
512 scenario->set_host_path(std::string(host) +
"/dc=example,dc=com");
515 scenario->set_host_path(std::string(host) + host_path.substr(suffix_start));
523void CanonicalizeRtspAuthority(curl::fuzzer::proto::Scenario* scenario) {
524 const std::string& host_path = scenario->host_path();
525 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
526 if (suffix_start == std::string::npos) {
527 scenario->set_host_path(
"rtsp.test/stream");
530 scenario->set_host_path(
"rtsp.test" + host_path.substr(suffix_start));
540void CanonicalizeIpfsAuthority(curl::fuzzer::proto::Scenario* scenario) {
541 const std::string& host_path = scenario->host_path();
542 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
543 std::string canonical = scenario->scheme() == curl::fuzzer::proto::SCHEME_IPNS ? kDefaultIpnsName : kDefaultIpfsCid;
544 if (suffix_start != std::string::npos) {
545 canonical += host_path.substr(suffix_start);
550 scenario->set_host_path(canonical);
556void CanonicalizeMultiAuthority(curl::fuzzer::proto::Scenario* scenario) {
557 const std::string& host_path = scenario->host_path();
558 const std::size_t suffix_start = host_path.find_first_of(
"/?#");
559 if (suffix_start == std::string::npos) {
560 scenario->set_host_path(
"multi.test/");
563 scenario->set_host_path(
"multi.test" + host_path.substr(suffix_start));
566template <
typename RepeatedBytes>
567void BoundStringValues(RepeatedBytes* values, std::size_t count_limit, std::size_t value_limit) {
568 TrimRepeated(values, count_limit);
569 for (std::string& value : *values) {
570 if (value.size() > value_limit) {
571 value.resize(value_limit);
576template <
typename RepeatedBytes>
577void BoundHeaderValues(RepeatedBytes* headers, std::size_t limit) {
584void BoundConnectionShape(curl::fuzzer::proto::Connection* connection) {
586 const std::size_t raw_count =
static_cast<std::size_t
>(connection->on_readable_size());
592void BoundFileInput(std::string* input, std::size_t* remaining_bytes) {
594 if (input->size() > limit) {
595 input->resize(limit);
597 *remaining_bytes -= input->size();
600void BoundFileInputs(curl::fuzzer::proto::Scenario* scenario) {
602 BoundFileInput(scenario->mutable_cookie_file(), &remaining_bytes);
603 BoundFileInput(scenario->mutable_altsvc_file(), &remaining_bytes);
604 BoundFileInput(scenario->mutable_hsts_file(), &remaining_bytes);
605 BoundFileInput(scenario->mutable_netrc_file(), &remaining_bytes);
606 BoundFileInput(scenario->mutable_crl_file(), &remaining_bytes);
607 BoundFileInput(scenario->mutable_pinned_public_key_file(), &remaining_bytes);
611template <
typename Part>
612void BoundMimePartMetadata(Part* part) {
613 TrimMetadata(part->mutable_name());
614 TrimMetadata(part->mutable_filename());
615 TrimMetadata(part->mutable_content_type());
619void BoundGeneratedMimeData(curl::fuzzer::proto::GeneratedBytes* generated, std::size_t* remaining_bytes) {
624 const std::size_t pattern_size = generated->pattern().size();
625 if (pattern_size == 0 || *remaining_bytes == 0) {
626 generated->clear_repeat_count();
633 const std::size_t max_repeat_count = *remaining_bytes / pattern_size;
634 const std::size_t repeat_count =
635 std::min<std::size_t>(
static_cast<std::size_t
>(generated->repeat_count()), max_repeat_count);
636 generated->set_repeat_count(
static_cast<std::uint32_t
>(repeat_count));
637 *remaining_bytes -= repeat_count * pattern_size;
640void BoundMimeLeaf(curl::fuzzer::proto::MimeDataPart* part, std::size_t* remaining_generated_bytes) {
641 BoundMimePartMetadata(part);
642 if (part->content_case() == curl::fuzzer::proto::MimeDataPart::kGeneratedData) {
643 BoundGeneratedMimeData(part->mutable_generated_data(), remaining_generated_bytes);
652void BoundMimeShape(curl::fuzzer::proto::MimePost* post) {
656 std::size_t retained_top_parts = 0;
658 while (retained_top_parts <
static_cast<std::size_t
>(post->parts_size()) && remaining != 0) {
659 auto* part = post->mutable_parts(
static_cast<int>(retained_top_parts));
660 ++retained_top_parts;
662 BoundMimePartMetadata(part);
664 if (part->content_case() == curl::fuzzer::proto::MimePart::kData) {
670 if (part->content_case() == curl::fuzzer::proto::MimePart::kGeneratedData) {
671 BoundGeneratedMimeData(part->mutable_generated_data(), &remaining_generated_bytes);
674 if (part->content_case() != curl::fuzzer::proto::MimePart::kSubparts) {
678 auto* children = part->mutable_subparts()->mutable_parts();
680 for (
auto& child : *children) {
681 BoundMimeLeaf(&child, &remaining_generated_bytes);
686 TrimRepeated(post->mutable_parts(), retained_top_parts);
692void BoundUploadShape(curl::fuzzer::proto::UploadScript* upload, std::size_t data_limit, std::size_t read_step_limit,
693 std::size_t read_size_limit) {
694 if (upload->data().size() > data_limit) {
695 upload->mutable_data()->resize(data_limit);
700 while (
static_cast<std::size_t
>(upload->read_sizes_size()) > read_step_limit) {
701 upload->mutable_read_sizes()->RemoveLast();
703 for (
int i = 0; i < upload->read_sizes_size(); ++i) {
704 if (upload->read_sizes(i) > read_size_limit) {
705 upload->set_read_sizes(i,
static_cast<std::uint32_t
>(read_size_limit));
713template <
typename RepeatedScalar>
714void TrimRepeatedScalar(RepeatedScalar* values, std::size_t limit) {
715 while (
static_cast<std::size_t
>(values->size()) > limit) {
716 values->RemoveLast();
724void CanonicalizeAllocationFailures(curl::fuzzer::proto::Scenario* scenario) {
725 std::array<std::uint32_t, scenario_limits::kMaxAllocationFailures> retained{};
726 std::size_t retained_count = 0;
729 for (
const std::uint32_t raw : scenario->fail_allocations()) {
733 const std::uint32_t ordinal = 1U + ((raw - 1U) % maximum);
734 const auto begin = retained.begin();
735 const auto end = begin +
static_cast<std::ptrdiff_t
>(retained_count);
736 const auto position = std::lower_bound(begin, end, ordinal);
737 if (position != end && *position == ordinal) {
740 const std::size_t index =
static_cast<std::size_t
>(position - begin);
741 if (index >= retained.size()) {
744 if (retained_count < retained.size()) {
747 for (std::size_t destination = retained_count - 1; destination > index; --destination) {
748 retained[destination] = retained[destination - 1];
750 retained[index] = ordinal;
753 auto* values = scenario->mutable_fail_allocations();
755 for (std::size_t index = 0; index < retained_count; ++index) {
756 values->Add(retained[index]);
765void CanonicalizeAllocationFailureDrive(curl::fuzzer::proto::Scenario* scenario) {
766 if (!scenario->fail_allocations().empty() && scenario->has_api_plan() &&
767 scenario->api_plan().drive_mode() == curl::fuzzer::proto::API_DRIVE_EASY_EVENTS) {
768 scenario->mutable_api_plan()->set_drive_mode(curl::fuzzer::proto::API_DRIVE_EASY_PERFORM);
774void CanonicalizeApiDriveMode(curl::fuzzer::proto::ApiPlan* plan) {
775 switch (plan->drive_mode()) {
776 case curl::fuzzer::proto::API_DRIVE_MULTI_PERFORM:
777 case curl::fuzzer::proto::API_DRIVE_MULTI_SOCKET:
778 case curl::fuzzer::proto::API_DRIVE_EASY_PERFORM:
779 case curl::fuzzer::proto::API_DRIVE_EASY_EVENTS:
780 case curl::fuzzer::proto::API_DRIVE_CONNECT_ONLY:
783 plan->set_drive_mode(curl::fuzzer::proto::API_DRIVE_MULTI_PERFORM);
792void BoundApiPlanShape(curl::fuzzer::proto::ApiPlan* plan) {
797 CanonicalizeApiDriveMode(plan);
798 switch (plan->drive_mode()) {
799 case curl::fuzzer::proto::API_DRIVE_MULTI_PERFORM:
800 case curl::fuzzer::proto::API_DRIVE_MULTI_SOCKET:
802 case curl::fuzzer::proto::API_DRIVE_EASY_PERFORM:
803 case curl::fuzzer::proto::API_DRIVE_EASY_EVENTS:
804 case curl::fuzzer::proto::API_DRIVE_CONNECT_ONLY:
809 plan->set_wake_multi(
false);
810 plan->set_pause_response_once(
false);
821void CanonicalizeApiMimeRepeat(curl::fuzzer::proto::Scenario* scenario) {
822 if (!scenario->has_api_plan() || !scenario->api_plan().repeat_mime_post()) {
826 bool has_callback_part =
false;
827 if (scenario->has_mime_post()) {
828 for (
const auto& part : scenario->mime_post().parts()) {
829 if (part.content_case() == curl::fuzzer::proto::MimePart::kUploadCallback) {
830 has_callback_part =
true;
835 if (!scenario->has_upload() || !has_callback_part) {
836 scenario->mutable_api_plan()->clear_repeat_mime_post();
840 auto* plan = scenario->mutable_api_plan();
841 plan->set_drive_mode(curl::fuzzer::proto::API_DRIVE_MULTI_PERFORM);
842 plan->set_wake_multi(
false);
843 plan->set_pause_response_once(
false);
849void BoundMultiPlanShape(curl::fuzzer::proto::MultiPlan* plan) {
852 const std::uint32_t transfer_count = std::max(minimum, std::min(plan->transfer_count(), maximum));
853 plan->set_transfer_count(transfer_count);
854 plan->set_max_host_connections(std::min(plan->max_host_connections(), transfer_count));
855 plan->set_max_total_connections(std::min(plan->max_total_connections(), transfer_count));
856 plan->set_connection_cache_size(std::min(plan->connection_cache_size(), maximum * 2U));
859 switch (plan->drive_mode()) {
860 case curl::fuzzer::proto::MULTI_DRIVE_PERFORM:
861 case curl::fuzzer::proto::MULTI_DRIVE_SOCKET:
864 plan->set_drive_mode(curl::fuzzer::proto::MULTI_DRIVE_PERFORM);
868 switch (plan->state_probe_profile()) {
869 case curl::fuzzer::proto::MULTI_STATE_PROBE_NONE:
870 case curl::fuzzer::proto::MULTI_STATE_PROBE_PROGRESS_RATE_LIMIT:
873 plan->set_state_probe_profile(curl::fuzzer::proto::MULTI_STATE_PROBE_NONE);
877 for (
auto& action : *plan->mutable_actions()) {
878 action.set_transfer_selector(action.transfer_selector() % transfer_count);
879 switch (action.kind()) {
880 case curl::fuzzer::proto::MULTI_ACTION_NONE:
881 case curl::fuzzer::proto::MULTI_ACTION_PAUSE_RECV:
882 case curl::fuzzer::proto::MULTI_ACTION_PAUSE_SEND:
883 case curl::fuzzer::proto::MULTI_ACTION_PAUSE_ALL:
884 case curl::fuzzer::proto::MULTI_ACTION_RESUME:
885 case curl::fuzzer::proto::MULTI_ACTION_REMOVE:
886 case curl::fuzzer::proto::MULTI_ACTION_READD:
889 action.set_kind(curl::fuzzer::proto::MULTI_ACTION_NONE);
898void CanonicalizeHttp3HeaderName(std::string* name) {
907 for (
char&
byte : *name) {
908 const unsigned char value =
static_cast<unsigned char>(byte);
909 const bool alpha = (value >=
'A' && value <=
'Z') || (value >=
'a' && value <=
'z');
910 const bool digit = value >=
'0' && value <=
'9';
911 const bool punctuation = value ==
'!' || value ==
'#' || value ==
'$' || value ==
'%' || value ==
'&' ||
912 value ==
'\'' || value ==
'*' || value ==
'+' || value ==
'-' || value ==
'.' ||
913 value ==
'^' || value ==
'_' || value ==
'`' || value ==
'|' || value ==
'~';
914 if (value >=
'A' && value <=
'Z') {
915 byte =
static_cast<char>(value -
'A' +
'a');
916 }
else if (!alpha && !digit && !punctuation) {
925void CanonicalizeHttp3HeaderValue(std::string* value) {
929 for (
char&
byte : *value) {
930 const unsigned char character =
static_cast<unsigned char>(byte);
931 if ((character < 0x20U && character !=
'\t') || character == 0x7fU) {
940template <
typename RepeatedHeaders>
941void BoundHttp3Headers(RepeatedHeaders* headers, std::size_t count_limit, std::size_t* remaining_bytes) {
942 TrimRepeated(headers, count_limit);
943 std::size_t retained = 0;
944 while (retained <
static_cast<std::size_t
>(headers->size()) && *remaining_bytes != 0) {
945 auto* header = headers->Mutable(
static_cast<int>(retained));
946 CanonicalizeHttp3HeaderName(header->mutable_name());
947 CanonicalizeHttp3HeaderValue(header->mutable_value());
949 if (header->name().size() > *remaining_bytes) {
950 header->mutable_name()->resize(*remaining_bytes);
951 header->clear_value();
952 }
else if (header->value().size() > *remaining_bytes - header->name().size()) {
953 header->mutable_value()->resize(*remaining_bytes - header->name().size());
955 *remaining_bytes -= header->name().size() + header->value().size();
958 TrimRepeated(headers, retained);
961void CanonicalizeHttp3StreamRole(curl::fuzzer::proto::Http3StreamRole* role) {
963 case curl::fuzzer::proto::HTTP3_STREAM_RESPONSE:
964 case curl::fuzzer::proto::HTTP3_STREAM_CONTROL:
965 case curl::fuzzer::proto::HTTP3_STREAM_QPACK_ENCODER:
966 case curl::fuzzer::proto::HTTP3_STREAM_QPACK_DECODER:
969 *role = curl::fuzzer::proto::HTTP3_STREAM_RESPONSE;
974void BoundHttp3RawData(std::string* data, std::size_t* remaining_raw_bytes) {
976 if (data->size() > limit) {
979 *remaining_raw_bytes -= data->size();
982void BoundHttp2StreamRef(curl::fuzzer::proto::Http2StreamRef* stream) {
983 switch (stream->target_case()) {
984 case curl::fuzzer::proto::Http2StreamRef::kRequestIndex:
985 stream->set_request_index(stream->request_index() % 16U);
987 case curl::fuzzer::proto::Http2StreamRef::kPushIndex:
988 stream->set_push_index(stream->push_index() % 16U);
990 case curl::fuzzer::proto::Http2StreamRef::kExplicitId:
991 stream->set_explicit_id(stream->explicit_id() & 0x7fffffffU);
993 case curl::fuzzer::proto::Http2StreamRef::kConnection:
994 case curl::fuzzer::proto::Http2StreamRef::kLatestRequest:
995 case curl::fuzzer::proto::Http2StreamRef::TARGET_NOT_SET:
1001void BoundHttp2Settings(curl::fuzzer::proto::Http2Settings* settings) {
1003 for (
auto& entry : *settings->mutable_entries()) {
1006 entry.set_identifier(entry.identifier() & 0xffffU);
1007 switch (entry.identifier()) {
1011 entry.set_value(entry.value() & 1U);
1014 entry.set_value(entry.value() & 0x7fffffffU);
1017 if (entry.value() < 16384U || entry.value() > 0x00ffffffU) {
1018 entry.set_value(16384U + entry.value() % (0x00ffffffU - 16384U + 1U));
1030void BoundHttp2RawData(std::string* data, std::size_t* remaining_raw_bytes) {
1032 if (data->size() > limit) {
1033 data->resize(limit);
1035 *remaining_raw_bytes -= data->size();
1041void BoundHttp2PlanShape(curl::fuzzer::proto::Http2Plan* plan) {
1043 BoundHttp2Settings(plan->mutable_initial_settings());
1044 plan->mutable_initial_settings()->set_ack(
false);
1045 if (plan->stream_weight_after_headers() > 256U) {
1046 plan->set_stream_weight_after_headers(1U + (plan->stream_weight_after_headers() - 1U) % 256U);
1048 if (plan->actions().empty()) {
1049 auto* response = plan->add_actions()->mutable_headers();
1050 response->set_status_code(200);
1051 response->set_end_stream(
true);
1057 for (
auto& action : *plan->mutable_actions()) {
1058 switch (action.action_case()) {
1059 case curl::fuzzer::proto::Http2Action::kSettings:
1060 BoundHttp2Settings(action.mutable_settings());
1062 case curl::fuzzer::proto::Http2Action::kHeaders: {
1063 auto* headers = action.mutable_headers();
1064 BoundHttp2StreamRef(headers->mutable_stream());
1065 if (!headers->trailers()) {
1066 if (headers->status_code() == 0U) {
1067 headers->set_status_code(200U);
1068 }
else if (headers->status_code() < 100U || headers->status_code() > 599U) {
1069 headers->set_status_code(100U + headers->status_code() % 500U);
1075 case curl::fuzzer::proto::Http2Action::kData: {
1076 auto* data = action.mutable_data();
1077 BoundHttp2StreamRef(data->mutable_stream());
1078 if (data->data().size() > remaining_data_bytes) {
1079 data->mutable_data()->resize(remaining_data_bytes);
1081 remaining_data_bytes -= data->data().size();
1084 case curl::fuzzer::proto::Http2Action::kWindowUpdate: {
1085 auto* update = action.mutable_window_update();
1086 BoundHttp2StreamRef(update->mutable_stream());
1087 update->set_increment(std::max(1U, update->increment() & 0x7fffffffU));
1090 case curl::fuzzer::proto::Http2Action::kRstStream:
1091 BoundHttp2StreamRef(action.mutable_rst_stream()->mutable_stream());
1093 case curl::fuzzer::proto::Http2Action::kPing:
1094 if (action.ping().opaque_data().size() > 8U) {
1095 action.mutable_ping()->mutable_opaque_data()->resize(8U);
1098 case curl::fuzzer::proto::Http2Action::kGoaway:
1099 BoundHttp2StreamRef(action.mutable_goaway()->mutable_last_stream());
1100 BoundHttp2RawData(action.mutable_goaway()->mutable_debug_data(), &remaining_raw_bytes);
1102 case curl::fuzzer::proto::Http2Action::kPushPromise:
1103 BoundHttp2StreamRef(action.mutable_push_promise()->mutable_parent_stream());
1104 BoundHttp2StreamRef(action.mutable_push_promise()->mutable_promised_stream());
1106 &remaining_header_bytes);
1108 case curl::fuzzer::proto::Http2Action::kWait: {
1109 auto* wait = action.mutable_wait();
1110 BoundHttp2StreamRef(wait->mutable_stream());
1111 if (wait->event() < curl::fuzzer::proto::HTTP2_CLIENT_EVENT_SETTINGS ||
1112 wait->event() > curl::fuzzer::proto::HTTP2_CLIENT_EVENT_END_STREAM) {
1113 wait->set_event(curl::fuzzer::proto::HTTP2_CLIENT_EVENT_SETTINGS);
1115 wait->set_count(std::max(1U, std::min(wait->count(), 16U)));
1118 case curl::fuzzer::proto::Http2Action::kYieldTurns:
1121 case curl::fuzzer::proto::Http2Action::kWireFrame:
1122 action.mutable_wire_frame()->set_type(action.wire_frame().type() & 0xffU);
1123 action.mutable_wire_frame()->set_flags(action.wire_frame().flags() & 0xffU);
1124 action.mutable_wire_frame()->set_stream_id(action.wire_frame().stream_id() & 0x7fffffffU);
1125 action.mutable_wire_frame()->set_declared_length(action.wire_frame().declared_length() & 0x00ffffffU);
1126 BoundHttp2RawData(action.mutable_wire_frame()->mutable_payload(), &remaining_raw_bytes);
1128 case curl::fuzzer::proto::Http2Action::kRawBytes:
1129 BoundHttp2RawData(action.mutable_raw_bytes(), &remaining_raw_bytes);
1131 case curl::fuzzer::proto::Http2Action::ACTION_NOT_SET: {
1132 auto* response = action.mutable_headers();
1133 response->set_status_code(200);
1134 response->set_end_stream(
true);
1144void BoundHttp3PlanShape(curl::fuzzer::proto::Http3Plan* plan) {
1145 if (plan->use_h1_connect_udp_proxy()) {
1146 plan->clear_actions();
1150 if (plan->actions().empty()) {
1151 auto* response = plan->add_actions()->mutable_structured_response();
1152 response->set_status_code(200);
1153 response->set_finish_stream(
true);
1159 std::size_t retained_actions = 0;
1160 bool connection_closed =
false;
1161 for (
auto& action : *plan->mutable_actions()) {
1162 if (connection_closed) {
1166 switch (action.action_case()) {
1167 case curl::fuzzer::proto::Http3Action::kStructuredResponse: {
1168 auto* response = action.mutable_structured_response();
1169 if (response->status_code() == 0U) {
1170 response->set_status_code(200U);
1171 }
else if (response->status_code() < 100U || response->status_code() > 599U) {
1172 response->set_status_code(100U + response->status_code() % 500U);
1175 &remaining_header_bytes);
1177 &remaining_header_bytes);
1179 for (std::string& chunk : *response->mutable_body_chunks()) {
1180 if (chunk.size() > remaining_body_bytes) {
1181 chunk.resize(remaining_body_bytes);
1183 remaining_body_bytes -= chunk.size();
1188 case curl::fuzzer::proto::Http3Action::kStreamWrite: {
1189 auto* write = action.mutable_stream_write();
1190 auto role = write->role();
1191 CanonicalizeHttp3StreamRole(&role);
1192 write->set_role(role);
1193 BoundHttp3RawData(write->mutable_data(), &remaining_raw_bytes);
1197 case curl::fuzzer::proto::Http3Action::kOpenUnidirectionalStream: {
1198 auto* stream = action.mutable_open_unidirectional_stream();
1199 BoundHttp3RawData(stream->mutable_data(), &remaining_raw_bytes);
1203 case curl::fuzzer::proto::Http3Action::kStreamReset: {
1204 auto* reset = action.mutable_stream_reset();
1205 auto role = reset->role();
1206 CanonicalizeHttp3StreamRole(&role);
1207 reset->set_role(role);
1212 case curl::fuzzer::proto::Http3Action::kGoaway:
1216 case curl::fuzzer::proto::Http3Action::kConnectionClose:
1217 action.mutable_connection_close()->set_application_error_code(
1219 connection_closed =
true;
1222 case curl::fuzzer::proto::Http3Action::ACTION_NOT_SET: {
1223 auto* response = action.mutable_structured_response();
1224 response->set_status_code(200);
1225 response->set_finish_stream(
true);
1230 TrimRepeated(plan->mutable_actions(), retained_actions);
1236void BoundScenarioShape(curl::fuzzer::proto::Scenario* scenario) {
1242 if (scenario->has_mime_post()) {
1243 BoundMimeShape(scenario->mutable_mime_post());
1245 if (scenario->has_upload()) {
1246 const bool telnet = scenario->scheme() == curl::fuzzer::proto::SCHEME_TELNET;
1248 const std::size_t read_step_limit =
1250 const std::size_t read_size_limit =
1252 BoundUploadShape(scenario->mutable_upload(), data_limit, read_step_limit, read_size_limit);
1255 BoundConnectionShape(scenario->mutable_connection());
1257 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
1258 BoundConnectionShape(&connection);
1262 BoundFileInputs(scenario);
1268void PruneAndBoundScenarioShape(curl::fuzzer::proto::Scenario* scenario,
TargetProfile profile,
1270 if (prune_conditional_eligibility !=
nullptr) {
1271 prune_conditional_eligibility(scenario, profile);
1273 BoundScenarioShape(scenario);
1278void CanonicalizeDeepHttpSelectors(curl::fuzzer::proto::Scenario* scenario) {
1279 switch (scenario->http_transport_mode()) {
1280 case curl::fuzzer::proto::HTTP_TRANSPORT_DIRECT:
1281 case curl::fuzzer::proto::HTTP_TRANSPORT_FORWARD_PROXY:
1282 case curl::fuzzer::proto::HTTP_TRANSPORT_CONNECT_PROXY:
1283 case curl::fuzzer::proto::HTTP_TRANSPORT_UNIX_SOCKET:
1286 scenario->clear_http_transport_mode();
1289 switch (scenario->proxy_socket_option_mode()) {
1290 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_DEFAULT:
1291 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_HOSTNAME:
1292 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV4_CIDR:
1293 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV6_CIDR:
1294 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_ENV_HTTP_PROXY:
1295 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_LOOPBACK_INTERFACE_KEEPALIVE:
1298 scenario->clear_proxy_socket_option_mode();
1307std::uint64_t IntegralMutationValue(
const curl::fuzzer::proto::SetOption& option) {
1308 switch (option.value_case()) {
1309 case curl::fuzzer::proto::SetOption::kUintValue:
1310 return option.uint_value();
1311 case curl::fuzzer::proto::SetOption::kBoolValue:
1312 return option.bool_value() ? 1U : 0U;
1313 case curl::fuzzer::proto::SetOption::kStringValue:
1314 case curl::fuzzer::proto::SetOption::VALUE_NOT_SET:
1322void CanonicalizeLocalPortRange(curl::fuzzer::proto::Scenario* scenario) {
1323 for (
auto& option : *scenario->mutable_options()) {
1324 if (option.option_id() == curl::fuzzer::proto::CURLOPT_LOCALPORTRANGE) {
1325 option.set_uint_value(std::min<std::uint64_t>(IntegralMutationValue(option), kMaxLocalPortRange));
1334void CanonicalizeFastHttpVersion(curl::fuzzer::proto::Scenario* scenario) {
1335 for (
auto& option : *scenario->mutable_options()) {
1336 if (option.option_id() != curl::fuzzer::proto::CURLOPT_HTTP_VERSION) {
1339 const std::uint64_t version = IntegralMutationValue(option);
1341 if (version <= CURL_HTTP_VERSION_2TLS) {
1342 option.set_uint_value(version);
1344 option.set_uint_value(CURL_HTTP_VERSION_NONE);
1351void CanonicalizeFtpOptionModes(curl::fuzzer::proto::Scenario* scenario) {
1352 for (
auto& option : *scenario->mutable_options()) {
1353 switch (option.option_id()) {
1354 case curl::fuzzer::proto::CURLOPT_FTP_CREATE_MISSING_DIRS:
1355 option.set_uint_value(IntegralMutationValue(option) % 3U);
1357 case curl::fuzzer::proto::CURLOPT_FTP_FILEMETHOD:
1358 option.set_uint_value(IntegralMutationValue(option) % 4U);
1360 case curl::fuzzer::proto::CURLOPT_FTPPORT:
1363 option.set_string_value(
"127.0.0.1");
1365 case curl::fuzzer::proto::CURLOPT_FTP_USE_EPRT:
1366 option.set_bool_value(IntegralMutationValue(option) != 0U);
1377void CanonicalizeTftpOptionModes(curl::fuzzer::proto::Scenario* scenario) {
1378 for (
auto& option : *scenario->mutable_options()) {
1379 if (option.option_id() != curl::fuzzer::proto::CURLOPT_TFTP_BLKSIZE) {
1382 std::uint64_t value = IntegralMutationValue(option);
1386 option.set_uint_value(std::max<std::uint64_t>(8, std::min<std::uint64_t>(value, 65464)));
1395void CanonicalizeRtspOptionModes(curl::fuzzer::proto::Scenario* scenario) {
1396 for (
auto& option : *scenario->mutable_options()) {
1397 switch (option.option_id()) {
1398 case curl::fuzzer::proto::CURLOPT_RTSP_REQUEST: {
1399 const std::uint64_t value = IntegralMutationValue(option);
1404 const bool supported =
1405 value >= CURL_RTSPREQ_OPTIONS && value < CURL_RTSPREQ_LAST && value != CURL_RTSPREQ_RECEIVE;
1406 option.set_uint_value(supported ? value : CURL_RTSPREQ_OPTIONS);
1409 case curl::fuzzer::proto::CURLOPT_RTSP_CLIENT_CSEQ:
1410 case curl::fuzzer::proto::CURLOPT_RTSP_SERVER_CSEQ:
1411 option.set_uint_value(std::min<std::uint64_t>(IntegralMutationValue(option),
1412 static_cast<std::uint64_t
>(std::numeric_limits<int>::max())));
1425void RemoveDeepHttpShape(curl::fuzzer::proto::Scenario* scenario) {
1426 scenario->clear_mime_post();
1427 scenario->clear_upload();
1428 scenario->clear_subsequent_connections();
1430 auto* connection = scenario->mutable_connection();
1431 connection->clear_server_frames();
1432 connection->clear_manual_probes();
1433 connection->clear_backpressure();
1440void RemoveIgnoredH2ProxyShape(curl::fuzzer::proto::Scenario* scenario) {
1441 scenario->clear_subsequent_connections();
1442 auto* connection = scenario->mutable_connection();
1443 connection->clear_server_frames();
1444 connection->clear_manual_probes();
1445 connection->clear_backpressure();
1453void RemoveIgnoredWebSocketShape(curl::fuzzer::proto::Scenario* scenario) {
1454 scenario->clear_subsequent_connections();
1455 scenario->clear_mime_post();
1463void RemoveNonTelnetShape(curl::fuzzer::proto::Scenario* scenario) {
1464 scenario->clear_subsequent_connections();
1465 scenario->clear_request_headers();
1466 scenario->clear_mime_post();
1468 auto* connection = scenario->mutable_connection();
1469 connection->clear_server_frames();
1470 connection->clear_manual_probes();
1471 connection->clear_backpressure();
1477void RemoveTelnetOnlyShape(curl::fuzzer::proto::Scenario* scenario) {
1478 scenario->clear_telnet_options();
1479 if (scenario->has_upload() && scenario->upload().terminal() == curl::fuzzer::proto::UPLOAD_TERMINAL_PAUSE) {
1480 scenario->mutable_upload()->set_terminal(curl::fuzzer::proto::UPLOAD_TERMINAL_EOF);
1487void RemoveApiOnlyShape(curl::fuzzer::proto::Scenario* scenario) { scenario->clear_api_plan(); }
1491void RemoveMultiOnlyShape(curl::fuzzer::proto::Scenario* scenario) { scenario->clear_multi_plan(); }
1496void RemoveIgnoredHttp3Shape(curl::fuzzer::proto::Scenario* scenario) {
1497 if (!scenario->http3_plan().use_h1_connect_udp_proxy()) {
1498 scenario->clear_connection();
1500 scenario->clear_subsequent_connections();
1501 RemoveTelnetOnlyShape(scenario);
1502 RemoveApiOnlyShape(scenario);
1503 RemoveMultiOnlyShape(scenario);
1510void RemoveUnusedFileTransferConnectionShape(curl::fuzzer::proto::Connection* connection,
1511 bool retain_backpressure =
false) {
1512 connection->clear_server_frames();
1513 connection->clear_manual_probes();
1514 if (!retain_backpressure) {
1515 connection->clear_backpressure();
1523void RemoveIgnoredFtpShape(curl::fuzzer::proto::Scenario* scenario) {
1524 scenario->clear_request_headers();
1525 scenario->clear_mime_post();
1526 RemoveTelnetOnlyShape(scenario);
1527 RemoveApiOnlyShape(scenario);
1528 RemoveMultiOnlyShape(scenario);
1530 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1532 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
1533 RemoveUnusedFileTransferConnectionShape(&connection);
1540void RemoveIgnoredTftpShape(curl::fuzzer::proto::Scenario* scenario) {
1541 scenario->clear_subsequent_connections();
1542 scenario->clear_request_headers();
1543 scenario->clear_mime_post();
1544 RemoveTelnetOnlyShape(scenario);
1545 RemoveApiOnlyShape(scenario);
1546 RemoveMultiOnlyShape(scenario);
1547 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1555void RemoveIgnoredSmtpShape(curl::fuzzer::proto::Scenario* scenario) {
1556 scenario->clear_subsequent_connections();
1557 scenario->clear_request_headers();
1558 RemoveTelnetOnlyShape(scenario);
1559 RemoveApiOnlyShape(scenario);
1560 RemoveMultiOnlyShape(scenario);
1561 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1569void RemoveIgnoredImapShape(curl::fuzzer::proto::Scenario* scenario) {
1570 scenario->clear_subsequent_connections();
1571 scenario->clear_request_headers();
1572 RemoveTelnetOnlyShape(scenario);
1573 RemoveApiOnlyShape(scenario);
1574 RemoveMultiOnlyShape(scenario);
1575 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection(),
true);
1581void RemoveIgnoredPop3Shape(curl::fuzzer::proto::Scenario* scenario) {
1582 scenario->clear_subsequent_connections();
1583 scenario->clear_request_headers();
1584 scenario->clear_mime_post();
1585 scenario->clear_upload();
1586 RemoveTelnetOnlyShape(scenario);
1587 RemoveApiOnlyShape(scenario);
1588 RemoveMultiOnlyShape(scenario);
1589 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection(),
true);
1592void RemoveIgnoredGopherShape(curl::fuzzer::proto::Scenario* scenario) {
1593 scenario->clear_subsequent_connections();
1594 scenario->clear_request_headers();
1595 scenario->clear_mime_post();
1596 scenario->clear_upload();
1597 RemoveTelnetOnlyShape(scenario);
1598 RemoveApiOnlyShape(scenario);
1599 RemoveMultiOnlyShape(scenario);
1600 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1606void RemoveIgnoredDictShape(curl::fuzzer::proto::Scenario* scenario) {
1607 scenario->clear_subsequent_connections();
1608 scenario->clear_request_headers();
1609 scenario->clear_mime_post();
1610 scenario->clear_upload();
1611 RemoveTelnetOnlyShape(scenario);
1612 RemoveApiOnlyShape(scenario);
1613 RemoveMultiOnlyShape(scenario);
1614 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1619 TrimRepeated(scenario->mutable_connection()->mutable_on_readable(), 1);
1627void RemoveIgnoredMqttShape(curl::fuzzer::proto::Scenario* scenario) {
1628 scenario->clear_subsequent_connections();
1629 scenario->clear_request_headers();
1630 scenario->clear_mime_post();
1631 scenario->clear_upload();
1632 RemoveTelnetOnlyShape(scenario);
1633 RemoveApiOnlyShape(scenario);
1634 RemoveMultiOnlyShape(scenario);
1635 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1642void RemoveIgnoredFileShape(curl::fuzzer::proto::Scenario* scenario) {
1643 scenario->clear_connection();
1644 scenario->clear_subsequent_connections();
1645 scenario->clear_request_headers();
1646 scenario->clear_mime_post();
1647 RemoveTelnetOnlyShape(scenario);
1648 RemoveApiOnlyShape(scenario);
1649 RemoveMultiOnlyShape(scenario);
1657void RemoveIgnoredLdapShape(curl::fuzzer::proto::Scenario* scenario) {
1658 scenario->clear_subsequent_connections();
1659 scenario->clear_request_headers();
1660 scenario->clear_mime_post();
1661 scenario->clear_upload();
1662 RemoveTelnetOnlyShape(scenario);
1663 RemoveApiOnlyShape(scenario);
1664 RemoveMultiOnlyShape(scenario);
1665 RemoveUnusedFileTransferConnectionShape(scenario->mutable_connection());
1673void RemoveIgnoredRtspShape(curl::fuzzer::proto::Scenario* scenario) {
1674 scenario->clear_subsequent_connections();
1675 scenario->clear_mime_post();
1676 RemoveTelnetOnlyShape(scenario);
1677 RemoveApiOnlyShape(scenario);
1678 RemoveMultiOnlyShape(scenario);
1680 auto* connection = scenario->mutable_connection();
1681 connection->clear_initial_response();
1682 RemoveUnusedFileTransferConnectionShape(connection);
1689void RemoveIgnoredIpfsShape(curl::fuzzer::proto::Scenario* scenario) {
1690 RemoveApiOnlyShape(scenario);
1691 RemoveMultiOnlyShape(scenario);
1692 RemoveTelnetOnlyShape(scenario);
1693 RemoveDeepHttpShape(scenario);
1699std::uint32_t CanonicalizeNonZero(std::uint32_t value, std::uint32_t minimum, std::uint32_t maximum) {
1703 return std::max(minimum, std::min(value, maximum));
1714curl::fuzzer::proto::Scheme PlaintextScheme(curl::fuzzer::proto::Scheme scheme) {
1716 case curl::fuzzer::proto::SCHEME_WS:
1717 case curl::fuzzer::proto::SCHEME_WSS:
1718 return curl::fuzzer::proto::SCHEME_WS;
1719 case curl::fuzzer::proto::SCHEME_HTTP:
1720 case curl::fuzzer::proto::SCHEME_HTTPS:
1721 case curl::fuzzer::proto::SCHEME_TELNET:
1722 case curl::fuzzer::proto::SCHEME_FTP:
1723 case curl::fuzzer::proto::SCHEME_TFTP:
1724 case curl::fuzzer::proto::SCHEME_DICT:
1725 case curl::fuzzer::proto::SCHEME_FILE:
1726 case curl::fuzzer::proto::SCHEME_UNSPECIFIED:
1728 return curl::fuzzer::proto::SCHEME_HTTP;
1735void ClearAllBackpressure(curl::fuzzer::proto::Scenario* scenario) {
1736 if (scenario->has_connection()) {
1737 scenario->mutable_connection()->clear_backpressure();
1739 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
1740 connection.clear_backpressure();
1747void CanonicalizeOptionalBackpressure(curl::fuzzer::proto::Connection* connection) {
1748 if (!connection->has_backpressure()) {
1751 auto* backpressure = connection->mutable_backpressure();
1752 if (backpressure->recv_buf_bytes() == 0 && backpressure->drain_limit() != 0) {
1753 backpressure->set_recv_buf_bytes(kDefaultBackpressureBufferBytes);
1755 backpressure->set_recv_buf_bytes(
1756 CanonicalizeNonZero(backpressure->recv_buf_bytes(), kMinBackpressureBufferBytes, kMaxBackpressureBufferBytes));
1758 backpressure->set_drain_limit(CanonicalizeNonZero(backpressure->drain_limit(), 1, kMaxDrainBytesPerIteration));
1764void CanonicalizeMailBackpressure(curl::fuzzer::proto::Connection* connection) {
1765 if (!connection->has_backpressure()) {
1768 auto* backpressure = connection->mutable_backpressure();
1769 if (backpressure->recv_buf_bytes() == 0) {
1770 connection->clear_backpressure();
1773 backpressure->set_recv_buf_bytes(
1774 CanonicalizeNonZero(backpressure->recv_buf_bytes(), kMinBackpressureBufferBytes, kMaxBackpressureBufferBytes));
1775 backpressure->clear_drain_limit();
1783void ApplyLanePolicy(curl::fuzzer::proto::Scenario* scenario,
TargetProfile profile,
1785 if (scenario ==
nullptr) {
1802 scenario->clear_file_source();
1809 scenario->mutable_connection()->clear_proxy_protocol();
1810 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
1811 connection.clear_proxy_protocol();
1820 scenario->clear_scheme();
1827 scenario->clear_scheme();
1834 scenario->clear_scheme();
1840 scenario->scheme() == curl::fuzzer::proto::SCHEME_LDAPS)) {
1841 scenario->clear_scheme();
1848 scenario->clear_scheme();
1853 scenario->clear_scheme();
1860 scenario->scheme() == curl::fuzzer::proto::SCHEME_IPNS)) {
1861 scenario->clear_scheme();
1868 scenario->clear_accept_h2_push();
1876 scenario->clear_tls_certificate_chain();
1882 scenario->clear_tls_group_profile();
1888 scenario->clear_http3_plan();
1893 scenario->clear_http2_plan();
1897 scenario->http_transport_mode() == curl::fuzzer::proto::HTTP_TRANSPORT_CONNECT_PROXY;
1899 scenario->clear_socks_proxy_mode();
1900 if (!deep_http_haproxy) {
1901 scenario->clear_haproxy_protocol();
1908 scenario->clear_ldap_starttls();
1912 scenario->clear_pop3_starttls_filter_allocation_failure();
1916 scenario->clear_ftp_auth_tls_filter_allocation_failure();
1920 scenario->clear_gopher_probe_mode();
1924 scenario->clear_rtsp_probe_mode();
1928 scenario->clear_mqtt_probe_mode();
1932 scenario->clear_smtp_probe_mode();
1936 scenario->clear_http2_connect_flush_probe();
1940 scenario->clear_http_transport_mode();
1941 scenario->clear_proxy_socket_option_mode();
1945 scenario->clear_resolve_entries();
1946 scenario->clear_happy_eyeballs();
1947 scenario->clear_doh();
1948 scenario->clear_resolver_mode();
1955 scenario->clear_mail_rcpt();
1966 scenario->clear_probe_multi_pollset();
1972 scenario->clear_h2_forward_proxy();
1979 scenario->clear_cookie_file();
1980 scenario->clear_altsvc_file();
1981 scenario->clear_hsts_file();
1982 scenario->clear_netrc_file();
1989 scenario->clear_crl_file();
1990 scenario->clear_pinned_public_key_file();
1991 scenario->clear_tls_client_credential_profile();
1992 scenario->clear_tls_handshake_profile();
1996 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTPS);
1997 RemoveIgnoredHttp3Shape(scenario);
1998 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2002 if (!scenario->http3_plan().use_h1_connect_udp_proxy()) {
2003 scenario->clear_connection();
2005 BoundHttp3PlanShape(scenario->mutable_http3_plan());
2006 CanonicalizeHttp3Authority(scenario);
2007 CanonicalizeTlsCertificateChain(scenario);
2014 scenario->set_scheme(curl::fuzzer::proto::SCHEME_TELNET);
2015 RemoveApiOnlyShape(scenario);
2016 RemoveMultiOnlyShape(scenario);
2017 RemoveNonTelnetShape(scenario);
2018 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2024 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2025 RemoveApiOnlyShape(scenario);
2026 RemoveMultiOnlyShape(scenario);
2027 RemoveTelnetOnlyShape(scenario);
2028 RemoveDeepHttpShape(scenario);
2029 CanonicalizeFastHttpVersion(scenario);
2030 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2035 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2036 RemoveApiOnlyShape(scenario);
2037 RemoveMultiOnlyShape(scenario);
2038 RemoveTelnetOnlyShape(scenario);
2039 RemoveIgnoredH2ProxyShape(scenario);
2040 switch (scenario->connection().proxy_protocol()) {
2041 case curl::fuzzer::proto::PROXY_PROTOCOL_HTTP2:
2042 case curl::fuzzer::proto::PROXY_PROTOCOL_HTTP1:
2045 scenario->mutable_connection()->set_proxy_protocol(curl::fuzzer::proto::PROXY_PROTOCOL_HTTP2);
2048 if (scenario->connection().proxy_protocol() == curl::fuzzer::proto::PROXY_PROTOCOL_HTTP1) {
2049 scenario->clear_h2_forward_proxy();
2051 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2052 CanonicalizeH2ProxyOriginAuthority(scenario);
2058 : curl::fuzzer::proto::SCHEME_HTTP);
2059 RemoveApiOnlyShape(scenario);
2060 RemoveMultiOnlyShape(scenario);
2061 RemoveTelnetOnlyShape(scenario);
2062 RemoveIgnoredH2ProxyShape(scenario);
2063 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2064 if (scenario->http2_connect_flush_probe()) {
2067 scenario->clear_http2_plan();
2068 scenario->clear_connection();
2069 scenario->clear_subsequent_connections();
2071 if (scenario->has_http2_plan()) {
2072 auto* connection = scenario->mutable_connection();
2073 connection->clear_initial_response();
2074 connection->clear_on_readable();
2075 connection->clear_server_frames();
2076 BoundHttp2PlanShape(scenario->mutable_http2_plan());
2078 CanonicalizeTlsAuthority(scenario);
2080 CanonicalizeTlsCertificateChain(scenario);
2081 CanonicalizeTlsGroupProfile(scenario);
2087 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2088 switch (scenario->socks_proxy_mode()) {
2089 case curl::fuzzer::proto::SOCKS_PROXY_SOCKS4:
2090 case curl::fuzzer::proto::SOCKS_PROXY_SOCKS4A:
2091 case curl::fuzzer::proto::SOCKS_PROXY_SOCKS5:
2092 case curl::fuzzer::proto::SOCKS_PROXY_SOCKS5_HOSTNAME:
2095 scenario->set_socks_proxy_mode(curl::fuzzer::proto::SOCKS_PROXY_SOCKS4);
2098 RemoveApiOnlyShape(scenario);
2099 RemoveMultiOnlyShape(scenario);
2100 RemoveTelnetOnlyShape(scenario);
2101 RemoveDeepHttpShape(scenario);
2102 scenario->mutable_connection()->clear_initial_response();
2103 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2104 CanonicalizeSocksAuthority(scenario);
2112 switch (scenario->resolver_mode()) {
2113 case curl::fuzzer::proto::RESOLVER_MODE_DEFAULT:
2114 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_POSITIVE:
2115 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_NEGATIVE:
2116 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_LINK_LOCAL:
2117 case curl::fuzzer::proto::RESOLVER_MODE_UNIX_SOCKET:
2118 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_PARTIAL:
2119 case curl::fuzzer::proto::RESOLVER_MODE_GLOBAL_LIFECYCLE:
2120 case curl::fuzzer::proto::RESOLVER_MODE_THREADED_QUEUED_CANCEL:
2123 scenario->clear_resolver_mode();
2126 if (scenario->has_doh()) {
2127 if (!curl::fuzzer::proto::DohResponseMode_IsValid(scenario->doh().response_mode())) {
2128 scenario->mutable_doh()->set_response_mode(curl::fuzzer::proto::DOH_RESPONSE_MODE_NORMAL);
2130 if (!curl::fuzzer::proto::DohTransportMode_IsValid(scenario->doh().transport_mode())) {
2131 scenario->mutable_doh()->set_transport_mode(curl::fuzzer::proto::DOH_TRANSPORT_HTTP);
2133 if (!curl::fuzzer::proto::DohOptionProbeMode_IsValid(scenario->doh().option_probe_mode())) {
2134 scenario->mutable_doh()->set_option_probe_mode(curl::fuzzer::proto::DOH_OPTION_PROBE_DEFAULT);
2136 if (scenario->doh().option_probe_mode() != curl::fuzzer::proto::DOH_OPTION_PROBE_DEFAULT) {
2137 scenario->mutable_doh()->set_transport_mode(curl::fuzzer::proto::DOH_TRANSPORT_HTTPS);
2140 const bool fixed_resolver_mode = scenario->resolver_mode() != curl::fuzzer::proto::RESOLVER_MODE_DEFAULT;
2141 if (fixed_resolver_mode) {
2142 scenario->clear_resolve_entries();
2143 scenario->clear_happy_eyeballs();
2144 scenario->clear_doh();
2146 const bool uses_doh = scenario->has_doh();
2147 scenario->set_scheme(uses_doh ? curl::fuzzer::proto::SCHEME_HTTPS : curl::fuzzer::proto::SCHEME_HTTP);
2148 RemoveApiOnlyShape(scenario);
2149 RemoveMultiOnlyShape(scenario);
2150 RemoveTelnetOnlyShape(scenario);
2151 RemoveDeepHttpShape(scenario);
2156 if (IsThreadedResolverMode(scenario->resolver_mode())) {
2157 scenario->mutable_connection()->mutable_backpressure()->set_drain_limit(1);
2159 if (scenario->resolver_mode() == curl::fuzzer::proto::RESOLVER_MODE_THREADED_QUEUED_CANCEL) {
2164 scenario->set_trace_config(
"+THREADS");
2170 scenario->clear_resolve_entries();
2171 scenario->clear_happy_eyeballs();
2172 if (scenario->has_http2_plan()) {
2173 auto* connection = scenario->mutable_connection();
2174 connection->clear_initial_response();
2175 connection->clear_on_readable();
2176 connection->clear_server_frames();
2177 BoundHttp2PlanShape(scenario->mutable_http2_plan());
2180 scenario->clear_http2_plan();
2184 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2185 CanonicalizeResolverAuthority(scenario);
2194 const auto scheme = scenario->scheme();
2195 const bool implicit_tls = scheme == curl::fuzzer::proto::SCHEME_FTPS;
2196 scenario->set_scheme(implicit_tls ? curl::fuzzer::proto::SCHEME_FTPS : curl::fuzzer::proto::SCHEME_FTP);
2198 scenario->clear_ftp_auth_tls_filter_allocation_failure();
2200 if (scenario->ftp_auth_tls_filter_allocation_failure()) {
2201 scenario->clear_fail_allocations();
2203 RemoveIgnoredFtpShape(scenario);
2204 CanonicalizeFtpOptionModes(scenario);
2205 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2206 CanonicalizeFtpAuthority(scenario);
2211 scenario->set_scheme(curl::fuzzer::proto::SCHEME_TFTP);
2212 RemoveIgnoredTftpShape(scenario);
2213 CanonicalizeTftpOptionModes(scenario);
2214 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2215 CanonicalizeTftpAuthority(scenario);
2224 const auto scheme = scenario->scheme();
2225 scenario->set_scheme(scheme == curl::fuzzer::proto::SCHEME_SMTPS ? curl::fuzzer::proto::SCHEME_SMTPS
2226 : curl::fuzzer::proto::SCHEME_SMTP);
2227 CanonicalizeSmtpProbeMode(scenario);
2228 if (scenario->scheme() == curl::fuzzer::proto::SCHEME_SMTPS) {
2229 scenario->clear_smtp_probe_mode();
2231 if (scenario->smtp_probe_mode() == curl::fuzzer::proto::SMTP_PROBE_STARTTLS_FILTER_ALLOCATION_FAILURE) {
2232 scenario->clear_fail_allocations();
2234 if (scenario->smtp_probe_mode() == curl::fuzzer::proto::SMTP_PROBE_SEND_BACKPRESSURE) {
2235 scenario->clear_mail_rcpt();
2236 scenario->clear_upload();
2237 scenario->clear_mime_post();
2239 RemoveIgnoredSmtpShape(scenario);
2240 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2241 if (scenario->smtp_probe_mode() == curl::fuzzer::proto::SMTP_PROBE_SEND_BACKPRESSURE) {
2242 scenario->set_probe_multi_pollset(
true);
2243 auto* backpressure = scenario->mutable_connection()->mutable_backpressure();
2244 backpressure->set_recv_buf_bytes(kSmtpProbeBufferBytes);
2245 backpressure->set_drain_limit(kSmtpProbeDrainBytes);
2247 CanonicalizeSmtpAuthority(scenario);
2255 const auto scheme = scenario->scheme();
2256 scenario->set_scheme(scheme == curl::fuzzer::proto::SCHEME_IMAPS ? curl::fuzzer::proto::SCHEME_IMAPS
2257 : curl::fuzzer::proto::SCHEME_IMAP);
2258 RemoveIgnoredImapShape(scenario);
2259 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2260 CanonicalizeMailBackpressure(scenario->mutable_connection());
2261 CanonicalizeImapAuthority(scenario);
2269 const auto scheme = scenario->scheme();
2270 scenario->set_scheme(scheme == curl::fuzzer::proto::SCHEME_POP3S ? curl::fuzzer::proto::SCHEME_POP3S
2271 : curl::fuzzer::proto::SCHEME_POP3);
2272 if (scenario->scheme() == curl::fuzzer::proto::SCHEME_POP3S) {
2273 scenario->clear_pop3_starttls_filter_allocation_failure();
2275 if (scenario->pop3_starttls_filter_allocation_failure()) {
2276 scenario->clear_fail_allocations();
2278 RemoveIgnoredPop3Shape(scenario);
2279 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2280 CanonicalizeMailBackpressure(scenario->mutable_connection());
2281 CanonicalizePop3Authority(scenario);
2290 CanonicalizeMqttProbeMode(scenario);
2291 const auto probe = scenario->mqtt_probe_mode();
2292 const auto scheme = scenario->scheme();
2293 scenario->set_scheme(probe == curl::fuzzer::proto::MQTT_PROBE_DEFAULT && scheme == curl::fuzzer::proto::SCHEME_MQTTS
2294 ? curl::fuzzer::proto::SCHEME_MQTTS
2295 : curl::fuzzer::proto::SCHEME_MQTT);
2296 RemoveIgnoredMqttShape(scenario);
2297 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2298 if (probe == curl::fuzzer::proto::MQTT_PROBE_SEND_BACKPRESSURE) {
2299 auto* backpressure = scenario->mutable_connection()->mutable_backpressure();
2300 backpressure->set_recv_buf_bytes(kMqttProbeBufferBytes);
2301 backpressure->set_drain_limit(kMqttProbeDrainBytes);
2302 scenario->set_probe_multi_pollset(
true);
2304 CanonicalizeMqttAuthority(scenario);
2309 scenario->set_scheme(curl::fuzzer::proto::SCHEME_DICT);
2310 RemoveIgnoredDictShape(scenario);
2311 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2312 CanonicalizeDictAuthority(scenario);
2317 CanonicalizeGopherProbeMode(scenario);
2318 const auto probe = scenario->gopher_probe_mode();
2319 if (probe == curl::fuzzer::proto::GOPHER_PROBE_TLS_SESSION_KEY_LIMIT) {
2320 scenario->set_scheme(curl::fuzzer::proto::SCHEME_GOPHERS);
2321 }
else if (probe != curl::fuzzer::proto::GOPHER_PROBE_DEFAULT) {
2322 scenario->set_scheme(curl::fuzzer::proto::SCHEME_GOPHER);
2324 scenario->set_scheme(scenario->scheme() == curl::fuzzer::proto::SCHEME_GOPHERS
2325 ? curl::fuzzer::proto::SCHEME_GOPHERS
2326 : curl::fuzzer::proto::SCHEME_GOPHER);
2328 RemoveIgnoredGopherShape(scenario);
2329 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2330 if (probe == curl::fuzzer::proto::GOPHER_PROBE_TLS_SESSION_KEY_LIMIT) {
2331 scenario->set_host_path(std::string(kGopherTlsPeerKeyHostBytes,
'g') +
"/1/session-key-limit");
2333 CanonicalizeTlsAuthority(scenario);
2339 scenario->set_scheme(curl::fuzzer::proto::SCHEME_FILE);
2340 scenario->clear_host_path();
2341 RemoveIgnoredFileShape(scenario);
2342 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2354 const auto scheme = scenario->scheme();
2355 scenario->set_scheme(scheme == curl::fuzzer::proto::SCHEME_LDAPS ? curl::fuzzer::proto::SCHEME_LDAPS
2356 : curl::fuzzer::proto::SCHEME_LDAP);
2357 if (scenario->scheme() == curl::fuzzer::proto::SCHEME_LDAPS) {
2358 scenario->clear_ldap_starttls();
2360 RemoveIgnoredLdapShape(scenario);
2361 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2362 CanonicalizeLdapAuthority(scenario);
2367 scenario->set_scheme(curl::fuzzer::proto::SCHEME_RTSP);
2368 RemoveIgnoredRtspShape(scenario);
2369 CanonicalizeRtspOptionModes(scenario);
2370 CanonicalizeRtspProbeMode(scenario);
2371 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2372 CanonicalizeRtspAuthority(scenario);
2379 scenario->set_scheme(scenario->scheme() == curl::fuzzer::proto::SCHEME_IPNS ? curl::fuzzer::proto::SCHEME_IPNS
2380 : curl::fuzzer::proto::SCHEME_IPFS);
2381 RemoveIgnoredIpfsShape(scenario);
2382 CanonicalizeFastHttpVersion(scenario);
2383 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2384 CanonicalizeIpfsAuthority(scenario);
2396 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2399 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2402 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2405 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTPS);
2429 scenario->set_scheme(curl::fuzzer::proto::SCHEME_WS);
2432 scenario->set_scheme(curl::fuzzer::proto::SCHEME_WSS);
2435 scenario->set_scheme(PlaintextScheme(scenario->scheme()));
2459 RemoveTelnetOnlyShape(scenario);
2461 RemoveApiOnlyShape(scenario);
2464 RemoveMultiOnlyShape(scenario);
2467 CanonicalizeDeepHttpSelectors(scenario);
2470 CanonicalizeApiDriveMode(scenario->mutable_api_plan());
2472 PruneAndBoundScenarioShape(scenario, profile, prune_conditional_eligibility);
2483 if (scenario->proxy_socket_option_mode() != curl::fuzzer::proto::PROXY_SOCKET_OPTION_DEFAULT) {
2486 scenario->clear_http_transport_mode();
2487 CanonicalizeProxySocketOptionAuthority(scenario);
2490 scenario->clear_altsvc_file();
2491 scenario->clear_hsts_file();
2492 }
else if (scenario->http_transport_mode() != curl::fuzzer::proto::HTTP_TRANSPORT_DIRECT) {
2493 CanonicalizeHttpTransportAuthority(scenario);
2497 scenario->clear_altsvc_file();
2498 scenario->clear_hsts_file();
2499 }
else if (!scenario->altsvc_file().empty()) {
2500 CanonicalizeAltSvcAuthority(scenario);
2502 if (scenario->http_transport_mode() == curl::fuzzer::proto::HTTP_TRANSPORT_CONNECT_PROXY &&
2503 scenario->haproxy_protocol()) {
2508 auto* backpressure = scenario->mutable_connection()->mutable_backpressure();
2509 backpressure->set_recv_buf_bytes(kHaproxyConnectBufferBytes);
2510 backpressure->set_drain_limit(kHaproxyConnectDrainBytes);
2511 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
2512 connection.clear_backpressure();
2515 scenario->clear_haproxy_protocol();
2516 ClearAllBackpressure(scenario);
2518 if (scenario->http_transport_mode() != curl::fuzzer::proto::HTTP_TRANSPORT_CONNECT_PROXY) {
2519 scenario->clear_probe_multi_pollset();
2524 ClearAllBackpressure(scenario);
2528 if (scenario->has_api_plan()) {
2529 BoundApiPlanShape(scenario->mutable_api_plan());
2530 CanonicalizeApiMimeRepeat(scenario);
2535 ClearAllBackpressure(scenario);
2536 CanonicalizeMultiAuthority(scenario);
2540 scenario->set_scheme(curl::fuzzer::proto::SCHEME_HTTP);
2541 auto* plan = scenario->mutable_multi_plan();
2542 BoundMultiPlanShape(plan);
2543 TrimRepeated(scenario->mutable_subsequent_connections(), plan->transfer_count() - 1U);
2548 ClearAllBackpressure(scenario);
2549 CanonicalizeTlsAuthority(scenario);
2550 CanonicalizeTlsCertificateChain(scenario);
2551 CanonicalizeTlsClientCredentialProfile(scenario);
2552 CanonicalizeTlsHandshakeProfile(scenario);
2581 ClearAllBackpressure(scenario);
2582 RemoveIgnoredWebSocketShape(scenario);
2586 ClearAllBackpressure(scenario);
2587 RemoveIgnoredWebSocketShape(scenario);
2588 CanonicalizeTlsAuthority(scenario);
2589 CanonicalizeTlsCertificateChain(scenario);
2614 if (scenario->scheme() == curl::fuzzer::proto::SCHEME_WS) {
2615 RemoveIgnoredWebSocketShape(scenario);
2617 auto* backpressure = scenario->mutable_connection()->mutable_backpressure();
2618 if (backpressure->recv_buf_bytes() == 0) {
2622 backpressure->set_recv_buf_bytes(kDefaultBackpressureBufferBytes);
2624 backpressure->set_recv_buf_bytes(CanonicalizeNonZero(backpressure->recv_buf_bytes(),
2625 kMinBackpressureBufferBytes, kMaxBackpressureBufferBytes));
2627 backpressure->set_drain_limit(CanonicalizeNonZero(backpressure->drain_limit(), 1, kMaxDrainBytesPerIteration));
2628 for (
auto& connection : *scenario->mutable_subsequent_connections()) {
2629 CanonicalizeOptionalBackpressure(&connection);
2644 if (scenario ==
nullptr) {
2647 CanonicalizeAllocationFailures(scenario);
2648 CanonicalizeAllocationFailureDrive(scenario);
2649 CanonicalizeLocalPortRange(scenario);
2672 ApplyLanePolicy(scenario, profile, prune_conditional_eligibility);
2677 for (
auto& option : *scenario->mutable_options()) {
2678 if (option.value_case() == curl::fuzzer::proto::SetOption::kStringValue) {
2679 TrimMetadata(option.mutable_string_value());
void CanonicalizeOptionValueCases(curl::fuzzer::proto::Scenario *scenario)
Restore each recognized option's consumed oneof member without calling libcurl.
Pure interpretation and normalization of structured curl options.
Shared complexity limits for structured scenarios.
constexpr std::size_t kMaxUploadReadSize
Larger read requests are indistinguishable once the whole body fits.
constexpr std::size_t kMaxHttp3Trailers
Trailer lists need fewer entries while retaining duplicate-name behavior.
constexpr std::size_t kMaxHttp2Settings
Bound each SETTINGS payload while retaining every standard identifier and several unknown extension v...
constexpr std::size_t kMaxHttp3BodyChunks
Bound the number of DATA-frame boundaries independently of total bytes.
constexpr std::size_t kMaxTelnetOptionBytes
Preserve curl's explicit over-1000-byte TTYPE/XDISPLOC rejection paths without giving arbitrary optio...
constexpr std::size_t kMaxHttp2Actions
Ordered H2 work can express startup, barriers, informational responses, flow-control changes,...
constexpr std::size_t kMaxHttp2YieldTurns
Sixteen turns preserve meaningful scheduler boundaries without letting a single scalar consume the co...
constexpr std::size_t kMinMultiTransfers
Two handles are the minimum that can enter shared-multi scheduling, while four align with the mock's ...
constexpr std::size_t kMaxHttp3Headers
Keep each structured header block small enough for cheap QPACK encoding.
constexpr std::size_t kMaxTelnetUploadReadSize
The TELNET peer drains immediately before each callback result.
constexpr std::uint64_t kMaxQuicVarint
QUIC variable-length integers reserve their two high bits for encoding.
constexpr std::size_t kMaxTelnetOptions
TELNET has only a handful of meaningful negotiated preferences.
constexpr std::size_t kMaxHttp3RawWriteBytes
Raw plaintext is primarily for malformed frame/QPACK prefixes; a compact per-action cap preserves tha...
constexpr std::size_t kMaxUploadReadSteps
Short-read scripts need several transitions, not mutation-sized sequences.
constexpr std::size_t kMaxApiReentrantSelectors
Each reentrancy selector fires one public API call from inside a callback.
constexpr std::size_t kMaxHttp2RawFrameBytes
Raw frame payloads target malformed parsing rather than bulk-body work.
constexpr std::size_t kMaxHttp3Actions
Ordered H3 work needs enough slots to interleave response fragments with stream and connection state ...
constexpr std::size_t kMaxMultiActions
Ordered lifecycle transitions remain useful in pairs (pause/resume and remove/re-add); sixteen permit...
constexpr std::size_t kMaxMimeDataBytes
MIME payloads remain large enough to cross encoder buffer boundaries.
constexpr std::size_t kMaxHttp2RawBytes
Bound aggregate raw escape data across an action sequence.
constexpr std::size_t kMaxResponseChunks
Enough response boundaries to exercise incremental parsers while keeping per-perform delivery work fi...
constexpr std::size_t kMaxHttp2HeaderBytes
Share one metadata ceiling across all H2 header blocks in a scenario.
constexpr std::size_t kMaxHttp2Headers
Keep structured HPACK work proportional to the action budget.
constexpr std::size_t kMaxMultiTransfers
Maximum easy handles configured in one shared-multi fuzz iteration.
constexpr std::size_t kMaxMailRecipientBytes
Keep recipient mailbox bytes within curl's normal address-processing range; oversized suffixes add no...
constexpr std::size_t kMaxMailRecipients
SMTP envelope recipients are schema-native because CURLOPT_MAIL_RCPT is a curl_slist.
constexpr std::size_t kMaxTelnetUploadReadSteps
OSS-Fuzz's local AF_UNIX peer normally fills curl's 4 KiB TELNET reads, so the bounded 8 KiB response...
constexpr std::size_t kMaxApiShareDataSelectors
A share handle has only a small fixed set of shareable data families.
constexpr std::size_t kMaxRequestHeaders
Request headers retain useful combinatorial interactions at this size.
constexpr std::size_t kMaxNestedMimeParts
One bounded child layer is sufficient to enter recursive MIME code.
constexpr std::size_t kMaxTotalMimeParts
Share a total budget so many parents cannot multiply their child caps.
constexpr std::size_t kMaxIpfsHostPathBytes
IPFS and IPNS inputs carry one CID/name plus a gateway path.
constexpr std::size_t kMaxUploadBytes
Maximum callback-backed body bytes visible in one scenario.
constexpr std::size_t kMaxMimeHeadersPerPart
Per-part headers are bounded separately from the part count.
constexpr std::size_t kMaxConnections
Four sockets cover redirect/auth flows without permitting mutation-sized connection chains to dominat...
constexpr std::size_t kMaxApiStringBytes
URL escaping can expand input threefold.
constexpr std::size_t kMaxFileInputBytes
One filename-only parser input can span many lines and cross curl's normal transfer buffer boundary w...
constexpr std::size_t kMaxResolveEntries
Host-cache mutations need only a compact sequence of add/remove/wildcard entries.
constexpr std::size_t kMaxApiInfoSelectors
One API iteration can cheaply inspect several result families, but an unbounded list would repeatedly...
constexpr std::size_t kMaxAllocationOrdinal
Fold mutated ordinals into a range large enough for the bounded transfer drivers while keeping most s...
constexpr std::size_t kMaxHttp2DataBytes
Structured DATA remains large enough to cross curl's callback boundary.
constexpr std::size_t kMaxHttp3HeaderBytes
Share one metadata budget across every structured header and trailer block so many actions cannot mul...
constexpr std::size_t kMaxResolveEntryBytes
CURLOPT_RESOLVE consumes NUL-terminated host:port:address records.
constexpr std::size_t kMaxHttp3HeaderValueBytes
Values use the shared metadata ceiling used by other header-bearing APIs.
constexpr std::size_t kMaxHttp3HeaderNameBytes
Header names are tokens rather than general metadata.
constexpr std::size_t kMaxHttp3BodyBytes
A response body can still cross curl's normal 16 KiB callback boundary.
constexpr std::size_t kMaxOptions
Scalar options are cheap, but a finite list prevents protobuf allocation from growing independently o...
constexpr std::size_t kMaxGeneratedMimeDataBytes
Retain both sides of curl's 64 KiB send-buffer boundary.
constexpr std::size_t kMaxTelnetUploadBytes
TELNET writes upload bytes while its blocking driver owns the thread, so keep total callback work sma...
constexpr std::size_t kMaxTopLevelMimeParts
Bound top-level MIME traversal before curl recursively serializes it.
constexpr std::size_t kMaxMetadataBytes
Metadata reaches NUL-terminated APIs, where giant suffixes add no coverage.
constexpr std::size_t kMaxGeneratedMimePatternBytes
Longer repeated patterns are better expressed as ordinary MIME data and make the compact source less ...
constexpr std::size_t kMaxDictHostPathBytes
DICT builds its complete command synchronously before the outer mock loop can drain curl's socket.
constexpr std::size_t kMaxHttp3RawBytes
Share one ceiling across all raw actions so sixteen maximum-sized writes cannot make one fuzzer itera...
constexpr std::size_t kMaxFileInputTotalBytes
Share a ceiling across filename-backed fixtures so populating several in one scenario cannot multiply...
void NormalizeScenarioForExecution(curl::fuzzer::proto::Scenario *scenario)
Apply execution-only allocation-failure safety rules.
void NormalizeScenarioForTarget(curl::fuzzer::proto::Scenario *scenario, TargetProfile profile, ConditionalEligibilityPruner prune_conditional_eligibility)
Complete normalization for a loaded or mutated fixed-target Scenario.
Mutation policies that keep each proto fuzzer in one intentional performance and protocol lane.
void(*)(curl::fuzzer::proto::Scenario *, TargetProfile) ConditionalEligibilityPruner
Generated callback that removes conditionally ineligible fields and options.
TargetProfile
Identifies one compiled proto-fuzzer lane.
@ kFastSmtp
Exercise single-connection SMTP and implicit-TLS SMTPS mail transfers.
@ kMulti
Exercise several easy handles through one shared multi handle.
@ kFastWebSocket
Exercise plaintext WebSocket framing without wall-clock waits.
@ kProxyTransport
Exercise HTTP through an in-process SOCKS proxy, optionally preceded by a HAProxy protocol-v1 prefix ...
@ kFastGopher
Exercise Gopher selectors through the bounded stream peer.
@ kApi
Exercise easy, share, multi, URL, and result API lifecycles.
@ kFastMqtt
Exercise binary MQTT and implicit-TLS MQTTS CONNECT/PUBLISH/SUBSCRIBE exchanges through the packet-aw...
@ kFastDict
Exercise line-based DICT lookups through the raw stream peer.
@ kFastHttp
Keep ordinary HTTP iterations cheap enough for a high mutation rate.
@ kFastFtp
Exercise FTP control and passive data connections, including implicit-TLS FTPS, without external I/O.
@ kFastRtsp
Exercise RTSP request/response exchanges and interleaved RTP delivery through the request-aligned str...
@ kResolver
Exercise localhost lookup and structured CURLOPT_RESOLVE host-cache work.
@ kFastHttp2
Exercise HTTP/2 origin frames over plaintext prior knowledge.
@ kH2Proxy
Exercise an HTTP/1.1 origin through an HTTPS/HTTP2 CONNECT proxy.
@ kTiming
Isolate deterministic backpressure and timed-wait behavior.
@ kFastSecureWebSocket
Exercise WebSocket framing through a verified TLS connection.
@ kFastFile
Exercise file:// URL parsing against a fixed read-only local target.
@ kHttpsH2
Exercise raw HTTP/2 origin frames after a verified TLS/ALPN handshake.
@ kFastTftp
Exercise packet-preserving TFTP exchanges over the loopback UDP peer.
@ kFastImap
Exercise single-connection IMAP mailbox transfers through the control peer.
@ kFastHttp3
Exercise HTTP/3 over a valid in-process QUIC/TLS connection.
@ kFastTelnet
Exercise bounded TELNET negotiation and callback-backed input.
@ kDeepHttp
Retain HTTP's complete structured request and response surface.
@ kCompatibility
Preserve the original mixed target and its accumulated corpus exactly.
@ kFastHttps
Exercise a complete HTTPS exchange against the in-process TLS peer.
@ kFastIpfs
Exercise curl's ipfs:// and ipns:// gateway rewrite as an ordinary HTTP GET against the in-process HT...
@ kFastLdap
Exercise binary BER LDAP bind and search exchanges through the OpenLDAP-backed single-socket peer.
@ kFastPop3
Exercise single-connection POP3 mailbox transfers through the control peer.
void BoundTelnetResponse(curl::fuzzer::proto::Connection *connection)
Retain the response prefix that TelnetMockServer can preload safely.
Shared TELNET response normalization.