⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libhttp.c

📁 this ebook is for GSM if any one has interest in it you can take it
💻 C
字号:
#include <sys/socket.h>#include <sys/types.h>#include <sys/time.h>#include <event.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include <strings.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <glib/glist.h>#include "libhttp.h"//#define DEBUG#ifdef DEBUG#define Dprintf		printf#else#define Dprintf( a... )#endifint http_get_cmd(char *cmd) {	if (strcasecmp("GET", cmd) == 0)		return HC_CMD_GET;	if (strcasecmp("POST", cmd) == 0)		return HC_CMD_POST;	if (strcasecmp("HEAD", cmd) == 0)		return HC_CMD_HEAD;	return HC_CMD_UNKNOWN;}/* Split line into string elements seperated by space or tab */static int split_string_by_space(char *input, char **elem, int max) {	int	no;	char	*i=input;	for(no=0;no<max;) {		/* Skip space or tab */		while(*i == ' ' || *i == '\t' || *i == '\r' || *i == '\n')			*i++=0x0;		if(*i == 0x0)			break;		/* Store pointer */		elem[no++]=i;		/* Skip non space */		while(*i != ' ' && *i != '\t' && *i != 0x0)			i++;		/* End of String ? */		if(*i == 0x0)			break;	}	return no;}/* * Parse a string like HTTP/1.0 or HTTP/1.1 and return * the protocol and version * * * HP_UNKNOWN		- Unknown protocol * HP_HTTP		- Seems to be HTTP without/with broken/with unknown version * HP_HTTP10		- HTTP/1.0 * HP_HTTP11		- HTTP/1.1 * */static int http_parse_proto(char *pstr) {	char		*pver, *dotptr, *endptr;	int		major, minor;	/* Check if we are dealing with HTTP */	if (strncasecmp(pstr, "HTTP", 4) != 0)		return HP_UNKNOWN;	pver=strchr(pstr, '/');	if (!pver)		return HP_HTTP;	major=strtol(++pver, &dotptr, 10);	/* 1.0 or 1.1 */	if (*dotptr != '.')		return HP_HTTP;	minor=strtol(++dotptr, &endptr, 10);	/* String should end after [major].[minor] */	if (*endptr != 0x0)		return HP_HTTP;	Dprintf("%s: major %d minor %d\n", __FUNCTION__, major, minor);	if (major == 1 && minor == 0)		return HP_HTTP10;	if (major == 1 && minor == 1)		return HP_HTTP11;	return HP_HTTP;}/* * Read the first line - PUT/GET/POST etc ... * * GET <url> HTTP/<version> * */static int http_parse_command_url(struct http_connection *hc, struct evbuffer *input) {	char	*p=(char *) EVBUFFER_DATA(input);	char	*elem[10];	int	no;	no=split_string_by_space(p, elem, 10);	/* Need "CMD URL PROTO/VERSION" which makes it 3 parms */	if (no != 3)		return 0;	if ((hc->cmd=http_get_cmd(elem[0])) == HC_CMD_UNKNOWN)		return 0;	hc->url=strdup(elem[1]);	hc->proto=http_parse_proto(elem[2]);	if (hc->proto == HP_HTTP11)		hc->keepalive=1;	else		hc->keepalive=0;	return 1;}static int http_parse_attrib(struct http_connection *hc, struct evbuffer *input) {	char	*p=(char *) EVBUFFER_DATA(input);	struct	http_attrib	*ha;	char	*token, *value;	token=p;	while(*p != ':' && *p != ' ' && *p != 0x0)		p++;	/* Did we find the colon as delimiter ?	 * If not something went really wrong - terminate the connection	 */	if (*p == ':')		*p++=0x0;	else		return 0;	while(*p == ' ' || *p == '\t')		p++;	value=p;	ha=malloc(sizeof(struct http_attrib));	ha->token=strdup(token);	ha->value=strdup(value);	hc->attrib=g_list_append(hc->attrib, ha);	Dprintf("%s: %s %s\n", __FUNCTION__, token, value);	return 1;}/* * HTTP/1.1 404 Not Found * Date: Wed, 17 May 2006 17:33:00 GMT * Server: Apache/2.0.54 (Debian GNU/Linux) * Content-Length: 310 * Connection: close * Content-Type: text/html; charset=iso-8859-1 * */static char *http_static_msg_404 ="<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"> \<html><head> \<title>404 Not Found</title> \</head><body> \<h1>404 Not Found</h1> \</body> \</html>";int http_url_handler_404(struct http_connection *hc, int cbtype, void *arg) {	int		err;	Dprintf("%s: cbtype %d\n", __FUNCTION__, cbtype);	/* Answer with 404 page on QUERY */	if (cbtype == HCB_QUERY) {		err=http_return_simple(hc,				"404 Not found",				"text/html",				http_static_msg_404,				strlen(http_static_msg_404));		return 1;	}	/*	 * Drop connection if socket gets writeable again	 * or we have an error	 */	http_request_end(hc);	return 1;}size_t http_get_queue(struct http_connection *hc) {	return EVBUFFER_LENGTH(hc->bev->output);}/* * Function to return an http chunk with previous unknown size. HTTP/1.1 allows * for chunked transfers which HTTP/1.0 doesnt know about. There is no legal way * to do this so we hope our best. * */int http_return_stream(struct http_connection *hc, void *data, size_t datalen) {	/* We are chunked and done sending - end session */	if (!data) {		/* Chunked transfer - send a 0 chunk */		if (hc->proto == HP_HTTP11) {			evbuffer_add_printf(hc->evb,"0\r\n\r\n");			bufferevent_write_buffer(hc->bev, hc->evb);		}		hc->status=HC_STATUS_END;		return 1;	}	/* In case of Transfer-Encoding: chunked send a chunk - otherwise just data */	if (hc->proto == HP_HTTP11) {		evbuffer_add_printf(hc->evb,"%x\r\n", datalen);		evbuffer_add(hc->evb, data, datalen);		evbuffer_add_printf(hc->evb, "\r\n");	} else {		evbuffer_add(hc->evb, data, datalen);	}	bufferevent_write_buffer(hc->bev, hc->evb);	Dprintf("%s: output buffer len %d\n", __FUNCTION__,			EVBUFFER_LENGTH(hc->bev->output));	return 1;}int http_header_add(struct http_connection *hc, char *fmt, ...) {	va_list ap;	va_start(ap, fmt);	hc->hsize+=vsprintf(&hc->hdr[hc->hsize], fmt, ap);	hc->hdr[hc->hsize++]=0x0d;	hc->hdr[hc->hsize++]=0x0a;	hc->hdr[hc->hsize]=0x00;	va_end(ap);	return 0;}int http_header_end(struct http_connection *hc) {	if (hc->keepalive)		http_header_add(hc, "Connection: keep-alive");	else		http_header_add(hc, "Connection: close");	hc->hsize+=sprintf(&hc->hdr[hc->hsize], "\r\n");	bufferevent_write(hc->bev, hc->hdr, hc->hsize);	hc->hsize=0;	return 0;}int http_header_clength(struct http_connection *hc, ssize_t length) {	if (length >= 0)		http_header_add(hc, "Content-Length: %d", length);	else {		if (hc->proto == HP_HTTP11)			http_header_add(hc, "Transfer-Encoding: chunked");	}	return 0;}int http_header_nocache(struct http_connection *hc) {	http_header_add(hc, "Pragma: no-cache");	http_header_add(hc, "Cache-Control: no-cache");	return 0;}int http_header_start(struct http_connection *hc, char *result, char *type) {	struct tm	*tm;	time_t		t;	/* Wed, 17 May 2006 17:33:00 GMT */	t=time(NULL);	tm=gmtime(&t);	hc->hsize=0;	hc->hsize+=sprintf(&hc->hdr[hc->hsize],			"HTTP/1.1 %s\r\n", result);	hc->hsize+=sprintf(&hc->hdr[hc->hsize],			"Date: ");	hc->hsize+=strftime(&hc->hdr[hc->hsize],			MAX_HEADER_SIZE-hc->hsize,			"%a, %d %b %Y %H:%M:%S %Z\r\n", tm);	http_header_add(hc, "Content-Type: %s", type);	return 0;}/* * Send a simple request answer: * Content-Length: is set - No chunked, partial transfer, * After requests gets answered - connection will be closed * */int http_return_simple(struct http_connection *hc, char *result,		char *type, void *data, size_t datalen) {	http_header_start(hc, result, type);	http_header_clength(hc, datalen);	http_header_end(hc);	bufferevent_write(hc->bev, data, datalen);	hc->status=HC_STATUS_END;	return 1;}static int http_process_query(struct http_connection *hc) {	struct http_url *hu;	/*	 * FIXME Need to parse url to parameters, unescaping	 * characters etc ...	 *	 */	hu=g_hash_table_lookup(hc->server->urls, hc->url);	Dprintf("%s: hu %p\n", __FUNCTION__, hu);	if (hu) {		hc->url_handler=hu->cb;		return hc->url_handler(hc, HCB_QUERY, hu->arg);	}	return hc->url_handler(hc, HCB_QUERY, NULL);}static int http_read_head(struct http_connection *hc, struct bufferevent *bev) {	struct evbuffer	*input = EVBUFFER_INPUT(bev);	u_char		*eol, *p;	int		err, drainlen;	while((eol=evbuffer_find(input, (u_char *) "\n", 1)) != NULL) {		/* get begin of line */		p=EVBUFFER_DATA(input);		/* Line length */		drainlen=eol-p+1;		/*		 * Remove \n and if exists the \r		 * FIXME Is this robust enough ?		 */		*eol=0x0;		if (eol > p && *(eol-1) == '\r')			*(--eol) = 0x0;		if (!hc->url) {			/* Did we have the first line with command and url ? */			err=http_parse_command_url(hc, input);		} else if (eol == p) {			err=http_process_query(hc);		} else {			err=http_parse_attrib(hc, input);		}		/* tell buffer to remove leading bytes */		evbuffer_drain(input, drainlen);		if (!err)			return 0;	}	return 1;}/* * Free Request based resources from the http_connection * */static void http_request_free(struct http_connection *hc) {	GList			*item;	struct http_attrib	*ha;	if (hc->url)		free(hc->url);	hc->url=NULL;	/* Free http attributes */	while((item=g_list_first(hc->attrib))) {		hc->attrib=g_list_remove_link(hc->attrib, item);		ha=item->data;		free(ha->token);		free(ha->value);		free(ha);		g_list_free(item);	}}/* * Drop the connection in case of error of non keepalive */void http_drop_connection(struct http_connection *hc) {	struct http_server	*hs=hc->server;	Dprintf("%s:%d\n", __FUNCTION__, __LINE__);	hs->conn=g_list_remove(hs->conn, hc);	bufferevent_disable(hc->bev, EV_READ|EV_WRITE);	bufferevent_free(hc->bev);	http_request_free(hc);	close(hc->fd);	evbuffer_free(hc->evb);	free(hc);}/* * Application signals http request end - either * drop the connection or simply free the request * resources. * */void http_request_end(struct http_connection *hc) {	if (!hc->keepalive) {		http_drop_connection(hc);	} else {		http_request_free(hc);		hc->status=HC_STATUS_HEAD;		hc->url_handler=&http_url_handler_404;		hc->hsize=0;	}}/* * Callback handler for EV_READ of the client connection. If data * arrives for our handler */static void http_cb_read(struct bufferevent *bev, void *arg) {	struct http_connection	*hc=arg;	Dprintf("%s:%d\n", __FUNCTION__, __LINE__);	switch(hc->status) {		case(HC_STATUS_END):			hc->url_handler(hc, HCB_END, hc->arg);			break;		case(HC_STATUS_HEAD):			if (!http_read_head(hc, bev))				hc->url_handler(hc, HCB_ERROR, hc->arg);			break;		case(HC_STATUS_BODY):			hc->url_handler(hc, HCB_READ, hc->arg);			break;	}}static void http_cb_write(struct bufferevent *bev, void *arg) {	struct http_connection	*hc=arg;	Dprintf("%s:%d\n", __FUNCTION__, __LINE__);	if (hc->status != HC_STATUS_END)		hc->url_handler(hc, HCB_WRITE, hc->arg);	if (hc->status == HC_STATUS_END)		hc->url_handler(hc, HCB_END, hc->arg);}static void http_cb_error(struct bufferevent *bev, short what, void *arg) {	struct http_connection	*hc=arg;	Dprintf("%s:%d\n", __FUNCTION__, __LINE__);	hc->url_handler(hc, HCB_ERROR, hc->arg);}static void http_connect(int fd, short ev, void *arg) {	struct http_server	*hs=arg;	struct http_connection	*hc;	struct sockaddr_in	sin;	socklen_t		slen=sizeof(struct sockaddr_in);	int			nfd;	unsigned long		flags;	nfd=accept(fd, (struct sockaddr *) &sin, &slen);	if (nfd < 0)		return;	Dprintf("%s:%d New connection\n", __FUNCTION__, __LINE__);	/* Set new socket O_NONBLOCK */	flags=fcntl(nfd, F_GETFL);	fcntl(nfd, F_SETFL, flags | O_NONBLOCK);	hc=calloc(1, sizeof(struct http_connection));	hc->fd=nfd;	hc->server=hs;	hc->status=HC_STATUS_HEAD;	hc->cid=hs->cid++;	hc->evb=evbuffer_new();	/* Copy remote endpoint sockaddr to http_connection structure */	memcpy(&hc->sin, &sin, sizeof(struct sockaddr_in));	hc->bev=bufferevent_new(hc->fd, http_cb_read, http_cb_write, http_cb_error, hc);	bufferevent_enable(hc->bev, EV_READ);	hc->url_handler=&http_url_handler_404;	hs->conn=g_list_append(hs->conn, hc);}int http_register_url(struct http_server *hs, struct http_url *hu) {	while(hu->url) {		g_hash_table_insert(hs->urls, hu->url, hu);		hu++;	}	return 1;}struct http_server *http_init(int port) {	struct http_server	*hs;	unsigned long		flags;	int			one=1;	hs=calloc(1, sizeof(struct http_server));	hs->port=port;	hs->urls=g_hash_table_new(g_str_hash, g_str_equal);	hs->fd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);	setsockopt(hs->fd, SOL_SOCKET, SO_REUSEADDR,			(void *) &one, sizeof(int));	hs->sin.sin_family=AF_INET;	hs->sin.sin_port=htons(port);	hs->sin.sin_addr.s_addr=INADDR_ANY;	if (bind(hs->fd, (struct sockaddr *) &hs->sin,				sizeof(struct sockaddr_in)))		return NULL;	if (listen(hs->fd, 3))		return NULL;	flags=fcntl(hs->fd, F_GETFL);	fcntl(hs->fd, F_GETFL, flags | O_NONBLOCK);	event_set(&hs->ev, hs->fd, EV_READ|EV_PERSIST, http_connect, (void *) hs);	event_add(&hs->ev, NULL);	return hs;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -