/src/kamailio/src/core/parser/parse_methods.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2004 Juha Heinanen |
3 | | * |
4 | | * This file is part of Kamailio, a free SIP server. |
5 | | * |
6 | | * Kamailio is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version |
10 | | * |
11 | | * Kamailio is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | /*! \file |
22 | | * \brief Parser :: Parse Methods |
23 | | * |
24 | | * \ingroup parser |
25 | | */ |
26 | | |
27 | | #include <strings.h> |
28 | | #include "../dprint.h" |
29 | | #include "../trim.h" |
30 | | #include "parse_methods.h" |
31 | | |
32 | | |
33 | | /*! \brief |
34 | | * Check if argument is valid RFC3261 token character. |
35 | | */ |
36 | | static int token_char(char _c) |
37 | 0 | { |
38 | 0 | return (_c >= 65 && _c <= 90) || /* upper alpha */ |
39 | 0 | (_c >= 97 && _c <= 122) || /* lower aplha */ |
40 | 0 | (_c >= 48 && _c <= 57) || /* digits */ |
41 | 0 | (_c == '-') || (_c == '.') || (_c == '!') || (_c == '%') |
42 | 0 | || (_c == '*') || (_c == '_') || (_c == '+') || (_c == '`') |
43 | 0 | || (_c == '\'') || (_c == '~'); |
44 | 0 | } |
45 | | |
46 | | |
47 | | /*! \brief Parse a string containing a method. |
48 | | * |
49 | | * Parse a method pointed by s & assign its enum bit to method. The string |
50 | | * _must_ contain _only_ the method (without trailing or heading whitespace). |
51 | | * \return 0 on success, -1 on error |
52 | | */ |
53 | | int parse_method_name(const str *const s, enum request_method *const method) |
54 | 16.2k | { |
55 | 16.2k | if(unlikely(!s || !method)) { |
56 | 0 | LM_ERR("Invalid parameter value\n"); |
57 | 0 | return -1; |
58 | 0 | } |
59 | | |
60 | 16.2k | if(unlikely(!s->len || (s->s == 0))) { |
61 | 0 | LM_DBG("No input\n"); |
62 | 0 | *method = METHOD_OTHER; |
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | 16.2k | switch((s->s)[0]) { |
67 | | /* ordered after probability of apparition on a normal proxy */ |
68 | 598 | case 'R': |
69 | 1.04k | case 'r': |
70 | 1.04k | if(likely((s->len == 8) && !strncasecmp(s->s + 1, "egister", 7))) { |
71 | 235 | *method = METHOD_REGISTER; |
72 | 235 | return 0; |
73 | 235 | } |
74 | 806 | if(likely((s->len == 5) && !strncasecmp(s->s + 1, "efer", 4))) { |
75 | 237 | *method = METHOD_REFER; |
76 | 237 | return 0; |
77 | 237 | } |
78 | 569 | break; |
79 | 569 | case 'A': |
80 | 762 | case 'a': |
81 | 762 | if(likely((s->len == 3) && !strncasecmp(s->s + 1, "ck", 2))) { |
82 | 240 | *method = METHOD_ACK; |
83 | 240 | return 0; |
84 | 240 | } |
85 | 522 | break; |
86 | 1.11k | case 'I': |
87 | 1.52k | case 'i': |
88 | 1.52k | if(likely((s->len == 6) && !strncasecmp(s->s + 1, "nvite", 5))) { |
89 | 235 | *method = METHOD_INVITE; |
90 | 235 | return 0; |
91 | 235 | } |
92 | 1.29k | if(likely((s->len == 4) && !strncasecmp(s->s + 1, "nfo", 3))) { |
93 | 238 | *method = METHOD_INFO; |
94 | 238 | return 0; |
95 | 238 | } |
96 | 1.05k | break; |
97 | 1.20k | case 'P': |
98 | 2.21k | case 'p': |
99 | 2.21k | if(likely((s->len == 5) && !strncasecmp(s->s + 1, "rack", 4))) { |
100 | 253 | *method = METHOD_PRACK; |
101 | 253 | return 0; |
102 | 253 | } |
103 | 1.95k | if(likely((s->len == 7) && !strncasecmp(s->s + 1, "ublish", 6))) { |
104 | 235 | *method = METHOD_PUBLISH; |
105 | 235 | return 0; |
106 | 235 | } |
107 | 1.72k | if(likely((s->len == 4) && !strncasecmp(s->s + 1, "ost", 3))) { |
108 | 295 | *method = METHOD_POST; |
109 | 295 | return 0; |
110 | 295 | } |
111 | 1.42k | if(likely((s->len == 3) && !strncasecmp(s->s + 1, "ut", 2))) { |
112 | 295 | *method = METHOD_PUT; |
113 | 295 | return 0; |
114 | 295 | } |
115 | 1.13k | break; |
116 | 1.13k | case 'C': |
117 | 1.01k | case 'c': |
118 | 1.01k | if(likely((s->len == 6) && !strncasecmp(s->s + 1, "ancel", 5))) { |
119 | 298 | *method = METHOD_CANCEL; |
120 | 298 | return 0; |
121 | 298 | } |
122 | 713 | break; |
123 | 713 | case 'B': |
124 | 733 | case 'b': |
125 | 733 | if(likely((s->len == 3) && !strncasecmp(s->s + 1, "ye", 2))) { |
126 | 310 | *method = METHOD_BYE; |
127 | 310 | return 0; |
128 | 310 | } |
129 | 423 | break; |
130 | 505 | case 'M': |
131 | 902 | case 'm': |
132 | 902 | if(likely((s->len == 7) && !strncasecmp(s->s + 1, "essage", 6))) { |
133 | 230 | *method = METHOD_MESSAGE; |
134 | 230 | return 0; |
135 | 230 | } |
136 | 672 | break; |
137 | 672 | case 'O': |
138 | 899 | case 'o': |
139 | 899 | if(likely((s->len == 7) && !strncasecmp(s->s + 1, "ptions", 6))) { |
140 | 235 | *method = METHOD_OPTIONS; |
141 | 235 | return 0; |
142 | 235 | } |
143 | 664 | break; |
144 | 664 | case 'S': |
145 | 1.28k | case 's': |
146 | 1.28k | if(likely((s->len == 9) && !strncasecmp(s->s + 1, "ubscribe", 8))) { |
147 | 280 | *method = METHOD_SUBSCRIBE; |
148 | 280 | return 0; |
149 | 280 | } |
150 | 1.00k | break; |
151 | 1.00k | case 'N': |
152 | 902 | case 'n': |
153 | 902 | if(likely((s->len == 6) && !strncasecmp(s->s + 1, "otify", 5))) { |
154 | 235 | *method = METHOD_NOTIFY; |
155 | 235 | return 0; |
156 | 235 | } |
157 | 667 | break; |
158 | 667 | case 'U': |
159 | 690 | case 'u': |
160 | 690 | if(likely((s->len == 6) && !strncasecmp(s->s + 1, "pdate", 5))) { |
161 | 237 | *method = METHOD_UPDATE; |
162 | 237 | return 0; |
163 | 237 | } |
164 | 453 | break; |
165 | 453 | case 'D': |
166 | 1.33k | case 'd': |
167 | 1.33k | if(likely((s->len == 6) && !strncasecmp(s->s + 1, "elete", 5))) { |
168 | 349 | *method = METHOD_DELETE; |
169 | 349 | return 0; |
170 | 349 | } |
171 | 989 | break; |
172 | 989 | case 'G': |
173 | 990 | case 'g': |
174 | 990 | if(likely((s->len == 3) && !strncasecmp(s->s + 1, "et", 2))) { |
175 | 235 | *method = METHOD_GET; |
176 | 235 | return 0; |
177 | 235 | } |
178 | 755 | break; |
179 | 755 | case 'K': |
180 | 744 | case 'k': |
181 | 744 | if(likely((s->len == 4) && !strncasecmp(s->s + 1, "dmq", 3))) { |
182 | 237 | *method = METHOD_KDMQ; |
183 | 237 | return 0; |
184 | 237 | } |
185 | 507 | break; |
186 | 1.18k | default: |
187 | 1.18k | break; |
188 | 16.2k | } |
189 | | /* unknown method */ |
190 | 11.3k | *method = METHOD_OTHER; |
191 | 11.3k | return 0; |
192 | 16.2k | } |
193 | | |
194 | | |
195 | | /*! \brief |
196 | | * Parse a method pointed by _next, assign its enum bit to _method, and update |
197 | | * _next past the method. Returns 1 if parse succeeded and 0 otherwise. |
198 | | */ |
199 | | static int parse_method_advance( |
200 | | str *const _next, enum request_method *const _method) |
201 | 0 | { |
202 | 0 | char *end; |
203 | |
|
204 | 0 | if(unlikely(!_next || !_method)) { |
205 | 0 | LM_ERR("Invalid parameter value\n"); |
206 | 0 | return 0; |
207 | 0 | } |
208 | | |
209 | 0 | if(unlikely(!_next->len || !_next->s)) { |
210 | 0 | DBG("No input\n"); |
211 | 0 | *_method = METHOD_OTHER; |
212 | 0 | return 1; |
213 | 0 | } |
214 | 0 | end = _next->s + _next->len; |
215 | |
|
216 | 0 | switch((_next->s)[0]) { |
217 | 0 | case 'A': |
218 | 0 | case 'a': |
219 | 0 | if((_next->len > 2) && !strncasecmp(_next->s + 1, "ck", 2)) { |
220 | 0 | *_method = METHOD_ACK; |
221 | 0 | _next->len -= 3; |
222 | 0 | _next->s += 3; |
223 | 0 | goto found; |
224 | 0 | } else { |
225 | 0 | goto unknown; |
226 | 0 | } |
227 | | |
228 | 0 | case 'B': |
229 | 0 | case 'b': |
230 | 0 | if((_next->len > 2) && !strncasecmp(_next->s + 1, "ye", 2)) { |
231 | 0 | *_method = METHOD_BYE; |
232 | 0 | _next->len -= 3; |
233 | 0 | _next->s += 3; |
234 | 0 | goto found; |
235 | 0 | } else { |
236 | 0 | goto unknown; |
237 | 0 | } |
238 | | |
239 | 0 | case 'C': |
240 | 0 | case 'c': |
241 | 0 | if((_next->len > 5) && !strncasecmp(_next->s + 1, "ancel", 5)) { |
242 | 0 | *_method = METHOD_CANCEL; |
243 | 0 | _next->len -= 6; |
244 | 0 | _next->s += 6; |
245 | 0 | goto found; |
246 | 0 | } else { |
247 | 0 | goto unknown; |
248 | 0 | } |
249 | | |
250 | 0 | case 'I': |
251 | 0 | case 'i': |
252 | 0 | if((_next->len > 3) |
253 | 0 | && ((*(_next->s + 1) == 'N') || (*(_next->s + 1) == 'n'))) { |
254 | 0 | if(!strncasecmp(_next->s + 2, "fo", 2)) { |
255 | 0 | *_method = METHOD_INFO; |
256 | 0 | _next->len -= 4; |
257 | 0 | _next->s += 4; |
258 | 0 | goto found; |
259 | 0 | } |
260 | | |
261 | 0 | if((_next->len > 5) && !strncasecmp(_next->s + 2, "vite", 4)) { |
262 | 0 | *_method = METHOD_INVITE; |
263 | 0 | _next->len -= 6; |
264 | 0 | _next->s += 6; |
265 | 0 | goto found; |
266 | 0 | } |
267 | 0 | } |
268 | 0 | goto unknown; |
269 | | |
270 | 0 | case 'M': |
271 | 0 | case 'm': |
272 | 0 | if((_next->len > 6) && !strncasecmp(_next->s + 1, "essage", 6)) { |
273 | 0 | *_method = METHOD_MESSAGE; |
274 | 0 | _next->len -= 7; |
275 | 0 | _next->s += 7; |
276 | 0 | goto found; |
277 | 0 | } else { |
278 | 0 | goto unknown; |
279 | 0 | } |
280 | | |
281 | 0 | case 'N': |
282 | 0 | case 'n': |
283 | 0 | if((_next->len > 5) && !strncasecmp(_next->s + 1, "otify", 5)) { |
284 | 0 | *_method = METHOD_NOTIFY; |
285 | 0 | _next->len -= 6; |
286 | 0 | _next->s += 6; |
287 | 0 | goto found; |
288 | 0 | } else { |
289 | 0 | goto unknown; |
290 | 0 | } |
291 | | |
292 | 0 | case 'O': |
293 | 0 | case 'o': |
294 | 0 | if((_next->len > 6) && !strncasecmp(_next->s + 1, "ptions", 6)) { |
295 | 0 | *_method = METHOD_OPTIONS; |
296 | 0 | _next->len -= 7; |
297 | 0 | _next->s += 7; |
298 | 0 | goto found; |
299 | 0 | } else { |
300 | 0 | goto unknown; |
301 | 0 | } |
302 | | |
303 | 0 | case 'P': |
304 | 0 | case 'p': |
305 | 0 | if((_next->len > 4) && !strncasecmp(_next->s + 1, "rack", 4)) { |
306 | 0 | *_method = METHOD_PRACK; |
307 | 0 | _next->len -= 5; |
308 | 0 | _next->s += 5; |
309 | 0 | goto found; |
310 | 0 | } |
311 | 0 | if((_next->len > 6) && !strncasecmp(_next->s + 1, "ublish", 6)) { |
312 | 0 | *_method = METHOD_PUBLISH; |
313 | 0 | _next->len -= 7; |
314 | 0 | _next->s += 7; |
315 | 0 | goto found; |
316 | 0 | } |
317 | 0 | if((_next->len > 3) && !strncasecmp(_next->s + 1, "ost", 3)) { |
318 | 0 | *_method = METHOD_POST; |
319 | 0 | _next->len -= 4; |
320 | 0 | _next->s += 4; |
321 | 0 | goto found; |
322 | 0 | } |
323 | 0 | if((_next->len > 2) && !strncasecmp(_next->s + 1, "ut", 2)) { |
324 | 0 | *_method = METHOD_PUT; |
325 | 0 | _next->len -= 3; |
326 | 0 | _next->s += 3; |
327 | 0 | goto found; |
328 | 0 | } |
329 | 0 | goto unknown; |
330 | | |
331 | 0 | case 'R': |
332 | 0 | case 'r': |
333 | 0 | if((_next->len > 4) |
334 | 0 | && ((*(_next->s + 1) == 'E') || (*(_next->s + 1) == 'e'))) { |
335 | 0 | if(!strncasecmp(_next->s + 2, "fer", 3)) { |
336 | 0 | *_method = METHOD_REFER; |
337 | 0 | _next->len -= 5; |
338 | 0 | _next->s += 5; |
339 | 0 | goto found; |
340 | 0 | } |
341 | | |
342 | 0 | if((_next->len > 7) |
343 | 0 | && !strncasecmp(_next->s + 2, "gister", 6)) { |
344 | 0 | *_method = METHOD_REGISTER; |
345 | 0 | _next->len -= 8; |
346 | 0 | _next->s += 8; |
347 | 0 | goto found; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | goto unknown; |
351 | | |
352 | 0 | case 'S': |
353 | 0 | case 's': |
354 | 0 | if((_next->len > 8) && !strncasecmp(_next->s + 1, "ubscribe", 8)) { |
355 | 0 | *_method = METHOD_SUBSCRIBE; |
356 | 0 | _next->len -= 9; |
357 | 0 | _next->s += 9; |
358 | 0 | goto found; |
359 | 0 | } else { |
360 | 0 | goto unknown; |
361 | 0 | } |
362 | | |
363 | 0 | case 'U': |
364 | 0 | case 'u': |
365 | 0 | if((_next->len > 5) && !strncasecmp(_next->s + 1, "pdate", 5)) { |
366 | 0 | *_method = METHOD_UPDATE; |
367 | 0 | _next->len -= 6; |
368 | 0 | _next->s += 6; |
369 | 0 | goto found; |
370 | 0 | } else { |
371 | 0 | goto unknown; |
372 | 0 | } |
373 | 0 | case 'D': |
374 | 0 | case 'd': |
375 | 0 | if((_next->len > 5) && !strncasecmp(_next->s + 1, "elete", 5)) { |
376 | 0 | *_method = METHOD_DELETE; |
377 | 0 | _next->len -= 6; |
378 | 0 | _next->s += 6; |
379 | 0 | goto found; |
380 | 0 | } else { |
381 | 0 | goto unknown; |
382 | 0 | } |
383 | 0 | case 'G': |
384 | 0 | case 'g': |
385 | 0 | if((_next->len > 2) && !strncasecmp(_next->s + 1, "et", 2)) { |
386 | 0 | *_method = METHOD_GET; |
387 | 0 | _next->len -= 3; |
388 | 0 | _next->s += 3; |
389 | 0 | goto found; |
390 | 0 | } else { |
391 | 0 | goto unknown; |
392 | 0 | } |
393 | 0 | case 'K': |
394 | 0 | case 'k': |
395 | 0 | if((_next->len > 3) && !strncasecmp(_next->s + 1, "dmq", 3)) { |
396 | 0 | *_method = METHOD_KDMQ; |
397 | 0 | _next->len -= 4; |
398 | 0 | _next->s += 4; |
399 | 0 | goto found; |
400 | 0 | } else { |
401 | 0 | goto unknown; |
402 | 0 | } |
403 | 0 | default: |
404 | 0 | goto unknown; |
405 | 0 | } |
406 | | |
407 | 0 | unknown: |
408 | 0 | if(token_char(*(_next->s))) { |
409 | 0 | do { |
410 | 0 | _next->s++; |
411 | 0 | _next->len--; |
412 | 0 | } while(_next->len && token_char(*(_next->s))); |
413 | 0 | *_method = METHOD_OTHER; |
414 | 0 | return 1; |
415 | 0 | } else { |
416 | 0 | return 0; |
417 | 0 | } |
418 | 0 | found: |
419 | | /* check if the method really ends here (if not return 0) */ |
420 | 0 | return (_next->s >= end) || (!token_char(*(_next->s))); |
421 | 0 | } |
422 | | |
423 | | |
424 | | /*! \brief |
425 | | * Parse comma separated list of methods pointed by _body and assign their |
426 | | * enum bits to _methods. Returns 0 on success and -1 on failure. |
427 | | */ |
428 | | int parse_methods(const str *const _body, unsigned int *const _methods) |
429 | 0 | { |
430 | 0 | str next; |
431 | 0 | unsigned int method; |
432 | |
|
433 | 0 | method = 0; /* fixes silly gcc 4.x warning */ |
434 | |
|
435 | 0 | if(!_body || !_methods) { |
436 | 0 | LM_ERR("Invalid parameter value\n"); |
437 | 0 | return -1; |
438 | 0 | } |
439 | | |
440 | 0 | next.len = _body->len; |
441 | 0 | next.s = _body->s; |
442 | |
|
443 | 0 | trim_leading(&next); |
444 | |
|
445 | 0 | *_methods = 0; |
446 | |
|
447 | 0 | if(next.len == 0) { |
448 | 0 | return 0; |
449 | 0 | } |
450 | | |
451 | 0 | while(1) { |
452 | 0 | if(parse_method_advance(&next, &method)) { |
453 | 0 | *_methods |= method; |
454 | 0 | } else { |
455 | 0 | LM_ERR("Invalid method\n"); |
456 | 0 | return -1; |
457 | 0 | } |
458 | | |
459 | 0 | trim_leading(&next); |
460 | 0 | if(next.len) { |
461 | 0 | if(next.s[0] == ',') { |
462 | 0 | next.len--; |
463 | 0 | next.s++; |
464 | 0 | trim_leading(&next); |
465 | 0 | if(next.len == 0) { |
466 | 0 | LM_ERR("Method expected\n"); |
467 | 0 | return 0; |
468 | 0 | } |
469 | 0 | } else { |
470 | 0 | LM_ERR("Comma expected\n"); |
471 | 0 | return -1; |
472 | 0 | } |
473 | 0 | } else { |
474 | 0 | break; |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | 0 | return 0; |
479 | 0 | } |