From 750f37fde79ed84cbfcf6e25255d6849daa65172 Mon Sep 17 00:00:00 2001 From: "Ian M. Jones" Date: Sat, 7 Mar 2020 13:16:03 +0000 Subject: [PATCH] vweb: fix serving static files --- examples/vweb/vweb_assets/assets/index.css | 19 ++++++ examples/vweb/vweb_assets/assets/v-logo.svg | 1 + examples/vweb/vweb_assets/favicon.ico | Bin 0 -> 15406 bytes examples/vweb/vweb_assets/index.html | 12 ++++ examples/vweb/vweb_assets/main.v | 53 +++++++++++++++ vlib/vweb/vweb.v | 69 ++++++++++---------- 6 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 examples/vweb/vweb_assets/assets/index.css create mode 100644 examples/vweb/vweb_assets/assets/v-logo.svg create mode 100644 examples/vweb/vweb_assets/favicon.ico create mode 100644 examples/vweb/vweb_assets/index.html create mode 100644 examples/vweb/vweb_assets/main.v 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 0000000000000000000000000000000000000000..fa834c378eefbad8b5ff7211e4158d5ac5e62816 GIT binary patch literal 15406 zcmeHOYiu0V72Xg6DJ3F6A#H`gfYd~^6{JD5s1k}QH81MLJL5@WduHQMXYG9@BtNPo zMOnx8&dl!GA+d>2lBx(0Q85T8c|acCwT+<&g({7rv{h*YD&$d;v}!`g)6?(Rd)Ifz zyYpDPF;YF!=+1qdbH01#%)R%Vd&lFM;F;)|I@N=;%+qka$McBC<0&f}%+I*hcA{X0CK8E69%Pz;tMxn@^Jt(uWm<-Uw2|AFqk%{3o11s43!DS&QWZp&zj z!S3I!U1;cGUz-#9&Q57!Mpce6T1q#s5R61fJk}{m6YY3(X*F|r+Py6`hSpGFB*UVS z3{}ptqwm&~7kK)YS4&2MXmKaP!i!e)2O0x6f&M={efx4@Q1$@5cs8ZX`DQU5>A1g| zr^P!skq8OL2C!!_q#{CfF?z_}l~1p!o*vJ;3emrpQtrgNzRc5itNuq*Ve!ZL z^upy-gYQl=kF=^R=V|c{j~ZmUxbg1(&hvmimz(J!`$L{S9amJ=Mh^;co<128K4f*2 zrkmyI-MZ4x)9=%3a`pec0E$BNLL)(!_8%~XJXn~b%s?+PeY)oG;oWsaUx>e<6EBSA(TWmBhdm=j@iQ7je zEuXqC;hh56=d9#!dCF(#q1>EwF7c#yNcAs05F$~bb_e;e9yH?HeO!@O#eZ@H@t5BK>SLW6`Zg9k6vFk9$d}5N9 zTYC?btMaSKh`7CwT(0bsSj=;s8`;#hM_=-orEGlj7?XumNG#`M4bwl>wT6Yq+{y>< ztyc1}w);2cw-Q|E)cGBV?bkl8?IQ8P8-`*k&akb!TF=vnR9m zb}8xAMz%rz5aW}I_t~b+} z^N`(ZDSycSGLue#9e&Kq8}=L$d(A|AeowPRP;vhlhR#p?dr-{g&FNLdiM0R4{*+lK6wyhK}XAK*7^448xJ4<@jim2P}Q^zSRIPeWvPAfJ$mipzlOOQ(Gxdut7eD@OxA1_L@@bI6I# zxiN3F0Hs5^CF zOJG<` zbPxO=WRkVtE{1>OimGYA^PW@u*>*>04lKsASULQ25%C?%^I5#@13USXt%tdB$ILq> zNjKmdNCMYY7k#)~N{kEmck=jbpLOM5IHOQu#%#{FMFcO-WSntx9-^Y!*{vK4Ss5ib2^Po z2Uh98T2oV8#ioG2zc(rW$cist*VZs_wjJ?v=Y9eDe9+07l=k?6=ad`$<1FMyF4yb$ zM?pB?20z-KqO$_L9?Z{}Hzxs09N4co#*e*=9$g8WdD-QGCrsnJi#}XQ;=hV5fxx6< zya)aXQEko{nd~0@Jl>a(bN^Np<83ZatdOPy`*9ceX+6|i=wB4ZyDQ;;1bFOXQ~j8e zadt)d66qIMFC=#~y59q$ITiZHTu}K1<^=K$=uC^<`#7Iykmz@?f){K*f}7ULv={mr z?!(CAzbs`3QmjMe4*Ji4&i-~M}9 z=MGwTqAxpe_n~ix(a+D&&vWqOXgv`r#=2LP?L&!qp!_R+p*qUJ7&chdQwOia3& z=2qJ8Ek-}ma^g*~6Y@Ffyb;Y6STo&)_{)82M4Un6mKv4tx83+Pu7Pn4jB8-*HSk{~ CV;+D2 literal 0 HcmV?d00001 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) {