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