Coverage Report

Created: 2024-02-25 06:34

/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
}