blob: 921a1ed1d2b7d00a5b53dbd140cf5c05471ae9af [file] [log] [blame]
// Copyright 2010-2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: jmarantz@google.com (Joshua Marantz)
#ifndef PAGESPEED_KERNEL_HTTP_QUERY_PARAMS_H_
#define PAGESPEED_KERNEL_HTTP_QUERY_PARAMS_H_
#include "pagespeed/kernel/base/string_multi_map.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
namespace net_instaweb {
class GoogleUrl;
// Parses and rewrites URL query parameters.
class QueryParams {
public:
QueryParams() { }
// Parse the query part of the given URL, for example "x=0&y=1&z=2".
//
// Note that a query param value can be NULL, indicating that the name was not
// followed by a '='. So given "a=0&b&c=", the values will be {"0", NULL, ""}.
void ParseFromUrl(const GoogleUrl& gurl);
// Parse the given untrusted string containing just query parameters,
// for example "x=0&y=1&z=2". This is a wrapper method that constructs
// a GoogleUrl from a dummy URL with the given string appended as query
// params, then calls ParseFromUrl. Accordingly, the given string will
// be sanitized by the GoogleUrl constructor: anything after an embedded
// '#' will be discarded, '\t's & '\n's & '\r's will be discarded, control
// chars will be %-encoded, ' ' & '"' & '<' & '>' & DEL will be %-encoded,
// and, when building for open source, which uses chromium's version of
// url_canon, single-quote ("'") is also %-encoded.
void ParseFromUntrustedString(StringPiece query_param_string);
// Generates an escaped query-string.
GoogleString ToEscapedString() const;
int size() const { return map_.num_values(); }
bool empty() const { return map_.empty(); }
void Clear() { map_.Clear(); }
// Find the value(s) associated with a variable. Note that you may
// specify a variable multiple times by adding it multiple times
// with the same variable, and each of these values will be returned
// in the vector.
//
// Any non alphanumerics besides "-_.~" will be %-encoded, the
// Unescaped version will have those evaluted out. See
// http://en.wikipedia.org/wiki/Query_string#URL_encoding
//
// If you want to get back values with %-encodings as originally specified
// in the query_string passed to Parse(), use the Escaped APIs. If you want
// to get those values back decoded, uses the Unescaped APIs.
bool LookupEscaped(const StringPiece& name,
ConstStringStarVector* values) const {
return map_.Lookup(name, values);
}
// Note: there is no LookupUnescaped currently. If we did define one it
// might have this API:
// bool LookupUnescaped(const StringPiece& name, StringVector* values) const
// and we'd have to answer the question of what the semantics should be
// if some of the values were successfully unescaped, and others not.
// Looks up a single value. Returns NULL if the name is not found or more
// than one value is found. The Escaped version will be %-encoded per
// http://en.wikipedia.org/wiki/Query_string#URL_encoding, the
// Unescaped version will have those evaluated out, e.g.
// the escaped form "Hello%2c+World%21" corresponds to the unescaped
// form "Hello, World!".
const GoogleString* Lookup1Escaped(const StringPiece& name) const {
return map_.Lookup1(name);
}
// Looks up a single value. Returns false if the name is not found, more
// than one value is found, or there is an error encountered when unescaping.
// See the documentation for Lookup1Unescaped
bool Lookup1Unescaped(const StringPiece& name,
GoogleString* escaped_value) const;
bool Has(const StringPiece& name) const { return map_.Has(name); }
// Remove all variables by name. Returns true if anything was removed.
bool RemoveAll(const StringPiece& key) { return map_.RemoveAll(key); }
// Remove all variables by name. Returns true if anything was removed.
//
// The 'names' vector must be sorted based on StringCompareSensitive.
bool RemoveAllFromSortedArray(const StringPiece* names, int names_size) {
return map_.RemoveAllFromSortedArray(names, names_size);
}
StringPiece name(int index) const { return map_.name(index); }
// Returns an indexed value. Note that the returned value can be NULL,
// which indicates the query-param did not have an "=" sign, or it
// might be an empty string, indicating the query-param had an "="
// but no value after it.
//
// The return value is left in its original escaped form.
const GoogleString* EscapedValue(int index) const {
return map_.value(index);
}
// Sets *escaped_val to the unescaped value at an index. Returns false
// if there is no value (no "=" in the query param) or if the query
// parameter could not be decoded.
bool UnescapedValue(int index, GoogleString* escaped_val) const;
// Add a new variable. The value can be null.
void AddEscaped(const StringPiece& key, const StringPiece& value) {
return map_.Add(key, value);
}
void CopyFrom(const QueryParams& query_param) {
map_.CopyFrom(query_param.map_);
}
private:
StringMultiMapSensitive map_;
DISALLOW_COPY_AND_ASSIGN(QueryParams);
};
} // namespace net_instaweb
#endif // PAGESPEED_KERNEL_HTTP_QUERY_PARAMS_H_