summaryrefslogtreecommitdiff
path: root/appl/svc/httpd/cgiparse.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/svc/httpd/cgiparse.b')
-rw-r--r--appl/svc/httpd/cgiparse.b258
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;
+}