Coverage Report

Created: 2026-08-13 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/parser/parse_methods.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2004 Juha Heinanen
3
 *
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20
 *
21
 * History:
22
 * --------
23
 *  2005-07-05 - moved and merged method types in msg_parser.h (ramona)
24
 *             - changed and exported parse_method() to use it from other
25
 *               files (ramona)
26
 */
27
28
#include <strings.h>
29
#include "../dprint.h"
30
#include "../trim.h"
31
#include "../core_stats.h"
32
#include "parse_methods.h"
33
#include "msg_parser.h"
34
35
36
/*
37
 * Check if argument is valid RFC3261 token character.
38
 */
39
static inline int method_char(char _c)
40
456k
{
41
456k
  return (_c >= 65 && _c <= 90)    /* upper alpha */
42
255k
    || (_c >= 97 && _c <= 122)   /* lower aplha */
43
39.8k
    || (_c >= 48 && _c <= 57)    /* digits */
44
29.6k
    || (_c == '-') || (_c == '.') || (_c == '!') || (_c == '%')
45
19.9k
    || (_c == '*') || (_c == '_') || (_c == '+') || (_c == '`')
46
8.60k
    || (_c == '\'') || (_c == '~');
47
456k
}
48
49
50
/*
51
 * Parse a method pointed by start, end is the last character to check (if NULL
52
 * assume that start is a zero terminated string)
53
 * => assign enum bit to method.
54
 * Returns pointer to next char if parse succeeded
55
 * and NULL otherwise.
56
 */
