diff options
author | Dr Scofield | 2009-03-27 12:49:27 +0000 |
---|---|---|
committer | Dr Scofield | 2009-03-27 12:49:27 +0000 |
commit | bf4d701cd5ae74dfc0d52feddee1614b93f5a569 (patch) | |
tree | 0e229ad86f200df427e66a530e4ecbaafc64558b | |
parent | Forgot to comment an unnecessary log message on my last commit. (diff) | |
download | opensim-SC_OLD-bf4d701cd5ae74dfc0d52feddee1614b93f5a569.zip opensim-SC_OLD-bf4d701cd5ae74dfc0d52feddee1614b93f5a569.tar.gz opensim-SC_OLD-bf4d701cd5ae74dfc0d52feddee1614b93f5a569.tar.bz2 opensim-SC_OLD-bf4d701cd5ae74dfc0d52feddee1614b93f5a569.tar.xz |
From: Alan Webb <alan_webb@us.ibm.com>
Fixed problem with REST services caused by changes to the OpenSim
core code base - the comms manager had been 'modularized'.
Also added additional debugging to RemoteAdmin interface.
Diffstat (limited to '')
6 files changed, 67 insertions, 49 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 6465db2..329a489 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs | |||
@@ -48,6 +48,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
48 | { | 48 | { |
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 50 | ||
51 | private static Object rslock = new Object(); | ||
52 | |||
51 | private OpenSimBase m_app; | 53 | private OpenSimBase m_app; |
52 | private BaseHttpServer m_httpd; | 54 | private BaseHttpServer m_httpd; |
53 | private IConfig m_config; | 55 | private IConfig m_config; |
@@ -186,6 +188,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
186 | response.Value = responseData; | 188 | response.Value = responseData; |
187 | } | 189 | } |
188 | 190 | ||
191 | m_log.Info("[RADMIN]: Restart Region request complete"); | ||
189 | return response; | 192 | return response; |
190 | } | 193 | } |
191 | 194 | ||
@@ -194,6 +197,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
194 | XmlRpcResponse response = new XmlRpcResponse(); | 197 | XmlRpcResponse response = new XmlRpcResponse(); |
195 | Hashtable responseData = new Hashtable(); | 198 | Hashtable responseData = new Hashtable(); |
196 | 199 | ||
200 | m_log.Info("[RADMIN]: Alert request started"); | ||
201 | |||
197 | try | 202 | try |
198 | { | 203 | { |
199 | Hashtable requestData = (Hashtable) request.Params[0]; | 204 | Hashtable requestData = (Hashtable) request.Params[0]; |
@@ -230,6 +235,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
230 | response.Value = responseData; | 235 | response.Value = responseData; |
231 | } | 236 | } |
232 | 237 | ||
238 | m_log.Info("[RADMIN]: Alert request complete"); | ||
233 | return response; | 239 | return response; |
234 | } | 240 | } |
235 | 241 | ||
@@ -238,6 +244,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
238 | XmlRpcResponse response = new XmlRpcResponse(); | 244 | XmlRpcResponse response = new XmlRpcResponse(); |
239 | Hashtable responseData = new Hashtable(); | 245 | Hashtable responseData = new Hashtable(); |
240 | 246 | ||
247 | m_log.Info("[RADMIN]: Load height maps request started"); | ||
248 | |||
241 | try | 249 | try |
242 | { | 250 | { |
243 | Hashtable requestData = (Hashtable) request.Params[0]; | 251 | Hashtable requestData = (Hashtable) request.Params[0]; |
@@ -283,12 +291,16 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
283 | responseData["error"] = e.Message; | 291 | responseData["error"] = e.Message; |
284 | } | 292 | } |
285 | 293 | ||
294 | m_log.Info("[RADMIN]: Load height maps request complete"); | ||
295 | |||
286 | return response; | 296 | return response; |
287 | } | 297 | } |
288 | 298 | ||
289 | public XmlRpcResponse XmlRpcShutdownMethod(XmlRpcRequest request) | 299 | public XmlRpcResponse XmlRpcShutdownMethod(XmlRpcRequest request) |
290 | { | 300 | { |
301 | |||
291 | m_log.Info("[RADMIN]: Received Shutdown Administrator Request"); | 302 | m_log.Info("[RADMIN]: Received Shutdown Administrator Request"); |
303 | |||
292 | XmlRpcResponse response = new XmlRpcResponse(); | 304 | XmlRpcResponse response = new XmlRpcResponse(); |
293 | Hashtable responseData = new Hashtable(); | 305 | Hashtable responseData = new Hashtable(); |
294 | 306 | ||
@@ -347,6 +359,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
347 | 359 | ||
348 | response.Value = responseData; | 360 | response.Value = responseData; |
349 | } | 361 | } |
362 | m_log.Info("[RADMIN]: Shutdown Administrator Request complete"); | ||
350 | return response; | 363 | return response; |
351 | } | 364 | } |
352 | 365 | ||
@@ -433,7 +446,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
433 | XmlRpcResponse response = new XmlRpcResponse(); | 446 | XmlRpcResponse response = new XmlRpcResponse(); |
434 | Hashtable responseData = new Hashtable(); | 447 | Hashtable responseData = new Hashtable(); |
435 | 448 | ||
436 | lock (this) | 449 | lock (rslock) |
437 | { | 450 | { |
438 | int m_regionLimit = m_config.GetInt("region_limit", 0); | 451 | int m_regionLimit = m_config.GetInt("region_limit", 0); |
439 | 452 | ||
@@ -605,6 +618,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
605 | 618 | ||
606 | response.Value = responseData; | 619 | response.Value = responseData; |
607 | } | 620 | } |
621 | m_log.Info("[RADMIN]: CreateRegion: request complete"); | ||
608 | return response; | 622 | return response; |
609 | } | 623 | } |
610 | } | 624 | } |
@@ -641,7 +655,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
641 | XmlRpcResponse response = new XmlRpcResponse(); | 655 | XmlRpcResponse response = new XmlRpcResponse(); |
642 | Hashtable responseData = new Hashtable(); | 656 | Hashtable responseData = new Hashtable(); |
643 | 657 | ||
644 | lock (this) | 658 | lock (rslock) |
645 | { | 659 | { |
646 | try | 660 | try |
647 | { | 661 | { |
@@ -671,6 +685,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
671 | response.Value = responseData; | 685 | response.Value = responseData; |
672 | } | 686 | } |
673 | 687 | ||
688 | m_log.Info("[RADMIN]: DeleteRegion: request complete"); | ||
674 | return response; | 689 | return response; |
675 | } | 690 | } |
676 | } | 691 | } |
@@ -719,7 +734,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
719 | XmlRpcResponse response = new XmlRpcResponse(); | 734 | XmlRpcResponse response = new XmlRpcResponse(); |
720 | Hashtable responseData = new Hashtable(); | 735 | Hashtable responseData = new Hashtable(); |
721 | 736 | ||
722 | lock (this) | 737 | lock (rslock) |
723 | { | 738 | { |
724 | try | 739 | try |
725 | { | 740 | { |
@@ -779,6 +794,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
779 | 794 | ||
780 | response.Value = responseData; | 795 | response.Value = responseData; |
781 | } | 796 | } |
797 | m_log.Info("[RADMIN]: CreateUser: request complete"); | ||
782 | return response; | 798 | return response; |
783 | } | 799 | } |
784 | } | 800 | } |
@@ -852,6 +868,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
852 | response.Value = responseData; | 868 | response.Value = responseData; |
853 | } | 869 | } |
854 | 870 | ||
871 | m_log.Info("[RADMIN]: UserExists: request complete"); | ||
855 | return response; | 872 | return response; |
856 | } | 873 | } |
857 | 874 | ||
@@ -899,7 +916,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
899 | XmlRpcResponse response = new XmlRpcResponse(); | 916 | XmlRpcResponse response = new XmlRpcResponse(); |
900 | Hashtable responseData = new Hashtable(); | 917 | Hashtable responseData = new Hashtable(); |
901 | 918 | ||
902 | lock (this) | 919 | lock (rslock) |
903 | { | 920 | { |
904 | try | 921 | try |
905 | { | 922 | { |
@@ -1002,6 +1019,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1002 | } | 1019 | } |
1003 | } | 1020 | } |
1004 | 1021 | ||
1022 | m_log.Info("[RADMIN]: UpdateUserAccount: request complete"); | ||
1005 | return response; | 1023 | return response; |
1006 | } | 1024 | } |
1007 | 1025 | ||
@@ -1043,7 +1061,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1043 | XmlRpcResponse response = new XmlRpcResponse(); | 1061 | XmlRpcResponse response = new XmlRpcResponse(); |
1044 | Hashtable responseData = new Hashtable(); | 1062 | Hashtable responseData = new Hashtable(); |
1045 | 1063 | ||
1046 | lock (this) | 1064 | lock (rslock) |
1047 | { | 1065 | { |
1048 | try | 1066 | try |
1049 | { | 1067 | { |
@@ -1099,6 +1117,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1099 | response.Value = responseData; | 1117 | response.Value = responseData; |
1100 | } | 1118 | } |
1101 | 1119 | ||
1120 | m_log.Info("[RADMIN]: Load OAR Administrator Request complete"); | ||
1102 | return response; | 1121 | return response; |
1103 | } | 1122 | } |
1104 | } | 1123 | } |
@@ -1195,6 +1214,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1195 | response.Value = responseData; | 1214 | response.Value = responseData; |
1196 | } | 1215 | } |
1197 | 1216 | ||
1217 | m_log.Info("[RADMIN]: Save OAR Administrator Request complete"); | ||
1198 | return response; | 1218 | return response; |
1199 | } | 1219 | } |
1200 | 1220 | ||
@@ -1204,7 +1224,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1204 | XmlRpcResponse response = new XmlRpcResponse(); | 1224 | XmlRpcResponse response = new XmlRpcResponse(); |
1205 | Hashtable responseData = new Hashtable(); | 1225 | Hashtable responseData = new Hashtable(); |
1206 | 1226 | ||
1207 | lock (this) | 1227 | lock (rslock) |
1208 | { | 1228 | { |
1209 | try | 1229 | try |
1210 | { | 1230 | { |
@@ -1277,6 +1297,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1277 | response.Value = responseData; | 1297 | response.Value = responseData; |
1278 | } | 1298 | } |
1279 | 1299 | ||
1300 | m_log.Info("[RADMIN]: Load XML Administrator Request complete"); | ||
1280 | return response; | 1301 | return response; |
1281 | } | 1302 | } |
1282 | } | 1303 | } |
@@ -1360,6 +1381,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1360 | response.Value = responseData; | 1381 | response.Value = responseData; |
1361 | } | 1382 | } |
1362 | 1383 | ||
1384 | m_log.Info("[RADMIN]: Save XML Administrator Request complete"); | ||
1363 | return response; | 1385 | return response; |
1364 | } | 1386 | } |
1365 | 1387 | ||
@@ -1415,6 +1437,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1415 | response.Value = responseData; | 1437 | response.Value = responseData; |
1416 | } | 1438 | } |
1417 | 1439 | ||
1440 | m_log.Info("[RADMIN]: Query XML Administrator Request complete"); | ||
1418 | return response; | 1441 | return response; |
1419 | } | 1442 | } |
1420 | 1443 | ||
@@ -1422,4 +1445,4 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1422 | { | 1445 | { |
1423 | } | 1446 | } |
1424 | } | 1447 | } |
1425 | } \ No newline at end of file | 1448 | } |
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs index 8ab9fd2..62e18c4 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs | |||
@@ -69,11 +69,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
69 | 69 | ||
70 | internal static IRestHandler Plugin = null; | 70 | internal static IRestHandler Plugin = null; |
71 | internal static OpenSimBase main = null; | 71 | internal static OpenSimBase main = null; |
72 | internal static CommunicationsManager Comms = null; | ||
73 | internal static IInventoryServices InventoryServices = null; | ||
74 | internal static IUserService UserServices = null; | ||
75 | internal static IAvatarService AvatarServices = null; | ||
76 | internal static IAssetCache AssetServices = null; | ||
77 | internal static string Prefix = null; | 72 | internal static string Prefix = null; |
78 | internal static IConfig Config = null; | 73 | internal static IConfig Config = null; |
79 | internal static string GodKey = null; | 74 | internal static string GodKey = null; |
@@ -88,6 +83,39 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
88 | internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 | 83 | internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 |
89 | 84 | ||
90 | /// <summary> | 85 | /// <summary> |
86 | /// These are all dependent upon the Comms manager | ||
87 | /// being initialized. So they have to be properties | ||
88 | /// because the comms manager is now a module and is | ||
89 | /// not guaranteed to be there when the rest handler | ||
90 | /// initializes. | ||
91 | /// </summary> | ||
92 | |||
93 | internal static CommunicationsManager Comms | ||
94 | { | ||
95 | get { return main.CommunicationsManager; } | ||
96 | } | ||
97 | |||
98 | internal static IInventoryServices InventoryServices | ||
99 | { | ||
100 | get { return Comms.InventoryService; } | ||
101 | } | ||
102 | |||
103 | internal static IUserService UserServices | ||
104 | { | ||
105 | get { return Comms.UserService; } | ||
106 | } | ||
107 | |||
108 | internal static IAvatarService AvatarServices | ||
109 | { | ||
110 | get { return Comms.AvatarService; } | ||
111 | } | ||
112 | |||
113 | internal static IAssetCache AssetServices | ||
114 | { | ||
115 | get { return Comms.AssetCache; } | ||
116 | } | ||
117 | |||
118 | /// <summary> | ||
91 | /// HTTP requires that status information be generated for PUT | 119 | /// HTTP requires that status information be generated for PUT |
92 | /// and POST opertaions. This is in support of that. The | 120 | /// and POST opertaions. This is in support of that. The |
93 | /// operation verb gets substituted into the first string, | 121 | /// operation verb gets substituted into the first string, |
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs index 667cf57..fad0438 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs | |||
@@ -55,16 +55,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
55 | Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); | 55 | Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); |
56 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | 56 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); |
57 | 57 | ||
58 | // This is better than a null reference. | ||
59 | |||
60 | if (Rest.AvatarServices == null) | ||
61 | throw new Exception(String.Format("{0} OpenSim inventory services are not available", | ||
62 | MsgId)); | ||
63 | |||
64 | if (Rest.UserServices == null) | ||
65 | throw new Exception(String.Format("{0} OpenSim user profile services are not available", | ||
66 | MsgId)); | ||
67 | |||
68 | // If a relative path was specified for the handler's domain, | 58 | // If a relative path was specified for the handler's domain, |
69 | // add the standard prefix to make it absolute, e.g. /admin | 59 | // add the standard prefix to make it absolute, e.g. /admin |
70 | 60 | ||
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs index 3475d32..043fca8 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs | |||
@@ -46,12 +46,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
46 | Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); | 46 | Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); |
47 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | 47 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); |
48 | 48 | ||
49 | // This is better than a null reference. | ||
50 | |||
51 | if (Rest.AssetServices == null) | ||
52 | throw new Exception(String.Format("{0} OpenSim asset services are not available", | ||
53 | MsgId)); | ||
54 | |||
55 | // If the handler specifies a relative path for its domain | 49 | // If the handler specifies a relative path for its domain |
56 | // then we must add the standard absolute prefix, e.g. /admin | 50 | // then we must add the standard absolute prefix, e.g. /admin |
57 | 51 | ||
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs index f0a5308..5ff9da3 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs | |||
@@ -227,16 +227,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
227 | // them easy to reach from anywhere in the assembly. | 227 | // them easy to reach from anywhere in the assembly. |
228 | 228 | ||
229 | Rest.main = openSim; | 229 | Rest.main = openSim; |
230 | if(Rest.main == null) | ||
231 | throw new Exception("OpenSim base pointer is null"); | ||
232 | |||
230 | Rest.Plugin = this; | 233 | Rest.Plugin = this; |
231 | Rest.Comms = Rest.main.CommunicationsManager; | ||
232 | Rest.UserServices = Rest.Comms.UserService; | ||
233 | Rest.InventoryServices = Rest.Comms.InventoryService; | ||
234 | Rest.AssetServices = Rest.Comms.AssetCache; | ||
235 | Rest.AvatarServices = Rest.Comms.AvatarService; | ||
236 | Rest.Config = Config; | 234 | Rest.Config = Config; |
237 | Rest.Prefix = Prefix; | 235 | Rest.Prefix = Prefix; |
238 | Rest.GodKey = GodKey; | 236 | Rest.GodKey = GodKey; |
239 | |||
240 | Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate); | 237 | Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate); |
241 | Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme); | 238 | Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme); |
242 | Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure); | 239 | Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure); |
@@ -253,7 +250,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
253 | (Rest.Authenticate ? "" : "not ")); | 250 | (Rest.Authenticate ? "" : "not ")); |
254 | 251 | ||
255 | Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId, | 252 | Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId, |
256 | (Rest.Authenticate ? "" : "not ")); | 253 | (Rest.Secure ? "" : "not ")); |
257 | 254 | ||
258 | Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId, | 255 | Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId, |
259 | (Rest.ExtendedEscape ? "" : "not ")); | 256 | (Rest.ExtendedEscape ? "" : "not ")); |
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs index 9935046..95e3d71 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs | |||
@@ -62,20 +62,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
62 | Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); | 62 | Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); |
63 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | 63 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); |
64 | 64 | ||
65 | // This is better than a null reference. | ||
66 | |||
67 | if (Rest.InventoryServices == null) | ||
68 | throw new Exception(String.Format("{0} OpenSim inventory services are not available", | ||
69 | MsgId)); | ||
70 | |||
71 | if (Rest.UserServices == null) | ||
72 | throw new Exception(String.Format("{0} OpenSim user services are not available", | ||
73 | MsgId)); | ||
74 | |||
75 | if (Rest.AssetServices == null) | ||
76 | throw new Exception(String.Format("{0} OpenSim asset services are not available", | ||
77 | MsgId)); | ||
78 | |||
79 | // If a relative path was specified for the handler's domain, | 65 | // If a relative path was specified for the handler's domain, |
80 | // add the standard prefix to make it absolute, e.g. /admin | 66 | // add the standard prefix to make it absolute, e.g. /admin |
81 | 67 | ||