/* * 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. * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Net; using OpenMetaverse; namespace OpenSim.Framework { public class RegionURI { private static readonly byte[] schemaSep = osUTF8.GetASCIIBytes("://"); private static readonly byte[] altschemaSep = osUTF8.GetASCIIBytes("|!!"); private static readonly byte[] nameSep = osUTF8.GetASCIIBytes(":/ "); private static readonly byte[] altnameSep = osUTF8.GetASCIIBytes(":/ +|"); private static readonly byte[] escapePref = osUTF8.GetASCIIBytes("+%"); private static readonly byte[] altPortSepPref = osUTF8.GetASCIIBytes(":|"); private static readonly byte[] forbidonname = osUTF8.GetASCIIBytes(".,:;\\/"); public enum URIFlags : int { None = 0, //Valid = 1 << 0, HasHost = 1 << 1, HasResolvedHost = 1 << 2, HasUserName = 1 << 3, HasUserPass = 1 << 4, HasRegionName = 1 << 5, HasCoords = 1 << 6, IsLocalGrid = 1 << 7 // this must be set externally } public URIFlags Flags; public IPAddress IP; public string originalURI = string.Empty; public string Schema = "http://"; public string Host = string.Empty; public int Port = 80; public string RegionName = string.Empty; public string Username = string.Empty; public string UserPass = string.Empty; public int X = 127; public int Y = 127; public int Z = 2; public RegionURI(string _originalURI) { originalURI = _originalURI; Parse(_originalURI); if (!HasHost && HasRegionName) Flags |= URIFlags.IsLocalGrid; } public RegionURI(string _originalURI, GridInfo gi) { originalURI = _originalURI; Parse(_originalURI); if(!HasHost) { if(!HasRegionName) Flags = URIFlags.None; else Flags |= URIFlags.IsLocalGrid; return; } if(gi == null) return; if (gi.IsLocalGrid(HostUrl) == 1) { Host = string.Empty; Flags &= ~URIFlags.HasHost; Flags |= URIFlags.IsLocalGrid; return; } if (!ResolveDNS()) { Flags = URIFlags.None; } } public void Parse(string inputURI) { Flags = URIFlags.None; if (string.IsNullOrWhiteSpace(inputURI)) return; osUTF8Slice input = new osUTF8Slice(inputURI); input.SelfTrimStart((byte)' '); input.SelfTrimStart((byte)'+'); int firstDot = input.IndexOf((byte)'.'); if (firstDot == 0) return; osUTF8Slice tmpSlice; int indx = input.IndexOf(schemaSep); if (indx == 0) return; if (indx < 0) indx = input.IndexOf(altschemaSep); if (indx == 0) return; if (indx > 0) { if (indx < 2 || input.Length < indx + 4 || (firstDot > 0 && indx > firstDot)) return; bool issecure = false; tmpSlice = input.SubUTF8(0, indx).Clone(); tmpSlice.ToASCIILowerSelf(); if (tmpSlice.EndsWith((byte)'s')) { issecure = true; tmpSlice.SelfTrimEnd((byte)'s'); } switch (tmpSlice.ToString()) { case "http": case "hg": case "hop": case "surl": case "x-grid-info": // only https has this defined if (issecure) { Schema = "https://"; Port = 443; } break; default: return; } indx += 3; input.SubUTF8Self(indx); firstDot -= indx; } int namestart = 0; if (firstDot > 0) { int hostend = -1; osUTF8Slice hosttmp = input.Clone(); indx = input.IndexOfAny(altPortSepPref); if (indx > 0) { if (indx < firstDot) return; hostend = indx; ++indx; int tmpport = 0; byte c; while (indx < input.Length) { c = input[indx]; if (c < (byte)'0' || c > (byte)'9') break; tmpport *= 10; tmpport += c - (byte)'0'; ++indx; } if (indx > hostend + 1) { if (tmpport > 64 * 1024) return; Port = tmpport; } input.SubUTF8Self(indx); input.SelfTrimStart(altnameSep); } else { indx = input.IndexOfAny(altnameSep); if (indx < 0) { hostend = input.Length; namestart = -1; } else { hostend = indx; namestart = indx + 1; } } if (hostend <= 0) return; hosttmp.SubUTF8Self(0, hostend); indx = hosttmp.IndexOf((byte)'@'); if (indx >= 0) { if (indx > 0) { tmpSlice = hosttmp.SubUTF8(0, indx); int indx2 = tmpSlice.IndexOfAny(escapePref); if (indx2 >= 0) { Username = Uri.UnescapeDataString(tmpSlice.ToString()); Username = Username.Replace('+', ' '); } else Username = tmpSlice.ToString(); if (Username.Length > 0) Flags |= URIFlags.HasUserName; } ++indx; hosttmp.SubUTF8Self(indx); } if (hosttmp.Length == 0) { Flags = URIFlags.None; return; } indx = hosttmp.IndexOfAny(escapePref); if (indx >= 0) { string blabla = Uri.UnescapeDataString(hosttmp.ToString()); blabla = blabla.Replace('+', ' '); hosttmp = new osUTF8Slice(blabla); } hosttmp.ToASCIILowerSelf(); Host = hosttmp.ToString(); UriHostNameType type = Uri.CheckHostName(Host); if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic) { Flags = URIFlags.None; return; } Flags |= URIFlags.HasHost; } if (namestart < 0 || input.Length == 0) return; input.SubUTF8Self(namestart); input.SelfTrimStart((byte)' '); input.SelfTrimStart((byte)'+'); int firstCoord = input.IndexOf((byte)'/'); if (firstCoord == 0) { Flags = URIFlags.None; return; } if (firstCoord < 0) firstCoord = input.IndexOf((byte)'('); if (firstCoord > 0) tmpSlice = input.SubUTF8(0, firstCoord); else tmpSlice = input; indx = tmpSlice.IndexOfAny(escapePref); if (indx >= 0) { string blabla = Uri.UnescapeDataString(tmpSlice.ToString()); blabla = blabla.Replace('+', ' '); tmpSlice = new osUTF8Slice(blabla); } tmpSlice.SelfTrimEnd((byte)' '); if (tmpSlice.Length <= 0) return; if(tmpSlice.IndexOfAny(forbidonname) > 0) { Flags = URIFlags.None; return; } RegionName = tmpSlice.ToString(); Flags |= URIFlags.HasRegionName; if (firstCoord > 0) { if (input[firstCoord] == (byte)'/') { ++firstCoord; int tmp = 0; tmpSlice = input.SubUTF8(firstCoord); int indx2 = 0; while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } X = tmp; tmpSlice.SubUTF8Self(indx2); indx = tmpSlice.IndexOf((byte)'/'); if (indx >= 0) { ++indx; tmpSlice.SubUTF8Self(indx); indx2 = 0; tmp = 0; while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } Y = tmp; tmpSlice.SubUTF8Self(indx2); indx = tmpSlice.IndexOf((byte)'/'); if (indx >= 0) { ++indx; tmpSlice.SubUTF8Self(indx); indx2 = 0; tmp = 0; int sig = 1; if (tmpSlice[indx2] == (byte)'-') { sig = -1; indx2++; } while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } Z = sig * tmp; } } } else // (,,) case { ++firstCoord; int tmp = 0; tmpSlice = input.SubUTF8(firstCoord); int indx2 = tmpSlice.IndexOf((byte)')'); if (indx2 == 0) return; if (indx2 > 0) tmpSlice.SubUTF8Self(0, indx2); indx2 = 0; tmpSlice.SelfTrimStart((byte)' '); tmpSlice.SelfTrimStart((byte)'+'); while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } X = tmp; tmpSlice.SubUTF8Self(indx2); indx = tmpSlice.IndexOf((byte)','); if (indx >= 0) { ++indx; tmpSlice.SubUTF8Self(indx); tmpSlice.SelfTrimStart((byte)' '); tmpSlice.SelfTrimStart((byte)'+'); indx2 = 0; tmp = 0; while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } Y = tmp; tmpSlice.SubUTF8Self(indx2); indx = tmpSlice.IndexOf((byte)','); if (indx >= 0) { ++indx; tmpSlice.SubUTF8Self(indx); tmpSlice.SelfTrimStart((byte)' '); tmpSlice.SelfTrimStart((byte)'+'); indx2 = 0; tmp = 0; int sig = 1; if (tmpSlice[indx2] == (byte)'-') { sig = -1; indx2++; } while (indx2 < tmpSlice.Length) { byte c = tmpSlice[indx2]; if (c < (byte)'0' || c > (byte)'9') break; tmp *= 10; tmp += c - (byte)'0'; ++indx2; } if (indx2 == 0) { Flags = URIFlags.None; return; } Z = sig * tmp; } } } } return; } public bool ResolveDNS() { if ((Flags & URIFlags.HasHost) != 0) { IPAddress ip = Util.GetHostFromDNS(Host); if (ip != null) { IP = ip; Flags |= URIFlags.HasResolvedHost; return true; } } return false; } public bool IsValid { get { return (Flags & (URIFlags.HasHost | URIFlags.HasRegionName)) != 0; } } public bool HasHost { get { return (Flags & URIFlags.HasHost) != 0; } } public bool HasRegionName { get { return (Flags & URIFlags.HasRegionName) != 0; } } public string HostUrl { get { return (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port) : ""; } } public string HostUrlEndSlash { get { return (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port + "/") : ""; } } public string RegionUrlAndName { get { string ret = (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port + "/") : ""; if ((Flags & URIFlags.HasRegionName) != 0) ret += RegionName; return ret; } } public string RegionHostPortSpaceName { get { string ret = (Flags & URIFlags.HasHost) != 0 ? (Host + ":" + Port + "/ ") : ""; // space needed for compatibility if ((Flags & URIFlags.HasRegionName) != 0) ret += RegionName; return ret; } } // this needs to be set before get public bool IsLocalGrid { get { return (Flags & URIFlags.IsLocalGrid) != 0; } set { if(value) { Host = string.Empty; Flags &= ~URIFlags.HasHost; Flags |= URIFlags.IsLocalGrid; } } } } }