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