* Added HttpStreamHandler, a generic HTTP handler that does not require creating a new class for each request handler
* Added WebUtil.UrlEncode() that converts spaces to %20 instead of + (to match incoming HTTP request strings) * Fixed a potential startup issue in SimianProfiles * Added new handlers to SimianGrid for incoming messagesslimupdates
parent
b10811a13b
commit
32e9fb2634
|
@ -40,6 +40,39 @@ using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
namespace OpenSim.Framework
|
namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A generic HTTP request handler
|
||||||
|
/// </summary>
|
||||||
|
public class HttpStreamHandler : IStreamHandler
|
||||||
|
{
|
||||||
|
public delegate void HttpStreamCallback(OSHttpRequest httpRequest, OSHttpResponse httpResponse);
|
||||||
|
|
||||||
|
private string m_contentType;
|
||||||
|
private string m_httpMethod;
|
||||||
|
private string m_path;
|
||||||
|
private HttpStreamCallback m_callback;
|
||||||
|
|
||||||
|
public string ContentType { get { return m_contentType; } }
|
||||||
|
public string HttpMethod { get { return m_httpMethod; } }
|
||||||
|
public string Path { get { return m_path; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
public HttpStreamHandler(string contentType, string httpMethod, string path, HttpStreamCallback callback)
|
||||||
|
{
|
||||||
|
m_contentType = contentType;
|
||||||
|
m_httpMethod = httpMethod;
|
||||||
|
m_path = path;
|
||||||
|
m_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(string path, Stream request, Stream response, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
|
||||||
|
{
|
||||||
|
m_callback(httpRequest, httpResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Miscellaneous static methods and extension methods related to the web
|
/// Miscellaneous static methods and extension methods related to the web
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -176,6 +209,16 @@ namespace OpenSim.Framework
|
||||||
return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } };
|
return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes a URL string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">Unencoded string to encode</param>
|
||||||
|
/// <returns>URL-encoded string</returns>
|
||||||
|
public static string UrlEncode(string str)
|
||||||
|
{
|
||||||
|
return HttpUtility.UrlEncode(str).Replace("+", "%20");
|
||||||
|
}
|
||||||
|
|
||||||
#region Uri
|
#region Uri
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Client;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using OpenSim.Framework.Servers.HttpServer;
|
||||||
|
|
||||||
|
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
|
||||||
|
|
||||||
|
namespace OpenSim.Services.Connectors.SimianGrid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles logins and teleports
|
||||||
|
/// </summary>
|
||||||
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
|
||||||
|
public class RezAvatar : INonSharedRegionModule
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log =
|
||||||
|
LogManager.GetLogger(
|
||||||
|
MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private Scene m_scene;
|
||||||
|
private GridRegion m_gridRegion;
|
||||||
|
private ISimulationService m_simulationService;
|
||||||
|
|
||||||
|
#region INonSharedRegionModule
|
||||||
|
|
||||||
|
public Type ReplaceableInterface { get { return null; } }
|
||||||
|
public void RegionLoaded(Scene scene) { }
|
||||||
|
public void Close() { }
|
||||||
|
|
||||||
|
public RezAvatar() { }
|
||||||
|
public string Name { get { return "RezAvatar"; } }
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
m_scene = scene;
|
||||||
|
m_gridRegion = new GridRegion
|
||||||
|
{
|
||||||
|
RegionID = scene.RegionInfo.RegionID,
|
||||||
|
RegionLocX = (int)scene.RegionInfo.RegionLocX,
|
||||||
|
RegionLocY = (int)scene.RegionInfo.RegionLocY,
|
||||||
|
RegionName = scene.RegionInfo.RegionName
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Simian.IsSimianEnabled(scene.Config, "UserAccountServices", "SimianUserAccountServiceConnector"))
|
||||||
|
{
|
||||||
|
m_simulationService = scene.RequestModuleInterface<ISimulationService>();
|
||||||
|
if (m_simulationService != null)
|
||||||
|
m_simulationService = m_simulationService.GetInnerService();
|
||||||
|
|
||||||
|
string urlFriendlySceneName = WebUtil.UrlEncode(scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
MainServer.Instance.AddStreamHandler(new HttpStreamHandler("application/xml+llsd", "GET", "/scenes/" + urlFriendlySceneName + "/public_region_seed_capability",
|
||||||
|
PublicRegionSeedCapabilityHandler));
|
||||||
|
MainServer.Instance.AddStreamHandler(new HttpStreamHandler(null, "POST", "/scenes/" + urlFriendlySceneName + "/rez_avatar/request",
|
||||||
|
RezAvatarRequestHandler));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene)
|
||||||
|
{
|
||||||
|
if (Simian.IsSimianEnabled(scene.Config, "UserAccountServices", this.Name))
|
||||||
|
{
|
||||||
|
string urlFriendlySceneName = WebUtil.UrlEncode(scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
MainServer.Instance.RemoveStreamHandler("GET", "/scenes/" + urlFriendlySceneName + "/public_region_seed_capability");
|
||||||
|
MainServer.Instance.RemoveStreamHandler("GET", "/scenes/" + urlFriendlySceneName + "/rez_avatar/request");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scene = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion INonSharedRegionModule
|
||||||
|
|
||||||
|
public RezAvatar(IConfigSource source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialise(IConfigSource source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PublicRegionSeedCapabilityHandler(OSHttpRequest httpRequest, OSHttpResponse httpResponse)
|
||||||
|
{
|
||||||
|
// Build a seed capability response that contains the rez_avatar/request capability (a hardcoded URL)
|
||||||
|
OSDMap responseMap = new OSDMap();
|
||||||
|
|
||||||
|
Uri httpAddress = new Uri("http://" + m_scene.RegionInfo.ExternalHostName + ":" + m_scene.RegionInfo.HttpPort + "/");
|
||||||
|
string urlFriendlySceneName = WebUtil.UrlEncode(m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
OSDMap capabilities = new OSDMap();
|
||||||
|
capabilities["rez_avatar/request"] = OSD.FromUri(new Uri(httpAddress, "/scenes/" + urlFriendlySceneName + "/rez_avatar/request"));
|
||||||
|
|
||||||
|
responseMap["capabilities"] = capabilities;
|
||||||
|
|
||||||
|
WebUtil.SendJSONResponse(httpResponse, responseMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RezAvatarRequestHandler(OSHttpRequest httpRequest, OSHttpResponse httpResponse)
|
||||||
|
{
|
||||||
|
OSDMap requestMap = null;
|
||||||
|
try { requestMap = OSDParser.Deserialize(httpRequest.InputStream) as OSDMap; }
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
Vector3 lookAt = Vector3.UnitX;
|
||||||
|
RegionInfo regInfo = m_scene.RegionInfo;
|
||||||
|
|
||||||
|
// Unpack the rez_avatar/request into an AgentCircuitData structure
|
||||||
|
AgentCircuitData agentCircuit = BuildAgentCircuitFromRezAvatarRequest(requestMap);
|
||||||
|
|
||||||
|
OSDMap responseMap = new OSDMap();
|
||||||
|
|
||||||
|
if (agentCircuit != null && agentCircuit.AgentID != UUID.Zero)
|
||||||
|
{
|
||||||
|
if (agentCircuit.startpos == Vector3.Zero)
|
||||||
|
{
|
||||||
|
m_log.Info("rez_avatar/request did not contain a position, setting to default");
|
||||||
|
agentCircuit.startpos = new Vector3(128f, 128f, 25f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to create an agent from the AgentCircuitData info
|
||||||
|
string reason;
|
||||||
|
if (m_simulationService.CreateAgent(m_gridRegion, agentCircuit, agentCircuit.teleportFlags, out reason))
|
||||||
|
{
|
||||||
|
// Build the seed capability URL for this agent
|
||||||
|
Uri seedCapability = new Uri("http://" + regInfo.ExternalHostName + ":" + regInfo.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/");
|
||||||
|
|
||||||
|
m_log.Info("rez_avatar/request created agent " + agentCircuit.firstname + " " + agentCircuit.lastname +
|
||||||
|
" with circuit code " + agentCircuit.circuitcode + " and seed capability " + seedCapability);
|
||||||
|
|
||||||
|
IPAddress externalAddress = regInfo.ExternalEndPoint.Address;
|
||||||
|
uint regionX, regionY;
|
||||||
|
Utils.LongToUInts(regInfo.RegionHandle, out regionX, out regionY);
|
||||||
|
|
||||||
|
responseMap["connect"] = OSD.FromBoolean(true);
|
||||||
|
responseMap["agent_id"] = OSD.FromUUID(agentCircuit.AgentID);
|
||||||
|
responseMap["sim_host"] = OSD.FromString(externalAddress.ToString());
|
||||||
|
responseMap["sim_port"] = OSD.FromInteger(regInfo.ExternalEndPoint.Port);
|
||||||
|
responseMap["region_seed_capability"] = OSD.FromUri(seedCapability);
|
||||||
|
responseMap["position"] = OSD.FromVector3(agentCircuit.startpos);
|
||||||
|
responseMap["look_at"] = OSD.FromVector3(lookAt);
|
||||||
|
|
||||||
|
// Region information
|
||||||
|
responseMap["region_id"] = OSD.FromUUID(regInfo.RegionID);
|
||||||
|
responseMap["region_x"] = OSD.FromInteger(regionX);
|
||||||
|
responseMap["region_y"] = OSD.FromInteger(regionY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Warn("Denied rez_avatar/request for " + agentCircuit.firstname + " " + agentCircuit.lastname + ": " + reason);
|
||||||
|
responseMap["message"] = OSD.FromString(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responseMap["message"] = OSD.FromString("Invalid or incomplete request");
|
||||||
|
}
|
||||||
|
|
||||||
|
WebUtil.SendJSONResponse(httpResponse, responseMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AgentCircuitData BuildAgentCircuitFromRezAvatarRequest(OSDMap request)
|
||||||
|
{
|
||||||
|
AgentCircuitData agentCircuit = new AgentCircuitData();
|
||||||
|
agentCircuit.AgentID = request["agent_id"].AsUUID();
|
||||||
|
agentCircuit.BaseFolder = request["base_folder"].AsUUID();
|
||||||
|
agentCircuit.CapsPath = request["caps_path"].AsString();
|
||||||
|
agentCircuit.child = request["child_agent"].AsBoolean();
|
||||||
|
agentCircuit.circuitcode = request["circuit_code"].AsUInteger();
|
||||||
|
agentCircuit.firstname = request["first_name"].AsString();
|
||||||
|
agentCircuit.InventoryFolder = request["inventory_folder"].AsUUID();
|
||||||
|
agentCircuit.lastname = request["last_name"].AsString();
|
||||||
|
agentCircuit.SecureSessionID = request["secure_session_id"].AsUUID();
|
||||||
|
agentCircuit.ServiceSessionID = String.Empty;
|
||||||
|
agentCircuit.ServiceURLs = new Dictionary<string, object>(0);
|
||||||
|
agentCircuit.SessionID = request["session_id"].AsUUID();
|
||||||
|
agentCircuit.startpos = request["position"].AsVector3();
|
||||||
|
agentCircuit.teleportFlags = request["teleport_flags"].AsUInteger();
|
||||||
|
if (agentCircuit.teleportFlags == 0)
|
||||||
|
agentCircuit.teleportFlags = (uint)TeleportFlags.ViaLogin;
|
||||||
|
|
||||||
|
#region Children Seed Caps
|
||||||
|
|
||||||
|
if (request["children_seeds"].Type == OSDType.Array)
|
||||||
|
{
|
||||||
|
OSDArray childrenSeeds = (OSDArray)request["children_seeds"];
|
||||||
|
agentCircuit.ChildrenCapSeeds = new Dictionary<ulong, string>(childrenSeeds.Count);
|
||||||
|
for (int i = 0; i < childrenSeeds.Count; i++)
|
||||||
|
{
|
||||||
|
if (childrenSeeds[i].Type == OSDType.Map)
|
||||||
|
{
|
||||||
|
OSDMap pair = (OSDMap)childrenSeeds[i];
|
||||||
|
ulong handle;
|
||||||
|
if (!UInt64.TryParse(pair["handle"].AsString(), out handle))
|
||||||
|
continue;
|
||||||
|
string seed = pair["seed"].AsString();
|
||||||
|
if (!agentCircuit.ChildrenCapSeeds.ContainsKey(handle))
|
||||||
|
agentCircuit.ChildrenCapSeeds.Add(handle, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
agentCircuit.ChildrenCapSeeds = new Dictionary<ulong, string>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Children Seed Caps
|
||||||
|
|
||||||
|
#region Appearance
|
||||||
|
|
||||||
|
agentCircuit.Appearance = new AvatarAppearance(agentCircuit.AgentID);
|
||||||
|
agentCircuit.Appearance.Serial = request["appearance_serial"].AsInteger();
|
||||||
|
if (request["wearables"].Type == OSDType.Array)
|
||||||
|
{
|
||||||
|
OSDArray wearables = (OSDArray)request["wearables"];
|
||||||
|
for (int i = 0; i < wearables.Count / 2; i++)
|
||||||
|
{
|
||||||
|
agentCircuit.Appearance.Wearables[i].ItemID = wearables[i * 2].AsUUID();
|
||||||
|
agentCircuit.Appearance.Wearables[i].AssetID = wearables[(i * 2) + 1].AsUUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request["attachments"].Type == OSDType.Array)
|
||||||
|
{
|
||||||
|
OSDArray attachArray = (OSDArray)request["attachments"];
|
||||||
|
List<AttachmentData> attachments = new List<AttachmentData>(attachArray.Count);
|
||||||
|
for (int i = 0; i < attachArray.Count; i++)
|
||||||
|
{
|
||||||
|
if (attachArray[i].Type == OSDType.Map)
|
||||||
|
attachments.Add(new AttachmentData((OSDMap)attachArray[i]));
|
||||||
|
}
|
||||||
|
agentCircuit.Appearance.SetAttachments(attachments.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Appearance
|
||||||
|
|
||||||
|
return agentCircuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OSDMap BuildRezAvatarRequestFromAgentCircuit(AgentCircuitData agentCircuit)
|
||||||
|
{
|
||||||
|
return new OSDMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,7 +88,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
||||||
|
|
||||||
public void Initialise(IConfigSource source)
|
public void Initialise(IConfigSource source)
|
||||||
{
|
{
|
||||||
if (Simian.IsSimianEnabled(source, "UserAccountServices", this.Name))
|
if (Simian.IsSimianEnabled(source, "UserAccountServices", "SimianUserAccountServiceConnector"))
|
||||||
{
|
{
|
||||||
IConfig gridConfig = source.Configs["UserAccountService"];
|
IConfig gridConfig = source.Configs["UserAccountService"];
|
||||||
if (gridConfig == null)
|
if (gridConfig == null)
|
||||||
|
|
Loading…
Reference in New Issue