diff --git a/examples/vweb/vweb_assets/assets/index.css b/examples/vweb/vweb_assets/assets/index.css
new file mode 100644
index 0000000000..4ad9eb895f
--- /dev/null
+++ b/examples/vweb/vweb_assets/assets/index.css
@@ -0,0 +1,19 @@
+body {
+ font-family: Arial, Helvetica, sans-serif;
+ color: #eee;
+ background-color: #333;
+ background-image: url("v-logo.svg");
+ background-repeat: no-repeat;
+ background-size: 10em;
+ margin: 0;
+ padding-left: 11em;
+}
+
+h1 {
+ color: #6699CC;
+}
+
+img.logo {
+ float: left;
+ width: 10em;
+}
diff --git a/examples/vweb/vweb_assets/assets/v-logo.svg b/examples/vweb/vweb_assets/assets/v-logo.svg
new file mode 100644
index 0000000000..9a4ec604c0
--- /dev/null
+++ b/examples/vweb/vweb_assets/assets/v-logo.svg
@@ -0,0 +1 @@
+
diff --git a/examples/vweb/vweb_assets/favicon.ico b/examples/vweb/vweb_assets/favicon.ico
new file mode 100644
index 0000000000..fa834c378e
Binary files /dev/null and b/examples/vweb/vweb_assets/favicon.ico differ
diff --git a/examples/vweb/vweb_assets/index.html b/examples/vweb/vweb_assets/index.html
new file mode 100644
index 0000000000..bdfa670d29
--- /dev/null
+++ b/examples/vweb/vweb_assets/index.html
@@ -0,0 +1,12 @@
+
+
+
+ @title
+ @subtitle
+ @message
+
+
+
diff --git a/examples/vweb/vweb_assets/main.v b/examples/vweb/vweb_assets/main.v
new file mode 100644
index 0000000000..c266e11892
--- /dev/null
+++ b/examples/vweb/vweb_assets/main.v
@@ -0,0 +1,53 @@
+module main
+
+import (
+ vweb
+ vweb.assets
+ time
+)
+
+const (
+ port = 8081
+)
+
+pub struct App {
+mut:
+ vweb vweb.Context
+}
+
+fn main() {
+ vweb.run(port)
+}
+
+pub fn (app mut App) init() {
+ // Arbitary mime type.
+ app.vweb.serve_static('/favicon.ico', 'favicon.ico', 'img/x-icon')
+ // Automatically make available known static mime types found in given directory.
+ app.vweb.handle_static('assets')
+ // This would make available all known static mime types from current
+ // directory and below.
+ //app.vweb.handle_static('.')
+}
+
+pub fn (app mut App) reset() {}
+
+fn (app mut App) index() {
+ // We can dynamically specify which assets are to be used in template.
+ mut am := assets.new_manager()
+ am.add_css('assets/index.css')
+
+ css := am.include_css(false)
+ title := 'VWeb Assets Example'
+ subtitle := 'VWeb can serve static assets too!'
+ message := 'It also has an Assets Manager that allows dynamically specifying which CSS and JS files to be used.'
+
+ $vweb.html()
+}
+
+fn (app mut App) text() {
+ app.vweb.text('Hello, world from vweb!')
+}
+
+fn (app mut App) time() {
+ app.vweb.text(time.now().format())
+}
diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v
index f1e10de6f7..dcb7c11d07 100644
--- a/vlib/vweb/vweb.v
+++ b/vlib/vweb/vweb.v
@@ -10,6 +10,7 @@ import (
net.http
net.urllib
strings
+ filepath
)
pub const (
@@ -250,8 +251,8 @@ fn handle_conn(conn net.Socket, app mut T) {
req: req
conn: conn
form: map[string]string
- static_files: map[string]string
- static_mime_types: map[string]string
+ static_files: app.vweb.static_files
+ static_mime_types: app.vweb.static_mime_types
}
//}
if req.method in methods_with_form {
@@ -269,10 +270,17 @@ fn handle_conn(conn net.Socket, app mut T) {
}
// Serve a static file if it's one
- // if app.vweb.handle_static() {
- // conn.close()
- // continue
- // }
+ static_file := app.vweb.static_files[app.vweb.req.url]
+ mime_type := app.vweb.static_mime_types[app.vweb.req.url]
+
+ if static_file != '' && mime_type != '' {
+ data := os.read_file(static_file) or {
+ conn.send_string(HTTP_404) or {}
+ return
+ }
+ app.vweb.send_response_to_client(mime_type, data)
+ return
+ }
// Call the right action
$if debug {
@@ -316,45 +324,40 @@ fn (ctx mut Context) parse_form(s string) {
fn (ctx mut Context) scan_static_directory(directory_path, mount_path string) {
files := os.ls(directory_path) or { panic(err) }
+
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[i..i + 1] + ext
- }
- if file[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 {
if os.is_dir(file) {
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]
+ } else if file.contains('.') && ! file.starts_with('.') && ! file.ends_with('.') {
+ ext := filepath.ext(file)
+
+ // Rudimentary guard against adding files not in mime_types.
+ // Use serve_static directly to add non-standard mime types.
+ if ext in mime_types {
+ ctx.serve_static(mount_path + '/' + file, directory_path + '/' + file, mime_types[ext])
+ }
}
}
}
}
pub fn (ctx mut Context) handle_static(directory_path string) bool {
- if ctx.done { return false }
- 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 }
- return ctx.send_response_to_client(mime_type, data)
+ if ctx.done || ! os.exists(directory_path) {
+ return false
}
- return false
+
+ dir_path := directory_path.trim_space()
+ mut mount_path := ''
+
+ if dir_path != '.' && os.is_dir(dir_path) {
+ mount_path = '/' + dir_path
+ }
+
+ ctx.scan_static_directory(directory_path, mount_path)
+
+ return true
}
pub fn (ctx mut Context) serve_static(url, file_path, mime_type string) {