Change the "ctx.prune" option to match the command-line client default.
[cvs2svn.git] / test-data / resync-misgroups-cvsrepos / httpp / httpp.c,v
blobb8679a0fc0cf935c098f209478df772e1f99c6f3
1 head    1.23;
2 access;
3 symbols
4         libshout-2_0:1.23
5         libshout-2_0b3:1.23
6         libshout-2_0b2:1.22
7         libshout_2_0b1:1.22
8         libogg2-zerocopy:1.8.0.2
9         start:1.1.1.1
10         xiph:1.1.1;
11 locks; strict;
12 comment @ * @;
15 1.23
16 date    2003.07.07.01.49.27;    author brendan; state Exp;
17 branches;
18 next    1.22;
20 1.22
21 date    2003.06.18.15.52.25;    author karl;    state Exp;
22 branches;
23 next    1.21;
25 1.21
26 date    2003.06.18.11.13.11;    author karl;    state Exp;
27 branches;
28 next    1.20;
30 1.20
31 date    2003.06.09.22.30.09;    author brendan; state Exp;
32 branches;
33 next    1.19;
35 1.19
36 date    2003.06.05.17.09.12;    author brendan; state Exp;
37 branches;
38 next    1.18;
40 1.18
41 date    2003.03.15.02.10.18;    author msmith;  state Exp;
42 branches;
43 next    1.17;
45 1.17
46 date    2003.03.09.22.56.46;    author karl;    state Exp;
47 branches;
48 next    1.16;
50 1.16
51 date    2003.03.08.16.05.38;    author karl;    state Exp;
52 branches;
53 next    1.15;
55 1.15
56 date    2003.03.08.05.27.17;    author msmith;  state Exp;
57 branches;
58 next    1.14;
60 1.14
61 date    2003.03.08.04.57.02;    author msmith;  state Exp;
62 branches;
63 next    1.13;
65 1.13
66 date    2003.03.06.01.55.20;    author brendan; state Exp;
67 branches;
68 next    1.12;
70 1.12
71 date    2003.01.17.09.01.04;    author msmith;  state Exp;
72 branches;
73 next    1.11;
75 1.11
76 date    2003.01.16.05.48.31;    author brendan; state Exp;
77 branches;
78 next    1.10;
80 1.10
81 date    2003.01.15.23.46.56;    author brendan; state Exp;
82 branches;
83 next    1.9;
85 1.9
86 date    2002.12.31.06.28.39;    author msmith;  state Exp;
87 branches;
88 next    1.8;
90 1.8
91 date    2002.08.16.14.22.44;    author msmith;  state Exp;
92 branches;
93 next    1.7;
95 1.7
96 date    2002.08.05.14.48.03;    author msmith;  state Exp;
97 branches;
98 next    1.6;
101 date    2002.05.03.15.04.56;    author msmith;  state Exp;
102 branches;
103 next    1.5;
106 date    2002.04.05.09.28.25;    author msmith;  state Exp;
107 branches;
108 next    1.4;
111 date    2002.02.11.09.11.18;    author msmith;  state Exp;
112 branches;
113 next    1.3;
116 date    2001.10.20.07.40.09;    author jack;    state Exp;
117 branches;
118 next    1.2;
121 date    2001.10.20.04.41.54;    author jack;    state Exp;
122 branches;
123 next    1.1;
126 date    2001.09.10.02.28.47;    author jack;    state Exp;
127 branches
128         1.1.1.1;
129 next    ;
131 1.1.1.1
132 date    2001.09.10.02.28.47;    author jack;    state Exp;
133 branches;
134 next    ;
137 desc
141 1.23
143 @httpp goes through the rinse cycle
145 text
146 @/* Httpp.c
148 ** http parsing engine
151 #ifdef HAVE_CONFIG_H
152  #include <config.h>
153 #endif
155 #include <stdio.h>
157 #include <stdlib.h>
158 #include <string.h>
159 #include <ctype.h>
160 #ifdef HAVE_STRINGS_H
161 #include <strings.h>
162 #endif
164 #include <avl/avl.h>
165 #include "httpp.h"
167 #ifdef _WIN32
168 #define strcasecmp stricmp
169 #endif
171 #define MAX_HEADERS 32
173 /* internal functions */
175 /* misc */
176 static char *_lowercase(char *str);
178 /* for avl trees */
179 static int _compare_vars(void *compare_arg, void *a, void *b);
180 static int _free_vars(void *key);
182 http_parser_t *httpp_create_parser(void)
184     return (http_parser_t *)malloc(sizeof(http_parser_t));
187 void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
189     http_varlist_t *list;
191     parser->req_type = httpp_req_none;
192     parser->uri = NULL;
193     parser->vars = avl_tree_new(_compare_vars, NULL);
194     parser->queryvars = avl_tree_new(_compare_vars, NULL);
196     /* now insert the default variables */
197     list = defaults;
198     while (list != NULL) {
199         httpp_setvar(parser, list->var.name, list->var.value);
200         list = list->next;
201     }
204 static int split_headers(char *data, unsigned long len, char **line)
206     /* first we count how many lines there are 
207     ** and set up the line[] array     
208     */
209     int lines = 0;
210     unsigned long i;
211     line[lines] = data;
212     for (i = 0; i < len && lines < MAX_HEADERS; i++) {
213         if (data[i] == '\r')
214             data[i] = '\0';
215         if (data[i] == '\n') {
216             lines++;
217             data[i] = '\0';
218             if (i + 1 < len) {
219                 if (data[i + 1] == '\n' || data[i + 1] == '\r')
220                     break;
221                 line[lines] = &data[i + 1];
222             }
223         }
224     }
226     i++;
227     while (data[i] == '\n') i++;
229     return lines;
232 static void parse_headers(http_parser_t *parser, char **line, int lines)
234     int i,l;
235     int whitespace, where, slen;
236     char *name = NULL;
237     char *value = NULL;
239     /* parse the name: value lines. */
240     for (l = 1; l < lines; l++) {
241         where = 0;
242         whitespace = 0;
243         name = line[l];
244         value = NULL;
245         slen = strlen(line[l]);
246         for (i = 0; i < slen; i++) {
247             if (line[l][i] == ':') {
248                 whitespace = 1;
249                 line[l][i] = '\0';
250             } else {
251                 if (whitespace) {
252                     whitespace = 0;
253                     while (i < slen && line[l][i] == ' ')
254                         i++;
256                     if (i < slen)
257                         value = &line[l][i];
258                     
259                     break;
260                 }
261             }
262         }
263         
264         if (name != NULL && value != NULL) {
265             httpp_setvar(parser, _lowercase(name), value);
266             name = NULL; 
267             value = NULL;
268         }
269     }
272 int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri)
274     char *data;
275     char *line[MAX_HEADERS];
276     int lines, slen,i, whitespace=0, where=0,code;
277     char *version=NULL, *resp_code=NULL, *message=NULL;
278     
279     if(http_data == NULL)
280         return 0;
282     /* make a local copy of the data, including 0 terminator */
283     data = (char *)malloc(len+1);
284     if (data == NULL) return 0;
285     memcpy(data, http_data, len);
286     data[len] = 0;
288     lines = split_headers(data, len, line);
290     /* In this case, the first line contains:
291      * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
292      */
293     slen = strlen(line[0]);
294     version = line[0];
295     for(i=0; i < slen; i++) {
296         if(line[0][i] == ' ') {
297             line[0][i] = 0;
298             whitespace = 1;
299         } else if(whitespace) {
300             whitespace = 0;
301             where++;
302             if(where == 1)
303                 resp_code = &line[0][i];
304             else {
305                 message = &line[0][i];
306                 break;
307             }
308         }
309     }
311     if(version == NULL || resp_code == NULL || message == NULL) {
312         free(data);
313         return 0;
314     }
316     httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
317     code = atoi(resp_code);
318     if(code < 200 || code >= 300) {
319         httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
320     }
322     httpp_setvar(parser, HTTPP_VAR_URI, uri);
323     httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
325     parse_headers(parser, line, lines);
327     free(data);
329     return 1;
332 static int hex(char c)
334     if(c >= '0' && c <= '9')
335         return c - '0';
336     else if(c >= 'A' && c <= 'F')
337         return c - 'A' + 10;
338     else if(c >= 'a' && c <= 'f')
339         return c - 'a' + 10;
340     else
341         return -1;
344 static char *url_escape(char *src)
346     int len = strlen(src);
347     unsigned char *decoded;
348     int i;
349     char *dst;
350     int done = 0;
352     decoded = calloc(1, len + 1);
354     dst = decoded;
356     for(i=0; i < len; i++) {
357         switch(src[i]) {
358         case '%':
359             if(i+2 >= len) {
360                 free(decoded);
361                 return NULL;
362             }
363             if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
364                 free(decoded);
365                 return NULL;
366             }
368             *dst++ = hex(src[i+1]) * 16  + hex(src[i+2]);
369             i+= 2;
370             break;
371         case '#':
372             done = 1;
373             break;
374         case 0:
375             free(decoded);
376             return NULL;
377             break;
378         default:
379             *dst++ = src[i];
380             break;
381         }
382         if(done)
383             break;
384     }
386     *dst = 0; /* null terminator */
388     return decoded;
391 /** TODO: This is almost certainly buggy in some cases */
392 static void parse_query(http_parser_t *parser, char *query)
394     int len;
395     int i=0;
396     char *key = query;
397     char *val=NULL;
399     if(!query || !*query)
400         return;
402     len = strlen(query);
404     while(i<len) {
405         switch(query[i]) {
406         case '&':
407             query[i] = 0;
408             if(val && key)
409                 httpp_set_query_param(parser, key, val);
410             key = query+i+1;
411             break;
412         case '=':
413             query[i] = 0;
414             val = query+i+1;
415             break;
416         }
417         i++;
418     }
420     if(val && key) {
421         httpp_set_query_param(parser, key, val);
422     }
425 /* The old shoutcast procotol. Don't look at this, it's really nasty */
426 int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
428     char *data;
429     char *line[MAX_HEADERS];
430     int lines;
432     if(http_data == NULL)
433         return 0;
435     data = malloc(len + 1);
436     memcpy(data, http_data, len);
437     data[len] = 0;
439     lines = split_headers(data, len, line);
441     /* Now, this protocol looks like:
442      * sourcepassword\n
443      * headers: as normal\n"
444      * \n
445      */
447     parser->req_type = httpp_req_source;
448     httpp_setvar(parser, HTTPP_VAR_URI, "/");
449     httpp_setvar(parser, HTTPP_VAR_ICYPASSWORD, line[0]);
450     httpp_setvar(parser, HTTPP_VAR_PROTOCOL, "ICY");
451     httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
452     /* This protocol is evil */
453     httpp_setvar(parser, HTTPP_VAR_VERSION, "666");
455     parse_headers(parser, line, lines);
457     free(data);
458     
459     return 1;
462 int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
464     char *data, *tmp;
465     char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
466     int i;
467     int lines;
468     char *req_type = NULL;
469     char *uri = NULL;
470     char *version = NULL;
471     int whitespace, where, slen;
473     if (http_data == NULL)
474         return 0;
476     /* make a local copy of the data, including 0 terminator */
477     data = (char *)malloc(len+1);
478     if (data == NULL) return 0;
479     memcpy(data, http_data, len);
480     data[len] = 0;
482     lines = split_headers(data, len, line);
484     /* parse the first line special
485     ** the format is:
486     ** REQ_TYPE URI VERSION
487     ** eg:
488     ** GET /index.html HTTP/1.0
489     */
490     where = 0;
491     whitespace = 0;
492     slen = strlen(line[0]);
493     req_type = line[0];
494     for (i = 0; i < slen; i++) {
495         if (line[0][i] == ' ') {
496             whitespace = 1;
497             line[0][i] = '\0';
498         } else {
499             /* we're just past the whitespace boundry */
500             if (whitespace) {
501                 whitespace = 0;
502                 where++;
503                 switch (where) {
504                 case 1:
505                     uri = &line[0][i];
506                     break;
507                 case 2:
508                     version = &line[0][i];
509                     break;
510                 }
511             }
512         }
513     }
515     if (strcasecmp("GET", req_type) == 0) {
516         parser->req_type = httpp_req_get;
517     } else if (strcasecmp("POST", req_type) == 0) {
518         parser->req_type = httpp_req_post;
519     } else if (strcasecmp("HEAD", req_type) == 0) {
520         parser->req_type = httpp_req_head;
521     } else if (strcasecmp("SOURCE", req_type) == 0) {
522         parser->req_type = httpp_req_source;
523     } else if (strcasecmp("PLAY", req_type) == 0) {
524         parser->req_type = httpp_req_play;
525     } else if (strcasecmp("STATS", req_type) == 0) {
526         parser->req_type = httpp_req_stats;
527     } else {
528         parser->req_type = httpp_req_unknown;
529     }
531     if (uri != NULL && strlen(uri) > 0) {
532         char *query;
533         if((query = strchr(uri, '?')) != NULL) {
534             *query = 0;
535             query++;
536             parse_query(parser, query);
537         }
539         parser->uri = strdup(uri);
540     } else {
541         free(data);
542         return 0;
543     }
545     if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
546         tmp[0] = '\0';
547         if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
548             httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
549             httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
550         } else {
551             free(data);
552             return 0;
553         }
554     } else {
555         free(data);
556         return 0;
557     }
559     if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
560         switch (parser->req_type) {
561         case httpp_req_get:
562             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
563             break;
564         case httpp_req_post:
565             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
566             break;
567         case httpp_req_head:
568             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
569             break;
570         case httpp_req_source:
571             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
572             break;
573         case httpp_req_play:
574             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
575             break;
576         case httpp_req_stats:
577             httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
578             break;
579         default:
580             break;
581         }
582     } else {
583         free(data);
584         return 0;
585     }
587     if (parser->uri != NULL) {
588         httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
589     } else {
590         free(data);
591         return 0;
592     }
594     parse_headers(parser, line, lines);
596     free(data);
598     return 1;
601 void httpp_setvar(http_parser_t *parser, char *name, char *value)
603     http_var_t *var;
605     if (name == NULL || value == NULL)
606         return;
608     var = (http_var_t *)malloc(sizeof(http_var_t));
609     if (var == NULL) return;
611     var->name = strdup(name);
612     var->value = strdup(value);
614     if (httpp_getvar(parser, name) == NULL) {
615         avl_insert(parser->vars, (void *)var);
616     } else {
617         avl_delete(parser->vars, (void *)var, _free_vars);
618         avl_insert(parser->vars, (void *)var);
619     }
622 char *httpp_getvar(http_parser_t *parser, char *name)
624     http_var_t var;
625     http_var_t *found;
626     void *fp;
628     fp = &found;
629     var.name = name;
630     var.value = NULL;
632     if (avl_get_by_key(parser->vars, &var, fp) == 0)
633         return found->value;
634     else
635         return NULL;
638 void httpp_set_query_param(http_parser_t *parser, char *name, char *value)
640     http_var_t *var;
642     if (name == NULL || value == NULL)
643         return;
645     var = (http_var_t *)malloc(sizeof(http_var_t));
646     if (var == NULL) return;
648     var->name = strdup(name);
649     var->value = url_escape(value);
651     if (httpp_get_query_param(parser, name) == NULL) {
652         avl_insert(parser->queryvars, (void *)var);
653     } else {
654         avl_delete(parser->queryvars, (void *)var, _free_vars);
655         avl_insert(parser->queryvars, (void *)var);
656     }
659 char *httpp_get_query_param(http_parser_t *parser, char *name)
661     http_var_t var;
662     http_var_t *found;
663     void *fp;
665     fp = &found;
666     var.name = name;
667     var.value = NULL;
669     if (avl_get_by_key(parser->queryvars, (void *)&var, fp) == 0)
670         return found->value;
671     else
672         return NULL;
675 void httpp_clear(http_parser_t *parser)
677     parser->req_type = httpp_req_none;
678     if (parser->uri)
679         free(parser->uri);
680     parser->uri = NULL;
681     avl_tree_free(parser->vars, _free_vars);
682     avl_tree_free(parser->queryvars, _free_vars);
683     parser->vars = NULL;
686 void httpp_destroy(http_parser_t *parser)
688     httpp_clear(parser);
689     free(parser);
692 static char *_lowercase(char *str)
694     char *p = str;
695     for (; *p != '\0'; p++)
696         *p = tolower(*p);
698     return str;
701 static int _compare_vars(void *compare_arg, void *a, void *b)
703     http_var_t *vara, *varb;
705     vara = (http_var_t *)a;
706     varb = (http_var_t *)b;
708     return strcmp(vara->name, varb->name);
711 static int _free_vars(void *key)
713     http_var_t *var;
715     var = (http_var_t *)key;
717     if (var->name)
718         free(var->name);
719     if (var->value)
720         free(var->value);
721     free(var);
723     return 1;
729 1.22
731 @ermmm, let's use the right operator.
733 text
734 @d34 2
735 a35 2
736 int _compare_vars(void *compare_arg, void *a, void *b);
737 int _free_vars(void *key);
738 d556 1
739 a556 1
740 int _compare_vars(void *compare_arg, void *a, void *b)
741 d566 1
742 a566 1
743 int _free_vars(void *key)
747 1.21
749 @minor cleanup, removes compiler warning, makes it static, and doesn't
750 re-evaluate string length each time.
752 text
753 @d550 1
754 a550 1
755     for (; *p |= '\0'; p++)
759 1.20
761 @gcc 3.3 warns: dereferencing type-punned pointer will break strict-aliasing rules
763 text
764 @d31 1
765 a31 1
766 char *_lowercase(char *str);
767 d547 1
768 a547 1
769 char *_lowercase(char *str)
770 d549 3
771 a551 3
772     long i;
773     for (i = 0; i < strlen(str); i++)
774         str[i] = tolower(str[i]);
778 1.19
780 @Karl's patch for freebsd, minus the sys/select.h test which breaks on OS X.
781 Also enables IPV6 in libshout!
783 text
784 @d481 1
785 d483 1
786 d487 1
787 a487 1
788     if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
789 d518 1
790 d520 1
791 d524 1
792 a524 1
793     if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
797 1.18
799 @Brendan was getting pissed off about inconsistent indentation styles.
800 Convert all tabs to 4 spaces. All code must now use 4 space indents.
802 text
803 @d15 3
807 1.17
809 @reduce include file namespace clutter for libshout and the associated
810 smaller libs.
812 text
813 @d36 1
814 a36 1
815         return (http_parser_t *)malloc(sizeof(http_parser_t));
816 d41 1
817 a41 1
818         http_varlist_t *list;
819 d43 11
820 a53 11
821         parser->req_type = httpp_req_none;
822         parser->uri = NULL;
823         parser->vars = avl_tree_new(_compare_vars, NULL);
824         parser->queryvars = avl_tree_new(_compare_vars, NULL);
826         /* now insert the default variables */
827         list = defaults;
828         while (list != NULL) {
829                 httpp_setvar(parser, list->var.name, list->var.value);
830                 list = list->next;
831         }
832 d58 4
833 a61 4
834         /* first we count how many lines there are 
835         ** and set up the line[] array   
836         */
837         int lines = 0;
838 d63 11
839 a73 11
840         line[lines] = data;
841         for (i = 0; i < len && lines < MAX_HEADERS; i++) {
842                 if (data[i] == '\r')
843                         data[i] = '\0';
844                 if (data[i] == '\n') {
845                         lines++;
846                         data[i] = '\0';
847                         if (i + 1 < len) {
848                                 if (data[i + 1] == '\n' || data[i + 1] == '\r')
849                                         break;
850                                 line[lines] = &data[i + 1];
851 d75 2
852 a76 2
853                 }
854         }
855 d78 2
856 a79 2
857         i++;
858         while (data[i] == '\n') i++;
859 d87 35
860 a121 35
861         int whitespace, where, slen;
862         char *name = NULL;
863         char *value = NULL;
865         /* parse the name: value lines. */
866         for (l = 1; l < lines; l++) {
867                 where = 0;
868                 whitespace = 0;
869                 name = line[l];
870                 value = NULL;
871                 slen = strlen(line[l]);
872                 for (i = 0; i < slen; i++) {
873                         if (line[l][i] == ':') {
874                                 whitespace = 1;
875                                 line[l][i] = '\0';
876                         } else {
877                                 if (whitespace) {
878                                         whitespace = 0;
879                                         while (i < slen && line[l][i] == ' ')
880                                                 i++;
882                                         if (i < slen)
883                                                 value = &line[l][i];
884                                         
885                                         break;
886                                 }
887                         }
888                 }
889                 
890                 if (name != NULL && value != NULL) {
891                         httpp_setvar(parser, _lowercase(name), value);
892                         name = NULL; 
893                         value = NULL;
894                 }
895         }
896 d126 4
897 a129 4
898         char *data;
899         char *line[MAX_HEADERS];
900         int lines, slen,i, whitespace=0, where=0,code;
901         char *version=NULL, *resp_code=NULL, *message=NULL;
902 d131 2
903 a132 2
904         if(http_data == NULL)
905                 return 0;
906 d134 5
907 a138 39
908         /* make a local copy of the data, including 0 terminator */
909         data = (char *)malloc(len+1);
910         if (data == NULL) return 0;
911         memcpy(data, http_data, len);
912         data[len] = 0;
914         lines = split_headers(data, len, line);
916         /* In this case, the first line contains:
917          * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
918          */
919         slen = strlen(line[0]);
920         version = line[0];
921         for(i=0; i < slen; i++) {
922                 if(line[0][i] == ' ') {
923                         line[0][i] = 0;
924                         whitespace = 1;
925                 } else if(whitespace) {
926                         whitespace = 0;
927                         where++;
928                         if(where == 1)
929                                 resp_code = &line[0][i];
930                         else {
931                                 message = &line[0][i];
932                                 break;
933                         }
934                 }
935         }
937         if(version == NULL || resp_code == NULL || message == NULL) {
938                 free(data);
939                 return 0;
940         }
942         httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
943         code = atoi(resp_code);
944         if(code < 200 || code >= 300) {
945                 httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
946         }
947 d140 1
948 a140 2
949         httpp_setvar(parser, HTTPP_VAR_URI, uri);
950         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
951 d142 20
952 a161 1
953         parse_headers(parser, line, lines);
954 d163 4
955 a166 1
956         free(data);
957 d168 14
958 a181 1
959         return 1;
960 d186 8
961 a193 8
962         if(c >= '0' && c <= '9')
963                 return c - '0';
964         else if(c >= 'A' && c <= 'F')
965                 return c - 'A' + 10;
966         else if(c >= 'a' && c <= 'f')
967                 return c - 'a' + 10;
968         else
969                 return -1;
970 d198 39
971 a236 39
972         int len = strlen(src);
973         unsigned char *decoded;
974         int i;
975         char *dst;
976         int done = 0;
978         decoded = calloc(1, len + 1);
980         dst = decoded;
982         for(i=0; i < len; i++) {
983                 switch(src[i]) {
984                 case '%':
985                         if(i+2 >= len) {
986                                 free(decoded);
987                                 return NULL;
988                         }
989                         if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
990                                 free(decoded);
991                                 return NULL;
992                         }
994                         *dst++ = hex(src[i+1]) * 16  + hex(src[i+2]);
995                         i+= 2;
996                         break;
997                 case '#':
998                         done = 1;
999                         break;
1000                 case 0:
1001                         free(decoded);
1002                         return NULL;
1003                         break;
1004                 default:
1005                         *dst++ = src[i];
1006                         break;
1007                 }
1008                 if(done)
1009                         break;
1010         }
1011 d238 1
1012 a238 1
1013         *dst = 0; /* null terminator */
1014 d240 1
1015 a240 1
1016         return decoded;
1017 d246 29
1018 a274 29
1019         int len;
1020         int i=0;
1021         char *key = query;
1022         char *val=NULL;
1024         if(!query || !*query)
1025                 return;
1027         len = strlen(query);
1029         while(i<len) {
1030                 switch(query[i]) {
1031                 case '&':
1032                         query[i] = 0;
1033                         if(val && key)
1034                                 httpp_set_query_param(parser, key, val);
1035                         key = query+i+1;
1036                         break;
1037                 case '=':
1038                         query[i] = 0;
1039                         val = query+i+1;
1040                         break;
1041                 }
1042                 i++;
1043         }
1045         if(val && key) {
1046                 httpp_set_query_param(parser, key, val);
1047         }
1048 d291 1
1049 a291 1
1050         lines = split_headers(data, len, line);
1051 d316 80
1052 a395 74
1053         char *data, *tmp;
1054         char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
1055         int i;
1056         int lines;
1057         char *req_type = NULL;
1058         char *uri = NULL;
1059         char *version = NULL;
1060         int whitespace, where, slen;
1062         if (http_data == NULL)
1063                 return 0;
1065         /* make a local copy of the data, including 0 terminator */
1066         data = (char *)malloc(len+1);
1067         if (data == NULL) return 0;
1068         memcpy(data, http_data, len);
1069         data[len] = 0;
1071         lines = split_headers(data, len, line);
1073         /* parse the first line special
1074         ** the format is:
1075         ** REQ_TYPE URI VERSION
1076         ** eg:
1077         ** GET /index.html HTTP/1.0
1078         */
1079         where = 0;
1080         whitespace = 0;
1081         slen = strlen(line[0]);
1082         req_type = line[0];
1083         for (i = 0; i < slen; i++) {
1084                 if (line[0][i] == ' ') {
1085                         whitespace = 1;
1086                         line[0][i] = '\0';
1087                 } else {
1088                         /* we're just past the whitespace boundry */
1089                         if (whitespace) {
1090                                 whitespace = 0;
1091                                 where++;
1092                                 switch (where) {
1093                                 case 1:
1094                                         uri = &line[0][i];
1095                                         break;
1096                                 case 2:
1097                                         version = &line[0][i];
1098                                         break;
1099                                 }
1100                         }
1101                 }
1102         }
1104         if (strcasecmp("GET", req_type) == 0) {
1105                 parser->req_type = httpp_req_get;
1106         } else if (strcasecmp("POST", req_type) == 0) {
1107                 parser->req_type = httpp_req_post;
1108         } else if (strcasecmp("HEAD", req_type) == 0) {
1109                 parser->req_type = httpp_req_head;
1110         } else if (strcasecmp("SOURCE", req_type) == 0) {
1111                 parser->req_type = httpp_req_source;
1112         } else if (strcasecmp("PLAY", req_type) == 0) {
1113                 parser->req_type = httpp_req_play;
1114         } else if (strcasecmp("STATS", req_type) == 0) {
1115                 parser->req_type = httpp_req_stats;
1116         } else {
1117                 parser->req_type = httpp_req_unknown;
1118         }
1120         if (uri != NULL && strlen(uri) > 0) {
1121                 char *query;
1122                 if((query = strchr(uri, '?')) != NULL) {
1123                         *query = 0;
1124                         query++;
1125                         parse_query(parser, query);
1126                 }
1127 d397 10
1128 a406 2
1129                 parser->uri = strdup(uri);
1130         } else {
1131 d411 27
1132 a437 48
1133         if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
1134                 tmp[0] = '\0';
1135                 if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
1136                         httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
1137                         httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
1138                 } else {
1139                         free(data);
1140                         return 0;
1141                 }
1142         } else {
1143                 free(data);
1144                 return 0;
1145         }
1147         if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
1148                 switch (parser->req_type) {
1149                 case httpp_req_get:
1150                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
1151                         break;
1152                 case httpp_req_post:
1153                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
1154                         break;
1155                 case httpp_req_head:
1156                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
1157                         break;
1158                 case httpp_req_source:
1159                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
1160                         break;
1161                 case httpp_req_play:
1162                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
1163                         break;
1164                 case httpp_req_stats:
1165                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
1166                         break;
1167                 default:
1168                         break;
1169                 }
1170         } else {
1171                 free(data);
1172                 return 0;
1173         }
1175         if (parser->uri != NULL) {
1176                 httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
1177         } else {
1178                 free(data);
1179                 return 0;
1180         }
1181 d439 6
1182 a444 1
1183         parse_headers(parser, line, lines);
1184 d446 3
1185 a448 1
1186         free(data);
1187 d450 1
1188 a450 1
1189         return 1;
1190 d455 1
1191 a455 1
1192         http_var_t *var;
1193 d457 2
1194 a458 2
1195         if (name == NULL || value == NULL)
1196                 return;
1197 d460 2
1198 a461 2
1199         var = (http_var_t *)malloc(sizeof(http_var_t));
1200         if (var == NULL) return;
1201 d463 9
1202 a471 9
1203         var->name = strdup(name);
1204         var->value = strdup(value);
1206         if (httpp_getvar(parser, name) == NULL) {
1207                 avl_insert(parser->vars, (void *)var);
1208         } else {
1209                 avl_delete(parser->vars, (void *)var, _free_vars);
1210                 avl_insert(parser->vars, (void *)var);
1211         }
1212 d476 2
1213 a477 2
1214         http_var_t var;
1215         http_var_t *found;
1216 d479 2
1217 a480 2
1218         var.name = name;
1219         var.value = NULL;
1220 d482 4
1221 a485 4
1222         if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
1223                 return found->value;
1224         else
1225                 return NULL;
1226 d490 1
1227 a490 1
1228         http_var_t *var;
1229 d492 2
1230 a493 2
1231         if (name == NULL || value == NULL)
1232                 return;
1233 d495 2
1234 a496 2
1235         var = (http_var_t *)malloc(sizeof(http_var_t));
1236         if (var == NULL) return;
1237 d498 9
1238 a506 9
1239         var->name = strdup(name);
1240         var->value = url_escape(value);
1242         if (httpp_get_query_param(parser, name) == NULL) {
1243                 avl_insert(parser->queryvars, (void *)var);
1244         } else {
1245                 avl_delete(parser->queryvars, (void *)var, _free_vars);
1246                 avl_insert(parser->queryvars, (void *)var);
1247         }
1248 d511 2
1249 a512 2
1250         http_var_t var;
1251         http_var_t *found;
1252 d514 2
1253 a515 2
1254         var.name = name;
1255         var.value = NULL;
1256 d517 4
1257 a520 4
1258         if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
1259                 return found->value;
1260         else
1261                 return NULL;
1262 d525 7
1263 a531 7
1264         parser->req_type = httpp_req_none;
1265         if (parser->uri)
1266                 free(parser->uri);
1267         parser->uri = NULL;
1268         avl_tree_free(parser->vars, _free_vars);
1269         avl_tree_free(parser->queryvars, _free_vars);
1270         parser->vars = NULL;
1271 d536 2
1272 a537 2
1273         httpp_clear(parser);
1274         free(parser);
1275 d542 3
1276 a544 3
1277         long i;
1278         for (i = 0; i < strlen(str); i++)
1279                 str[i] = tolower(str[i]);
1280 d546 1
1281 a546 1
1282         return str;
1283 d551 1
1284 a551 1
1285         http_var_t *vara, *varb;
1286 d553 2
1287 a554 2
1288         vara = (http_var_t *)a;
1289         varb = (http_var_t *)b;
1290 d556 1
1291 a556 1
1292         return strcmp(vara->name, varb->name);
1293 d561 1
1294 a561 1
1295         http_var_t *var;
1296 d563 1
1297 a563 1
1298         var = (http_var_t *)key;
1299 d565 5
1300 a569 5
1301         if (var->name)
1302                 free(var->name);
1303         if (var->value)
1304                 free(var->value);
1305         free(var);
1306 d571 1
1307 a571 1
1308         return 1;
1312 1.16
1314 @include the automake config.h file if the application defines one
1316 text
1317 @d16 1
1318 a16 1
1319 #include "avl.h"
1323 1.15
1325 @Set another parameter in the icy protocol parse that logging expects
1327 text
1328 @d6 4
1332 1.14
1334 @Added support for shoutcast login protocol (ewww...)
1336 text
1337 @d299 1
1341 1.13
1343 @Use gnu archive ACX_PTHREAD macro to figure out how to compile thread support.
1344 Also make it possible to build libshout without threads, albeit without locking
1345 in the resolver or avl trees.
1346 New option --disable-pthread too.
1348 text
1349 @d273 36
1350 d387 4
1351 a390 2
1352         } else
1353                 parser->uri = NULL;
1357 1.12
1359 @Fix some warnings, fix cflags.
1361 text
1362 @a11 1
1363 #include "thread.h"
1367 1.11
1369 @Indentation again, don't mind me
1371 text
1372 @d58 2
1373 a59 1
1374         int i, lines = 0;
1378 1.10
1380 @Make indentation consistent before doing other work
1382 text
1383 @d472 1
1384 a472 1
1385     var.value = NULL;
1391 @mp3 metadata complete. Still untested.
1393 text
1394 @d43 1
1395 a43 1
1396     parser->queryvars = avl_tree_new(_compare_vars, NULL);
1397 d122 4
1398 a125 4
1399     char *data;
1400     char *line[MAX_HEADERS];
1401     int lines, slen,i, whitespace=0, where=0,code;
1402     char *version=NULL, *resp_code=NULL, *message=NULL;
1403 d127 2
1404 a128 2
1405     if(http_data == NULL)
1406         return 0;
1407 d134 1
1408 a134 1
1409     data[len] = 0;
1410 d136 1
1411 a136 1
1412     lines = split_headers(data, len, line);
1413 d138 20
1414 a157 22
1415     /* In this case, the first line contains:
1416      * VERSION RESPONSE_CODE MESSAGE, such as
1417      * HTTP/1.0 200 OK
1418      */
1419     slen = strlen(line[0]);
1420     version = line[0];
1421     for(i=0; i < slen; i++) {
1422         if(line[0][i] == ' ') {
1423             line[0][i] = 0;
1424             whitespace = 1;
1425         }
1426         else if(whitespace) {
1427             whitespace = 0;
1428             where++;
1429             if(where == 1)
1430                 resp_code = &line[0][i];
1431             else {
1432                 message = &line[0][i];
1433                 break;
1434             }
1435         }
1436     }
1437 d159 4
1438 a162 10
1439     if(version == NULL || resp_code == NULL || message == NULL) {
1440         free(data);
1441         return 0;
1442     }
1444     httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
1445     code = atoi(resp_code);
1446     if(code < 200 || code >= 300) {
1447         httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
1448     }
1449 d164 7
1450 a170 1
1451     httpp_setvar(parser, HTTPP_VAR_URI, uri);
1452 d173 1
1453 a173 1
1454     parse_headers(parser, line, lines);
1455 d182 8
1456 a189 8
1457     if(c >= '0' && c <= '9')
1458         return c - '0';
1459     else if(c >= 'A' && c <= 'F')
1460         return c - 'A' + 10;
1461     else if(c >= 'a' && c <= 'f')
1462         return c - 'a' + 10;
1463     else
1464         return -1;
1465 d194 39
1466 a232 39
1467     int len = strlen(src);
1468     unsigned char *decoded;
1469     int i;
1470     char *dst;
1471     int done = 0;
1473     decoded = calloc(1, len + 1);
1475     dst = decoded;
1477     for(i=0; i < len; i++) {
1478         switch(src[i]) {
1479             case '%':
1480                 if(i+2 >= len) {
1481                     free(decoded);
1482                     return NULL;
1483                 }
1484                 if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
1485                     free(decoded);
1486                     return NULL;
1487                 }
1489                 *dst++ = hex(src[i+1]) * 16  + hex(src[i+2]);
1490                 i+= 2;
1491                 break;
1492             case '#':
1493                 done = 1;
1494                 break;
1495             case 0:
1496                 free(decoded);
1497                 return NULL;
1498                 break;
1499             default:
1500                 *dst++ = src[i];
1501                 break;
1502         }
1503         if(done)
1504             break;
1505     }
1506 d234 1
1507 a234 1
1508     *dst = 0; /* null terminator */
1509 d236 1
1510 a236 1
1511     return decoded;
1512 d242 29
1513 a270 30
1514     int len;
1515     int i=0;
1516     char *key = query;
1517     char *val=NULL;
1519     if(!query || !*query)
1520         return;
1522     len = strlen(query);
1524     while(i<len) {
1525         switch(query[i]) {
1526             case '&':
1527                 query[i] = 0;
1528                 if(val && key) {
1529                     httpp_set_query_param(parser, key, val);
1530                 }
1531                 key = query+i+1;
1532                 break;
1533             case '=':
1534                 query[i] = 0;
1535                 val = query+i+1;
1536                 break;
1537         }
1538         i++;
1539     }
1541     if(val && key) {
1542         httpp_set_query_param(parser, key, val);
1543     }
1544 d282 1
1545 a282 1
1546     int whitespace, where, slen;
1547 d291 1
1548 a291 1
1549     data[len] = 0;
1550 d293 1
1551 a293 1
1552     lines = split_headers(data, len, line);
1553 d342 7
1554 a348 8
1555         if (uri != NULL && strlen(uri) > 0) 
1556     {
1557         char *query;
1558         if((query = strchr(uri, '?')) != NULL) {
1559             *query = 0;
1560             query++;
1561             parse_query(parser, query);
1562         }
1563 d351 1
1564 a351 2
1565     }
1566         else
1567 d396 1
1568 a396 1
1569     if (parser->uri != NULL) {
1570 d403 1
1571 a403 1
1572     parse_headers(parser, line, lines);
1573 d437 1
1574 a437 1
1575     var.value = NULL;
1576 d493 2
1577 a494 2
1578     httpp_clear(parser);
1579     free(parser);
1585 @bugfixes for httpp_parse_response
1587 text
1588 @d43 1
1589 d182 94
1590 d345 9
1591 a353 1
1592         if (uri != NULL && strlen(uri) > 0)
1593 d355 1
1594 d442 1
1595 a442 1
1596         var.value = NULL;
1597 d450 35
1598 d492 1
1604 @Cleaned up version of Ciaran Anscomb's relaying patch.
1606 text
1607 @d165 1
1608 a168 2
1609         free(data);
1610         return 0;
1611 d172 1
1612 a172 1
1613         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "RELAY");
1619 @Memory leaks. Lots of little ones.
1621 text
1622 @d52 1
1623 a52 1
1624 int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
1625 a53 21
1626         char *data, *tmp;
1627         char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
1628         int i, l, retlen;
1629         int lines;
1630         char *req_type = NULL;
1631         char *uri = NULL;
1632         char *version = NULL;
1633         char *name = NULL;
1634         char *value = NULL;
1635         int whitespace, where;
1636         int slen;
1638         if (http_data == NULL)
1639                 return 0;
1641         /* make a local copy of the data, including 0 terminator */
1642         data = (char *)malloc(len+1);
1643         if (data == NULL) return 0;
1644         memcpy(data, http_data, len);
1645     data[len] = 0;
1647 d57 1
1648 a57 1
1649         lines = 0;
1650 d75 128
1651 a202 1
1652         retlen = i;
1653 d298 1
1654 a298 1
1655         if (parser->uri != NULL) {
1656 d305 1
1657 a305 31
1658         /* parse the name: value lines. */
1659         for (l = 1; l < lines; l++) {
1660                 where = 0;
1661                 whitespace = 0;
1662                 name = line[l];
1663                 value = NULL;
1664                 slen = strlen(line[l]);
1665                 for (i = 0; i < slen; i++) {
1666                         if (line[l][i] == ':') {
1667                                 whitespace = 1;
1668                                 line[l][i] = '\0';
1669                         } else {
1670                                 if (whitespace) {
1671                                         whitespace = 0;
1672                                         while (i < slen && line[l][i] == ' ')
1673                                                 i++;
1675                                         if (i < slen)
1676                                                 value = &line[l][i];
1677                                         
1678                                         break;
1679                                 }
1680                         }
1681                 }
1682                 
1683                 if (name != NULL && value != NULL) {
1684                         httpp_setvar(parser, _lowercase(name), value);
1685                         name = NULL; 
1686                         value = NULL;
1687                 }
1688         }
1689 d309 1
1690 a309 1
1691         return retlen;
1697 @Buffer overflows.
1699 Requires a change to the format plugin interface - jack: if you want this
1700 done differently, feel free to change it (or ask me to).
1702 text
1703 @d271 1
1704 a271 1
1705 void httpp_destroy(http_parser_t *parser)
1706 d279 6
1712 @Bunch of fixes:
1714  - connections are now matched to format plugins based on content-type headers,
1715    and are rejected if there isn't a format handler for that content-type, or
1716    there is no content-type at all.
1717  - format_vorbis now handles pages with granulepos of -1 in the headers
1718    correctly (this happens if the headers are fairly large, because of
1719    many comments, for example).
1720  - various #include fixes.
1721  - buffer overflow in httpp.c fixed.
1723 text
1724 @d6 2
1725 d20 2
1726 d55 1
1727 a55 1
1728         char *line[32]; /* limited to 32 lines, should be more than enough */
1729 d80 1
1730 a80 1
1731         for (i = 0; i < len; i++) {
1737 @Thanks to Akos Maroy <darkeye@@tyrell.hu> for this.  These variables need to
1738 be uppercase always in order to comply with the HTTP specification.
1739 While not a problem internal to icecast, they were slipping into the log
1740 files and breaking some less-than-robust parsers.
1742 text
1743 @d65 2
1744 a66 2
1745         /* make a local copy of the data */
1746         data = (char *)malloc(len);
1747 d69 1
1748 d81 3
1749 a83 3
1750                         if (i + 1 < len)
1751                                 if (data[i + 1] == '\n' || data[i + 1] == '\r') {
1752                                         data[i] = '\0';
1753 a84 3
1754                                 }
1755                         data[i] = '\0';
1756                         if (i < len - 1)
1757 d86 1
1763 @Win32 compatibility courtesy of Oddsock.
1765 text
1766 @d150 1
1767 a150 1
1768                         httpp_setvar(parser, HTTPP_VAR_PROTOCOL, _lowercase(version));
1769 d164 1
1770 a164 1
1771                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "get");
1772 d167 1
1773 a167 1
1774                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "post");
1775 d170 1
1776 a170 1
1777                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "head");
1778 d173 1
1779 a173 1
1780                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "source");
1781 d176 1
1782 a176 1
1783                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "play");
1784 d179 1
1785 a179 1
1786                         httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "stats");
1792 @Initial revision
1794 text
1795 @d14 4
1796 d54 5
1797 a58 4
1798         char *req_type;
1799         char *uri;
1800         char *version;
1801         char *name, *value;
1805 1.1.1.1
1807 @move to cvs
1809 text