57
char* parse_method(char* start, char* end, unsigned int* method)
58
150k
{
59
150k
  int len=0;
60
150k
  int max=0;
61
62
150k
   if (!start || !method) {
63
0
     LM_ERR("invalid parameter value\n");
64
0
     return NULL;
65
0
   }
66
67
150k
   if(end)
68
150k
     max = end - start;
69
150k
   *method = METHOD_UNDEF;
70
71
150k
   switch (start[0]) {
72
3.92k
     case 'A':
73
6.09k
     case 'a':
74
6.09k
      if(end && max<3)
75
2.50k
        goto unknown;
76
77
3.59k
      if ((start[1]=='c' || start[1]=='C')
78
2.91k
          && (start[2]=='k' || start[2]=='K'))
79
1.83k
      {
80
1.83k
        *method = METHOD_ACK;
81
1.83k
        len = 3;
82
1.83k
        goto done;
83
1.83k
      }
84
1.75k
      goto unknown;
85
86
20.0k
    case 'B':
87
23.7k
    case 'b':
88
23.7k
      if(end && max<3)
89
15.7k
        goto unknown;
90
91
8.07k
      if ((start[1]=='y' || start[1]=='Y')
92
3.37k
          && (start[2]=='e' || start[2]=='E'))
93
1.29k
      {
94
1.29k
        *method = METHOD_BYE;
95
1.29k
        len = 3;
96
1.29k
        goto done;
97
1.29k
      }
98
6.77k
      goto unknown;
99
100
6.77k
    case 'C':
101
6.35k
    case 'c':
102
6.35k
      if(end && max<6)
103
1.90k
        goto unknown;
104
4.44k
      if ((start[1]=='a' || start[1]=='A')
105
3.69k
          && (start[2]=='n' || start[2]=='N')
106
2.73k
          && (start[3]=='c' || start[3]=='C')
107
2.19k
          && (start[4]=='e' || start[4]=='E')
108
1.70k
          && (start[5]=='l' || start[5]=='L'))
109
1.23k
      {
110
1.23k
        *method = METHOD_CANCEL;
111
1.23k
        len = 6;
112
1.23k
        goto done;
113
1.23k
      }
114
3.21k
      goto unknown;
115
116
11.4k
    case 'I':
117
14.0k
    case 'i':
118
14.0k
      if(end && max<4)
119
3.36k
        goto unknown;
120
10.6k
      if(start[1]!='n' && start[1]!='N')
121
881
        goto unknown;
122
123
9.79k
      if ((start[2]=='f' || start[2]=='F')
124
1.95k
          && (start[3]=='o' || start[3]=='O'))
125
1.02k
      {
126
1.02k
        *method = METHOD_INFO;
127
1.02k
        len = 4;
128
1.02k
        goto done;
129
1.02k
      }
130
131
8.77k
      if(end && max<6)
132
1.04k
        goto unknown;
133
7.72k
      if ((start[2]=='v' || start[2]=='V')
134
7.09k
          && (start[3]=='i' || start[3]=='I')
135
4.02k
          && (start[4]=='t' || start[4]=='T')
136
3.42k
          && (start[5]=='e' || start[5]=='E'))
137
2.73k
      {
138
2.73k
        *method = METHOD_INVITE;
139
2.73k
        len = 6;
140
2.73k
        goto done;
141
2.73k
      }
142
4.99k
      goto unknown;
143
144
4.99k
    case 'M':
145
8.51k
    case 'm':
146
8.51k
      if(end && max<7)
147
3.04k
        goto unknown;
148
5.47k
      if ((start[1]=='e' || start[1]=='E')
149
4.90k
          && (start[2]=='s' || start[2]=='S')
150
4.15k
          && (start[3]=='s' || start[3]=='S')
151
2.51k
          && (start[4]=='a' || start[4]=='A')
152
2.02k
          && (start[5]=='g' || start[5]=='G')
153
1.49k
          && (start[6]=='e' || start[6]=='E')) {
154
900
        *method = METHOD_MESSAGE;
155
900
        len = 7;
156
900
        goto done;
157
900
      }
158
4.57k
      goto unknown;
159
160
4.57k
    case 'N':
161
10.4k
    case 'n':
162
10.4k
      if(end && max<6)
163
2.40k
        goto unknown;
164
8.02k
      if ((start[1]=='o' || start[1]=='O')
165
6.69k
          && (start[2]=='t' || start[2]=='T')
166
5.48k
          && (start[3]=='i' || start[3]=='I')
167
5.02k
          && (start[4]=='f' || start[4]=='F')
168
4.37k
          && (start[5]=='y' || start[5]=='Y'))
169
3.76k
      {
170
3.76k
        *method = METHOD_NOTIFY;
171
3.76k
        len = 6;
172
3.76k
        goto done;
173
3.76k
      }
174
4.26k
      goto unknown;
175
176
4.26k
    case 'O':
177
12.2k
    case 'o':
178
12.2k
      if(end && max<7)
179
4.21k
        goto unknown;
180
7.98k
      if((start[1]=='p' || start[1]=='P')
181
7.30k
          && (start[2]=='t' || start[2]=='T')
182
6.22k
          && (start[3]=='i' || start[3]=='I')
183
5.70k
          && (start[4]=='o' || start[4]=='O')
184
4.98k
          && (start[5]=='n' || start[5]=='N')
185
3.58k
          && (start[6]=='s' || start[6]=='S'))
186
1.95k
      {
187
1.95k
        *method = METHOD_OPTIONS;
188
1.95k
        len = 7;
189
1.95k
        goto done;
190
1.95k
      }
191
6.03k
      goto unknown;
192
193
6.03k
    case 'P':
194
11.6k
    case 'p':
195
11.6k
      if(end && max<5)
196
2.07k
        goto unknown;
197
9.62k
      if((start[1]=='r' || start[1]=='R')
198
4.30k
          && (start[2]=='a' || start[2]=='A')
199
3.16k
          && (start[3]=='c' || start[3]=='C')
200
2.59k
          && (start[4]=='k' || start[4]=='K'))
201
1.49k
      {
202
1.49k
        *method = METHOD_PRACK;
203
1.49k
        len = 5;
204
1.49k
        goto done;
205
1.49k
      }
206
207
8.12k
      if(end && max<7)
208
1.50k
        goto unknown;
209
210
6.62k
      if ((start[1]=='u' || start[1]=='U')
211
4.70k
           && (start[2]=='b' || start[2]=='B')
212
4.05k
           && (start[3]=='l' || start[3]=='L')
213
3.64k
           && (start[4]=='i' || start[4]=='I')
214
3.19k
           && (start[5]=='s' || start[5]=='S')
215
2.58k
           && (start[6]=='h' || start[6]=='H'))
216
1.88k
      {
217
1.88k
        *method = METHOD_PUBLISH;
218
1.88k
        len = 7;
219
1.88k
        goto done;
220
1.88k
      }
221
4.73k
      goto unknown;
222
223
7.40k
    case 'R':
224
12.1k
    case 'r':
225
12.1k
      if(end && max<5)
226
2.82k
        goto unknown;
227
9.28k
      if(start[1]!='e' && start[1]!='E')
228
540
        goto unknown;
229
230
8.74k
      if((start[2]=='f' || start[2]=='F')
231
3.41k
           && (start[3]=='e' || start[3]=='E')
232
2.61k
           && (start[4]=='r' || start[4]=='R'))
233
922
      {
234
922
        *method = METHOD_REFER;
235
922
        len = 5;
236
922
        goto done;
237
922
      }
238
239
7.82k
      if(end && max<8)
240
1.37k
        goto unknown;
241
242
6.44k
      if ((start[2]=='g' || start[2]=='G')
243
4.90k
           && (start[3]=='i' || start[3]=='I')
244
4.12k
           && (start[4]=='s' || start[4]=='S')
245
3.53k
           && (start[5]=='t' || start[5]=='T')
246
2.77k
           && (start[6]=='e' || start[6]=='E')
247
2.44k
           && (start[7]=='r' || start[7]=='R'))
248
1.35k
      {
249
1.35k
        *method = METHOD_REGISTER;
250
1.35k
        len = 8;
251
1.35k
        goto done;
252
1.35k
      }
253
5.09k
      goto unknown;
254
255
5.16k
    case 'S':
256
11.7k
    case 's':
257
11.7k
      if(end && max<9)
258
3.30k
        goto unknown;
259
8.44k
      if ((start[1]=='u' || start[1]=='U')
260
7.91k
           && (start[2]=='b' || start[2]=='B')
261
5.74k
           && (start[3]=='s' || start[3]=='S')
262
5.14k
           && (start[4]=='c' || start[4]=='C')
263
4.38k
           && (start[5]=='r' || start[5]=='R')
264
3.83k
           && (start[6]=='i' || start[6]=='I')
265
2.58k
           && (start[7]=='b' || start[7]=='B')
266
2.14k
           && (start[8]=='e' || start[8]=='E'))
267
1.46k
      {
268
1.46k
        *method = METHOD_SUBSCRIBE;
269
1.46k
        len = 9;
270
1.46k
        goto done;
271
1.46k
      }
272
6.98k
      goto unknown;
273
274
6.98k
    case 'U':
275
5.95k
    case 'u':
276
5.95k
      if(end && max<6)
277
1.25k
        goto unknown;
278
4.70k
      if ((start[1]=='p' || start[1]=='P')
279
4.08k
          && (start[2]=='d' || start[2]=='D')
280
3.06k
          && (start[3]=='a' || start[3]=='A')
281
2.58k
          && (start[4]=='t' || start[4]=='T')
282
2.01k
          && (start[5]=='e' || start[5]=='E')) {
283
957
        *method = METHOD_UPDATE;
284
957
        len = 6;
285
957
        goto done;
286
957
      }
287
3.74k
      goto unknown;
288
289
27.4k
    default:
290
27.4k
      goto unknown;
291
150k
    }
292
293
22.8k
done:
294
22.8k
  if(!end || (end && len < max))
295
7.09k
  {
296
7.09k
    if(start[len]!='\0' && start[len]!=',' && start[len]!=' '
297
4.08k
        && start[len]!='\t' && start[len]!='\r' && start[len]!='\n')
298
4.08k
      goto unknown;
299
7.09k
  }
300
301
18.7k
  return (start+len);
302
303
131k
unknown:
304
131k
  *method = METHOD_OTHER;
305
131k
  if(end)
306
131k
  {
307
586k
    while(len < max)
308
500k
    {
309
500k
      if((start[len]=='\0' || start[len]==',' || start[len]==' '
310
456k
            || start[len]=='\t' || start[len]=='\r'
311
456k
            || start[len]=='\n'))
312
44.3k
        return (start+len);
313
314
456k
      if(!method_char(start[len]))
315
1.50k
      {
316
1.50k
        LM_ERR("invalid character %c\n", start[len]);
317
1.50k
        return NULL;
318
1.50k
      }
319
320
454k
      len++;
321
454k
    }
322
85.8k
    return end;
323
131k
  }
324
325
0
  while(start[len]!='\0' && start[len]!=',' && start[len]!=' '
326
0
      && start[len]!='\t' && start[len]!='\r' && start[len]!='\n')
327
0
  {
328
0
    if(!method_char(start[len]))
329
0
    {
330
0
      LM_ERR("invalid character %c!\n", start[len]);
331
0
      return NULL;
332
0
    }
333
0
    len++;
334
0
  }
335
336
0
  return (start+len);
337
0
}
338
339
340
/*
341
 * Parse comma separated list of methods pointed by _body and assign their
342
 * enum bits to _methods.  Returns 0 on success and -1 on failure.
343
 */
