use module.libnasock; use std.os; use std.io; use std.unix; var socket = libnasock.socket; var http = func() { var sd=nil; return { establish:func(ip,port) { sd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP); while (socket.bind(sd,ip,port)<0) { println("[",os.time(),"] failed to bind socket "~sd~" at IP: "~ip~" port: "~port~"."); unix.sleep(5); println("[",os.time(),"] retrying..."); } socket.listen(sd,1); println("[",os.time(),"] start server at [",ip,":",port,"]"); }, shutdown:func() { println("[",os.time(),"] shutdown server"); socket.closesocket(sd); }, accept:func() { return socket.accept(sd); }, disconnect:func(client,log=0) { if (log) println("[",os.time(),"] [",client.ip,"] disconnected"); return socket.closesocket(client.sd); }, recv:func(client) { var data=socket.recv(client.sd,2048); if (!data.size) { println("[",os.time(),"] [",client.ip,"] closed connection"); return nil; } var first=split("\n",data.str)[0]; var (type,path)=split(" ",first)[0,1]; println("[",os.time(),"] [",client.ip,"] request ",type," [",path,"]"); return {type:type,path:path}; }, send:func(client,content) { println("[",os.time(),"] [",client.ip,"] get size ",size(content)," byte(s)"); return socket.send(client.sd,content); } }; }(); http.establish("127.0.0.1",8080); var highlight_style=" "; var html_read_file = func(filename) { var timer=maketimestamp(); timer.stamp(); var keyword=["var","func","for","while","foreach","forindex","break","continue","return","if","else","elsif","nil"]; var file_text=io.readfile(filename); var (s,index,len)=("",-1,size(file_text)); var content=""; var next = func() { if (index+1>=len) return index+1; index+=1; s=char(file_text[index]); return index; } var prev = func() { index-=1; s=char(file_text[index]); } while (1) { if (next()>=len) break; if (s==">") content~=">"; elsif (s=="<") content~="<"; elsif (s=="[" or s=="]" or s=="(" or s==")" or s=="{" or s=="}") content~=""~s~""; elsif (s=="=" or s=="," or s==";" or s==":" or s=="|" or s=="&" or s=="!" or s=="?" or s=="+" or s=="-" or s=="*" or s=="/" or s=="~" or s==".") content~=""~s~""; elsif (s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or s[0]<0 or s[0]>=128) { var tmp=""~s; # generate a new string while (1) { if (next()>=len) break; if (s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or ("0"[0]<=s[0] and s[0]<="9"[0]) or s[0]<0 or s[0]>=128) tmp~=s; else { prev(); break; } } var is_key=0; foreach(var i;keyword) if (tmp==i) { is_key=1; content~=""~tmp~""; break; } if (!is_key) content~=""~tmp~""; } elsif ("0"[0]<=s[0] and s[0]<="9"[0]) { content~=""~s; if (next()>=len) { content~=""; break; } if (s=="o") { content~="o"; while (1) { if (next()>=len) break; if ("0"[0]<=s[0] and s[0]<="7"[0]) content~=s; else break; } content~=""; prev(); } elsif (s=="x") { content~="x"; while (1) { if (next()>=len) break; if (("0"[0]<=s[0] and s[0]<="9"[0]) or ("a"[0]<=s[0] and s[0]<='f') or ("A"[0]<=s[0] or s[0]<="F")) content~=s; else break; } content~=""; prev(); } elsif (("0"[0]<=s[0] and s[0]<="9"[0]) or s=="." or s=="e") { while ("0"[0]<=s[0] and s[0]<="9"[0]) { content~=s; if (next()>=len) break; } if (s==".") { content~=s; if (next()>=len) break; } while ("0"[0]<=s[0] and s[0]<="9"[0]) { content~=s; if (next()>=len) break; } if (s=="e") { content~=s; if (next()>=len) break; if (s=="-" or s=="+") { content~=s; if (next()>=len) break; } } while ("0"[0]<=s[0] and s[0]<="9"[0]) { content~=s; if (next()>=len) break; } prev(); content~=""; } else { prev(); content~=""; } } elsif (s=="\"" or s=="'" or s=="`") { var quot=s~""; # generate a new string content~=""~s; while (1) { if (next()>=len) break; if (s==quot) { content~=s~""; break; } elsif (s=="\\") { content~=s; if (next()>=len) break; content~=s; } elsif (s==">") { content~=">"; } elsif (s=="<") { content~="<"; } else { content~=s; } } } elsif (s=="#") { content~=""~s; while (1) { if (next()>=len) break; if (s=="\n" or s=="\r") { content~=s; break; } elsif (s==">") { content~=">"; } elsif (s=="<") { content~="<"; } else { content~=s; } } content~=""; } else content~=s; } println("[",os.time(),"] analyzed [",filename,"] for ",timer.elapsedMSec(),"ms"); return content; } var respond={ ok:func(html) { println("[",os.time(),"] respond 200 OK"); return "Http/1.1 200 OK\n\n"~html~"\n"; }, not_found:func() { println("[",os.time(),"] respond 404 NOT FOUND"); return "Http/1.1 404 NOT FOUND\n\n 404 not found 404 NOT FOUND! \n"; }, teapot:func() { println("[",os.time(),"] respond 418 I'm a teapot"); return "Http/1.1 418 I'm a teapot\n\n I'm a teapot This server cannot brew coffee because it is a teapot. \n"; } }; var files = func() { var res={}; var dd=unix.opendir("./test"); while ((var name=unix.readdir(dd))!=nil) res[name]=1; return res; }(); while (1) { var client=http.accept(); var data=http.recv(client); if (data==nil) { http.disconnect(client); continue; } if (data.type=="GET") { var path=data.path; var args=split("?",path); var tmp={}; if (size(args)==2) { path=args[0]; args=split("=",args[1]); for (var i=0;i"~highlight_style~"\n
\n";
                var page_back="
\n\n\n"; http.send(client,respond.ok(page~html_read_file("./test/"~filename)~page_back)); } else { http.send(client,respond.ok(io.readfile("./doc/nasal-http-test-web.html"))); } } elsif (path=="/shutdown") { http.send(client,respond.ok("http server shutdown.")); break; } elsif (path=="/favicon.ico") http.send(client,respond.ok(io.readfile("./doc/pic/favicon.ico"))); elsif (path=="/license") http.send(client,respond.ok(io.readfile("./LICENSE"))); elsif (path=="/doc/pic/nasal.png" or path=="/doc/pic/social.png" or path=="/doc/pic/benchmark.png" or path=="/doc/pic/mandelbrot.png" or path=="/doc/pic/feigenbaum.png" or path=="/doc/pic/burningship.png") http.send(client,respond.ok(io.readfile("."~path))); else { var filename=substr(path,1,size(path)-1); if (contains(files,filename)) { var page=" "~filename~" "~highlight_style~"\n
\n";
                var page_back="
\n\n\n"; http.send(client,respond.ok(page~html_read_file("./test/"~filename)~page_back)); } elsif (filename=="teapot") http.send(client,respond.teapot()); else http.send(client,respond.not_found()); } } elsif (data.type=="POST") { http.send(client,respond.not_found); } http.disconnect(client); } http.shutdown();