1 /** 2 This module implements HTTP server functionalities through the use of vibe.d. 3 4 Originally conceived as a replacement of the SimpleHTTPServer library for python 5 for both use as standalone or library. 6 7 The entire code is encapsulated in a class that can be inherited. 8 9 Copyright: Francesco mecca 10 License: Public Domain 11 Authors: Francesco Mecca 12 */ 13 14 module dummy_web_server; 15 16 import vibe.core.core, vibe.http.server, vibe.http.router, vibe.http.fileserver; 17 import std.path; 18 import std.file; 19 import std.stdio; 20 import std.file; 21 import diet.html; 22 import vibe.stream.wrapper; 23 import std..string; 24 25 /** 26 The Serve class contains the whole logic of the program. 27 It is to be used when linking to this program. 28 */ 29 30 class Serve { 31 32 protected HTTPServerSettings settings = void; 33 protected URLRouter router = void; 34 bool verbose = false; 35 private string cwd = void; 36 private string file; 37 38 /** 39 * Constructor 40 */ 41 this(string host="127.0.0.1", short port=8000, string file=".", bool verbose=false) 42 { 43 if (host == "localhost") host = "127.0.0.1"; 44 this.verbose = verbose; 45 this.file = file; 46 settings = new HTTPServerSettings; 47 settings.port = port; 48 settings.bindAddresses = [host]; 49 router = addBuildPaths (); 50 } 51 52 53 /** 54 * Serve the directory specified using a Vibe.d event loop. 55 * The function first binds using the settings of the class 56 * then exectues the event loop. 57 */ 58 void serve() 59 { 60 listenHTTP(settings, router); 61 runEventLoop(); 62 } 63 64 /** 65 * Stop the event loop. 66 * It is automatically called at scope(exit) 67 */ 68 void stop() 69 { 70 exitEventLoop(); 71 } 72 73 /** 74 * Depending on the type of file: 75 * - file: serve the file only; 76 * - directory: build a listdir representation; 77 */ 78 protected URLRouter addBuildPaths () 79 { 80 auto router = new URLRouter; 81 auto fileUrl = "/"; // if a file is to be served, be the root 82 if (this.file.isDir) { 83 cwd = this.file; 84 router.get("/", &serveIndex); 85 router.any("*", &serveIndex); 86 fileUrl = "*"; 87 } else { 88 cwd = getcwd (); 89 } 90 router.get(fileUrl, serveStaticFiles(file)); // entry point for file, managed by vibe.d 91 92 return router; 93 } 94 95 /** 96 * Replies to request. 97 * Serve a file or build a listdir representation in case of a directory. 98 * It uses a diet template for the latter. 99 */ 100 protected void serveIndex (HTTPServerRequest req, HTTPServerResponse res) 101 { 102 if (verbose) infoVerbose(req, res); 103 104 auto requestedFile = cwd ~ req.requestURL; 105 if (!requestedFile.exists) { 106 //writeln ("Requested non existent file"); 107 } else if (!requestedFile.isDir) { 108 //writeln ("requestedFile"); 109 // pass through 110 } else { 111 auto cutHere = cwd.length + 1; // account for final "/" 112 // is a directory, use the template 113 //writeln ("Requested directory contents"); 114 auto dst = StreamOutputRange (res.bodyWriter); 115 auto title = "Directory listing for " ~ req.requestURL; 116 auto dir = dirEntries (requestedFile, SpanMode.shallow); 117 dst.compileHTMLDietFile !("temp.dt", title, dir, cutHere); 118 } 119 } 120 121 /** 122 * Function to override if custom informations are to be printed. 123 */ 124 protected void infoVerbose(HTTPServerRequest req, HTTPServerResponse res) 125 { 126 writeln (req.host ~ " - " ~ req.timeCreated().toString ~ " - " ~ req.toString()); 127 } 128 }