1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 "net/base/url_util.h" 6 7 #include <utility> 8 9 #include "base/logging.h" 10 #include "base/strings/string_piece.h" 11 #include "net/base/escape.h" 12 #include "url/gurl.h" 13 14 namespace net { 15 16 GURL AppendQueryParameter(const GURL& url, 17 const std::string& name, 18 const std::string& value) { 19 std::string query(url.query()); 20 21 if (!query.empty()) 22 query += "&"; 23 24 query += (EscapeQueryParamValue(name, true) + "=" + 25 EscapeQueryParamValue(value, true)); 26 GURL::Replacements replacements; 27 replacements.SetQueryStr(query); 28 return url.ReplaceComponents(replacements); 29 } 30 31 GURL AppendOrReplaceQueryParameter(const GURL& url, 32 const std::string& name, 33 const std::string& value) { 34 bool replaced = false; 35 std::string param_name = EscapeQueryParamValue(name, true); 36 std::string param_value = EscapeQueryParamValue(value, true); 37 38 const std::string input = url.query(); 39 url_parse::Component cursor(0, input.size()); 40 std::string output; 41 url_parse::Component key_range, value_range; 42 while (url_parse::ExtractQueryKeyValue( 43 input.data(), &cursor, &key_range, &value_range)) { 44 const base::StringPiece key( 45 input.data() + key_range.begin, key_range.len); 46 const base::StringPiece value( 47 input.data() + value_range.begin, value_range.len); 48 std::string key_value_pair; 49 // Check |replaced| as only the first pair should be replaced. 50 if (!replaced && key == param_name) { 51 replaced = true; 52 key_value_pair = (param_name + "=" + param_value); 53 } else { 54 key_value_pair.assign(input.data(), 55 key_range.begin, 56 value_range.end() - key_range.begin); 57 } 58 if (!output.empty()) 59 output += "&"; 60 61 output += key_value_pair; 62 } 63 if (!replaced) { 64 if (!output.empty()) 65 output += "&"; 66 67 output += (param_name + "=" + param_value); 68 } 69 GURL::Replacements replacements; 70 replacements.SetQueryStr(output); 71 return url.ReplaceComponents(replacements); 72 } 73 74 QueryIterator::QueryIterator(const GURL& url) 75 : url_(url), 76 at_end_(!url.is_valid()) { 77 if (!at_end_) { 78 query_ = url.parsed_for_possibly_invalid_spec().query; 79 Advance(); 80 } 81 } 82 83 QueryIterator::~QueryIterator() { 84 } 85 86 std::string QueryIterator::GetKey() const { 87 DCHECK(!at_end_); 88 if (key_.is_nonempty()) 89 return url_.spec().substr(key_.begin, key_.len); 90 return std::string(); 91 } 92 93 std::string QueryIterator::GetValue() const { 94 DCHECK(!at_end_); 95 if (value_.is_nonempty()) 96 return url_.spec().substr(value_.begin, value_.len); 97 return std::string(); 98 } 99 100 const std::string& QueryIterator::GetUnescapedValue() { 101 DCHECK(!at_end_); 102 if (value_.is_nonempty() && unescaped_value_.empty()) { 103 unescaped_value_ = UnescapeURLComponent( 104 GetValue(), 105 UnescapeRule::SPACES | 106 UnescapeRule::URL_SPECIAL_CHARS | 107 UnescapeRule::REPLACE_PLUS_WITH_SPACE); 108 } 109 return unescaped_value_; 110 } 111 112 bool QueryIterator::IsAtEnd() const { 113 return at_end_; 114 } 115 116 void QueryIterator::Advance() { 117 DCHECK (!at_end_); 118 key_.reset(); 119 value_.reset(); 120 unescaped_value_.clear(); 121 at_end_ = !url_parse::ExtractQueryKeyValue(url_.spec().c_str(), 122 &query_, 123 &key_, 124 &value_); 125 } 126 127 bool GetValueForKeyInQuery(const GURL& url, 128 const std::string& search_key, 129 std::string* out_value) { 130 for (QueryIterator it(url); !it.IsAtEnd(); it.Advance()) { 131 if (it.GetKey() == search_key) { 132 *out_value = it.GetUnescapedValue(); 133 return true; 134 } 135 } 136 return false; 137 } 138 139 } // namespace net 140