diff options
Diffstat (limited to 'appl/svc/httpd/cgiparse.b')
| -rw-r--r-- | appl/svc/httpd/cgiparse.b | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/appl/svc/httpd/cgiparse.b b/appl/svc/httpd/cgiparse.b new file mode 100644 index 00000000..4ff0d87c --- /dev/null +++ b/appl/svc/httpd/cgiparse.b @@ -0,0 +1,258 @@ +implement CgiParse; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "string.m"; + str: String; +include "bufio.m"; +include "daytime.m"; + daytime : Daytime; +include "parser.m"; + parser : Parser; +include "contents.m"; +include "cache.m"; +include "httpd.m"; + Private_info: import Httpd; +include "cgiparse.m"; + +stderr : ref Sys->FD; + +cgiparse(g: ref Private_info, req: Httpd->Request): ref CgiData +{ + ret: ref CgiData; + (ok, err) := loadmodules(); + if(ok == -1) { + sys->fprint(stderr, "CgiParse: %s\n", err ); + return nil; + } + + (ok, err, ret) = parse(g, req); + + if(ok < 0){ + sys->fprint( stderr, "CgiParse: %s\n", err ); + return nil; + } + return ret; +} + +badmod(p: string): (int, string) +{ + return (-1, sys->sprint("cannot load %s: %r", p)); +} + +loadmodules(): (int, string) +{ + if( sys == nil ) + sys = load Sys Sys->PATH; + stderr = sys->fildes(2); + if(daytime == nil) + daytime = load Daytime Daytime->PATH; + if(daytime == nil) + return badmod(Daytime->PATH); + if(str == nil) + str = load String String->PATH; + if(str == nil) + return badmod(String->PATH); + if( parser == nil ) + parser = load Parser Parser->PATH; + if( parser == nil ) + return badmod(Parser->PATH); + return (0, nil); +} + +parse(g: ref Private_info, req: Httpd->Request) : (int, string, ref CgiData) +{ + bufio := g.bufio; + Iobuf: import bufio; + + host, remote, referer, httphd : string; + form: list of (string, string); + + tmstamp := daytime->time(); + + (method, version, uri, search) := (req.method, req.version, req.uri, req.search); + + if(version != ""){ + if( g.version == nil ) + return (-1, "version unknown.", nil); + if( g.bout == nil ) + return (-1, "internal error, g.bout is nil.", nil); + if( g.bin == nil ) + return (-1, "internal error, g.bin is nil.", nil); + httphd = g.version + " 200 OK\r\n" + + "Server: Inferno-Httpd\r\n" + + "MIME-version: 1.0\r\n" + + "Date: " + tmstamp + "\r\n" + + "Content-type: text/html\r\n" + + "\r\n"; + } + + hstr := ""; + lastnl := 1; + eof := 0; + while((c := g.bin.getc()) != bufio->EOF ) { + if (c == '\r' ) { + hstr[len hstr] = c; + c = g.bin.getb(); + if( c == bufio->EOF ){ + eof = 1; + break; + } + } + hstr[len hstr] = c; + if(c == '\n' ){ + if( lastnl ) + break; + lastnl = 1; + } + else + lastnl = 0; + } + host = g.host; + remote = g.remotesys; + referer = g.referer; + (cnt, header) := parseheader( hstr ); + method = str->toupper( method); + if (method == "POST") { + s := ""; + while(!eof && cnt && (c = g.bin.getc()) != '\n' ) { + s[len s] = c; + cnt--; + if( c == '\r' ) + eof = 1; + } + form = parsequery(s); + } + for (ql := parsequery(req.search); ql != nil; ql = tl ql) + form = hd ql :: form; + return (0, nil, + ref CgiData(method, version, uri, search, tmstamp, host, remote, referer, + httphd, header, form)); +} + +parseheader(hstr: string): (int, list of (string, string)) +{ + header : list of (string, string); + cnt := 0; + if( hstr == nil || len hstr == 0 ) + return (0, nil); + (n, sl) := sys->tokenize( hstr, "\r\n" ); + if( n <= 0 ) + return (0, nil); + while( sl != nil ){ + s := hd sl; + sl = tl sl; + for( i := 0; i < len s; i++ ){ + if( s[i] == ':' ){ + tag := s[0:i+1]; + val := s[i+1:]; + if( val[len val - 1] == '\r' ) + val[len val - 1] = ' '; + if( val[len val - 1] == '\n' ) + val[len val - 1] = ' '; + header = (tag, val) :: header; + if(str->tolower( tag ) == "content-length:" ){ + if( val != nil && len val > 0 ) + cnt = int val; + else + cnt = 0; + } + break; + } + } + } + return (cnt, listrev( header )); +} + +listrev(s: list of (string, string)): list of (string, string) +{ + tmp : list of (string, string); + while( s != nil ) { + tmp = hd s :: tmp; + s = tl s; + } + return tmp; +} + +getbaseip() : string +{ + buf : array of byte; + fd := sys->open( "/net/bootp", Sys->OREAD ); + if( fd != nil ){ + (n, d) := sys->fstat( fd ); + if( n >= 0 ){ + if(int d.length > 0 ) + buf = array [int d.length] of byte; + else + buf = array [128] of byte; + n = sys->read( fd, buf, len buf ); + if( n > 0 ){ + (nil, sl) := sys->tokenize( string buf[0:n], " \t\n" ); + while( sl != nil ){ + if( hd sl == "ipaddr" ){ + sl = tl sl; + break; + } + sl = tl sl; + } + if( sl != nil ) + return "http://" + (hd sl); + } + } + } + return "http://beast2"; +} + +getbase() : string +{ + fd := sys->open( "/dev/sysname", Sys->OREAD ); + if( fd != nil ){ + buf := array [128] of byte; + n := sys->read( fd, buf, len buf ); + if( n > 0 ) + return "http://" + string buf[0:n]; + } + return "http://beast2"; +} + +gethost() : string +{ + fd := sys->open( "/dev/sysname", Sys->OREAD ); + if(fd != nil) { + buf := array [128] of byte; + n := sys->read( fd, buf, len buf ); + if( n > 0 ) + return string buf[0:n]; + } + return "none"; +} + +# parse a search string of the form +# tag=val&tag1=val1... +parsequery(search : string): list of (string, string) +{ + q: list of (string, string); + tag, val : string; + if (contains(search, '?')) + (nil,search) = str->splitr(search,"?"); + while(search!=nil){ + (tag,search) = str->splitl(search,"="); + if (search != nil) { + search=search[1:]; + (val,search) = str->splitl(search,"&"); + if (search!=nil) + search=search[1:]; + q = (parser->urlunesc(tag), parser->urlunesc(val)) :: q; + } + } + return q; +} + +contains(s: string, c: int): int +{ + for (i := 0; i < len s; i++) + if (s[i] == c) + return 1; + return 0; +} |
