#(ws4t - HTTP multi-threaded Web server for TBPL) #(Main loop) io close; 'io; sys version indexOf "Linux" ++ ? { io = CIO open "/var/log/ws4t.log"; } ?? { io = CIO open "ws4t.log"; }; tbpl_io fdwrite = io fdwrite; 'MAX_CONNECTIONS = 16; 'http_server = { thread_wait += 1; 'client_io ~= arg; client_io 'EOFError = { "" }; 'request = ""; request = client_io readline chomp!; 'REQUEST_METHOD = request find: "^[^ ]*"; 'REQUEST_URI = request right(0 - REQUEST_METHOD size + 1) find: "^[^ ]*"; 'REQUEST_PROTOCOL = request find: "[^ ]*$"; REQUEST_URI[0] == "/" ?? { REQUEST_URI = "/"; }; 'WL_SCRIPT = REQUEST_URI find: "^/[^/\\?]*"; 'QUERY_STRING = REQUEST_URI find: "\\?.*$"; 'WL_PATH = REQUEST_URI left (REQUEST_URI size - QUERY_STRING size) right (0 - WL_SCRIPT size); QUERY_STRING right! -1; 'headers = []; 'get_data = true; get_data while { 'str = ""; str = client_io readline chomp!; (str match: ": ") && (str size > 0) ? { headers create (str find ".*: " left! -2 tolower!) = str find ": .*" right -2; } ?? { get_data = false; }; }; headers contains "content-length" ?? { headers 'content-length = ""; }; headers contains "host" ?? { headers 'host = "kmeaw.com"; }; 'WL_REMOTE = client_io addr host; (WL_REMOTE == "192.168.0.1") && (headers contains "x-forwarded-for") ? { WL_REMOTE = headers x-forwarded-for; }; io outn "\{sys time}> \{REQUEST_METHOD} (\{headers content-length}) \{WL_REMOTE}: \{REQUEST_URI} (\{WL_SCRIPT})"; (WL_SCRIPT == "") || (WL_SCRIPT == "/") ? { WL_SCRIPT = "/tref.tbs"; WL_PATH = ""; }; (WL_SCRIPT right 4 == ".tbs") ? { 'WL_VERSION = 0001; 'WL_PROJECT = WL_SCRIPT left -4 right! -1; 'WL_CACHE = false; % contains WL_PROJECT ? { WL_CACHE = true; } ?? { lang require: "\{WL_PROJECT}/init.tbs"; }; % find WL_PROJECT contains "development" && WL_CACHE ? { % find WL_PROJECT delete; lang require: "\{WL_PROJECT}/init.tbs"; }; 'WL_ROOT ~= % find WL_PROJECT; WL_PATH left: 1 == "/" ?? { WL_PATH = "/" + WL_PATH; }; WL_PATH == "/" ? { WL_PATH = ""; }; WL_PATH right: 1 == "/" ? { WL_PATH left: -1; }; WL_PATH = WL_PROJECT + WL_PATH replace('to = " "; "/"); 'WL_TARGET ~= CObject expand WL_PATH; 'WL_GET = []; 'WL_POST = []; 'WL_DATA = []; 'WL_REQUIRE = { WL_DATA contains arg ?? { WL_DATA create: arg = ""; }; WL_DATA find: arg }; 'WL_RAW = client_io :readbytes 0 :valueOf headers content-length; { 'part = WL_RAW find "^[^&]*"; 'left = part; 'right = ""; part match "=" ? { left = part find "^[^=]*"; right = part find "[^=]*$" urldecode; }; WL_POST create: left = right; WL_DATA create: left = right; WL_RAW :right! 0 :- part size; WL_RAW left: 1 == "&" ? { WL_RAW right! -1; }; } while { WL_RAW size > 0 }; 'WL_RAW = QUERY_STRING; { 'part = WL_RAW find "^[^&]*"; 'left = part; 'right = ""; part match "=" ? { left = part find "^[^=]*"; right = part find "[^=]*$" urldecode; }; WL_GET create: left = right; WL_DATA create: left = right; WL_RAW :right! 0 :- part size; WL_RAW left: 1 == "&" ? { WL_RAW right! -1; }; } while { WL_RAW size > 0 }; 'text = ""; &WL_TARGET respondsTo "toWeb" ? { text = "HTTP/1.0 200 OK Connection: close Server: ws4t 0.2 "; text += &WL_TARGET toWeb; } ?? { text = "HTTP/1.0 404 Not Found Connection: close Server: ws4t 0.2 Content-Type: text/html Error in \{&WL_TARGET path}."; }; client_io out text; } ?? { (REQUEST_URI match "\\.\\.\\/") ? { client_io outn "HTTP/1.0 403 Forbidden"; client_io outn "Server: ws4t 0.2\n"; client_io outn "Breaking into this server is forbidden, sorry."; client_io close; } ?? { CIO exist ("./" += REQUEST_URI) ? { 'file_io = CIO :open "./" += REQUEST_URI; client_io outn "HTTP/1.0 200 OK"; 'data = file_io readlines; 'stat = CStat :new "./" += REQUEST_URI; client_io outn "Content-Length: \{data size}"; client_io outn "Last-Modified: \{sys :time_rfc stat mtime}"; client_io outn "Server: ws4t\n"; client_io :out data; file_io close; } ?? { client_io outn "HTTP/1.0 400 Not Found"; client_io outn "Server: ws4t\n"; client_io outn "The file or resource you have requested does not exist..."; }; }; }; sys sleep 100000; client_io flush; client_io close; thread_wait -= 1; }; #{Create a socket} 'socket = CSocket new; socket bind ; socket listen; sys version indexOf "Linux" ++ ? { 'pidfile = CIO open "/var/run/ws4t.pid"; pidfile :out sys getpid; pidfile close; sys setgid 1010; sys setuid 101; sys exec "id"; }; *thread_wait = 0; 'server_thread = true; 'socket_down = false; { server_thread while { { io outn "\{sys time}> [WRN] DoS attack detected!"; sys sleep: 1000000; } while { thread_wait > MAX_CONNECTIONS }; 'user_socket = socket accept; user_socket class equals CSocket ? { server_thread ? { &http_server :thread user_socket dup; } ?? { user_socket close; socket_down = true; }; }; sys sleep: 10000; }; socket close; } thread; io outn "\{sys time}> Server started."; sys version indexOf "Linux" ++ ? { sys chdir "/var/www/localhost/htdocs"; CIO exist "/var/run/ws4t.ctl" ?? { io outn: "\{sys time}> Control FIFO not found, aborting..."; } ? { CIO open: "/var/run/ws4t.ctl" readline; }; } ?? { true while { sys sleep: 10000000; }; }; server_thread = false; io outn "\{sys time}> Waiting all connections to close..."; { io outn "\{sys time}> \{thread_wait} connections pending."; sys sleep 1000000; } while { thread_wait > 0 }; io outn "\{sys time}> Shutting down main thread..."; socket_down ?? { CSocket new connect: close; }; io outn "\{sys time}> Server down."; io close;