Home | History | Annotate | Download | only in base
      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