implement FastCGI;
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "fastcgi.m";
log : chan of string;
logger()
{
logf := bufio->open("/usr/maht/fastcgi/fastcgi.log", sys->OWRITE);
while((txt := <- log) != nil) {
logf.puts(txt + "\n");
logf.flush();
}
}
Record.tostring(r : self ref Record) : string
{
pick rt := r {
Begin_Request =>
role : string;
case rt.role {
1 =>
role = "Responder";
2 =>
role = "Authorizer";
3 =>
role = "Filter";
* =>
role = "UNKNOWN!";
}
return sys->sprint("Begin_Request{Role:%s, Flags:%d, Res:%s}", role, int rt.flags, string rt.reserved);
Abort_Request =>
return "Abort_Request";
End_Request =>
pstatus : string;
case int rt.protocol_status {
0 =>
pstatus = "Request complete";
1 =>
pstatus = "Can't multiplex connection";
2 =>
pstatus = "Overloaded";
3 =>
pstatus = "Unknown Role";
* =>
pstatus = "UNKNOWN!";
}
return sys->sprint("End_Request{appStatus: %d, protoStatus: %s, Res: %s}", rt.application_status, pstatus, string rt.reserved);
Params =>
rstring := "Params{";
if(rt.params != nil) {
(k,v) := hd rt.params;
rstring += k + ": " + v;
for(t := tl rt.params; t != nil; t = tl t) {
(k,v) = hd t;
rstring += ", " + k + ": " + v;
}
}
return rstring += "}";
Stdin =>
if(rt.data == nil)
return "Stdin{}";
return "Stdin{" + string rt.data + "}";
Stdout =>
if(rt.data == nil)
return "Stdout{}";
return "Stdout{" + string rt.data + "}";
Stderr =>
if(rt.data == nil)
return "Stderr{}";
return "Stderr{" + string rt.data+ "}";
Data =>
if(rt.data == nil)
return "Data{}";
return "Data{" + string rt.data + "}";
Get_Values =>
rstring := "Get_Values{";
if(rt.values != nil) {
(k,v) := hd rt.values;
rstring += k + ": " + v;
for(t := tl rt.values; t != nil; t = tl t) {
(k,v) = hd t;
rstring += ", " + k + ": " + v;
}
}
return rstring += "}";
Get_Values_Result =>
rstring := "Get_Values_Result{";
if(rt.results != nil) {
(k,v) := hd rt.results;
rstring += k + ": " + v;
for(t := tl rt.results; t != nil; t = tl t) {
(k,v) = hd t;
rstring += ", " + k + ": " + v;
}
}
return rstring += "}";
* =>
return "UNKNOWN!";
}
}
Httpd.open_io(h : self ref Httpd) : int
{
h.io = bufio->open(sys->sprint("%s/data", h.conn.dir), Bufio->ORDWR);
if(h.io == nil) {
log <- = sys->sprint("%s/data failed to open", h.conn.dir);
return 0;
}
return 1;
}
Httpd.read_header(h : self ref Httpd) : (int, int, int, big)
{
header := array[8] of byte;
nread := h.io.read(header, 8);
if(nread != 8) {
log <- = sys->sprint("short record got %d bytes", nread);
return (-1,0,0,big 0);
}
if(header[0] != byte 1) {
log <- = sys->sprint("Protocol version mismatch : expected 1 got %d", int header[0]);
return (-1,0,0,big 0);
}
return ((int header[2] << 8) + int header[3], int header[1], (int header[4] << 8) + int header[5], big header[6]);
}
Httpd.read_varstring_length(h : self ref Httpd) : (int, int)
{
b3 := h.io.getb();
if(b3 < 0)
return (1, b3);
if((b3 & 16r80) == 0)
return (1, b3);
b2 := h.io.getb();
if(b2 < 0)
return (2, b2);
b1 := h.io.getb();
if(b1 < 0)
return (3, b1);
b0 := h.io.getb();
if(b0 < 0)
return (4, b0);
return (4, ((b3 & 16r7f) << 24) + (b2 << 16) + (b1 << 8) + b0);
}
Httpd.read_name_value_pairs(h : self ref Httpd, content_length: int) : (int, list of (string, string))
{
nvs : list of (string, string);
nvs = nil;
nread := 0;
jread : int;
name_length, value_length : int;
name, value : array of byte;
while(nread < content_length) {
(jread, name_length) = h.read_varstring_length();
nread += jread;
if(name_length < 0) {
log <- = sys->sprint("reading name_length : %r");
return(nread, nil);
}
(jread, value_length) = h.read_varstring_length();
nread += jread;
if(value_length < 0) {
log <- = sys->sprint("reading value_length : %r");
return(nread, nil);
}
if((nread + name_length + value_length) > content_length) {
log <- = sys->sprint("name/value too big for content_length : %r");
return(nread, nil);
}
name = array[name_length] of byte;
jread = h.io.read(name, name_length);
if(jread < 0) {
log <- = sys->sprint("reading name : %r");
return(nread, nil);
}
nread += jread;
if(jread != name_length)
return(nread, nil);
value = array[value_length] of byte;
jread = h.io.read(value, value_length);
if(jread < 0) {
log <- = sys->sprint("reading value : %r");
return(nread, nil);
}
nread += jread;
if(jread != value_length)
return(nread, nil);
nvs = (string name, string value) :: nvs;
}
return (nread, nvs);
}
Httpd.read_records(h : self ref Httpd, consumer : chan of ref Record)
{
if(!h.open_io()) return;
r : ref Record;
(id, rtype, content_length, padding) := h.read_header();
nread : int;
while(id >= 0) {
r = nil;
nread = 0;
case rtype {
BEGIN_REQUEST =>
if(content_length == 8) {
content := array[8] of byte;
if((nread = h.io.read(content, 8)) == 8) {
r = ref Record.Begin_Request((int content[0] << 8) + int content[1], content[2], content[3:8]);
}
}
ABORT_REQUEST =>
if(content_length == 0)
r = ref Record.Abort_Request();
END_REQUEST =>
if(content_length == 8) {
content := array[8] of byte;
if((nread = h.io.read(content, 8)) == 8) {
r = ref Record.End_Request((int content[0] << 24) + (int content[1] << 16) + (int content[2] << 8) + int content[3], content[4], content[5:8]);
}
}
PARAMS =>
if(content_length > 0) {
(jread, name_values) := h.read_name_value_pairs(content_length);
if(name_values != nil)
r = ref Record.Params(name_values);
nread = jread;
} else {
r = ref Record.Params(nil);
}
STDIN =>
if(content_length > 0) {
data := array[content_length] of byte;
nread = h.io.read(data, content_length);
if(nread == content_length)
r = ref Record.Stdin(data);
} else {
r = ref Record.Stdin(nil);
}
STDOUT =>
if(content_length > 0) {
data := array[content_length] of byte;
nread = h.io.read(data, content_length);
if(nread == content_length)
r = ref Record.Stdout(data);
} else {
r = ref Record.Stdout(nil);
}
STDERR =>
if(content_length > 0) {
data := array[content_length] of byte;
nread = h.io.read(data, content_length);
if(nread == content_length)
r = ref Record.Stderr(data);
} else {
r = ref Record.Stderr(nil);
}
DATA =>
if(content_length > 0) {
data := array[content_length] of byte;
nread = h.io.read(data, content_length);
if(nread == content_length)
r = ref Record.Data(data);
} else {
r = ref Record.Data(nil);
}
GET_VALUES =>
if(content_length > 0) {
(jread, name_values) := h.read_name_value_pairs(content_length);
if(name_values != nil)
r = ref Record.Get_Values(name_values);
nread = jread;
} else {
r = ref Record.Get_Values(nil);
}
GET_VALUES_RESULT =>
if(content_length > 0) {
(jread, name_values) := h.read_name_value_pairs(content_length);
if(name_values != nil)
r = ref Record.Get_Values_Result(name_values);
nread = jread;
} else {
r = ref Record.Get_Values_Result(nil);
}
* =>
log <- = "Skipping Unknown!";
h.io.seek(big content_length, Bufio->SEEKRELA);
}
if(r != nil)
consumer <- = r;
if(nread < 0) {
log <- = sys->sprint("Read Error: %r");
break;
}
if(nread > content_length) {
log <- = "Read too much data";
break;
}
if(nread < content_length) {
log <- = sys->sprint("Record type %d discarded", rtype);
h.io.seek(big (content_length - nread), Bufio->SEEKRELA);
}
if(padding > big 0)
h.io.seek(padding, Bufio->SEEKRELA);
(id, rtype, content_length, padding) = h.read_header();
}
}
listener(addr : string, consumer : chan of ref Record)
{
(i, socket) := sys->announce(addr);
if(i != 0) {
log <- = "listen failed";
return;
}
err : int;
server_id := 0;
while(1) {
h := ref Httpd;
(err, h.conn) = sys->listen(socket);
if(err == 0) {
h.server_id = server_id++;
spawn h.read_records(consumer);
}
}
}
log_record(r : ref Record) {
log <- = r.tostring();
}
processor(records : chan of ref Record)
{
for(r := <- records;;r = <- records)
if(r != nil)
spawn log_record(r);
}
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
bufio = load Bufio Bufio->PATH;
draw = load Draw Draw->PATH;
log = chan of string;
records := chan of ref Record;
spawn logger();
for(h := hd argv; tl argv != nil; argv = tl argv) {
log <- = h;
}
addr := "tcp!192.168.9.8!9888";
log <- = "Starting on " + addr;
spawn processor(records);
listener(addr, records);
}
# kill FastCGI; rm *.dis
|