1 module httpbin; 2 3 version(vibeD) { 4 } else 5 version (httpbin) 6 { 7 import requests.server.httpd; 8 import requests.utils; 9 import std.datetime; 10 import std.json; 11 import std.conv; 12 import std.range; 13 import std.string; 14 import core.thread; 15 import std.experimental.logger; 16 17 auto buildReply(ref HTTPD_Request rq) { 18 auto method = JSONValue(rq.method); 19 auto args = JSONValue(rq.query); 20 auto headers = JSONValue(rq.requestHeaders); 21 auto url = JSONValue(rq.uri.uri); 22 auto json = JSONValue(parseJSON(rq.json)); 23 auto data = JSONValue(rq.data); 24 auto form = JSONValue(rq.form); 25 auto files = JSONValue(rq.files); 26 auto reply = JSONValue([ 27 "method": method, 28 "headers": headers, 29 "args":args, 30 "json": json, 31 "url": url, 32 "data": data, 33 "form": form, 34 "files": files 35 ]); 36 return reply.toString(); 37 } 38 39 HTTPD httpbinApp() { 40 pragma(msg, "Compiling httpbin server"); 41 debug(requests) trace("start httpbin app"); 42 HTTPD server = new HTTPD(); 43 App httpbin = App("httpbin"); 44 45 httpbin.port = 8081; 46 httpbin.host = "127.0.0.1"; 47 httpbin.timeout = 10.seconds; 48 httpbin.rqLimit = 5; 49 server.app(httpbin); 50 51 auto root(in App app, ref HTTPD_Request rq, RequestArgs args) { 52 debug (httpd) trace("handler / called"); 53 auto rs = response(rq, buildReply(rq)); 54 rs.headers["Content-Type"] = "application/json"; 55 return rs; 56 } 57 auto get(in App app, ref HTTPD_Request rq, RequestArgs args) { 58 debug (httpd) trace("handler /get called"); 59 auto rs = response(rq, buildReply(rq)); 60 rs.headers["Content-Type"] = "application/json"; 61 return rs; 62 } 63 auto del(in App app, ref HTTPD_Request rq, RequestArgs args) { 64 if ( rq.method != "DELETE") { 65 auto rs = response(rq, "Illegal method %s".format(rq.method), 405); 66 return rs; 67 } 68 else { 69 auto rs = response(rq, buildReply(rq)); 70 return rs; 71 } 72 } 73 auto put(in App app, ref HTTPD_Request rq, RequestArgs args) { 74 if ( rq.method != "PUT") { 75 auto rs = response(rq, "Illegal method %s".format(rq.method), 405); 76 return rs; 77 } 78 else { 79 auto rs = response(rq, buildReply(rq)); 80 return rs; 81 } 82 } 83 auto patch(in App app, ref HTTPD_Request rq, RequestArgs args) { 84 if ( rq.method != "PATCH") { 85 auto rs = response(rq, "Illegal method %s".format(rq.method), 405); 86 return rs; 87 } 88 else { 89 auto rs = response(rq, buildReply(rq)); 90 return rs; 91 } 92 } 93 auto post(in App app, ref HTTPD_Request rq, RequestArgs args) { 94 auto rs = response(rq, buildReply(rq)); 95 return rs; 96 } 97 auto gzip(in App app, ref HTTPD_Request rq, RequestArgs args) { 98 auto content = ["gzipped":true]; 99 auto rs = response(rq, JSONValue(content).toPrettyString); 100 rs.compress(Compression.gzip); 101 rs.headers["Content-Type"] = "application/json"; 102 return rs; 103 } 104 auto deflate(in App app, ref HTTPD_Request rq, RequestArgs args) { 105 auto content = ["deflated":true]; 106 auto rs = response(rq, JSONValue(content).toPrettyString); 107 rs.compress(Compression.deflate); 108 return rs; 109 } 110 auto rel_redir(in App app, ref HTTPD_Request rq, RequestArgs args) { 111 auto rs = response(rq, buildReply(rq)); 112 auto redirects = to!long(args["redirects"]); 113 if ( redirects > 1 ) { 114 rs.headers["Location"] = "/relative-redirect/%d".format(redirects-1); 115 } else { 116 rs.headers["Location"] = "/get"; 117 } 118 rs.status = 302; 119 return rs; 120 } 121 auto abs_redir(in App app, ref HTTPD_Request rq, RequestArgs args) { 122 auto rs = response(rq, buildReply(rq)); 123 auto redirects = to!long(args["redirects"]); 124 if ( redirects > 1 ) { 125 rs.headers["Location"] = "http://127.0.0.1:8081/absolute-redirect/%d".format(redirects-1); 126 } else { 127 rs.headers["Location"] = "http://127.0.0.1:8081/get"; 128 } 129 rs.status = 302; 130 return rs; 131 } 132 auto cookiesSet(in App app, ref HTTPD_Request rq, RequestArgs args) { 133 Cookie[] cookies; 134 foreach(p; rq.query.byKeyValue) { 135 cookies ~= Cookie("/cookies", rq.requestHeaders["host"], p.key, p.value); 136 } 137 auto rs = response(rq, buildReply(rq), 302); 138 rs.headers["Location"] = "/cookies"; 139 rs.cookies = cookies; 140 return rs; 141 } 142 auto cookies(in App app, ref HTTPD_Request rq, RequestArgs args) { 143 auto cookies = ["cookies": JSONValue(rq.cookies)]; 144 auto rs = response(rq, JSONValue(cookies).toString); 145 return rs; 146 } 147 auto range(in App app, ref HTTPD_Request rq, RequestArgs args) { 148 auto size = to!size_t(args["size"]); 149 auto rs = response(rq, new ubyte[size].chunks(16)); 150 rs.compress(Compression.yes); 151 return rs; 152 } 153 auto basicAuth(in App app, ref HTTPD_Request rq, RequestArgs args) { 154 import std.base64; 155 auto user = args["user"]; 156 auto password= args["password"]; 157 auto auth = cast(string)Base64.decode(rq.requestHeaders["authorization"].split()[1]); 158 auto up = auth.split(":"); 159 short status; 160 if ( up[0]==user && up[1]==password) { 161 status = 200; 162 } else { 163 status = 401; 164 } 165 auto rs = response(rq, buildReply(rq), status); 166 rs.headers["Content-Type"] = "application/json"; 167 return rs; 168 } 169 auto delay(in App app, ref HTTPD_Request rq, RequestArgs args) { 170 auto delay = dur!"seconds"(to!long(args["delay"])); 171 Thread.sleep(delay); 172 auto rs = response(rq, buildReply(rq)); 173 rs.headers["Content-Type"] = "application/json"; 174 return rs; 175 } 176 auto stream(in App app, ref HTTPD_Request rq, RequestArgs args) { 177 auto lines = to!size_t(args["lines"]); 178 import std.stdio; 179 auto rs = response(rq, (buildReply(rq) ~ "\n").repeat(lines)); 180 rs.headers["Content-Type"] = "application/json"; 181 return rs; 182 } 183 server.addRoute(exactRoute(r"/", &root)). 184 addRoute(exactRoute(r"/get", &get)). 185 addRoute(exactRoute(r"/post", &post)). 186 addRoute(exactRoute(r"/delete", &del)). 187 addRoute(exactRoute(r"/put", &put)). 188 addRoute(exactRoute(r"/patch", &patch)). 189 addRoute(exactRoute(r"/cookies", &cookies)). 190 addRoute(exactRoute(r"/cookies/set", &cookiesSet)). 191 addRoute(exactRoute(r"/gzip", &gzip)). 192 addRoute(exactRoute(r"/deflate", &deflate)). 193 addRoute(regexRoute(r"/delay/(?P<delay>\d+)", &delay)). 194 addRoute(regexRoute(r"/stream/(?P<lines>\d+)", &stream)). 195 addRoute(regexRoute(r"/range/(?P<size>\d+)", &range)). 196 addRoute(regexRoute(r"/relative-redirect/(?P<redirects>\d+)", &rel_redir)). 197 addRoute(regexRoute(r"/absolute-redirect/(?P<redirects>\d+)", &abs_redir)). 198 addRoute(regexRoute(r"/basic-auth/(?P<user>[^/]+)/(?P<password>[^/]+)", &basicAuth)); 199 200 return server; 201 } 202 }