/* * This is a simple driver for Ryan Dahl's hand-bummed C http-parser * package. It is intended to read one HTTP request after another * from a file, nothing more. * * For "feature parity" with the Haskell code in RFC2616.hs, we * allocate and populate a simple structure describing each request, * since that's the sort of thing that many real applications would * themselves do and the library doesn't do this for us. * * For the http-parser source, see http://github.com/ry/http-parser/ *//* * Turn off this preprocessor symbol to have the callbacks do nothing * at all, which "improves performance" by about 50%. */#define LOOK_BUSY#include <assert.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>#include "http_parser.h"structhttp_string{size_tlen;charvalue[0];};structhttp_header{structhttp_string*name;structhttp_string*value;structhttp_header*next;};structhttp_request{structhttp_string*method;structhttp_string*uri;structhttp_header*headers,*last;};structdata{size_tcount;structhttp_requestreq;};staticvoid*xmalloc(size_tsize){void*ptr;if((ptr=malloc(size))==NULL){perror("malloc");exit(1);}returnptr;}staticstructhttp_string*xstrdup(constchar*src,size_tlen,size_textra){structhttp_string*dst=xmalloc(sizeof(*dst)+len+extra);memcpy(dst->value,src,len);dst->len=len;returndst;}staticvoidxstrcat(structhttp_string**dst,constchar*src,size_tlen){structhttp_string*p;if(*dst==NULL){*dst=xstrdup(src,len,0);return;}p=xstrdup((*dst)->value,(*dst)->len,len);memcpy(p->value+(*dst)->len,src,len);p->len+=len;free(*dst);*dst=p;}staticintbegin(http_parser*p){structdata*data=p->data;data->count++;return0;}staticinturl(http_parser*p,constchar*at,size_tlen){#ifdef LOOK_BUSYstructdata*data=p->data;xstrcat(&data->req.uri,at,len);#endifreturn0;}staticintheader_field(http_parser*p,constchar*at,size_tlen){#ifdef LOOK_BUSYstructdata*data=p->data;if(data->req.last&&data->req.last->value==NULL){xstrcat(&data->req.last->name,at,len);}else{structhttp_header*hdr=xmalloc(sizeof(*hdr));hdr->name=xstrdup(at,len,0);hdr->value=NULL;hdr->next=NULL;if(data->req.last!=NULL)data->req.last->next=hdr;data->req.last=hdr;if(data->req.headers==NULL)data->req.headers=hdr;}#endifreturn0;}staticintheader_value(http_parser*p,constchar*at,size_tlen){#ifdef LOOK_BUSYstructdata*data=p->data;xstrcat(&data->req.last->value,at,len);#endifreturn0;}staticintcomplete(http_parser*p){#ifdef LOOK_BUSYstructdata*data=p->data;structhttp_header*hdr,*next;free(data->req.method);free(data->req.uri);for(hdr=data->req.headers;hdr!=NULL;hdr=next){next=hdr->next;free(hdr->name);free(hdr->value);free(hdr);hdr=next;}data->req.method=NULL;data->req.uri=NULL;data->req.headers=NULL;data->req.last=NULL;#endif/* Bludgeon http_parser into understanding that we really want to * keep parsing after a request that in principle ought to close * the "connection". */if(!http_should_keep_alive(p)){p->http_major=1;p->http_minor=1;p->flags&=~6;}return0;}staticvoidparse(constchar*path,intfd){structdatadata;http_parserp;ssize_tnread;http_parser_init(&p,HTTP_REQUEST);p.on_message_begin=begin;p.on_url=url;p.on_header_field=header_field;p.on_header_value=header_value;p.on_message_complete=complete;p.data=&data;data.count=0;data.req.method=NULL;data.req.uri=NULL;data.req.headers=NULL;data.req.last=NULL;do{charbuf[HTTP_MAX_HEADER_SIZE];size_tnp;nread=read(fd,buf,sizeof(buf));np=http_parser_execute(&p,buf,nread);if(np!=nread){fprintf(stderr,"%s: parse failed\n",path);break;}}while(nread>0);printf("%ld\n",(unsignedlong)data.count);}intmain(intargc,char**argv){inti;for(i=1;i<argc;i++){intfd;fd=open(argv[i],O_RDONLY);if(fd==-1){perror(argv[i]);continue;}parse(argv[i],fd);close(fd);}return0;}/* * Local Variables: * c-file-style: "stroustrup" * End: */