diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl index dfeae6d64..80894319b 100644 --- a/apps/emqx/src/emqx_schema.erl +++ b/apps/emqx/src/emqx_schema.erl @@ -1540,7 +1540,8 @@ fields("broker") -> boolean(), #{ default => true, - desc => ?DESC(broker_route_batch_clean) + desc => "This config is stale since 4.3", + importance => ?IMPORTANCE_HIDDEN } )}, {"perf", diff --git a/apps/emqx_conf/src/emqx_conf.app.src b/apps/emqx_conf/src/emqx_conf.app.src index e6c3d9cd9..c31a16b9b 100644 --- a/apps/emqx_conf/src/emqx_conf.app.src +++ b/apps/emqx_conf/src/emqx_conf.app.src @@ -1,6 +1,6 @@ {application, emqx_conf, [ {description, "EMQX configuration management"}, - {vsn, "0.1.19"}, + {vsn, "0.1.20"}, {registered, []}, {mod, {emqx_conf_app, []}}, {applications, [kernel, stdlib, emqx_ctl]}, diff --git a/apps/emqx_conf/src/emqx_conf_schema.erl b/apps/emqx_conf/src/emqx_conf_schema.erl index 94cbfb221..b37c3f71e 100644 --- a/apps/emqx_conf/src/emqx_conf_schema.erl +++ b/apps/emqx_conf/src/emqx_conf_schema.erl @@ -508,6 +508,7 @@ fields("node") -> desc => ?DESC(node_crash_dump_file), default => crash_dump_file_default(), importance => ?IMPORTANCE_HIDDEN, + converter => fun ensure_unicode_path/2, 'readOnly' => true } )}, @@ -754,6 +755,7 @@ fields("rpc") -> file(), #{ mapping => "gen_rpc.certfile", + converter => fun ensure_unicode_path/2, desc => ?DESC(rpc_certfile) } )}, @@ -762,6 +764,7 @@ fields("rpc") -> file(), #{ mapping => "gen_rpc.keyfile", + converter => fun ensure_unicode_path/2, desc => ?DESC(rpc_keyfile) } )}, @@ -770,6 +773,7 @@ fields("rpc") -> file(), #{ mapping => "gen_rpc.cacertfile", + converter => fun ensure_unicode_path/2, desc => ?DESC(rpc_cacertfile) } )}, @@ -892,9 +896,10 @@ fields("log_file_handler") -> file(), #{ desc => ?DESC("log_file_handler_file"), - default => <<"${EMQX_LOG_DIR}/emqx.log">>, - converter => fun emqx_schema:naive_env_interpolation/1, - validator => fun validate_file_location/1 + converter => fun(Path, Opts) -> + emqx_schema:naive_env_interpolation(ensure_unicode_path(Path, Opts)) + end, + default => <<"${EMQX_LOG_DIR}/emqx.log">> } )}, {"rotation", @@ -1333,11 +1338,6 @@ emqx_schema_high_prio_roots() -> )}, lists:keyreplace("authorization", 1, Roots, Authz). -validate_file_location(File) -> - ValidFile = "^[/\\_a-zA-Z0-9\\.\\-]*$", - Error = "Invalid file name: " ++ ValidFile, - validator_string_re(File, ValidFile, Error). - validate_time_offset(Offset) -> ValidTimeOffset = "^([\\-\\+][0-1][0-9]:[0-6][0-9]|system|utc)$", Error = @@ -1355,3 +1355,20 @@ validator_string_re(Val, RE, Error) -> node_array() -> hoconsc:union([emqx_schema:comma_separated_atoms(), hoconsc:array(atom())]). + +ensure_unicode_path(undefined, _) -> + undefined; +ensure_unicode_path(Path, #{make_serializable := true}) -> + %% format back to serializable string + unicode:characters_to_binary(Path, utf8); +ensure_unicode_path(Path, Opts) when is_binary(Path) -> + case unicode:characters_to_list(Path, utf8) of + {R, _, _} when R =:= error orelse R =:= incomplete -> + throw({"bad_file_path_string", Path}); + PathStr -> + ensure_unicode_path(PathStr, Opts) + end; +ensure_unicode_path(Path, _) when is_list(Path) -> + Path; +ensure_unicode_path(Path, _) -> + throw({"not_string", Path}). diff --git a/apps/emqx_conf/test/emqx_conf_schema_tests.erl b/apps/emqx_conf/test/emqx_conf_schema_tests.erl index 06784e32d..4eaf3db6b 100644 --- a/apps/emqx_conf/test/emqx_conf_schema_tests.erl +++ b/apps/emqx_conf/test/emqx_conf_schema_tests.erl @@ -232,3 +232,47 @@ ensure_acl_conf() -> true -> ok; false -> file:write_file(File, <<"">>) end. + +log_path_test_() -> + Fh = fun(Path) -> + #{<<"log">> => #{<<"file_handlers">> => #{<<"name1">> => #{<<"file">> => Path}}}} + end, + Assert = fun(Name, Path, Conf) -> + ?assertMatch(#{log := #{file_handlers := #{Name := #{file := Path}}}}, Conf) + end, + + [ + {"default-values", fun() -> Assert(default, "log/emqx.log", check(#{})) end}, + {"file path with space", fun() -> Assert(name1, "a /b", check(Fh(<<"a /b">>))) end}, + {"windows", fun() -> Assert(name1, "c:\\a\\ b\\", check(Fh(<<"c:\\a\\ b\\">>))) end}, + {"unicoded", fun() -> Assert(name1, "路 径", check(Fh(<<"路 径"/utf8>>))) end}, + {"bad utf8", fun() -> + ?assertThrow( + {emqx_conf_schema, [ + #{ + kind := validation_error, + reason := {"bad_file_path_string", _} + } + ]}, + check(Fh(<<239, 32, 132, 47, 117, 116, 102, 56>>)) + ) + end}, + {"not string", fun() -> + ?assertThrow( + {emqx_conf_schema, [ + #{ + kind := validation_error, + reason := {"not_string", _} + } + ]}, + check(Fh(#{<<"foo">> => <<"bar">>})) + ) + end} + ]. + +check(Config) -> + Schema = emqx_conf_schema, + {_, Conf} = hocon_tconf:map(Schema, Config, [log], #{ + atom_key => false, required => false, format => map + }), + emqx_utils_maps:unsafe_atom_key_map(Conf). diff --git a/rel/i18n/emqx_schema.hocon b/rel/i18n/emqx_schema.hocon index af26d2fdb..5d6977b47 100644 --- a/rel/i18n/emqx_schema.hocon +++ b/rel/i18n/emqx_schema.hocon @@ -213,9 +213,6 @@ pending connections can grow to.""" fields_tcp_opts_backlog.label: """TCP backlog length""" -broker_route_batch_clean.desc: -"""Enable batch clean for deleted routes.""" - fields_mqtt_quic_listener_initial_window_packets.desc: """The size (in packets) of the initial congestion window for a connection. Default: 10""" diff --git a/rel/i18n/zh/emqx_schema.hocon b/rel/i18n/zh/emqx_schema.hocon index 835372868..0e329eac9 100644 --- a/rel/i18n/zh/emqx_schema.hocon +++ b/rel/i18n/zh/emqx_schema.hocon @@ -208,9 +208,6 @@ fields_tcp_opts_backlog.desc: fields_tcp_opts_backlog.label: """TCP 连接队列长度""" -broker_route_batch_clean.desc: -"""是否开启批量清除路由。""" - fields_mqtt_quic_listener_initial_window_packets.desc: """一个连接的初始拥堵窗口的大小(以包为单位)。默认值:10"""