📄 httpp.c,v
字号:
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.23date 2003.07.07.01.49.27; author brendan; state Exp;branches;next 1.22;1.22date 2003.06.18.15.52.25; author karl; state Exp;branches;next 1.21;1.21date 2003.06.18.11.13.11; author karl; state Exp;branches;next 1.20;1.20date 2003.06.09.22.30.09; author brendan; state Exp;branches;next 1.19;1.19date 2003.06.05.17.09.12; author brendan; state Exp;branches;next 1.18;1.18date 2003.03.15.02.10.18; author msmith; state Exp;branches;next 1.17;1.17date 2003.03.09.22.56.46; author karl; state Exp;branches;next 1.16;1.16date 2003.03.08.16.05.38; author karl; state Exp;branches;next 1.15;1.15date 2003.03.08.05.27.17; author msmith; state Exp;branches;next 1.14;1.14date 2003.03.08.04.57.02; author msmith; state Exp;branches;next 1.13;1.13date 2003.03.06.01.55.20; author brendan; state Exp;branches;next 1.12;1.12date 2003.01.17.09.01.04; author msmith; state Exp;branches;next 1.11;1.11date 2003.01.16.05.48.31; author brendan; state Exp;branches;next 1.10;1.10date 2003.01.15.23.46.56; author brendan; state Exp;branches;next 1.9;1.9date 2002.12.31.06.28.39; author msmith; state Exp;branches;next 1.8;1.8date 2002.08.16.14.22.44; author msmith; state Exp;branches;next 1.7;1.7date 2002.08.05.14.48.03; author msmith; state Exp;branches;next 1.6;1.6date 2002.05.03.15.04.56; author msmith; state Exp;branches;next 1.5;1.5date 2002.04.05.09.28.25; author msmith; state Exp;branches;next 1.4;1.4date 2002.02.11.09.11.18; author msmith; state Exp;branches;next 1.3;1.3date 2001.10.20.07.40.09; author jack; state Exp;branches;next 1.2;1.2date 2001.10.20.04.41.54; author jack; state Exp;branches;next 1.1;1.1date 2001.09.10.02.28.47; author jack; state Exp;branches 1.1.1.1;next ;1.1.1.1date 2001.09.10.02.28.47; author jack; state Exp;branches;next ;desc@@1.23log@httpp goes through the rinse cycle@text@/* Httpp.c**** http parsing engine*/#ifdef HAVE_CONFIG_H #include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <avl/avl.h>#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(i<len) { switch(query[i]) { case '&': query[i] = 0; if(val && key) httpp_set_query_param(parser, key, val); key = query+i+1; break; case '=': query[i] = 0; val = query+i+1; break; } i++; } if(val && key) { httpp_set_query_param(parser, key, val); }}/* The old shoutcast procotol. Don't look at this, it's really nasty */int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len){ char *data; char *line[MAX_HEADERS]; int lines; if(http_data == NULL) return 0; data = malloc(len + 1); memcpy(data, http_data, len); data[len] = 0; lines = split_headers(data, len, line); /* Now, this protocol looks like: * sourcepassword\n * headers: as normal\n" * \n */ parser->req_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -