* 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 messages
slimupdates
John Hurliman 2010-05-04 13:58:21 -07:00
parent b10811a13b
commit 32e9fb2634
3 changed files with 327 additions and 1 deletions

View File

@ -40,6 +40,39 @@ using OpenMetaverse.StructuredData;
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>
/// Miscellaneous static methods and extension methods related to the web
/// </summary>
@ -176,6 +209,16 @@ namespace OpenSim.Framework
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
/// <summary>

View File

@ -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();
}
}
}

View File

@ -88,7 +88,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
public void Initialise(IConfigSource source)
{
if (Simian.IsSimianEnabled(source, "UserAccountServices", this.Name))
if (Simian.IsSimianEnabled(source, "UserAccountServices", "SimianUserAccountServiceConnector"))
{
IConfig gridConfig = source.Configs["UserAccountService"];
if (gridConfig == null)