1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 /****************************************************************************
25
26 HdrUtils.h
27
28 Description: Convenience routines for dealing with hdrs and
29 values
30
31
32 ****************************************************************************/
33
34 #pragma once
35
36 #include "tscpp/util/TextView.h"
37 #include "tscore/ParseRules.h"
38 #include "MIME.h"
39
40 /** Accessor class to iterate over values in a multi-valued field.
41 *
42 * This implements the logic for quoted strings as specified in the RFC.
43 */
44 class HdrCsvIter
45 {
46 using TextView = ts::TextView;
47
48 public:
49 /** Construct the iterator in the initial state.
50 *
51 * @param s The separator character for sub-values.
52 */
m_separator(s)53 HdrCsvIter(char s = ',') : m_separator(s) {}
54
55 /** Get the first sub-value.
56 *
57 * @param m The multi-valued field.
58 * @param follow_dups Continue on to duplicate fields flag.
59 * @return A view of the first sub-value in multi-valued data.
60 */
61 TextView get_first(const MIMEField *m, bool follow_dups = true);
62 const char *get_first(const MIMEField *m, int *len, bool follow_dups = true);
63
64 /** Get the next sub-value.
65 *
66 * @return A view of the next subvalue, or an empty view if no more values.
67 *
68 * If @a follow_dups was set in the constructor, this will continue on to additional fields
69 * if those fields have the same name as the original field (e.g, are duplicates).
70 */
71 TextView get_next();
72 const char *get_next(int *len);
73
74 /** Get the current sub-value.
75 *
76 * @return A view of the current subvalue, or an empty view if no more values.
77 *
78 * The state of the iterator is not modified.
79 */
80 TextView get_current();
81 const char *get_current(int *len);
82
83 /** Get the @a nth sub-value in the field @a m.
84 *
85 * @param m Field.
86 * @param nth Index of the target sub-value.
87 * @param follow_dups Follow duplicate fields if necessary.
88 * @return The subvalue at index @a n, or an empty view if that does not exist.
89 */
90 TextView get_nth(MIMEField *m, int nth, bool follow_dups = true);
91 const char *get_nth(MIMEField *m, int *len, int n, bool follow_dups = true);
92
93 int count_values(MIMEField *field, bool follow_dups = true);
94
95 /** Get the first sub-value as an integer.
96 *
97 * @param m Field with the value.
98 * @param result [out] Set to the integer sub-value.
99 * @return @c true if there was an integer and @a result was set, @c false otherwise.
100 */
101 bool get_first_int(MIMEField *m, int &result);
102
103 /** Get the next subvalue as an integer.
104 *
105 * @param result [out] Set to the integer sub-value.
106 * @return @c true if there was an integer and @a result was set, @c false otherwise.
107 */
108 bool get_next_int(int &result);
109
110 private:
111 void find_csv();
112
113 /// The current field value.
114 TextView m_value;
115
116 /// Whether duplicates are being followed.
117 bool m_follow_dups = false;
118
119 /// The current sub-value.
120 TextView m_csv;
121
122 /// The field containing the current sub-value.
123 const MIMEField *m_cur_field = nullptr;
124
125 /// Separator for sub-values.
126 /// for the Cookie/Set-cookie headers, the separator is ';'
127 const char m_separator; // required constructor parameter, no initialization here.
128
129 void field_init(const MIMEField *m);
130 };
131
132 inline void
field_init(const MIMEField * m)133 HdrCsvIter::field_init(const MIMEField *m)
134 {
135 m_cur_field = m;
136 m_value.assign(m->m_ptr_value, m->m_len_value);
137 }
138
139 inline const char *
get_first(const MIMEField * m,int * len,bool follow_dups)140 HdrCsvIter::get_first(const MIMEField *m, int *len, bool follow_dups)
141 {
142 auto tv = this->get_first(m, follow_dups);
143 *len = static_cast<int>(tv.size());
144 return tv.data();
145 }
146
147 inline ts::TextView
get_first(const MIMEField * m,bool follow_dups)148 HdrCsvIter::get_first(const MIMEField *m, bool follow_dups)
149 {
150 field_init(m);
151 m_follow_dups = follow_dups;
152 this->find_csv();
153 return m_csv;
154 }
155
156 inline ts::TextView
get_next()157 HdrCsvIter::get_next()
158 {
159 this->find_csv();
160 return m_csv;
161 }
162
163 inline const char *
get_next(int * len)164 HdrCsvIter::get_next(int *len)
165 {
166 auto tv = this->get_next();
167 *len = static_cast<int>(tv.size());
168 return tv.data();
169 }
170
171 inline ts::TextView
get_current()172 HdrCsvIter::get_current()
173 {
174 return m_csv;
175 }
176
177 inline const char *
get_current(int * len)178 HdrCsvIter::get_current(int *len)
179 {
180 *len = static_cast<int>(m_csv.size());
181 return m_csv.data();
182 }
183
184 inline bool
get_first_int(MIMEField * m,int & result)185 HdrCsvIter::get_first_int(MIMEField *m, int &result)
186 {
187 auto val = this->get_first(m);
188
189 if (val) {
190 TextView parsed;
191 int n = ts::svtoi(val, &parsed);
192 if (parsed) {
193 result = n;
194 return true;
195 }
196 }
197 return false;
198 }
199
200 inline bool
get_next_int(int & result)201 HdrCsvIter::get_next_int(int &result)
202 {
203 auto val = this->get_next();
204
205 if (val) {
206 TextView parsed;
207 int n = ts::svtoi(val, &parsed);
208 if (parsed) {
209 result = n;
210 return true;
211 }
212 }
213 return false;
214 }
215