1 /*
2 * Fast 32-bit Header Field Name Parser
3 *
4 * Copyright (C) 2001-2003 FhG Fokus
5 *
6 * This file is part of Kamailio, a free SIP server.
7 *
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
12 *
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24 /** Parser :: Fast 32-bit Header Field Name Parser.
25 * @file
26 * @ingroup parser
27 */
28
29 #include "../comp_defs.h"
30 #include "../trim.h"
31 #include "../ut.h" /* q_memchr */
32 #include "parse_hname2.h"
33 #include "keys.h"
34
35 #define LOWER_BYTE(b) ((b) | 0x20)
36 #define LOWER_DWORD(d) ((d) | 0x20202020)
37
38 /** Skip all white-chars and return position of the first non-white char.
39 */
skip_ws(char * p,unsigned int size)40 static inline char* skip_ws(char* p, unsigned int size)
41 {
42 char* end;
43
44 end = p + size;
45 for(; p < end; p++) {
46 if ((*p != ' ') && (*p != '\t')) return p;
47 }
48 return p;
49 }
50
51 /*! \name
52 * Parser macros
53 */
54 /*@{ */
55 #include "case_via.h" /* Via */
56 #include "case_from.h" /* From */
57 #include "case_to.h" /* To */
58 #include "case_cseq.h" /* CSeq */
59 #include "case_call.h" /* Call-ID */
60 #include "case_cont.h" /* Contact, Content-Type, Content-Length, Content-Purpose,
61 * Content-Action, Content-Disposition */
62 #include "case_rout.h" /* Route */
63 #include "case_max.h" /* Max-Forwards */
64 #include "case_reco.h" /* Record-Route */
65 #include "case_auth.h" /* Authorization */
66 #include "case_expi.h" /* Expires */
67 #include "case_prox.h" /* Proxy-Authorization, Proxy-Require */
68 #include "case_allo.h" /* Allow */
69 #include "case_unsu.h" /* Unsupported */
70 #include "case_even.h" /* Event */
71 #include "case_sip.h" /* Sip-If-Match */
72 #include "case_acce.h" /* Accept, Accept-Language */
73 #include "case_orga.h" /* Organization */
74 #include "case_prio.h" /* Priority */
75 #include "case_subj.h" /* Subject */
76 #include "case_user.h" /* User-Agent */
77 #include "case_serv.h" /* Server */
78 #include "case_supp.h" /* Supported */
79 #include "case_dive.h" /* Diversion */
80 #include "case_remo.h" /* Remote-Party-ID */
81 #include "case_refe.h" /* Refer-To */
82 #include "case_sess.h" /* Session-Expires */
83 #include "case_reje.h" /* Reject-Contact */
84 #include "case_min.h" /* Min-SE */
85 #include "case_subs.h" /* Subscription-State */
86 #include "case_requ.h" /* Require */
87 #include "case_www.h" /* WWW-Authenticate */
88 #include "case_date.h" /* Date */
89 #include "case_iden.h" /* Identity, Identity-info */
90 #include "case_retr.h" /* Retry-After */
91 #include "case_path.h" /* Path */
92 #include "case_priv.h"
93 #include "case_reas.h" /* Reason */
94 #include "case_p_as.h" /* P-Asserted-Identity */
95 #include "case_p_pr.h" /* P-Preferred-Identity */
96
97 /*@} */
98
99 #define SAFE_READ(val, len) \
100 ((len) == 1 ? READ1(val) : ((len) == 2 ? READ2(val) : ((len) == 3 ? READ3(val) : ((len) > 3 ? READ4(val) : READ0(val)))))
101
102 #define READ(val) \
103 READ4(val)
104
105 #define READ4(val) \
106 (*((val) + 0) + (*((val) + 1) << 8) + (*((val) + 2) << 16) + (*((val) + 3) << 24))
107
108 #define READ3(val) \
109 (*((val) + 0) + (*((val) + 1) << 8) + (*((val) + 2) << 16))
110
111 #define READ2(val) \
112 (*((val) + 0) + (*((val) + 1) << 8))
113
114 #define READ1(val) \
115 (*((val) + 0))
116
117 #define READ0(val) \
118 (0)
119
120 #define FIRST_QUATERNIONS \
121 case _via1_: via1_CASE; \
122 case _from_: from_CASE; \
123 case _to12_: to12_CASE; \
124 case _cseq_: cseq_CASE; \
125 case _call_: call_CASE; \
126 case _cont_: cont_CASE; \
127 case _rout_: rout_CASE; \
128 case _max__: max_CASE; \
129 case _reco_: reco_CASE; \
130 case _via2_: via2_CASE; \
131 case _auth_: auth_CASE; \
132 case _supp_: supp_CASE; \
133 case _expi_: expi_CASE; \
134 case _prox_: prox_CASE; \
135 case _allo_: allo_CASE; \
136 case _unsu_: unsu_CASE; \
137 case _even_: even_CASE; \
138 case _sip_ : sip_CASE; \
139 case _acce_: acce_CASE; \
140 case _orga_: orga_CASE; \
141 case _prio_: prio_CASE; \
142 case _subj_: subj_CASE; \
143 case _subs_: subs_CASE; \
144 case _user_: user_CASE; \
145 case _serv_: serv_CASE; \
146 case _dive_: dive_CASE; \
147 case _remo_: remo_CASE; \
148 case _refe_: refe_CASE; \
149 case _sess_: sess_CASE; \
150 case _reje_: reje_CASE; \
151 case _min__: min_CASE; \
152 case _requ_: requ_CASE; \
153 case _www__: www_CASE; \
154 case _date_: date_CASE; \
155 case _iden_: iden_CASE; \
156 case _retr_: retr_CASE; \
157 case _path_: path_CASE; \
158 case _priv_: priv_CASE; \
159 case _reas_: reas_CASE; \
160 case _p_as_: p_as_CASE; \
161 case _p_pr_: p_pr_CASE;
162
163
164 #define PARSE_COMPACT(id) \
165 switch(*(p + 1)) { \
166 case ' ': \
167 hdr->type = id; \
168 p += 2; \
169 goto dc_end; \
170 \
171 case ':': \
172 hdr->type = id; \
173 hdr->name.len = 1; \
174 return (p + 2); \
175 }
176
parse_hname2(char * const begin,const char * const end,struct hdr_field * const hdr)177 char* parse_hname2(char* const begin, const char* const end, struct hdr_field* const hdr)
178 {
179 register char* p;
180 register unsigned int val;
181
182 if ((end - begin) < 4) {
183 hdr->type = HDR_ERROR_T;
184 return begin;
185 }
186
187 p = begin;
188
189 val = LOWER_DWORD(READ(p));
190 hdr->name.s = begin;
191
192 switch(val) {
193 FIRST_QUATERNIONS;
194
195 default:
196 switch(LOWER_BYTE(*p)) {
197 case 't':
198 switch(LOWER_BYTE(*(p + 1))) {
199 case 'o':
200 case ' ':
201 hdr->type = HDR_TO_T;
202 p += 2;
203 goto dc_end;
204
205 case ':':
206 hdr->type = HDR_TO_T;
207 hdr->name.len = 1;
208 return (p + 2);
209 }
210 break;
211
212 case 'v': PARSE_COMPACT(HDR_VIA_T); break;
213 case 'f': PARSE_COMPACT(HDR_FROM_T); break;
214 case 'i': PARSE_COMPACT(HDR_CALLID_T); break;
215 case 'm': PARSE_COMPACT(HDR_CONTACT_T); break;
216 case 'l': PARSE_COMPACT(HDR_CONTENTLENGTH_T); break;
217 case 'k': PARSE_COMPACT(HDR_SUPPORTED_T); break;
218 case 'c': PARSE_COMPACT(HDR_CONTENTTYPE_T); break;
219 case 'o': PARSE_COMPACT(HDR_EVENT_T); break;
220 case 'x': PARSE_COMPACT(HDR_SESSIONEXPIRES_T);break;
221 case 'a': PARSE_COMPACT(HDR_ACCEPTCONTACT_T); break;
222 case 'u': PARSE_COMPACT(HDR_ALLOWEVENTS_T); break;
223 case 'e': PARSE_COMPACT(HDR_CONTENTENCODING_T); break;
224 case 'b': PARSE_COMPACT(HDR_REFERREDBY_T); break;
225 case 'j': PARSE_COMPACT(HDR_REJECTCONTACT_T); break;
226 case 'd': PARSE_COMPACT(HDR_REQUESTDISPOSITION_T); break;
227 case 's': PARSE_COMPACT(HDR_SUBJECT_T); break;
228 case 'r': PARSE_COMPACT(HDR_REFER_TO_T); break;
229 case 'y': PARSE_COMPACT(HDR_IDENTITY_T); break;
230 case 'n': PARSE_COMPACT(HDR_IDENTITY_INFO_T); break;
231 }
232 goto other;
233 }
234
235 /* Double colon hasn't been found yet */
236 dc_end:
237 p = skip_ws(p, end - p);
238 if (*p != ':') {
239 goto other;
240 } else {
241 hdr->name.len = p - hdr->name.s;
242 trim_trailing(&hdr->name);
243 return (p + 1);
244 }
245
246 /* Unknown header type */
247 other:
248 p = q_memchr(p, ':', end - p);
249 if (!p) { /* No double colon found, error.. */
250 hdr->type = HDR_ERROR_T;
251 hdr->name.s = 0;
252 hdr->name.len = 0;
253 return 0;
254 } else {
255 hdr->type = HDR_OTHER_T;
256 hdr->name.len = p - hdr->name.s;
257 trim_trailing(&hdr->name);
258 /*hdr_update_type(hdr);*/
259 return (p + 1);
260 }
261 }
262
263 /**
264 * parse_hname2_short() - safer version to parse header name stored in short buffers
265 * - parse_hanem2() reads 4 bytes at once, expecting to walk through a buffer
266 * that contains more than the header name (e.g., sip msg buf, full header buf
267 * with name and body)
268 */
parse_hname2_short(char * const begin,const char * const end,struct hdr_field * const hdr)269 char* parse_hname2_short(char* const begin, const char* const end, struct hdr_field* const hdr)
270 {
271 #define HBUF_MAX_SIZE 256
272 char hbuf[HBUF_MAX_SIZE];
273 char *p;
274
275 if(end-begin>=HBUF_MAX_SIZE-4) {
276 p = q_memchr(begin, ':', end - begin);
277 if(p && p-4> begin) {
278 /* header name termination char found and enough space in buffer after it */
279 return parse_hname2(begin, end, hdr);
280 }
281 /* not enough space */
282 LM_ERR("not enough space to parse the header name in [%.*s] (%d)\n",
283 (int)(end-begin), begin, (int)(end-begin));
284 return NULL;
285 }
286 /* pad with whitespace - tipycal char after the ':' of the header name */
287 memset(hbuf, ' ', HBUF_MAX_SIZE);
288 memcpy(hbuf, begin, end-begin);
289 p = parse_hname2(hbuf, hbuf + 4 + (end-begin), hdr);
290 if(!p) {
291 LM_ERR("failed to parse the header name in [%.*s] (%d)\n",
292 (int)(end-begin), begin, (int)(end-begin));
293 return NULL;
294 }
295 return begin + (p-hbuf);
296 }
297