/* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2005 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cpp.html. */ module fcgi; import std.path; import std.file; import std.stdio; import std.c.stdlib; import dmdscript.script; import dmdscript.program; import dmdscript.errmsgs; import dmdscript.SrcFile; import dmdscript.threadcontext; import dmdscript.dobject; import fastcgi.bindingfastcgi; import fastcgi.Request; enum { EXITCODE_INIT_ERROR = 1, EXITCODE_INVALID_ARGS = 2, EXITCODE_RUNTIME_ERROR = 3, } version (Windows) { pragma(lib, "dmdscript"); } private enum FastCGIConnectionState { IS_FAST_CGIisFastCGI, isCGIBeforeRequest, isCGIAfterRequest }; int send (int fd, char[] str) { if (fd < 0) { //if (!OS_IsFcgi (fd)) { // writef("%s", str); // return str.length; //} throw new Exception("writing - filehandle closed"); } int written = OS_Write (fd, str.ptr, str.length); if (written < str.length) { char[] msg = "failed to write (" ~ std.string.toString(written) ~ "/" ~ std.string.toString(str.length) ~ ")"; log(msg); throw new Exception(msg); } return written; } char[] recv(int fd) { char buf[] = new char[1024]; if (fd < 0) { throw new Exception("reading - filehandle closed"); } int len = OS_Read (fd, buf.ptr, buf.length); if (len < 0) { return null; //???? } return buf[0..len]; } void log(char[] m) { std.file.append("/tmp/fcgi.exception",m ~ "\n"); } int main(char[][] args) { char[][] includes; try { OS_LibInit (null); //fileDescriptor_ = fileDescriptor; not sure what this is for. int fd = 0; char* p = getenv("FCGI_WEB_SERVER_ADDRS"); char[] validAddresses_ = p == null ? "" : std.string.toString(p); log("Got web srv addr: " ~ validAddresses_); bool isFCGI = cast(bool) OS_IsFcgi (fd); int counter = 0; do { log("waiting for connection"); auto r = new Request(fd, validAddresses_); if (r.fd < 0) { log("file connection < 0 :: " ~ std.string.toString(r.fd)); continue; } // we shoul have data in r available to do stuff with.. //log("got file handle " ~ std.string.toString(r.fd)); r.send("Content-type: text/html\r\n\r\n"); SrcFile m = new SrcFile(r.env["PATH_TRANSLATED"], includes, args); // libdirs set up.. char[][] libdirs ; libdirs ~= "/usr/lib/rooscript"; auto tc = ThreadContext.getThreadContext(); tc.stdout = r.getSendDelegate(); try { m.read(); m.compile(0, false ,libdirs); loadRequest(r, m); m.execute(); } catch(Exception runtime_e) { tc.stdout(runtime_e.toString()); } ThreadContext.resetContext(); r.finish(); } while (true); log("filehandle closed = ending"); } catch(Exception e) { log( e.toString() ); } return 0; } void loadRequest(Request r, inout SrcFile m) { auto reqobj = new Dobject(Dobject.getPrototype()); reqobj.Put("input", r.stdin,0); reqobj.Put("data", r.data,0); auto envobj = new Dobject(Dobject.getPrototype()); foreach(k,v;r.env) { envobj.Put(k,v,0); } reqobj.Put("env", envobj,0); void setVal(inout Dobject p, char[] key, char[] val) { log("set " ~ key ~ " to " ~ val); int i = std.string.find(key,'['); if (i < 0) { // we give it as we get it!! - so you can only access strange stuff with Request.get["xxx^v"] p.Put(key, std.uri.decode(val),0); return; } int ii = std.string.find(key[i+1..length],']'); if (ii < 0) { p.Put(key, std.uri.decodeComponent(val),0); return; } char[] lkey = key[0..i]; char[] rkey = (key[i+1..length])[0..ii]; char[] rem = (key[i+1..length])[ii+1..length]; // does object already have this? Dobject child; if (p.HasProperty(lkey)) { // what if it's not an object!!? child = p.Get(lkey).toObject(); } else { child = new Dobject(Dobject.getPrototype()); p.Put(lkey, child,0); } setVal(child, rkey ~ rem, val); } // urldecoding?! // we could split on & auto bits = std.string.split(r.env["QUERY_STRING"], "&"); auto getobj = new Dobject(Dobject.getPrototype()); foreach(item; bits) { log("kv = " ~ item); int i = std.string.find(item, "="); if (i < 0) { setVal(getobj, item, ""); continue; } log("REQ:" ~ item ~ " i=" ~ std.string.toString(i)); setVal(getobj, item[0..i], item[i+1..length]); } reqobj.Put("get", getobj,0); bits = std.string.split(r.stdin, "&"); auto postobj = new Dobject(Dobject.getPrototype()); foreach(item; bits) { log("kv = " ~ item); int i = std.string.find(item, "="); if (i < 0) { setVal(postobj, item, ""); continue; } log("REQ:" ~ item ~ " i=" ~ std.string.toString(i)); setVal(postobj, item[0..i], item[i+1..length]); } reqobj.Put("post", postobj,0); m.program.callcontext.global.Put("Request", reqobj, 0); }