344
int parse_methods(str* _body, unsigned int* _methods)
345
0
{
346
0
  str next;
347
0
  char *p;
348
0
  char *p0;
349
0
  unsigned int method;
350
351
0
  if (!_body || !_methods) {
352
0
    LM_ERR("invalid parameter value\n");
353
0
    return -1;
354
0
  }
355
356
0
  next.len = _body->len;
357
0
  next.s = _body->s;
358
359
0
  trim_leading(&next);
360
361
0
  *_methods = 0;
362
0
  if (next.len == 0) {
363
0
    goto done;
364
0
  }
365
366
0
  method = 0;
367
0
  p = next.s;
368
369
0
  while (p<next.s+next.len) {
370
0
    if((p0=parse_method(p, next.s+next.len, &method))!=NULL) {
371
0
      *_methods |= method;
372
0
      p = p0;
373
0
    } else {
374
0
      LM_ERR("invalid method [%.*s]\n", next.len, next.s);
375
0
      return -1;
376
0
    }
377
378
0
    while(p<next.s+next.len && (*p==' ' || *p=='\t'
379
0
          || *p=='\r' || *p=='\n'))
380
0
      p++;
381
0
    if(p>=next.s+next.len || *p == '\0')
382
0
      goto done;
383
384
385
0
    if (*p == ',')
386
0
    {
387
0
      p++;
388
0
      while(p<next.s+next.len && (*p==' ' || *p=='\t'
389
0
          || *p=='\r' || *p=='\n'))
390
0
        p++;
391
0
      if(p>=next.s+next.len)
392
0
        goto done;
393
0
    } else {
394
0
      LM_ERR("comma expected\n");
395
0
      return -1;
396
0
    }
397
0
  }
398
399
0
done:
400
0
  LM_DBG("methods 0x%X\n", *_methods);
401
0
  return 0;
402
0
}