Merge 7fc3112c74 into 0dff050735
commit
b7b9d05bd6
|
|
@ -3,13 +3,39 @@ module vweb
|
|||
import net.urllib
|
||||
import net.http
|
||||
|
||||
fn parse_middleware(args []MethodArgs, attrs []string) ?string {
|
||||
if 'use' in attrs {
|
||||
for arg in args {
|
||||
// ast.string_type_idx = 20
|
||||
if arg.typ != 20 {
|
||||
return error('middleware arguments should be string type, `$arg.name` does not meet that rule')
|
||||
}
|
||||
}
|
||||
|
||||
for attr in attrs {
|
||||
if attr.starts_with('/') {
|
||||
params_len := attr.split('/').filter(it != '' && it.starts_with(':')).len
|
||||
if params_len != args.len {
|
||||
return error('number of middleware arguments does not meet with number of path params')
|
||||
}
|
||||
|
||||
return attr
|
||||
}
|
||||
}
|
||||
|
||||
return error("please specify path as attribute for middleware, example: ['/admin']")
|
||||
}
|
||||
|
||||
return none
|
||||
}
|
||||
|
||||
// Parsing function attributes for methods and path.
|
||||
fn parse_attrs(name string, attrs []string) ?([]http.Method, string) {
|
||||
if attrs.len == 0 {
|
||||
return [http.Method.get], '/$name'
|
||||
}
|
||||
|
||||
mut x := attrs.clone()
|
||||
mut x := attrs.clone().filter(it.to_lower() != 'use')
|
||||
mut methods := []http.Method{}
|
||||
mut path := ''
|
||||
|
||||
|
|
|
|||
104
vlib/vweb/vweb.v
104
vlib/vweb/vweb.v
|
|
@ -399,7 +399,18 @@ pub fn run_at<T>(global_app &T, params RunParams) ? {
|
|||
|
||||
// Parsing methods attributes
|
||||
mut routes := map[string]Route{}
|
||||
mut middlewares := map[string]string{}
|
||||
$for method in T.methods {
|
||||
if middleware_path := parse_middleware(method.args, method.attrs) {
|
||||
middlewares[method.name] = middleware_path
|
||||
} else {
|
||||
// There is no `use` attribute, so it returns `none`
|
||||
if err.str() != 'none' {
|
||||
eprintln('error parsing `app.$method.name` attributes: $err')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
http_methods, route_path := parse_attrs(method.name, method.attrs) or {
|
||||
return error('error parsing method attributes: $err')
|
||||
}
|
||||
|
|
@ -430,12 +441,12 @@ pub fn run_at<T>(global_app &T, params RunParams) ? {
|
|||
eprintln('accept() failed with error: $err.msg()')
|
||||
continue
|
||||
}
|
||||
go handle_conn<T>(mut conn, mut request_app, routes)
|
||||
go handle_conn<T>(mut conn, mut request_app, routes, middlewares)
|
||||
}
|
||||
}
|
||||
|
||||
[manualfree]
|
||||
fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) {
|
||||
fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route, middlewares map[string]string) {
|
||||
conn.set_read_timeout(30 * time.second)
|
||||
conn.set_write_timeout(30 * time.second)
|
||||
defer {
|
||||
|
|
@ -527,15 +538,25 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) {
|
|||
for param in method.args {
|
||||
args << form[param.name]
|
||||
}
|
||||
app.$method(args)
|
||||
|
||||
fire_middlewares(mut app, url_words, middlewares)
|
||||
if app.done == false {
|
||||
app.$method(args)
|
||||
}
|
||||
} else {
|
||||
app.$method()
|
||||
fire_middlewares(mut app, url_words, middlewares)
|
||||
if app.done == false {
|
||||
app.$method()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if url_words.len == 0 && route_words == ['index'] && method.name == 'index' {
|
||||
app.$method()
|
||||
fire_middlewares(mut app, url_words, middlewares)
|
||||
if app.done == false {
|
||||
app.$method()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -544,7 +565,10 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) {
|
|||
if method_args.len != method.args.len {
|
||||
eprintln('warning: uneven parameters count ($method.args.len) in `$method.name`, compared to the vweb route `$method.attrs` ($method_args.len)')
|
||||
}
|
||||
app.$method(method_args)
|
||||
fire_middlewares(mut app, url_words, middlewares)
|
||||
if app.done == false {
|
||||
app.$method(method_args)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -554,6 +578,74 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) {
|
|||
conn.write(vweb.http_404.bytes()) or {}
|
||||
}
|
||||
|
||||
struct Firable_middleware {
|
||||
method string
|
||||
params []string
|
||||
path_len int
|
||||
}
|
||||
|
||||
fn fire_middlewares<T>(mut app T, url_words []string, middlewares map[string]string) {
|
||||
mut fire_those := []Firable_middleware{}
|
||||
for m, path in middlewares {
|
||||
path_words := path.split('/').filter(it != '')
|
||||
|
||||
if path_words.len == 0 {
|
||||
fire_those << Firable_middleware{
|
||||
method: m
|
||||
path_len: path_words.len
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if path_words.len > url_words.len {
|
||||
continue
|
||||
}
|
||||
|
||||
ext_words := url_words[..path_words.len]
|
||||
|
||||
if !path.contains('/:') && path_words == ext_words {
|
||||
fire_those << Firable_middleware{
|
||||
method: m
|
||||
path_len: path_words.len
|
||||
}
|
||||
} else if path_words.last().starts_with(':') && path_words.last().ends_with('...') {
|
||||
if params := route_matches(url_words, path_words) {
|
||||
fire_those << Firable_middleware{
|
||||
method: m
|
||||
params: params
|
||||
path_len: path_words.len
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if params := route_matches(ext_words, path_words) {
|
||||
fire_those << Firable_middleware{
|
||||
method: m
|
||||
params: params
|
||||
path_len: path_words.len
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fire_those.sort(a.path_len < b.path_len)
|
||||
|
||||
for f in fire_those {
|
||||
fire_middleware(mut app, f.method, f.params)
|
||||
}
|
||||
}
|
||||
|
||||
fn fire_middleware<T>(mut app T, method_name string, params []string) {
|
||||
$for method in T.methods {
|
||||
if method_name == method.name {
|
||||
if method.args.len > 0 && params.len == method.args.len {
|
||||
app.$method(params)
|
||||
} else {
|
||||
app.$method()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn route_matches(url_words []string, route_words []string) ?[]string {
|
||||
// URL path should be at least as long as the route path
|
||||
// except for the catchall route (`/:path...`)
|
||||
|
|
|
|||
Loading…
Reference in New Issue