From 6294c7878e631225bb7585d561c94492d6ca60d3 Mon Sep 17 00:00:00 2001
From: jilio <22717553+jilio@users.noreply.github.com>
Date: Wed, 31 Jul 2019 11:10:53 +0700
Subject: [PATCH] vweb: recursive handle_static with mime types

---
 examples/vweb/test_app.v |  3 +-
 vlib/vweb/vweb.v         | 74 +++++++++++++++++++++++++++++++++-------
 2 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/examples/vweb/test_app.v b/examples/vweb/test_app.v
index 213fdb9114..5a0f3dd4a4 100644
--- a/examples/vweb/test_app.v
+++ b/examples/vweb/test_app.v
@@ -17,8 +17,7 @@ fn main() {
 }
 
 pub fn (app mut App) init() {
-	app.vweb.serve_static('/css.css', 'static/css.css')
-	app.vweb.serve_static('/jquery.js', 'static/jquery.js')
+	app.vweb.handle_static('.')
 }
 
 pub fn (app mut App) json_endpoint() {
diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v
index 7c95c10521..2417c03605 100644
--- a/vlib/vweb/vweb.v
+++ b/vlib/vweb/vweb.v
@@ -1,7 +1,3 @@
-// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
-// Use of this source code is governed by an MIT license
-// that can be found in the LICENSE file.
-
 module vweb
 
 import (
@@ -12,7 +8,8 @@ import (
 ) 
 
 struct Context {
-	static_files map[string]string 
+	static_files map[string]string
+	static_mime_types map[string]string
 pub: 
 	req http.Request 
 	conn net.Socket 
@@ -74,7 +71,6 @@ $html
 } 
 
 pub fn run<T>(port int) { 
-	println('Running vweb app on http://localhost:$port ...')  
 	l := net.listen(port) or { panic('failed to listen') return } 
 	for {
 		conn := l.accept() or {
@@ -104,6 +100,7 @@ pub fn run<T>(port int) {
 				conn: conn 
 				post_form: map[string]string{} 
 				static_files: map[string]string{} 
+				static_mime_types: map[string]string{}
 			} 
 		} 
 		app.init() 
@@ -115,11 +112,13 @@ pub fn run<T>(port int) {
 			println('no vals for http') 
 			return 
 		} 
+
 		// Serve a static file if it's one 
-		if app.vweb.handle_static() {
-			conn.close()
-			continue 
-		} 
+		// if app.vweb.handle_static() {
+		// 	conn.close()
+		// 	continue 
+		// } 
+
 		// Call the right action 
 		app.$action() 
 		conn.close()
@@ -146,12 +145,60 @@ fn (ctx mut Context) parse_form(s string) {
 	}
 } 
 
-fn (ctx mut Context) handle_static() bool { 
+fn (ctx mut Context) scan_static_directory(directory_path, mount_path string) {
+	// mime types
+	mut mime_types := map[string]string{}
+	mime_types['.css'] = 'text/css; charset=utf-8'
+	mime_types['.gif'] = 'image/gif'
+	mime_types['.htm'] = 'text/html; charset=utf-8'
+	mime_types['.html'] = 'text/html; charset=utf-8'
+	mime_types['.jpg'] = 'image/jpeg'
+	mime_types['.js'] = 'application/javascript'
+	mime_types['.wasm'] = 'application/wasm'
+	mime_types['.pdf'] = 'application/pdf'
+	mime_types['.png'] = 'image/png'
+	mime_types['.svg'] = 'image/svg+xml'
+	mime_types['.xml'] = 'text/xml; charset=utf-8'
+
+	files := os.ls(directory_path)
+
+	if files.len > 0 {
+		for file in files {			
+			mut ext := ''
+			mut i := file.len
+			mut flag := true
+			for i > 0 {
+		 		i--
+				if flag {
+					ext = file.substr(i, i + 1) + ext
+				}
+				if file.substr(i, i + 1) == '.' {
+					flag = false
+				}
+			}
+
+			// todo: os.is_dir is broken now
+			//       so we expect that file is dir it has no extension
+			if flag {
+				ctx.scan_static_directory(directory_path + '/' + file, mount_path + '/' + file)
+			} else {
+				ctx.static_files[mount_path + '/' + file] = directory_path + '/' + file 
+				ctx.static_mime_types[mount_path + '/' + file] = mime_types[ext]
+			}
+		}
+	}
+}
+
+pub fn (ctx mut Context) handle_static(directory_path string) bool { 
+	ctx.scan_static_directory(directory_path, '')
+
 	static_file := ctx.static_files[ctx.req.url] 
+	mime_type := ctx.static_mime_types[ctx.req.url]
+
 	if static_file != '' { 
 		data := os.read_file(static_file) or { return false }  
 		ctx.conn.write('HTTP/1.1 200 OK 
-Content-Type: text/css 
+Content-Type: $mime_type
 
 $data 
 ')
@@ -160,8 +207,9 @@ $data
 	return false 
 } 
 
-pub fn (ctx mut Context) serve_static(url, file_path string) { 
+pub fn (ctx mut Context) serve_static(url, file_path, mime_type string) { 
 	ctx.static_files[url] = file_path 
+	ctx.static_mime_types[url] = mime_type
 }