1 // Copyright 2021 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <assert.h> 6 #include <stdlib.h> 7 8 #include <string> 9 10 #include "base/strings/string_number_conversions.h" 11 #include "testing/libfuzzer/proto/url.pb.h" 12 13 namespace url_proto { 14 15 namespace { 16 SlashToString(int slash)17std::string SlashToString(int slash) { 18 if (slash == url_proto::Url::NONE) 19 return ""; 20 if (slash == url_proto::Url::FORWARD) 21 return "/"; 22 if (slash == url_proto::Url::BACKWARD) { 23 return "\\"; 24 } 25 assert(false && "Received unexpected value for slash"); 26 // Silence compiler warning about not returning in non-void function. 27 return ""; 28 } 29 30 } // namespace 31 Convert(const url_proto::Url & url)32std::string Convert(const url_proto::Url& url) { 33 // Build url_string piece by piece from url and then return it. 34 std::string url_string = std::string(""); 35 36 if (url.has_scheme()) { // Get the scheme if Url has it. 37 // Append the scheme to the url. This may be empty. Then append a colon 38 // which is mandatory if there is a scheme. 39 url_string += url.scheme() + ":"; 40 } 41 42 // Just append the slashes without doing validation, since it would be too 43 // complex. libFuzzer will hopefully figure out good values. 44 for (const int slash : url.slashes()) 45 url_string += SlashToString(slash); 46 47 // Get host. This is simple since hosts are simply strings according to our 48 // definition. 49 if (url.has_host()) { 50 // Get userinfo if libFuzzer set it. Ensure that user is separated 51 // from the password by ":" (if a password is included) and that userinfo is 52 // separated from the host by "@". 53 if (url.has_userinfo()) { 54 url_string += url.userinfo().user(); 55 if (url.userinfo().has_password()) { 56 url_string += ":"; 57 url_string += url.userinfo().password(); 58 } 59 url_string += "@"; 60 } 61 url_string += url.host(); 62 63 // As explained in url.proto, if libFuzzer included a port in url ensure 64 // that it is preceded by the host and then ":". 65 if (url.has_port()) 66 // Convert url.port() from an unsigned 32 bit int before appending it. 67 url_string += ":" + base::NumberToString(url.port()); 68 } 69 70 // Append the path segments to the url, with each segment separated by 71 // the path_separator. 72 bool first_segment = true; 73 std::string path_separator = SlashToString(url.path_separator()); 74 for (const std::string& path_segment : url.path()) { 75 // There does not need to be a path, but if there is a path and a host, 76 // ensure the path begins with "/". 77 if (url.has_host() && first_segment) { 78 url_string += "/" + path_segment; 79 first_segment = false; 80 } else 81 url_string += path_separator + path_segment; 82 } 83 84 // Queries must be started by "?". If libFuzzer included a query in url, 85 // ensure that it is preceded by "?". Also separate query components with 86 // ampersands as is the convention. 87 bool first_component = true; 88 for (const std::string& query_component : url.query()) { 89 if (first_component) { 90 url_string += "?" + query_component; 91 first_component = false; 92 } else 93 url_string += "&" + query_component; 94 } 95 96 // Fragments must be started by "#". If libFuzzer included a fragment 97 // in url, ensure that it is preceded by "#". 98 if (url.has_fragment()) 99 url_string += "#" + url.fragment(); 100 101 return url_string; 102 } 103 104 } // namespace url_proto 105