forsyth20121205-174063a80cc13 years agoHistory
593 lines · 12.5 KB · Brainfuck
RawDownload
implement Parser; include "sys.m";	sys: Sys;include "draw.m";	draw: Draw;include "bufio.m";include "string.m";	str: String;include "daytime.m";	daytime: Daytime;include "contents.m";	contents : Contents;	Content: import contents;include "cache.m";include "httpd.m";	Private_info: import Httpd;	Internal, TempFail, Unimp, UnkVers, BadCont, BadReq, Syntax, 	BadSearch, NotFound, NoSearch , OnlySearch, Unauth, OK : import Httpd;	include "parser.m";include "date.m";	date : Date;include "alarms.m";	alarms: Alarms;	Alarm: import alarms;include "lock.m";	locks: Lock;	Semaphore: import locks; Error: adt {	num : string;	concise: string;	verbose: string;}; errormsg := array[] of {	Internal => Error("500 Internal Error", "Internal Error",		"This server could not process your request due to an interal error."),	TempFail =>	Error("500 Internal Error", "Temporary Failure",		"The object %s is currently inaccessible.<p>Please try again later."),	Unimp =>	Error("501 Not implemented", "Command not implemented",		"This server does not implement the %s command."),	UnkVers =>	Error("501 Not Implemented", "Unknown http version",		"This server does not know how to respond to http version %s."),	BadCont =>	Error("501 Not Implemented", "Impossible format",		"This server cannot produce %s in any of the formats your client accepts."),	BadReq =>	Error("400 Bad Request", "Strange Request",		"Your client sent a query that this server could not understand."),	Syntax =>	Error("400 Bad Request", "Garbled Syntax",		"Your client sent a query with incoherent syntax."),	BadSearch =>Error("400 Bad Request", "Inapplicable Search",		"Your client sent a search that cannot be applied to %s."),	NotFound =>Error("404 Not Found", "Object not found",		"The object %s does not exist on this server."),	NoSearch =>	Error("403 Forbidden", "Search not supported",		"The object %s does not support the search command."),	OnlySearch =>Error("403 Forbidden", "Searching Only",		"The object %s only supports the searching methods."),	Unauth =>	Error("401 Unauthorized", "Unauthorized",		"You are not authorized to see the object %s."),	OK =>	Error("200 OK", "everything is fine","Groovy man"),};	 badmodule(p: string){	sys->fprint(sys->fildes(2), "parse: cannot load %s: %r", p);	raise "fail:bad module";} lock: ref Semaphore; init(){	sys = load Sys Sys->PATH; 	date = load Date Date->PATH;	if (date==nil) badmodule(Date->PATH); 	daytime = load Daytime Daytime->PATH;	if(daytime == nil) badmodule(Daytime->PATH); 	contents = load Contents Contents->PATH;	if(contents == nil) badmodule(Contents->PATH); 	str = load String String->PATH;	if(str == nil) badmodule(String->PATH); 	alarms = load Alarms Alarms->PATH;	if(alarms == nil) badmodule(Alarms->PATH); 	locks = load Lock Lock->PATH;	if(locks == nil) badmodule(Lock->PATH);	locks->init();	lock = Semaphore.new();	date->init();} atexit(g: ref Private_info){	if (g.dbg_log!=nil){		sys->fprint(g.dbg_log,"At exit from parse, closing fds. \n");	}	if (g.bin!=nil)		g.bufio->g.bin.close();	if (g.bout!=nil)		g.bufio->g.bout.close();	g.bin=nil;	g.bout=nil;	exit;}  httpheaders(g: ref Private_info,vers : string){	if(vers == "")		return;	g.tok = '\n';	# 15 minutes to get request line	a := Alarm.alarm(15*1000*60); 	while(lex(g) != '\n'){		if(g.tok == Word && lex(g) == ':'){			if (g.dbg_log!=nil)				sys->fprint(g.dbg_log,"hitting parsejump. wordval is %s\n",										g.wordval);			parsejump(g,g.wordval);		}		while(g.tok != '\n')			lex(g);	}	a.stop();}  mimeok(g: ref Private_info,name : string,multipart : int,head : list of ref Content): list of ref Content{ 	generic, specific, s : string;	v : real; 	while(lex(g) != Word)		if(g.tok != ',')			return head; 	generic = g.wordval;	lex(g);	if(g.tok == '/' || multipart){		if(g.tok != '/')			return head;		if(lex(g) != Word)			return head;		specific = g.wordval;		lex(g);	}else		specific = "*";	tmp := contents->mkcontent(generic, specific);	head = tmp::head;	for(;;){		case g.tok {		';' =>			if(lex(g) == Word){				s = g.wordval;				if(lex(g) != '=' || lex(g) != Word)					return head;				v = 3.14; # should be strtof(g.wordval, nil);				if(s=="q")					tmp.q = v;				else					logit(g,sys->sprint(						"unknown %s param: %s %s",						name, s, g.wordval));			}			break;		',' =>			return  mimeok(g,name, multipart,head);		* =>			return head;		}		lex(g);	}	return head;} mimeaccept(g: ref Private_info,name : string){	g.oktype = mimeok(g,name, 1, g.oktype);} mimeacceptenc(g: ref Private_info,name : string){	g.okencode = mimeok(g,name, 0, g.okencode);} mimeacceptlang(g: ref Private_info,name : string){	g.oklang = mimeok(g,name, 0, g.oklang);} mimemodified(g: ref Private_info,name : string){	lexhead(g);	g.modtime = date->date2sec(g.wordval);	if (g.dbg_log!=nil){		sys->fprint(g.dbg_log,"modtime %d\n",g.modtime);	}	if(g.modtime == 0)		logit(g,sys->sprint("%s: %s", name, g.wordval));}  mimeagent(g: ref Private_info,nil : string){	lexhead(g);	g.client = g.wordval;} mimefrom(g: ref Private_info,nil : string){	lexhead(g);}  mimehost(g: ref Private_info,nil : string){	h : string;	lexhead(g);	(nil,h)=str->splitr(g.wordval," \t");	g.host = h;} mimereferer(g: ref Private_info,nil : string){	h : string;	lexhead(g);	(nil,h)=str->splitr(g.wordval," \t");	g.referer = h;} mimeclength(g: ref Private_info,nil : string){	h : string;	lexhead(g);	(nil,h)=str->splitr(g.wordval," \t");	g.clength = int h;} mimectype(g: ref Private_info,nil : string){	h : string;	lexhead(g);	(nil,h)=str->splitr(g.wordval," \t");	g.ctype = h;}  mimeignore(g: ref Private_info,nil : string){	lexhead(g);}  mimeunknown(g: ref Private_info,name : string){	lexhead(g);	if(g.client!="")		logit(g,sys->sprint("agent %s: ignoring header %s: %s ", 			g.client, name, g.wordval));	else		logit(g,sys->sprint("ignoring header %s: %s", name, g.wordval));}  parsejump(g: ref Private_info,k : string){	case k {  	"from" =>				mimefrom(g,k);	"if-modified-since" =>			mimemodified(g,k);	"accept" =>				mimeaccept(g,k);	"accept-encoding" =>			mimeacceptenc(g,k);	"accept-language" =>			mimeacceptlang(g,k);	"user-agent" =>				mimeagent(g,k);	"host" =>				mimehost(g,k);	"referer" =>				mimereferer(g,k);	"content-length" =>		mimeclength(g,k);	"content-type" =>		mimectype(g,k);	"authorization" or "chargeto" or "connection" or "forwarded" or	"pragma" or "proxy-agent" or "proxy-connection" or	"x-afs-tokens" or "x-serial-number" =>			mimeignore(g,k);	* =>						mimeunknown(g,k);	};	} lex(g: ref Private_info): int{	g.tok = lex1(g);	return g.tok;}  # rfc 822/rfc 1521 lexical analyzerlex1(g: ref Private_info): int{	level, c : int;	if(g.parse_eof)		return '\n'; # top:	for(;;){		c = getc(g);		case c {			 '(' =>				level = 1;				while((c = getc(g)) != Bufio->EOF){					if(c == '\\'){						c = getc(g);						if(c == Bufio->EOF)							return '\n';						continue;					}					if(c == '(')						level++;					else if(c == ')' && level == 1){						level--;						break;					}					else if(c == '\n'){						c = getc(g);						if(c == Bufio->EOF)							return '\n';							break;						if(c != ' ' && c != '\t'){							ungetc(g);							return '\n';						}					}				}	 		' ' or '\t' or '\r' =>				break;	 		'\n' =>				if(g.tok == '\n'){					g.parse_eof = 1;					return '\n';				}				c = getc(g);				if(c == Bufio->EOF)					return '\n';				if(c != ' ' && c != '\t'){					ungetc(g);					return '\n';				}			')' or '<' or '>' or '[' or ']' or '@' or '/' or ',' 			or ';' or ':' or '?' or '=' =>				return c; 	 		'"' =>				word(g,"\"");				getc(g);		# skip the closing quote 				return Word; 	 		* =>				ungetc(g);				word(g,"\"()<>@,;:/[]?=\r\n \t");				return Word;			}	}	return 0;	} # return the rest of an rfc 822, not including \r or \n# do not map to lower case lexhead(g: ref Private_info){	c, n: int;	n = 0;	while((c = getc(g)) != Bufio->EOF){		if(c == '\r')			c = wordcr(g);		else if(c == '\n')			c = wordnl(g);		if(c == '\n')			break;		if(c == '\\'){			c = getc(g);			if(c == Bufio->EOF)				break;		}		g.wordval[n++] = c;	}	g.tok = '\n';	g.wordval= g.wordval[0:n];} word(g: ref Private_info,stop : string){	c : int;	n := 0;	while((c = getc(g)) != Bufio->EOF){		if(c == '\r')			c = wordcr(g);		else if(c == '\n')			c = wordnl(g);		if(c == '\\'){			c = getc(g);			if(c == Bufio->EOF)				break;		}else if(str->in(c,stop)){				ungetc(g);				g.wordval = g.wordval[0:n];					return;			}		if(c >= 'A' && c <= 'Z')			c += 'a' - 'A';		g.wordval[n++] = c;	}	g.wordval = g.wordval[0:n];	# sys->print("returning from word");}  wordcr(g: ref Private_info): int{	c := getc(g);	if(c == '\n')		return wordnl(g);	ungetc(g);	return ' ';}  wordnl(g: ref Private_info): int{	c := getc(g);	if(c == ' ' || c == '\t')		return c;	ungetc(g);	return '\n';}  getc(g: ref Private_info): int{	c := g.bufio->g.bin.getc();	if(c == Bufio->EOF){		g.parse_eof = 1;		return c;	}	return c & 16r7f;} ungetc(g: ref Private_info){	# this is a dirty hack, I am tacitly assuming that characters read	# from stdin will be ASCII.....	g.bufio->g.bin.ungetc();} # go from url with ascii and %xx escapes to unicode, allowing for existing unencoded utf-8 urlunesc(s : string): string{	a := array[Sys->UTFmax*len s] of byte;	o := 0;	for(i := 0; i < len s; i++){		c := int s[i];		if(c < Runeself){			if(c == '%' && i+2 < len s){				d0 := hex(int s[i+1]);				if(d0 >= 0){					d1 := hex(int s[i+2]);					if(d1 >= 0){						i += 2;						c = d0*16 + d1;					}				}			} else if(c == '+'  || c == 0)				c = ' ';			a[o++] = byte c;		}else			o += sys->char2byte(c, a, o);	}	return string a[0: o];} hex(c: int): int{	if(c >= '0' && c <= '9')		return c-'0';

Lines 1–500 of 593.