ref: 2459e34d77e2e21ef829c0dfaafd99433899494f
dir: /appl/svc/httpd/cgiparse.b/
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;
}