head 1.23; access; symbols libshout-2_0:1.23 libshout-2_0b3:1.23 libshout-2_0b2:1.22 libshout_2_0b1:1.22 libogg2-zerocopy:1.8.0.2 start:1.1.1.1 xiph:1.1.1; locks; strict; comment @ * @; 1.23 date 2003.07.07.01.49.27; author brendan; state Exp; branches; next 1.22; 1.22 date 2003.06.18.15.52.25; author karl; state Exp; branches; next 1.21; 1.21 date 2003.06.18.11.13.11; author karl; state Exp; branches; next 1.20; 1.20 date 2003.06.09.22.30.09; author brendan; state Exp; branches; next 1.19; 1.19 date 2003.06.05.17.09.12; author brendan; state Exp; branches; next 1.18; 1.18 date 2003.03.15.02.10.18; author msmith; state Exp; branches; next 1.17; 1.17 date 2003.03.09.22.56.46; author karl; state Exp; branches; next 1.16; 1.16 date 2003.03.08.16.05.38; author karl; state Exp; branches; next 1.15; 1.15 date 2003.03.08.05.27.17; author msmith; state Exp; branches; next 1.14; 1.14 date 2003.03.08.04.57.02; author msmith; state Exp; branches; next 1.13; 1.13 date 2003.03.06.01.55.20; author brendan; state Exp; branches; next 1.12; 1.12 date 2003.01.17.09.01.04; author msmith; state Exp; branches; next 1.11; 1.11 date 2003.01.16.05.48.31; author brendan; state Exp; branches; next 1.10; 1.10 date 2003.01.15.23.46.56; author brendan; state Exp; branches; next 1.9; 1.9 date 2002.12.31.06.28.39; author msmith; state Exp; branches; next 1.8; 1.8 date 2002.08.16.14.22.44; author msmith; state Exp; branches; next 1.7; 1.7 date 2002.08.05.14.48.03; author msmith; state Exp; branches; next 1.6; 1.6 date 2002.05.03.15.04.56; author msmith; state Exp; branches; next 1.5; 1.5 date 2002.04.05.09.28.25; author msmith; state Exp; branches; next 1.4; 1.4 date 2002.02.11.09.11.18; author msmith; state Exp; branches; next 1.3; 1.3 date 2001.10.20.07.40.09; author jack; state Exp; branches; next 1.2; 1.2 date 2001.10.20.04.41.54; author jack; state Exp; branches; next 1.1; 1.1 date 2001.09.10.02.28.47; author jack; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2001.09.10.02.28.47; author jack; state Exp; branches; next ; desc @@ 1.23 log @httpp goes through the rinse cycle @ text @/* Httpp.c ** ** http parsing engine */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include #include "httpp.h" #ifdef _WIN32 #define strcasecmp stricmp #endif #define MAX_HEADERS 32 /* internal functions */ /* misc */ static char *_lowercase(char *str); /* for avl trees */ static int _compare_vars(void *compare_arg, void *a, void *b); static int _free_vars(void *key); http_parser_t *httpp_create_parser(void) { return (http_parser_t *)malloc(sizeof(http_parser_t)); } void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults) { http_varlist_t *list; parser->req_type = httpp_req_none; parser->uri = NULL; parser->vars = avl_tree_new(_compare_vars, NULL); parser->queryvars = avl_tree_new(_compare_vars, NULL); /* now insert the default variables */ list = defaults; while (list != NULL) { httpp_setvar(parser, list->var.name, list->var.value); list = list->next; } } static int split_headers(char *data, unsigned long len, char **line) { /* first we count how many lines there are ** and set up the line[] array */ int lines = 0; unsigned long i; line[lines] = data; for (i = 0; i < len && lines < MAX_HEADERS; i++) { if (data[i] == '\r') data[i] = '\0'; if (data[i] == '\n') { lines++; data[i] = '\0'; if (i + 1 < len) { if (data[i + 1] == '\n' || data[i + 1] == '\r') break; line[lines] = &data[i + 1]; } } } i++; while (data[i] == '\n') i++; return lines; } static void parse_headers(http_parser_t *parser, char **line, int lines) { int i,l; int whitespace, where, slen; char *name = NULL; char *value = NULL; /* parse the name: value lines. */ for (l = 1; l < lines; l++) { where = 0; whitespace = 0; name = line[l]; value = NULL; slen = strlen(line[l]); for (i = 0; i < slen; i++) { if (line[l][i] == ':') { whitespace = 1; line[l][i] = '\0'; } else { if (whitespace) { whitespace = 0; while (i < slen && line[l][i] == ' ') i++; if (i < slen) value = &line[l][i]; break; } } } if (name != NULL && value != NULL) { httpp_setvar(parser, _lowercase(name), value); name = NULL; value = NULL; } } } int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri) { char *data; char *line[MAX_HEADERS]; int lines, slen,i, whitespace=0, where=0,code; char *version=NULL, *resp_code=NULL, *message=NULL; if(http_data == NULL) return 0; /* make a local copy of the data, including 0 terminator */ data = (char *)malloc(len+1); if (data == NULL) return 0; memcpy(data, http_data, len); data[len] = 0; lines = split_headers(data, len, line); /* In this case, the first line contains: * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK */ slen = strlen(line[0]); version = line[0]; for(i=0; i < slen; i++) { if(line[0][i] == ' ') { line[0][i] = 0; whitespace = 1; } else if(whitespace) { whitespace = 0; where++; if(where == 1) resp_code = &line[0][i]; else { message = &line[0][i]; break; } } } if(version == NULL || resp_code == NULL || message == NULL) { free(data); return 0; } httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code); code = atoi(resp_code); if(code < 200 || code >= 300) { httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message); } httpp_setvar(parser, HTTPP_VAR_URI, uri); httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE"); parse_headers(parser, line, lines); free(data); return 1; } static int hex(char c) { if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; } static char *url_escape(char *src) { int len = strlen(src); unsigned char *decoded; int i; char *dst; int done = 0; decoded = calloc(1, len + 1); dst = decoded; for(i=0; i < len; i++) { switch(src[i]) { case '%': if(i+2 >= len) { free(decoded); return NULL; } if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) { free(decoded); return NULL; } *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]); i+= 2; break; case '#': done = 1; break; case 0: free(decoded); return NULL; break; default: *dst++ = src[i]; break; } if(done) break; } *dst = 0; /* null terminator */ return decoded; } /** TODO: This is almost certainly buggy in some cases */ static void parse_query(http_parser_t *parser, char *query) { int len; int i=0; char *key = query; char *val=NULL; if(!query || !*query) return; len = strlen(query); while(ireq_type = httpp_req_source; httpp_setvar(parser, HTTPP_VAR_URI, "/"); httpp_setvar(parser, HTTPP_VAR_ICYPASSWORD, line[0]); httpp_setvar(parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE"); /* This protocol is evil */ httpp_setvar(parser, HTTPP_VAR_VERSION, "666"); parse_headers(parser, line, lines); free(data); return 1; } int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len) { char *data, *tmp; char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */ int i; int lines; char *req_type = NULL; char *uri = NULL; char *version = NULL; int whitespace, where, slen; if (http_data == NULL) return 0; /* make a local copy of the data, including 0 terminator */ data = (char *)malloc(len+1); if (data == NULL) return 0; memcpy(data, http_data, len); data[len] = 0; lines = split_headers(data, len, line); /* parse the first line special ** the format is: ** REQ_TYPE URI VERSION ** eg: ** GET /index.html HTTP/1.0 */ where = 0; whitespace = 0; slen = strlen(line[0]); req_type = line[0]; for (i = 0; i < slen; i++) { if (line[0][i] == ' ') { whitespace = 1; line[0][i] = '\0'; } else { /* we're just past the whitespace boundry */ if (whitespace) { whitespace = 0; where++; switch (where) { case 1: uri = &line[0][i]; break; case 2: version = &line[0][i]; break; } } } } if (strcasecmp("GET", req_type) == 0) { parser->req_type = httpp_req_get; } else if (strcasecmp("POST", req_type) == 0) { parser->req_type = httpp_req_post; } else if (strcasecmp("HEAD", req_type) == 0) { parser->req_type = httpp_req_head; } else if (strcasecmp("SOURCE", req_type) == 0) { parser->req_type = httpp_req_source; } else if (strcasecmp("PLAY", req_type) == 0) { parser->req_type = httpp_req_play; } else if (strcasecmp("STATS", req_type) == 0) { parser->req_type = httpp_req_stats; } else { parser->req_type = httpp_req_unknown; } if (uri != NULL && strlen(uri) > 0) { char *query; if((query = strchr(uri, '?')) != NULL) { *query = 0; query++; parse_query(parser, query); } parser->uri = strdup(uri); } else { free(data); return 0; } if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) { tmp[0] = '\0'; if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) { httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version); httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]); } else { free(data); return 0; } } else { free(data); return 0; } if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) { switch (parser->req_type) { case httpp_req_get: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET"); break; case httpp_req_post: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST"); break; case httpp_req_head: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD"); break; case httpp_req_source: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE"); break; case httpp_req_play: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY"); break; case httpp_req_stats: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS"); break; default: break; } } else { free(data); return 0; } if (parser->uri != NULL) { httpp_setvar(parser, HTTPP_VAR_URI, parser->uri); } else { free(data); return 0; } parse_headers(parser, line, lines); free(data); return 1; } void httpp_setvar(http_parser_t *parser, char *name, char *value) { http_var_t *var; if (name == NULL || value == NULL) return; var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; var->name = strdup(name); var->value = strdup(value); if (httpp_getvar(parser, name) == NULL) { avl_insert(parser->vars, (void *)var); } else { avl_delete(parser->vars, (void *)var, _free_vars); avl_insert(parser->vars, (void *)var); } } char *httpp_getvar(http_parser_t *parser, char *name) { http_var_t var; http_var_t *found; void *fp; fp = &found; var.name = name; var.value = NULL; if (avl_get_by_key(parser->vars, &var, fp) == 0) return found->value; else return NULL; } void httpp_set_query_param(http_parser_t *parser, char *name, char *value) { http_var_t *var; if (name == NULL || value == NULL) return; var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; var->name = strdup(name); var->value = url_escape(value); if (httpp_get_query_param(parser, name) == NULL) { avl_insert(parser->queryvars, (void *)var); } else { avl_delete(parser->queryvars, (void *)var, _free_vars); avl_insert(parser->queryvars, (void *)var); } } char *httpp_get_query_param(http_parser_t *parser, char *name) { http_var_t var; http_var_t *found; void *fp; fp = &found; var.name = name; var.value = NULL; if (avl_get_by_key(parser->queryvars, (void *)&var, fp) == 0) return found->value; else return NULL; } void httpp_clear(http_parser_t *parser) { parser->req_type = httpp_req_none; if (parser->uri) free(parser->uri); parser->uri = NULL; avl_tree_free(parser->vars, _free_vars); avl_tree_free(parser->queryvars, _free_vars); parser->vars = NULL; } void httpp_destroy(http_parser_t *parser) { httpp_clear(parser); free(parser); } static char *_lowercase(char *str) { char *p = str; for (; *p != '\0'; p++) *p = tolower(*p); return str; } static int _compare_vars(void *compare_arg, void *a, void *b) { http_var_t *vara, *varb; vara = (http_var_t *)a; varb = (http_var_t *)b; return strcmp(vara->name, varb->name); } static int _free_vars(void *key) { http_var_t *var; var = (http_var_t *)key; if (var->name) free(var->name); if (var->value) free(var->value); free(var); return 1; } @ 1.22 log @ermmm, let's use the right operator. @ text @d34 2 a35 2 int _compare_vars(void *compare_arg, void *a, void *b); int _free_vars(void *key); d556 1 a556 1 int _compare_vars(void *compare_arg, void *a, void *b) d566 1 a566 1 int _free_vars(void *key) @ 1.21 log @minor cleanup, removes compiler warning, makes it static, and doesn't re-evaluate string length each time. @ text @d550 1 a550 1 for (; *p |= '\0'; p++) @ 1.20 log @gcc 3.3 warns: dereferencing type-punned pointer will break strict-aliasing rules @ text @d31 1 a31 1 char *_lowercase(char *str); d547 1 a547 1 char *_lowercase(char *str) d549 3 a551 3 long i; for (i = 0; i < strlen(str); i++) str[i] = tolower(str[i]); @ 1.19 log @Karl's patch for freebsd, minus the sys/select.h test which breaks on OS X. Also enables IPV6 in libshout! @ text @d481 1 d483 1 d487 1 a487 1 if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0) d518 1 d520 1 d524 1 a524 1 if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0) @ 1.18 log @Brendan was getting pissed off about inconsistent indentation styles. Convert all tabs to 4 spaces. All code must now use 4 space indents. @ text @d15 3 @ 1.17 log @reduce include file namespace clutter for libshout and the associated smaller libs. @ text @d36 1 a36 1 return (http_parser_t *)malloc(sizeof(http_parser_t)); d41 1 a41 1 http_varlist_t *list; d43 11 a53 11 parser->req_type = httpp_req_none; parser->uri = NULL; parser->vars = avl_tree_new(_compare_vars, NULL); parser->queryvars = avl_tree_new(_compare_vars, NULL); /* now insert the default variables */ list = defaults; while (list != NULL) { httpp_setvar(parser, list->var.name, list->var.value); list = list->next; } d58 4 a61 4 /* first we count how many lines there are ** and set up the line[] array */ int lines = 0; d63 11 a73 11 line[lines] = data; for (i = 0; i < len && lines < MAX_HEADERS; i++) { if (data[i] == '\r') data[i] = '\0'; if (data[i] == '\n') { lines++; data[i] = '\0'; if (i + 1 < len) { if (data[i + 1] == '\n' || data[i + 1] == '\r') break; line[lines] = &data[i + 1]; d75 2 a76 2 } } d78 2 a79 2 i++; while (data[i] == '\n') i++; d87 35 a121 35 int whitespace, where, slen; char *name = NULL; char *value = NULL; /* parse the name: value lines. */ for (l = 1; l < lines; l++) { where = 0; whitespace = 0; name = line[l]; value = NULL; slen = strlen(line[l]); for (i = 0; i < slen; i++) { if (line[l][i] == ':') { whitespace = 1; line[l][i] = '\0'; } else { if (whitespace) { whitespace = 0; while (i < slen && line[l][i] == ' ') i++; if (i < slen) value = &line[l][i]; break; } } } if (name != NULL && value != NULL) { httpp_setvar(parser, _lowercase(name), value); name = NULL; value = NULL; } } d126 4 a129 4 char *data; char *line[MAX_HEADERS]; int lines, slen,i, whitespace=0, where=0,code; char *version=NULL, *resp_code=NULL, *message=NULL; d131 2 a132 2 if(http_data == NULL) return 0; d134 5 a138 39 /* make a local copy of the data, including 0 terminator */ data = (char *)malloc(len+1); if (data == NULL) return 0; memcpy(data, http_data, len); data[len] = 0; lines = split_headers(data, len, line); /* In this case, the first line contains: * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK */ slen = strlen(line[0]); version = line[0]; for(i=0; i < slen; i++) { if(line[0][i] == ' ') { line[0][i] = 0; whitespace = 1; } else if(whitespace) { whitespace = 0; where++; if(where == 1) resp_code = &line[0][i]; else { message = &line[0][i]; break; } } } if(version == NULL || resp_code == NULL || message == NULL) { free(data); return 0; } httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code); code = atoi(resp_code); if(code < 200 || code >= 300) { httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message); } d140 1 a140 2 httpp_setvar(parser, HTTPP_VAR_URI, uri); httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE"); d142 20 a161 1 parse_headers(parser, line, lines); d163 4 a166 1 free(data); d168 14 a181 1 return 1; d186 8 a193 8 if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; d198 39 a236 39 int len = strlen(src); unsigned char *decoded; int i; char *dst; int done = 0; decoded = calloc(1, len + 1); dst = decoded; for(i=0; i < len; i++) { switch(src[i]) { case '%': if(i+2 >= len) { free(decoded); return NULL; } if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) { free(decoded); return NULL; } *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]); i+= 2; break; case '#': done = 1; break; case 0: free(decoded); return NULL; break; default: *dst++ = src[i]; break; } if(done) break; } d238 1 a238 1 *dst = 0; /* null terminator */ d240 1 a240 1 return decoded; d246 29 a274 29 int len; int i=0; char *key = query; char *val=NULL; if(!query || !*query) return; len = strlen(query); while(ireq_type = httpp_req_get; } else if (strcasecmp("POST", req_type) == 0) { parser->req_type = httpp_req_post; } else if (strcasecmp("HEAD", req_type) == 0) { parser->req_type = httpp_req_head; } else if (strcasecmp("SOURCE", req_type) == 0) { parser->req_type = httpp_req_source; } else if (strcasecmp("PLAY", req_type) == 0) { parser->req_type = httpp_req_play; } else if (strcasecmp("STATS", req_type) == 0) { parser->req_type = httpp_req_stats; } else { parser->req_type = httpp_req_unknown; } if (uri != NULL && strlen(uri) > 0) { char *query; if((query = strchr(uri, '?')) != NULL) { *query = 0; query++; parse_query(parser, query); } d397 10 a406 2 parser->uri = strdup(uri); } else { d411 27 a437 48 if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) { tmp[0] = '\0'; if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) { httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version); httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]); } else { free(data); return 0; } } else { free(data); return 0; } if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) { switch (parser->req_type) { case httpp_req_get: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET"); break; case httpp_req_post: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST"); break; case httpp_req_head: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD"); break; case httpp_req_source: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE"); break; case httpp_req_play: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY"); break; case httpp_req_stats: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS"); break; default: break; } } else { free(data); return 0; } if (parser->uri != NULL) { httpp_setvar(parser, HTTPP_VAR_URI, parser->uri); } else { free(data); return 0; } d439 6 a444 1 parse_headers(parser, line, lines); d446 3 a448 1 free(data); d450 1 a450 1 return 1; d455 1 a455 1 http_var_t *var; d457 2 a458 2 if (name == NULL || value == NULL) return; d460 2 a461 2 var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; d463 9 a471 9 var->name = strdup(name); var->value = strdup(value); if (httpp_getvar(parser, name) == NULL) { avl_insert(parser->vars, (void *)var); } else { avl_delete(parser->vars, (void *)var, _free_vars); avl_insert(parser->vars, (void *)var); } d476 2 a477 2 http_var_t var; http_var_t *found; d479 2 a480 2 var.name = name; var.value = NULL; d482 4 a485 4 if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0) return found->value; else return NULL; d490 1 a490 1 http_var_t *var; d492 2 a493 2 if (name == NULL || value == NULL) return; d495 2 a496 2 var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; d498 9 a506 9 var->name = strdup(name); var->value = url_escape(value); if (httpp_get_query_param(parser, name) == NULL) { avl_insert(parser->queryvars, (void *)var); } else { avl_delete(parser->queryvars, (void *)var, _free_vars); avl_insert(parser->queryvars, (void *)var); } d511 2 a512 2 http_var_t var; http_var_t *found; d514 2 a515 2 var.name = name; var.value = NULL; d517 4 a520 4 if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0) return found->value; else return NULL; d525 7 a531 7 parser->req_type = httpp_req_none; if (parser->uri) free(parser->uri); parser->uri = NULL; avl_tree_free(parser->vars, _free_vars); avl_tree_free(parser->queryvars, _free_vars); parser->vars = NULL; d536 2 a537 2 httpp_clear(parser); free(parser); d542 3 a544 3 long i; for (i = 0; i < strlen(str); i++) str[i] = tolower(str[i]); d546 1 a546 1 return str; d551 1 a551 1 http_var_t *vara, *varb; d553 2 a554 2 vara = (http_var_t *)a; varb = (http_var_t *)b; d556 1 a556 1 return strcmp(vara->name, varb->name); d561 1 a561 1 http_var_t *var; d563 1 a563 1 var = (http_var_t *)key; d565 5 a569 5 if (var->name) free(var->name); if (var->value) free(var->value); free(var); d571 1 a571 1 return 1; @ 1.16 log @include the automake config.h file if the application defines one @ text @d16 1 a16 1 #include "avl.h" @ 1.15 log @Set another parameter in the icy protocol parse that logging expects @ text @d6 4 @ 1.14 log @Added support for shoutcast login protocol (ewww...) @ text @d299 1 @ 1.13 log @Use gnu archive ACX_PTHREAD macro to figure out how to compile thread support. Also make it possible to build libshout without threads, albeit without locking in the resolver or avl trees. New option --disable-pthread too. @ text @d273 36 d387 4 a390 2 } else parser->uri = NULL; @ 1.12 log @Fix some warnings, fix cflags. @ text @a11 1 #include "thread.h" @ 1.11 log @Indentation again, don't mind me @ text @d58 2 a59 1 int i, lines = 0; @ 1.10 log @Make indentation consistent before doing other work @ text @d472 1 a472 1 var.value = NULL; @ 1.9 log @mp3 metadata complete. Still untested. @ text @d43 1 a43 1 parser->queryvars = avl_tree_new(_compare_vars, NULL); d122 4 a125 4 char *data; char *line[MAX_HEADERS]; int lines, slen,i, whitespace=0, where=0,code; char *version=NULL, *resp_code=NULL, *message=NULL; d127 2 a128 2 if(http_data == NULL) return 0; d134 1 a134 1 data[len] = 0; d136 1 a136 1 lines = split_headers(data, len, line); d138 20 a157 22 /* In this case, the first line contains: * VERSION RESPONSE_CODE MESSAGE, such as * HTTP/1.0 200 OK */ slen = strlen(line[0]); version = line[0]; for(i=0; i < slen; i++) { if(line[0][i] == ' ') { line[0][i] = 0; whitespace = 1; } else if(whitespace) { whitespace = 0; where++; if(where == 1) resp_code = &line[0][i]; else { message = &line[0][i]; break; } } } d159 4 a162 10 if(version == NULL || resp_code == NULL || message == NULL) { free(data); return 0; } httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code); code = atoi(resp_code); if(code < 200 || code >= 300) { httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message); } d164 7 a170 1 httpp_setvar(parser, HTTPP_VAR_URI, uri); d173 1 a173 1 parse_headers(parser, line, lines); d182 8 a189 8 if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; d194 39 a232 39 int len = strlen(src); unsigned char *decoded; int i; char *dst; int done = 0; decoded = calloc(1, len + 1); dst = decoded; for(i=0; i < len; i++) { switch(src[i]) { case '%': if(i+2 >= len) { free(decoded); return NULL; } if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) { free(decoded); return NULL; } *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]); i+= 2; break; case '#': done = 1; break; case 0: free(decoded); return NULL; break; default: *dst++ = src[i]; break; } if(done) break; } d234 1 a234 1 *dst = 0; /* null terminator */ d236 1 a236 1 return decoded; d242 29 a270 30 int len; int i=0; char *key = query; char *val=NULL; if(!query || !*query) return; len = strlen(query); while(iuri != NULL) { d403 1 a403 1 parse_headers(parser, line, lines); d437 1 a437 1 var.value = NULL; d493 2 a494 2 httpp_clear(parser); free(parser); @ 1.8 log @bugfixes for httpp_parse_response @ text @d43 1 d182 94 d345 9 a353 1 if (uri != NULL && strlen(uri) > 0) d355 1 d442 1 a442 1 var.value = NULL; d450 35 d492 1 @ 1.7 log @Cleaned up version of Ciaran Anscomb's relaying patch. @ text @d165 1 a168 2 free(data); return 0; d172 1 a172 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "RELAY"); @ 1.6 log @Memory leaks. Lots of little ones. @ text @d52 1 a52 1 int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len) a53 21 char *data, *tmp; char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */ int i, l, retlen; int lines; char *req_type = NULL; char *uri = NULL; char *version = NULL; char *name = NULL; char *value = NULL; int whitespace, where; int slen; if (http_data == NULL) return 0; /* make a local copy of the data, including 0 terminator */ data = (char *)malloc(len+1); if (data == NULL) return 0; memcpy(data, http_data, len); data[len] = 0; d57 1 a57 1 lines = 0; d75 128 a202 1 retlen = i; d298 1 a298 1 if (parser->uri != NULL) { d305 1 a305 31 /* parse the name: value lines. */ for (l = 1; l < lines; l++) { where = 0; whitespace = 0; name = line[l]; value = NULL; slen = strlen(line[l]); for (i = 0; i < slen; i++) { if (line[l][i] == ':') { whitespace = 1; line[l][i] = '\0'; } else { if (whitespace) { whitespace = 0; while (i < slen && line[l][i] == ' ') i++; if (i < slen) value = &line[l][i]; break; } } } if (name != NULL && value != NULL) { httpp_setvar(parser, _lowercase(name), value); name = NULL; value = NULL; } } d309 1 a309 1 return retlen; @ 1.5 log @Buffer overflows. Requires a change to the format plugin interface - jack: if you want this done differently, feel free to change it (or ask me to). @ text @d271 1 a271 1 void httpp_destroy(http_parser_t *parser) d279 6 @ 1.4 log @Bunch of fixes: - connections are now matched to format plugins based on content-type headers, and are rejected if there isn't a format handler for that content-type, or there is no content-type at all. - format_vorbis now handles pages with granulepos of -1 in the headers correctly (this happens if the headers are fairly large, because of many comments, for example). - various #include fixes. - buffer overflow in httpp.c fixed. @ text @d6 2 d20 2 d55 1 a55 1 char *line[32]; /* limited to 32 lines, should be more than enough */ d80 1 a80 1 for (i = 0; i < len; i++) { @ 1.3 log @Thanks to Akos Maroy for this. These variables need to be uppercase always in order to comply with the HTTP specification. While not a problem internal to icecast, they were slipping into the log files and breaking some less-than-robust parsers. @ text @d65 2 a66 2 /* make a local copy of the data */ data = (char *)malloc(len); d69 1 d81 3 a83 3 if (i + 1 < len) if (data[i + 1] == '\n' || data[i + 1] == '\r') { data[i] = '\0'; a84 3 } data[i] = '\0'; if (i < len - 1) d86 1 @ 1.2 log @Win32 compatibility courtesy of Oddsock. @ text @d150 1 a150 1 httpp_setvar(parser, HTTPP_VAR_PROTOCOL, _lowercase(version)); d164 1 a164 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "get"); d167 1 a167 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "post"); d170 1 a170 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "head"); d173 1 a173 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "source"); d176 1 a176 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "play"); d179 1 a179 1 httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "stats"); @ 1.1 log @Initial revision @ text @d14 4 d54 5 a58 4 char *req_type; char *uri; char *version; char *name, *value; @ 1.1.1.1 log @move to cvs @ text @@