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 }