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 + @css +
+ +

@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) {