diff --git a/vlib/vweb/tests/controller_test.v b/vlib/vweb/tests/controller_test.v index 7b83c6f616034e..2201132c74bd83 100644 --- a/vlib/vweb/tests/controller_test.v +++ b/vlib/vweb/tests/controller_test.v @@ -88,6 +88,16 @@ fn test_other_path() { assert x.body == 'Other path' } +fn test_other_hided_home() { + x := http.get('http://${localserver}/other/hide') or { panic(err) } + assert x.body == 'Other' +} + +fn test_other_hided_path() { + x := http.get('http://${localserver}/other/hide/path') or { panic(err) } + assert x.body == 'Other path' +} + fn test_different_404() { res_app := http.get('http://${localserver}/zxcnbnm') or { panic(err) } assert res_app.status() == .not_found diff --git a/vlib/vweb/tests/controller_test_server.v b/vlib/vweb/tests/controller_test_server.v index 5caabbbf69ee17..a4767ee2037dc2 100644 --- a/vlib/vweb/tests/controller_test_server.v +++ b/vlib/vweb/tests/controller_test_server.v @@ -18,6 +18,10 @@ struct Other { vweb.Context } +struct OtherHidedByOther { + vweb.Context +} + fn exit_after_timeout(timeout_in_ms int) { time.sleep(timeout_in_ms * time.millisecond) println('>> webserver: pid: ${os.getpid()}, exiting ...') @@ -38,6 +42,7 @@ fn main() { controllers: [ vweb.controller('/admin', &Admin{}), vweb.controller('/other', &Other{}), + vweb.controller('/other/hide', &OtherHidedByOther{}), ] } @@ -85,6 +90,16 @@ pub fn (mut app Other) other_path() vweb.Result { return app.text('Other path') } +['/'] +pub fn (mut app OtherHidedByOther) other_home() vweb.Result { + return app.text('Other') +} + +['/path'] +pub fn (mut app OtherHidedByOther) other_path() vweb.Result { + return app.text('Other path') +} + // utility functions: pub fn (mut app App) shutdown() vweb.Result { diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index d3054ee09b965f..25ed9eb7e19fb9 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -522,10 +522,16 @@ pub fn run_at[T](global_app &T, params RunParams) ! { routes := generate_routes(global_app)! // check duplicate routes in controllers + mut controllers_sorted := []&ControllerPath{} $if T is ControllerInterface { mut paths := []string{} - for controller in global_app.controllers { + controllers_sorted = global_app.controllers.clone() + controllers_sorted.sort(a.path.len > b.path.len) + for controller in controllers_sorted { if controller.host == '' { + if controller.path in paths { + return error('conflicting paths: duplicate controller handling the route "${controller.path}"') + } paths << controller.path } } @@ -564,6 +570,7 @@ pub fn run_at[T](global_app &T, params RunParams) ! { ch <- &RequestParams{ connection: connection global_app: unsafe { global_app } + controllers: controllers_sorted routes: &routes } } @@ -612,7 +619,7 @@ fn new_request_app[T](global_app &T, ctx Context, tid int) &T { } [manualfree] -fn handle_conn[T](mut conn net.TcpConn, global_app &T, routes &map[string]Route, tid int) { +fn handle_conn[T](mut conn net.TcpConn, global_app &T, controllers []&ControllerPath, routes &map[string]Route, tid int) { conn.set_read_timeout(30 * time.second) conn.set_write_timeout(30 * time.second) defer { @@ -680,7 +687,7 @@ fn handle_conn[T](mut conn net.TcpConn, global_app &T, routes &map[string]Route, // match controller paths $if T is ControllerInterface { - for controller in global_app.controllers { + for controller in controllers { // skip controller if the hosts don't match if controller.host != '' && host != controller.host { continue @@ -1077,8 +1084,9 @@ fn filter(s string) string { // Worker functions for the thread pool: struct RequestParams { - global_app voidptr - routes &map[string]Route + global_app voidptr + controllers []&ControllerPath + routes &map[string]Route mut: connection &net.TcpConn } @@ -1103,7 +1111,8 @@ fn (mut w Worker[T]) process_incomming_requests() { $if vweb_trace_worker_scan ? { eprintln(sid) } - handle_conn[T](mut params.connection, params.global_app, params.routes, w.id) + handle_conn[T](mut params.connection, params.global_app, params.controllers, params.routes, + w.id) } $if vweb_trace_worker_scan ? { eprintln('[vweb] closing worker ${w.id}.')