Constant HTTP
Source pub const HTTP: &str = "\"stream.spl\" import\n\"net.spl\" import\n\n\"http\" net:register\n\nconstruct net:http namespace {\n Request\n Response\n help\n ;\n register { | with name this ;\n name \"net:http\" register-field\n }\n urlencode { str | with str this ;\n [ { | with x ;\n x\n x \"0\" :_char lt not\n x \"9\" :_char gt not and\n x \"a\" :_char lt not\n x \"z\" :_char gt not and or\n x \"A\" :_char lt not\n x \"Z\" :_char gt not and or\n not\n if {\n pop\n \"%\" :_char\n x _mega:_str_radix<16> _array =x\n x:len 1 eq if { \"0\" :_char }\n x:to-stack\n } \n } str _array :foreach ] _str\n }\n urldecode { str | with str this ;\n str _array =str\n [ \n def i 0 =i\n while { i str:len lt } {\n i str:get dup \"%\" :_char eq if {\n pop\n i ++ =i\n i i 2 + str:sub _str :_mega_radix<16> _int\n i ++ =i\n }\n i ++ =i\n }\n ] _str\n }\n}\n\nconstruct net:http:Request {\n host port\n method path\n headers\n body\n ;\n construct { this | with host port method path this ;\n host this:=host\n port this:=port\n method this:=method\n path this:=path\n List:new this:=headers\n \"\" this:=body\n this\n }\n add-header { this | with header this ;\n header this:headers:push\n this\n }\n set-body { this | with body this ;\n body this:=body\n this\n }\n send { net:http:Response | with this ;\n def stream this:host this:port StreamTypes:tcp:create =stream\n def response net:http:Response:new =response\n\n this:method:to-bytes stream:write-exact;\n \" \" :to-bytes stream:write-exact;\n this:path:to-bytes stream:write-exact;\n \" HTTP/1.0\\r\\n\" :to-bytes stream:write-exact;\n\n \"Host: \" :to-bytes stream:write-exact;\n this:host:to-bytes stream:write-exact;\n \"\\r\\nConnection: Close\\r\\nUser-Agent: http.spl v0.1 2023-03 (spl@mail.tudbut.de)\\r\\n\"\n :to-bytes stream:write-exact;\n\n { | with header ;\n header:to-bytes stream:write-exact;\n \"\\r\\n\" stream:write-exact;\n } this:headers:foreach\n\n \"Content-Length: \" :to-bytes stream:write-exact;\n def body this:body:to-bytes =body\n body:len _str:to-bytes stream:write-exact;\n \"\\r\\n\\r\\n\" :to-bytes stream:write-exact;\n \n body stream:write-exact;\n stream:flush;\n\n def response 1024 stream:read-to-end =response\n\n response net:http:Response:new:read-from-bytes\n\n stream:close;\n }\n}\n\nconstruct net:http:help namespace {\n ;\n assert-str { | with expected iter _ ;\n [ { | pop iter:next } (expected _array):len:foreach ] _str\n expected _str\n eq not if {\n \"Expected \" expected concat throw\n }\n }\n until-str { str | with expected iter _ ;\n def match 0 =match\n def bytes expected:to-bytes =bytes\n [\n while { match bytes:len eq not } {\n iter:next dup (match bytes:get) eq dup if {\n match ++ =match\n } not if {\n 0 =match\n }\n } \n { | pop pop } match:foreach\n ] _str\n }\n}\n\nconstruct net:http:Response {\n version\n state-num state-msg\n headers\n body\n ;\n construct { this | with this ;\n MicroMap:new this:=headers\n \"\" this:=body\n this\n }\n read-from-bytes { this | with bytes this ;\n use net:http:help\n bytes:iter =bytes\n \"HTTP/\" bytes help:assert-str\n \" \" bytes help:until-str this:=version\n \" \" bytes help:until-str _mega this:=state-num\n \"\\r\\n\" bytes help:until-str this:=state-msg\n while { \"\\r\\n\" bytes help:until-str dup \"\" eq not } {\n def iter \": \" swap:split:iter =iter\n (\n iter:next \": \"\n iter:join \n ) this:headers:set;\n } pop\n 0 (\"Content-Length\" this:headers:get _mega) bytes:collect:sub this:=body\n this\n }\n content-type { str | with this ;\n \"Content-Type\" this:headers:get\n }\n}\n";