| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/base/url_util.h" |
| |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "base/strings/string_piece.h" |
| #include "net/base/escape.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| |
| GURL AppendQueryParameter(const GURL& url, |
| const std::string& name, |
| const std::string& value) { |
| std::string query(url.query()); |
| |
| if (!query.empty()) |
| query += "&"; |
| |
| query += (EscapeQueryParamValue(name, true) + "=" + |
| EscapeQueryParamValue(value, true)); |
| GURL::Replacements replacements; |
| replacements.SetQueryStr(query); |
| return url.ReplaceComponents(replacements); |
| } |
| |
| GURL AppendOrReplaceQueryParameter(const GURL& url, |
| const std::string& name, |
| const std::string& value) { |
| bool replaced = false; |
| std::string param_name = EscapeQueryParamValue(name, true); |
| std::string param_value = EscapeQueryParamValue(value, true); |
| |
| const std::string input = url.query(); |
| url::Component cursor(0, input.size()); |
| std::string output; |
| url::Component key_range, value_range; |
| while (url::ExtractQueryKeyValue(input.data(), &cursor, &key_range, |
| &value_range)) { |
| const base::StringPiece key( |
| input.data() + key_range.begin, key_range.len); |
| const base::StringPiece value( |
| input.data() + value_range.begin, value_range.len); |
| std::string key_value_pair; |
| // Check |replaced| as only the first pair should be replaced. |
| if (!replaced && key == param_name) { |
| replaced = true; |
| key_value_pair = (param_name + "=" + param_value); |
| } else { |
| key_value_pair.assign(input.data(), |
| key_range.begin, |
| value_range.end() - key_range.begin); |
| } |
| if (!output.empty()) |
| output += "&"; |
| |
| output += key_value_pair; |
| } |
| if (!replaced) { |
| if (!output.empty()) |
| output += "&"; |
| |
| output += (param_name + "=" + param_value); |
| } |
| GURL::Replacements replacements; |
| replacements.SetQueryStr(output); |
| return url.ReplaceComponents(replacements); |
| } |
| |
| QueryIterator::QueryIterator(const GURL& url) |
| : url_(url), |
| at_end_(!url.is_valid()) { |
| if (!at_end_) { |
| query_ = url.parsed_for_possibly_invalid_spec().query; |
| Advance(); |
| } |
| } |
| |
| QueryIterator::~QueryIterator() { |
| } |
| |
| std::string QueryIterator::GetKey() const { |
| DCHECK(!at_end_); |
| if (key_.is_nonempty()) |
| return url_.spec().substr(key_.begin, key_.len); |
| return std::string(); |
| } |
| |
| std::string QueryIterator::GetValue() const { |
| DCHECK(!at_end_); |
| if (value_.is_nonempty()) |
| return url_.spec().substr(value_.begin, value_.len); |
| return std::string(); |
| } |
| |
| const std::string& QueryIterator::GetUnescapedValue() { |
| DCHECK(!at_end_); |
| if (value_.is_nonempty() && unescaped_value_.empty()) { |
| unescaped_value_ = UnescapeURLComponent( |
| GetValue(), |
| UnescapeRule::SPACES | |
| UnescapeRule::URL_SPECIAL_CHARS | |
| UnescapeRule::REPLACE_PLUS_WITH_SPACE); |
| } |
| return unescaped_value_; |
| } |
| |
| bool QueryIterator::IsAtEnd() const { |
| return at_end_; |
| } |
| |
| void QueryIterator::Advance() { |
| DCHECK (!at_end_); |
| key_.reset(); |
| value_.reset(); |
| unescaped_value_.clear(); |
| at_end_ = |
| !url::ExtractQueryKeyValue(url_.spec().c_str(), &query_, &key_, &value_); |
| } |
| |
| bool GetValueForKeyInQuery(const GURL& url, |
| const std::string& search_key, |
| std::string* out_value) { |
| for (QueryIterator it(url); !it.IsAtEnd(); it.Advance()) { |
| if (it.GetKey() == search_key) { |
| *out_value = it.GetUnescapedValue(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace net |