parse_methods.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Copyright (c) 2004 Juha Heinanen
  3. *
  4. * This file is part of ser, a free SIP server.
  5. *
  6. * ser 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. * ser 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. /*! \file
  21. * \brief Parser :: Parse Methods
  22. *
  23. * \ingroup parser
  24. */
  25. #include <strings.h>
  26. #include "../dprint.h"
  27. #include "../trim.h"
  28. #include "parse_methods.h"
  29. /*! \brief
  30. * Check if argument is valid RFC3261 token character.
  31. */
  32. static int token_char(char _c)
  33. {
  34. return (_c >= 65 && _c <= 90) || /* upper alpha */
  35. (_c >= 97 && _c <= 122) || /* lower aplha */
  36. (_c >= 48 && _c <= 57) || /* digits */
  37. (_c == '-') || (_c == '.') || (_c == '!') || (_c == '%') ||
  38. (_c == '*') || (_c == '_') || (_c == '+') || (_c == '`') ||
  39. (_c == '\'') || (_c == '~');
  40. }
  41. /*! \brief Parse a string containing a method.
  42. *
  43. * Parse a method pointed by s & assign its enum bit to method. The string
  44. * _must_ contain _only_ the method (without trailing or heading whitespace).
  45. * \return 0 on success, -1 on error
  46. */
  47. int parse_method_name(const str* const s, enum request_method* const method)
  48. {
  49. if (unlikely(!s || !method)) {
  50. LOG(L_ERR, "Invalid parameter value\n");
  51. return -1;
  52. }
  53. if (unlikely(!s->len || (s->s==0))) {
  54. DBG("No input\n");
  55. *method = METHOD_OTHER;
  56. return 0;
  57. }
  58. switch ((s->s)[0]) {
  59. /* ordered after probability of aparition on a normal proxy */
  60. case 'R':
  61. case 'r':
  62. if (likely((s->len == 8) &&
  63. !strncasecmp(s->s + 1, "egister", 7))) {
  64. *method = METHOD_REGISTER;
  65. return 0;
  66. }
  67. if (likely((s->len==5) && !strncasecmp(s->s + 1, "efer", 4))) {
  68. *method = METHOD_REFER;
  69. return 0;
  70. }
  71. break;
  72. case 'A':
  73. case 'a':
  74. if (likely((s->len==3) && !strncasecmp(s->s + 1, "ck", 2))) {
  75. *method = METHOD_ACK;
  76. return 0;
  77. }
  78. break;
  79. case 'I':
  80. case 'i':
  81. if (likely((s->len==6) && !strncasecmp(s->s + 1, "nvite", 5))){
  82. *method = METHOD_INVITE;
  83. return 0;
  84. }
  85. if (likely((s->len==4) && !strncasecmp(s->s + 1, "nfo", 3))) {
  86. *method = METHOD_INFO;
  87. return 0;
  88. }
  89. break;
  90. case 'P':
  91. case 'p':
  92. if (likely((s->len==5) && !strncasecmp(s->s + 1, "rack", 4))) {
  93. *method = METHOD_PRACK;
  94. return 0;
  95. }
  96. if (likely((s->len==7) && !strncasecmp(s->s + 1, "ublish", 6))) {
  97. *method = METHOD_PUBLISH;
  98. return 0;
  99. }
  100. break;
  101. case 'C':
  102. case 'c':
  103. if (likely((s->len==6) && !strncasecmp(s->s + 1, "ancel", 5))) {
  104. *method = METHOD_CANCEL;
  105. return 0;
  106. }
  107. break;
  108. case 'B':
  109. case 'b':
  110. if (likely((s->len==3) && !strncasecmp(s->s + 1, "ye", 2))) {
  111. *method = METHOD_BYE;
  112. return 0;
  113. }
  114. break;
  115. case 'M':
  116. case 'm':
  117. if (likely((s->len==7) && !strncasecmp(s->s + 1, "essage", 6))) {
  118. *method = METHOD_MESSAGE;
  119. return 0;
  120. }
  121. break;
  122. case 'O':
  123. case 'o':
  124. if (likely((s->len==7) && !strncasecmp(s->s + 1, "ptions", 6))) {
  125. *method = METHOD_OPTIONS;
  126. return 0;
  127. }
  128. break;
  129. case 'S':
  130. case 's':
  131. if (likely((s->len==9) && !strncasecmp(s->s + 1, "ubscribe", 8))) {
  132. *method = METHOD_SUBSCRIBE;
  133. return 0;
  134. }
  135. break;
  136. case 'N':
  137. case 'n':
  138. if (likely((s->len==6) && !strncasecmp(s->s + 1, "otify", 5))){
  139. *method = METHOD_NOTIFY;
  140. return 0;
  141. }
  142. break;
  143. case 'U':
  144. case 'u':
  145. if (likely((s->len==6) && !strncasecmp(s->s + 1, "pdate", 5))){
  146. *method = METHOD_UPDATE;
  147. return 0;
  148. }
  149. break;
  150. default:
  151. break;
  152. }
  153. /* unknown method */
  154. *method = METHOD_OTHER;
  155. return 0;
  156. }
  157. /*! \brief
  158. * Parse a method pointed by _next, assign its enum bit to _method, and update
  159. * _next past the method. Returns 1 if parse succeeded and 0 otherwise.
  160. */
  161. static int parse_method_advance(str* const _next, enum request_method* const _method)
  162. {
  163. char* end;
  164. if (unlikely(!_next || !_method)) {
  165. LOG(L_ERR, "Invalid parameter value\n");
  166. return 0;
  167. }
  168. if (unlikely(!_next->len || !_next->s)) {
  169. DBG("No input\n");
  170. *_method = METHOD_OTHER;
  171. return 1;
  172. }
  173. end=_next->s+_next->len;
  174. switch ((_next->s)[0]) {
  175. case 'A':
  176. case 'a':
  177. if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ck", 2)) {
  178. *_method = METHOD_ACK;
  179. _next->len -= 3;
  180. _next->s += 3;
  181. goto found;
  182. } else {
  183. goto unknown;
  184. }
  185. case 'B':
  186. case 'b':
  187. if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ye", 2)) {
  188. *_method = METHOD_BYE;
  189. _next->len -= 3;
  190. _next->s += 3;
  191. goto found;
  192. } else {
  193. goto unknown;
  194. }
  195. case 'C':
  196. case 'c':
  197. if ((_next->len > 5) && !strncasecmp(_next->s + 1, "ancel", 5)) {
  198. *_method = METHOD_CANCEL;
  199. _next->len -= 6;
  200. _next->s += 6;
  201. goto found;
  202. } else {
  203. goto unknown;
  204. }
  205. case 'I':
  206. case 'i':
  207. if ((_next->len > 3) &&
  208. ((*(_next->s + 1) == 'N') || (*(_next->s + 1) == 'n'))) {
  209. if (!strncasecmp(_next->s + 2, "fo", 2)) {
  210. *_method = METHOD_INFO;
  211. _next->len -= 4;
  212. _next->s += 4;
  213. goto found;
  214. }
  215. if ((_next->len > 5) && !strncasecmp(_next->s + 2, "vite", 4)) {
  216. *_method = METHOD_INVITE;
  217. _next->len -= 6;
  218. _next->s += 6;
  219. goto found;
  220. }
  221. }
  222. goto unknown;
  223. case 'M':
  224. case 'm':
  225. if ((_next->len > 6) && !strncasecmp(_next->s + 1, "essage", 6)) {
  226. *_method = METHOD_MESSAGE;
  227. _next->len -= 7;
  228. _next->s += 7;
  229. goto found;
  230. } else {
  231. goto unknown;
  232. }
  233. case 'N':
  234. case 'n':
  235. if ((_next->len > 5) && !strncasecmp(_next->s + 1, "otify", 5)) {
  236. *_method = METHOD_NOTIFY;
  237. _next->len -= 6;
  238. _next->s += 6;
  239. goto found;
  240. } else {
  241. goto unknown;
  242. }
  243. case 'O':
  244. case 'o':
  245. if ((_next->len > 6) && !strncasecmp(_next->s + 1, "ptions", 6)) {
  246. *_method = METHOD_OPTIONS;
  247. _next->len -= 7;
  248. _next->s += 7;
  249. goto found;
  250. } else {
  251. goto unknown;
  252. }
  253. case 'P':
  254. case 'p':
  255. if ((_next->len > 4) && !strncasecmp(_next->s + 1, "rack", 4)) {
  256. *_method = METHOD_PRACK;
  257. _next->len -= 5;
  258. _next->s += 5;
  259. goto found;
  260. }
  261. if ((_next->len > 6) && !strncasecmp(_next->s + 1, "ublish", 6)) {
  262. *_method = METHOD_PUBLISH;
  263. _next->len -= 7;
  264. _next->s += 7;
  265. goto found;
  266. }
  267. goto unknown;
  268. case 'R':
  269. case 'r':
  270. if ((_next->len > 4) &&
  271. ((*(_next->s + 1) == 'E') || (*(_next->s + 1) == 'e'))) {
  272. if (!strncasecmp(_next->s + 2, "fer", 3)) {
  273. *_method = METHOD_REFER;
  274. _next->len -= 5;
  275. _next->s += 5;
  276. goto found;
  277. }
  278. if ((_next->len > 7) && !strncasecmp(_next->s + 2, "gister", 6)) {
  279. *_method = METHOD_REGISTER;
  280. _next->len -= 8;
  281. _next->s += 8;
  282. goto found;
  283. }
  284. }
  285. goto unknown;
  286. case 'S':
  287. case 's':
  288. if ((_next->len > 8) && !strncasecmp(_next->s + 1, "ubscribe", 8)) {
  289. *_method = METHOD_SUBSCRIBE;
  290. _next->len -= 9;
  291. _next->s += 9;
  292. goto found;
  293. } else {
  294. goto unknown;
  295. }
  296. case 'U':
  297. case 'u':
  298. if ((_next->len > 5) && !strncasecmp(_next->s + 1, "pdate", 5)) {
  299. *_method = METHOD_UPDATE;
  300. _next->len -= 6;
  301. _next->s += 6;
  302. goto found;
  303. } else {
  304. goto unknown;
  305. }
  306. default:
  307. goto unknown;
  308. }
  309. unknown:
  310. if (token_char(*(_next->s))) {
  311. do {
  312. _next->s++;
  313. _next->len--;
  314. } while (_next->len && token_char(*(_next->s)));
  315. *_method = METHOD_OTHER;
  316. return 1;
  317. } else {
  318. return 0;
  319. }
  320. found:
  321. /* check if the method really ends here (if not return 0) */
  322. return (_next->s>=end) || (!token_char(*(_next->s)));
  323. }
  324. /*! \brief
  325. * Parse comma separated list of methods pointed by _body and assign their
  326. * enum bits to _methods. Returns 0 on success and -1 on failure.
  327. */
  328. int parse_methods(const str* const _body, unsigned int* const _methods)
  329. {
  330. str next;
  331. unsigned int method;
  332. method=0; /* fixes silly gcc 4.x warning */
  333. if (!_body || !_methods) {
  334. LOG(L_ERR, "parse_methods: Invalid parameter value\n");
  335. return -1;
  336. }
  337. next.len = _body->len;
  338. next.s = _body->s;
  339. trim_leading(&next);
  340. *_methods = 0;
  341. if (next.len == 0) {
  342. return 0;
  343. }
  344. while (1) {
  345. if (parse_method_advance(&next, &method)) {
  346. *_methods |= method;
  347. } else {
  348. LOG(L_ERR, "ERROR: parse_methods: Invalid method\n");
  349. return -1;
  350. }
  351. trim_leading(&next);
  352. if (next.len) {
  353. if (next.s[0] == ',') {
  354. next.len--;
  355. next.s++;
  356. trim_leading(&next);
  357. if (next.len == 0) {
  358. LOG(L_ERR, "ERROR: parse_methods: Method expected\n");
  359. return 0;
  360. }
  361. } else {
  362. LOG(L_ERR, "ERROR: parse_methods: Comma expected\n");
  363. return -1;
  364. }
  365. } else {
  366. break;
  367. }
  368. }
  369. return 0;
  370. }