PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/icecast-2.3.2/src/httpp/httpp.c

#
C | 556 lines | 440 code | 88 blank | 28 comment | 154 complexity | a0f782509b1c39859107a11442855798 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. /* Httpp.c
  2. **
  3. ** http parsing engine
  4. **
  5. ** This program is distributed under the GNU General Public License, version 2.
  6. ** A copy of this license is included with this source.
  7. */
  8. #ifdef HAVE_CONFIG_H
  9. #include <config.h>
  10. #endif
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #ifdef HAVE_STRINGS_H
  16. #include <strings.h>
  17. #endif
  18. #include "avl/avl.h"
  19. #include "httpp.h"
  20. #ifdef _WIN32
  21. #define strcasecmp stricmp
  22. #endif
  23. #define MAX_HEADERS 32
  24. /* internal functions */
  25. /* misc */
  26. static char *_lowercase(char *str);
  27. /* for avl trees */
  28. static int _compare_vars(void *compare_arg, void *a, void *b);
  29. static int _free_vars(void *key);
  30. http_parser_t *httpp_create_parser(void)
  31. {
  32. return (http_parser_t *)malloc(sizeof(http_parser_t));
  33. }
  34. void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
  35. {
  36. http_varlist_t *list;
  37. parser->req_type = httpp_req_none;
  38. parser->uri = NULL;
  39. parser->vars = avl_tree_new(_compare_vars, NULL);
  40. parser->queryvars = avl_tree_new(_compare_vars, NULL);
  41. /* now insert the default variables */
  42. list = defaults;
  43. while (list != NULL) {
  44. httpp_setvar(parser, list->var.name, list->var.value);
  45. list = list->next;
  46. }
  47. }
  48. static int split_headers(char *data, unsigned long len, char **line)
  49. {
  50. /* first we count how many lines there are
  51. ** and set up the line[] array
  52. */
  53. int lines = 0;
  54. unsigned long i;
  55. line[lines] = data;
  56. for (i = 0; i < len && lines < MAX_HEADERS; i++) {
  57. if (data[i] == '\r')
  58. data[i] = '\0';
  59. if (data[i] == '\n') {
  60. lines++;
  61. data[i] = '\0';
  62. if (lines >= MAX_HEADERS)
  63. return MAX_HEADERS;
  64. if (i + 1 < len) {
  65. if (data[i + 1] == '\n' || data[i + 1] == '\r')
  66. break;
  67. line[lines] = &data[i + 1];
  68. }
  69. }
  70. }
  71. i++;
  72. while (i < len && data[i] == '\n') i++;
  73. return lines;
  74. }
  75. static void parse_headers(http_parser_t *parser, char **line, int lines)
  76. {
  77. int i,l;
  78. int whitespace, where, slen;
  79. char *name = NULL;
  80. char *value = NULL;
  81. /* parse the name: value lines. */
  82. for (l = 1; l < lines; l++) {
  83. where = 0;
  84. whitespace = 0;
  85. name = line[l];
  86. value = NULL;
  87. slen = strlen(line[l]);
  88. for (i = 0; i < slen; i++) {
  89. if (line[l][i] == ':') {
  90. whitespace = 1;
  91. line[l][i] = '\0';
  92. } else {
  93. if (whitespace) {
  94. whitespace = 0;
  95. while (i < slen && line[l][i] == ' ')
  96. i++;
  97. if (i < slen)
  98. value = &line[l][i];
  99. break;
  100. }
  101. }
  102. }
  103. if (name != NULL && value != NULL) {
  104. httpp_setvar(parser, _lowercase(name), value);
  105. name = NULL;
  106. value = NULL;
  107. }
  108. }
  109. }
  110. int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned long len, const char *uri)
  111. {
  112. char *data;
  113. char *line[MAX_HEADERS];
  114. int lines, slen,i, whitespace=0, where=0,code;
  115. char *version=NULL, *resp_code=NULL, *message=NULL;
  116. if(http_data == NULL)
  117. return 0;
  118. /* make a local copy of the data, including 0 terminator */
  119. data = (char *)malloc(len+1);
  120. if (data == NULL) return 0;
  121. memcpy(data, http_data, len);
  122. data[len] = 0;
  123. lines = split_headers(data, len, line);
  124. /* In this case, the first line contains:
  125. * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
  126. */
  127. slen = strlen(line[0]);
  128. version = line[0];
  129. for(i=0; i < slen; i++) {
  130. if(line[0][i] == ' ') {
  131. line[0][i] = 0;
  132. whitespace = 1;
  133. } else if(whitespace) {
  134. whitespace = 0;
  135. where++;
  136. if(where == 1)
  137. resp_code = &line[0][i];
  138. else {
  139. message = &line[0][i];
  140. break;
  141. }
  142. }
  143. }
  144. if(version == NULL || resp_code == NULL || message == NULL) {
  145. free(data);
  146. return 0;
  147. }
  148. httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
  149. code = atoi(resp_code);
  150. if(code < 200 || code >= 300) {
  151. httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
  152. }
  153. httpp_setvar(parser, HTTPP_VAR_URI, uri);
  154. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
  155. parse_headers(parser, line, lines);
  156. free(data);
  157. return 1;
  158. }
  159. static int hex(char c)
  160. {
  161. if(c >= '0' && c <= '9')
  162. return c - '0';
  163. else if(c >= 'A' && c <= 'F')
  164. return c - 'A' + 10;
  165. else if(c >= 'a' && c <= 'f')
  166. return c - 'a' + 10;
  167. else
  168. return -1;
  169. }
  170. static char *url_escape(const char *src)
  171. {
  172. int len = strlen(src);
  173. unsigned char *decoded;
  174. int i;
  175. char *dst;
  176. int done = 0;
  177. decoded = calloc(1, len + 1);
  178. dst = (char *)decoded;
  179. for(i=0; i < len; i++) {
  180. switch(src[i]) {
  181. case '%':
  182. if(i+2 >= len) {
  183. free(decoded);
  184. return NULL;
  185. }
  186. if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
  187. free(decoded);
  188. return NULL;
  189. }
  190. *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]);
  191. i+= 2;
  192. break;
  193. case '+':
  194. *dst++ = ' ';
  195. break;
  196. case '#':
  197. done = 1;
  198. break;
  199. case 0:
  200. free(decoded);
  201. return NULL;
  202. break;
  203. default:
  204. *dst++ = src[i];
  205. break;
  206. }
  207. if(done)
  208. break;
  209. }
  210. *dst = 0; /* null terminator */
  211. return (char *)decoded;
  212. }
  213. /** TODO: This is almost certainly buggy in some cases */
  214. static void parse_query(http_parser_t *parser, char *query)
  215. {
  216. int len;
  217. int i=0;
  218. char *key = query;
  219. char *val=NULL;
  220. if(!query || !*query)
  221. return;
  222. len = strlen(query);
  223. while(i<len) {
  224. switch(query[i]) {
  225. case '&':
  226. query[i] = 0;
  227. if(val && key)
  228. httpp_set_query_param(parser, key, val);
  229. key = query+i+1;
  230. break;
  231. case '=':
  232. query[i] = 0;
  233. val = query+i+1;
  234. break;
  235. }
  236. i++;
  237. }
  238. if(val && key) {
  239. httpp_set_query_param(parser, key, val);
  240. }
  241. }
  242. int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len)
  243. {
  244. char *data, *tmp;
  245. char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
  246. int i;
  247. int lines;
  248. char *req_type = NULL;
  249. char *uri = NULL;
  250. char *version = NULL;
  251. int whitespace, where, slen;
  252. if (http_data == NULL)
  253. return 0;
  254. /* make a local copy of the data, including 0 terminator */
  255. data = (char *)malloc(len+1);
  256. if (data == NULL) return 0;
  257. memcpy(data, http_data, len);
  258. data[len] = 0;
  259. lines = split_headers(data, len, line);
  260. /* parse the first line special
  261. ** the format is:
  262. ** REQ_TYPE URI VERSION
  263. ** eg:
  264. ** GET /index.html HTTP/1.0
  265. */
  266. where = 0;
  267. whitespace = 0;
  268. slen = strlen(line[0]);
  269. req_type = line[0];
  270. for (i = 0; i < slen; i++) {
  271. if (line[0][i] == ' ') {
  272. whitespace = 1;
  273. line[0][i] = '\0';
  274. } else {
  275. /* we're just past the whitespace boundry */
  276. if (whitespace) {
  277. whitespace = 0;
  278. where++;
  279. switch (where) {
  280. case 1:
  281. uri = &line[0][i];
  282. break;
  283. case 2:
  284. version = &line[0][i];
  285. break;
  286. }
  287. }
  288. }
  289. }
  290. if (strcasecmp("GET", req_type) == 0) {
  291. parser->req_type = httpp_req_get;
  292. } else if (strcasecmp("POST", req_type) == 0) {
  293. parser->req_type = httpp_req_post;
  294. } else if (strcasecmp("HEAD", req_type) == 0) {
  295. parser->req_type = httpp_req_head;
  296. } else if (strcasecmp("SOURCE", req_type) == 0) {
  297. parser->req_type = httpp_req_source;
  298. } else if (strcasecmp("PLAY", req_type) == 0) {
  299. parser->req_type = httpp_req_play;
  300. } else if (strcasecmp("STATS", req_type) == 0) {
  301. parser->req_type = httpp_req_stats;
  302. } else {
  303. parser->req_type = httpp_req_unknown;
  304. }
  305. if (uri != NULL && strlen(uri) > 0) {
  306. char *query;
  307. if((query = strchr(uri, '?')) != NULL) {
  308. httpp_setvar(parser, HTTPP_VAR_RAWURI, uri);
  309. httpp_setvar(parser, HTTPP_VAR_QUERYARGS, query);
  310. *query = 0;
  311. query++;
  312. parse_query(parser, query);
  313. }
  314. parser->uri = strdup(uri);
  315. } else {
  316. free(data);
  317. return 0;
  318. }
  319. if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
  320. tmp[0] = '\0';
  321. if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
  322. httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
  323. httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
  324. } else {
  325. free(data);
  326. return 0;
  327. }
  328. } else {
  329. free(data);
  330. return 0;
  331. }
  332. if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
  333. switch (parser->req_type) {
  334. case httpp_req_get:
  335. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
  336. break;
  337. case httpp_req_post:
  338. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
  339. break;
  340. case httpp_req_head:
  341. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
  342. break;
  343. case httpp_req_source:
  344. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
  345. break;
  346. case httpp_req_play:
  347. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
  348. break;
  349. case httpp_req_stats:
  350. httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
  351. break;
  352. default:
  353. break;
  354. }
  355. } else {
  356. free(data);
  357. return 0;
  358. }
  359. if (parser->uri != NULL) {
  360. httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
  361. } else {
  362. free(data);
  363. return 0;
  364. }
  365. parse_headers(parser, line, lines);
  366. free(data);
  367. return 1;
  368. }
  369. void httpp_setvar(http_parser_t *parser, const char *name, const char *value)
  370. {
  371. http_var_t *var;
  372. if (name == NULL || value == NULL)
  373. return;
  374. var = (http_var_t *)malloc(sizeof(http_var_t));
  375. if (var == NULL) return;
  376. var->name = strdup(name);
  377. var->value = strdup(value);
  378. if (httpp_getvar(parser, name) == NULL) {
  379. avl_insert(parser->vars, (void *)var);
  380. } else {
  381. avl_delete(parser->vars, (void *)var, _free_vars);
  382. avl_insert(parser->vars, (void *)var);
  383. }
  384. }
  385. const char *httpp_getvar(http_parser_t *parser, const char *name)
  386. {
  387. http_var_t var;
  388. http_var_t *found;
  389. void *fp;
  390. if (parser == NULL || name == NULL)
  391. return NULL;
  392. fp = &found;
  393. var.name = (char*)name;
  394. var.value = NULL;
  395. if (avl_get_by_key(parser->vars, &var, fp) == 0)
  396. return found->value;
  397. else
  398. return NULL;
  399. }
  400. void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value)
  401. {
  402. http_var_t *var;
  403. if (name == NULL || value == NULL)
  404. return;
  405. var = (http_var_t *)malloc(sizeof(http_var_t));
  406. if (var == NULL) return;
  407. var->name = strdup(name);
  408. var->value = url_escape(value);
  409. if (httpp_get_query_param(parser, name) == NULL) {
  410. avl_insert(parser->queryvars, (void *)var);
  411. } else {
  412. avl_delete(parser->queryvars, (void *)var, _free_vars);
  413. avl_insert(parser->queryvars, (void *)var);
  414. }
  415. }
  416. const char *httpp_get_query_param(http_parser_t *parser, const char *name)
  417. {
  418. http_var_t var;
  419. http_var_t *found;
  420. void *fp;
  421. fp = &found;
  422. var.name = (char *)name;
  423. var.value = NULL;
  424. if (avl_get_by_key(parser->queryvars, (void *)&var, fp) == 0)
  425. return found->value;
  426. else
  427. return NULL;
  428. }
  429. void httpp_clear(http_parser_t *parser)
  430. {
  431. parser->req_type = httpp_req_none;
  432. if (parser->uri)
  433. free(parser->uri);
  434. parser->uri = NULL;
  435. avl_tree_free(parser->vars, _free_vars);
  436. avl_tree_free(parser->queryvars, _free_vars);
  437. parser->vars = NULL;
  438. }
  439. void httpp_destroy(http_parser_t *parser)
  440. {
  441. httpp_clear(parser);
  442. free(parser);
  443. }
  444. static char *_lowercase(char *str)
  445. {
  446. char *p = str;
  447. for (; *p != '\0'; p++)
  448. *p = tolower(*p);
  449. return str;
  450. }
  451. static int _compare_vars(void *compare_arg, void *a, void *b)
  452. {
  453. http_var_t *vara, *varb;
  454. vara = (http_var_t *)a;
  455. varb = (http_var_t *)b;
  456. return strcmp(vara->name, varb->name);
  457. }
  458. static int _free_vars(void *key)
  459. {
  460. http_var_t *var;
  461. var = (http_var_t *)key;
  462. if (var->name)
  463. free(var->name);
  464. if (var->value)
  465. free(var->value);
  466. free(var);
  467. return 1;
  468. }