]> git.ipfire.org Git - thirdparty/squid.git/blob - src/mgr/QueryParams.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / mgr / QueryParams.cc
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 16 Cache Manager API */
10
11 #include "squid.h"
12 #include "base/TextException.h"
13 #include "ipc/TypedMsgHdr.h"
14 #include "mgr/IntParam.h"
15 #include "mgr/QueryParams.h"
16 #include "mgr/StringParam.h"
17 #include "parser/Tokenizer.h"
18 #include "sbuf/StringConvert.h"
19
20 #include <limits>
21
22 Mgr::QueryParam::Pointer
23 Mgr::QueryParams::get(const String& name) const
24 {
25 Must(name.size() != 0);
26 Params::const_iterator pos = find(name);
27 return (pos == params.end() ? NULL : pos->second);
28 }
29
30 void
31 Mgr::QueryParams::pack(Ipc::TypedMsgHdr& msg) const
32 {
33 msg.putInt(params.size());
34 for (Params::const_iterator iter = params.begin(); iter != params.end(); ++iter) {
35 Must(iter->first.size() != 0);
36 msg.putString(iter->first);
37 Must(iter->second != NULL);
38 iter->second->pack(msg);
39 }
40 }
41
42 void
43 Mgr::QueryParams::unpack(const Ipc::TypedMsgHdr& msg)
44 {
45 int count = msg.getInt();
46 Must(count >= 0);
47 params.clear();
48 for ( ; count > 0; --count) {
49 String name;
50 msg.getString(name);
51 Must(name.size() != 0);
52 QueryParam::Type type;
53 msg.getPod(type);
54 QueryParam::Pointer value = CreateParam(type);
55 value->unpackValue(msg);
56 params.push_back(Param(name, value));
57 }
58 }
59
60 Mgr::QueryParams::Params::const_iterator
61 Mgr::QueryParams::find(const String& name) const
62 {
63 Must(name.size() != 0);
64 Params::const_iterator iter = params.begin();
65 for ( ; iter != params.end(); ++iter) {
66 if (name.caseCmp(iter->first) == 0)
67 break;
68 }
69 return iter;
70 }
71
72 /**
73 * Parses the value part of a "param=value" URL section.
74 * Value can be a comma-separated list of integers or an opaque string.
75 *
76 * value = *pchar | ( 1*DIGIT *( ',' 1*DIGIT ) )
77 *
78 * \note opaque string may be a list with a non-integer (e.g., "1,2,3,z")
79 */
80 Mgr::QueryParam::Pointer
81 ParseParamValue(const SBuf &rawValue)
82 {
83 static const CharacterSet comma("comma", ",");
84
85 Parser::Tokenizer tok(rawValue);
86 std::vector<int> array;
87 int64_t intVal = 0;
88 while (tok.int64(intVal, 10, false)) {
89 Must(intVal >= std::numeric_limits<int>::min());
90 Must(intVal <= std::numeric_limits<int>::max());
91 array.emplace_back(intVal);
92 // integer list has comma between values.
93 // Require at least one potential DIGIT after the skipped ','
94 if (tok.remaining().length() > 1)
95 (void)tok.skipOne(comma);
96 }
97
98 if (tok.atEnd())
99 return new Mgr::IntParam(array);
100 else
101 return new Mgr::StringParam(SBufToString(rawValue));
102 }
103
104 /**
105 * Syntax:
106 * query = [ param *( '&' param ) ]
107 * param = name '=' value
108 * name = [a-zA-Z0-9]+
109 * value = *pchar | ( 1*DIGIT *( ',' 1*DIGIT ) )
110 */
111 void
112 Mgr::QueryParams::Parse(Parser::Tokenizer &tok, QueryParams &aParams)
113 {
114 static const CharacterSet nameChars = CharacterSet("param-name", "_") + CharacterSet::ALPHA + CharacterSet::DIGIT;
115 static const CharacterSet valueChars = CharacterSet("param-value", "&= #").complement();
116 static const CharacterSet delimChars("param-delim", "&");
117
118 while (!tok.atEnd()) {
119
120 // TODO: remove '#' processing when AnyP::Uri splits 'query#fragment' properly
121 // #fragment handled by caller. Do not throw.
122 if (tok.remaining()[0] == '#')
123 return;
124
125 if (tok.skipAll(delimChars))
126 continue;
127
128 SBuf nameStr;
129 if (!tok.prefix(nameStr, nameChars))
130 throw TextException("invalid query parameter name", Here());
131 if (!tok.skip('='))
132 throw TextException("missing parameter value", Here());
133
134 SBuf valueStr;
135 if (!tok.prefix(valueStr, valueChars))
136 throw TextException("missing or malformed parameter value", Here());
137
138 const auto name = SBufToString(nameStr);
139 const auto value = ParseParamValue(valueStr);
140 aParams.params.emplace_back(name, value);
141 }
142 }
143
144 Mgr::QueryParam::Pointer
145 Mgr::QueryParams::CreateParam(QueryParam::Type aType)
146 {
147 switch (aType) {
148 case QueryParam::ptInt:
149 return new IntParam();
150
151 case QueryParam::ptString:
152 return new StringParam();
153
154 default:
155 throw TexcHere("unknown parameter type");
156 break;
157 }
158 return NULL;
159 }