• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)17 std::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)32 std::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