RegionURI.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * - Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * - Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. * - Neither the name of the openmetaverse.org nor the names
  11. * of its contributors may be used to endorse or promote products derived from
  12. * this software without specific prior written permission.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  18. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. * POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. using System;
  27. using System.Net;
  28. using OpenMetaverse;
  29. namespace OpenSim.Framework
  30. {
  31. public class RegionURI
  32. {
  33. private static readonly byte[] schemaSep = osUTF8.GetASCIIBytes("://");
  34. private static readonly byte[] altschemaSep = osUTF8.GetASCIIBytes("|!!");
  35. private static readonly byte[] nameSep = osUTF8.GetASCIIBytes(":/ ");
  36. private static readonly byte[] altnameSep = osUTF8.GetASCIIBytes(":/ +|");
  37. private static readonly byte[] escapePref = osUTF8.GetASCIIBytes("+%");
  38. private static readonly byte[] altPortSepPref = osUTF8.GetASCIIBytes(":|");
  39. private static readonly byte[] forbidonname = osUTF8.GetASCIIBytes(".,:;\\/");
  40. public enum URIFlags : int
  41. {
  42. None = 0,
  43. //Valid = 1 << 0,
  44. HasHost = 1 << 1,
  45. HasResolvedHost = 1 << 2,
  46. HasUserName = 1 << 3,
  47. HasUserPass = 1 << 4,
  48. HasRegionName = 1 << 5,
  49. HasCoords = 1 << 6,
  50. IsLocalGrid = 1 << 7 // this must be set externally
  51. }
  52. public URIFlags Flags;
  53. public IPAddress IP;
  54. public string originalURI = string.Empty;
  55. public string Schema = "http://";
  56. public string Host = string.Empty;
  57. public int Port = 80;
  58. public string RegionName = string.Empty;
  59. public string Username = string.Empty;
  60. public string UserPass = string.Empty;
  61. public int X = 127;
  62. public int Y = 127;
  63. public int Z = 2;
  64. public RegionURI(string _originalURI)
  65. {
  66. originalURI = _originalURI;
  67. Parse(_originalURI);
  68. if (!HasHost && HasRegionName)
  69. Flags |= URIFlags.IsLocalGrid;
  70. }
  71. public RegionURI(string _originalURI, GridInfo gi)
  72. {
  73. originalURI = _originalURI;
  74. Parse(_originalURI);
  75. if(!HasHost)
  76. {
  77. if(!HasRegionName)
  78. Flags = URIFlags.None;
  79. else
  80. Flags |= URIFlags.IsLocalGrid;
  81. return;
  82. }
  83. if(gi == null)
  84. return;
  85. if (gi.IsLocalGrid(HostUrl) == 1)
  86. {
  87. Host = string.Empty;
  88. Flags &= ~URIFlags.HasHost;
  89. Flags |= URIFlags.IsLocalGrid;
  90. return;
  91. }
  92. if (!ResolveDNS())
  93. {
  94. Flags = URIFlags.None;
  95. }
  96. }
  97. public void Parse(string inputURI)
  98. {
  99. Flags = URIFlags.None;
  100. if (string.IsNullOrWhiteSpace(inputURI))
  101. return;
  102. osUTF8Slice input = new osUTF8Slice(inputURI);
  103. input.SelfTrimStart((byte)' ');
  104. input.SelfTrimStart((byte)'+');
  105. int firstDot = input.IndexOf((byte)'.');
  106. if (firstDot == 0)
  107. return;
  108. osUTF8Slice tmpSlice;
  109. int indx = input.IndexOf(schemaSep);
  110. if (indx == 0)
  111. return;
  112. if (indx < 0)
  113. indx = input.IndexOf(altschemaSep);
  114. if (indx == 0)
  115. return;
  116. if (indx > 0)
  117. {
  118. if (indx < 2 || input.Length < indx + 4 || (firstDot > 0 && indx > firstDot))
  119. return;
  120. bool issecure = false;
  121. tmpSlice = input.SubUTF8(0, indx).Clone();
  122. tmpSlice.ToASCIILowerSelf();
  123. if (tmpSlice.EndsWith((byte)'s'))
  124. {
  125. issecure = true;
  126. tmpSlice.SelfTrimEnd((byte)'s');
  127. }
  128. switch (tmpSlice.ToString())
  129. {
  130. case "http":
  131. case "hg":
  132. case "hop":
  133. case "surl":
  134. case "x-grid-info":
  135. // only https has this defined
  136. if (issecure)
  137. {
  138. Schema = "https://";
  139. Port = 443;
  140. }
  141. break;
  142. default:
  143. return;
  144. }
  145. indx += 3;
  146. input.SubUTF8Self(indx);
  147. firstDot -= indx;
  148. }
  149. int namestart = 0;
  150. if (firstDot > 0)
  151. {
  152. int hostend = -1;
  153. osUTF8Slice hosttmp = input.Clone();
  154. indx = input.IndexOfAny(altPortSepPref);
  155. if (indx > 0)
  156. {
  157. if (indx < firstDot)
  158. return;
  159. hostend = indx;
  160. ++indx;
  161. int tmpport = 0;
  162. byte c;
  163. while (indx < input.Length)
  164. {
  165. c = input[indx];
  166. if (c < (byte)'0' || c > (byte)'9')
  167. break;
  168. tmpport *= 10;
  169. tmpport += c - (byte)'0';
  170. ++indx;
  171. }
  172. if (indx > hostend + 1)
  173. {
  174. if (tmpport > 64 * 1024)
  175. return;
  176. Port = tmpport;
  177. }
  178. input.SubUTF8Self(indx);
  179. input.SelfTrimStart(altnameSep);
  180. }
  181. else
  182. {
  183. indx = input.IndexOfAny(altnameSep);
  184. if (indx < 0)
  185. {
  186. hostend = input.Length;
  187. namestart = -1;
  188. }
  189. else
  190. {
  191. hostend = indx;
  192. namestart = indx + 1;
  193. }
  194. }
  195. if (hostend <= 0)
  196. return;
  197. hosttmp.SubUTF8Self(0, hostend);
  198. indx = hosttmp.IndexOf((byte)'@');
  199. if (indx >= 0)
  200. {
  201. if (indx > 0)
  202. {
  203. tmpSlice = hosttmp.SubUTF8(0, indx);
  204. int indx2 = tmpSlice.IndexOfAny(escapePref);
  205. if (indx2 >= 0)
  206. {
  207. Username = Uri.UnescapeDataString(tmpSlice.ToString());
  208. Username = Username.Replace('+', ' ');
  209. }
  210. else
  211. Username = tmpSlice.ToString();
  212. if (Username.Length > 0)
  213. Flags |= URIFlags.HasUserName;
  214. }
  215. ++indx;
  216. hosttmp.SubUTF8Self(indx);
  217. }
  218. if (hosttmp.Length == 0)
  219. {
  220. Flags = URIFlags.None;
  221. return;
  222. }
  223. indx = hosttmp.IndexOfAny(escapePref);
  224. if (indx >= 0)
  225. {
  226. string blabla = Uri.UnescapeDataString(hosttmp.ToString());
  227. blabla = blabla.Replace('+', ' ');
  228. hosttmp = new osUTF8Slice(blabla);
  229. }
  230. hosttmp.ToASCIILowerSelf();
  231. Host = hosttmp.ToString();
  232. UriHostNameType type = Uri.CheckHostName(Host);
  233. if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic)
  234. {
  235. Flags = URIFlags.None;
  236. return;
  237. }
  238. Flags |= URIFlags.HasHost;
  239. }
  240. if (namestart < 0 || input.Length == 0)
  241. return;
  242. input.SubUTF8Self(namestart);
  243. input.SelfTrimStart((byte)' ');
  244. input.SelfTrimStart((byte)'+');
  245. int firstCoord = input.IndexOf((byte)'/');
  246. if (firstCoord == 0)
  247. {
  248. Flags = URIFlags.None;
  249. return;
  250. }
  251. if (firstCoord < 0)
  252. firstCoord = input.IndexOf((byte)'(');
  253. if (firstCoord > 0)
  254. tmpSlice = input.SubUTF8(0, firstCoord);
  255. else
  256. tmpSlice = input;
  257. indx = tmpSlice.IndexOfAny(escapePref);
  258. if (indx >= 0)
  259. {
  260. string blabla = Uri.UnescapeDataString(tmpSlice.ToString());
  261. blabla = blabla.Replace('+', ' ');
  262. tmpSlice = new osUTF8Slice(blabla);
  263. }
  264. tmpSlice.SelfTrimEnd((byte)' ');
  265. if (tmpSlice.Length <= 0)
  266. return;
  267. if(tmpSlice.IndexOfAny(forbidonname) > 0)
  268. {
  269. Flags = URIFlags.None;
  270. return;
  271. }
  272. RegionName = tmpSlice.ToString();
  273. Flags |= URIFlags.HasRegionName;
  274. if (firstCoord > 0)
  275. {
  276. if (input[firstCoord] == (byte)'/')
  277. {
  278. ++firstCoord;
  279. int tmp = 0;
  280. tmpSlice = input.SubUTF8(firstCoord);
  281. int indx2 = 0;
  282. while (indx2 < tmpSlice.Length)
  283. {
  284. byte c = tmpSlice[indx2];
  285. if (c < (byte)'0' || c > (byte)'9')
  286. break;
  287. tmp *= 10;
  288. tmp += c - (byte)'0';
  289. ++indx2;
  290. }
  291. if (indx2 == 0)
  292. {
  293. Flags = URIFlags.None;
  294. return;
  295. }
  296. X = tmp;
  297. tmpSlice.SubUTF8Self(indx2);
  298. indx = tmpSlice.IndexOf((byte)'/');
  299. if (indx >= 0)
  300. {
  301. ++indx;
  302. tmpSlice.SubUTF8Self(indx);
  303. indx2 = 0;
  304. tmp = 0;
  305. while (indx2 < tmpSlice.Length)
  306. {
  307. byte c = tmpSlice[indx2];
  308. if (c < (byte)'0' || c > (byte)'9')
  309. break;
  310. tmp *= 10;
  311. tmp += c - (byte)'0';
  312. ++indx2;
  313. }
  314. if (indx2 == 0)
  315. {
  316. Flags = URIFlags.None;
  317. return;
  318. }
  319. Y = tmp;
  320. tmpSlice.SubUTF8Self(indx2);
  321. indx = tmpSlice.IndexOf((byte)'/');
  322. if (indx >= 0)
  323. {
  324. ++indx;
  325. tmpSlice.SubUTF8Self(indx);
  326. indx2 = 0;
  327. tmp = 0;
  328. int sig = 1;
  329. if (tmpSlice[indx2] == (byte)'-')
  330. {
  331. sig = -1;
  332. indx2++;
  333. }
  334. while (indx2 < tmpSlice.Length)
  335. {
  336. byte c = tmpSlice[indx2];
  337. if (c < (byte)'0' || c > (byte)'9')
  338. break;
  339. tmp *= 10;
  340. tmp += c - (byte)'0';
  341. ++indx2;
  342. }
  343. if (indx2 == 0)
  344. {
  345. Flags = URIFlags.None;
  346. return;
  347. }
  348. Z = sig * tmp;
  349. }
  350. }
  351. }
  352. else // (,,) case
  353. {
  354. ++firstCoord;
  355. int tmp = 0;
  356. tmpSlice = input.SubUTF8(firstCoord);
  357. int indx2 = tmpSlice.IndexOf((byte)')');
  358. if (indx2 == 0)
  359. return;
  360. if (indx2 > 0)
  361. tmpSlice.SubUTF8Self(0, indx2);
  362. indx2 = 0;
  363. tmpSlice.SelfTrimStart((byte)' ');
  364. tmpSlice.SelfTrimStart((byte)'+');
  365. while (indx2 < tmpSlice.Length)
  366. {
  367. byte c = tmpSlice[indx2];
  368. if (c < (byte)'0' || c > (byte)'9')
  369. break;
  370. tmp *= 10;
  371. tmp += c - (byte)'0';
  372. ++indx2;
  373. }
  374. if (indx2 == 0)
  375. {
  376. Flags = URIFlags.None;
  377. return;
  378. }
  379. X = tmp;
  380. tmpSlice.SubUTF8Self(indx2);
  381. indx = tmpSlice.IndexOf((byte)',');
  382. if (indx >= 0)
  383. {
  384. ++indx;
  385. tmpSlice.SubUTF8Self(indx);
  386. tmpSlice.SelfTrimStart((byte)' ');
  387. tmpSlice.SelfTrimStart((byte)'+');
  388. indx2 = 0;
  389. tmp = 0;
  390. while (indx2 < tmpSlice.Length)
  391. {
  392. byte c = tmpSlice[indx2];
  393. if (c < (byte)'0' || c > (byte)'9')
  394. break;
  395. tmp *= 10;
  396. tmp += c - (byte)'0';
  397. ++indx2;
  398. }
  399. if (indx2 == 0)
  400. {
  401. Flags = URIFlags.None;
  402. return;
  403. }
  404. Y = tmp;
  405. tmpSlice.SubUTF8Self(indx2);
  406. indx = tmpSlice.IndexOf((byte)',');
  407. if (indx >= 0)
  408. {
  409. ++indx;
  410. tmpSlice.SubUTF8Self(indx);
  411. tmpSlice.SelfTrimStart((byte)' ');
  412. tmpSlice.SelfTrimStart((byte)'+');
  413. indx2 = 0;
  414. tmp = 0;
  415. int sig = 1;
  416. if (tmpSlice[indx2] == (byte)'-')
  417. {
  418. sig = -1;
  419. indx2++;
  420. }
  421. while (indx2 < tmpSlice.Length)
  422. {
  423. byte c = tmpSlice[indx2];
  424. if (c < (byte)'0' || c > (byte)'9')
  425. break;
  426. tmp *= 10;
  427. tmp += c - (byte)'0';
  428. ++indx2;
  429. }
  430. if (indx2 == 0)
  431. {
  432. Flags = URIFlags.None;
  433. return;
  434. }
  435. Z = sig * tmp;
  436. }
  437. }
  438. }
  439. }
  440. return;
  441. }
  442. public bool ResolveDNS()
  443. {
  444. if ((Flags & URIFlags.HasHost) != 0)
  445. {
  446. IPAddress ip = Util.GetHostFromDNS(Host);
  447. if (ip != null)
  448. {
  449. IP = ip;
  450. Flags |= URIFlags.HasResolvedHost;
  451. return true;
  452. }
  453. }
  454. return false;
  455. }
  456. public bool IsValid
  457. {
  458. get { return (Flags & (URIFlags.HasHost | URIFlags.HasRegionName)) != 0; }
  459. }
  460. public bool HasHost
  461. {
  462. get { return (Flags & URIFlags.HasHost) != 0; }
  463. }
  464. public bool HasRegionName
  465. {
  466. get { return (Flags & URIFlags.HasRegionName) != 0; }
  467. }
  468. public string HostUrl
  469. {
  470. get { return (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port) : ""; }
  471. }
  472. public string HostUrlEndSlash
  473. {
  474. get { return (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port + "/") : ""; }
  475. }
  476. public string RegionUrlAndName
  477. {
  478. get
  479. {
  480. string ret = (Flags & URIFlags.HasHost) != 0 ? (Schema + Host + ":" + Port + "/") : "";
  481. if ((Flags & URIFlags.HasRegionName) != 0)
  482. ret += RegionName;
  483. return ret;
  484. }
  485. }
  486. public string RegionHostPortSpaceName
  487. {
  488. get
  489. {
  490. string ret = (Flags & URIFlags.HasHost) != 0 ? (Host + ":" + Port + "/ ") : ""; // space needed for compatibility
  491. if ((Flags & URIFlags.HasRegionName) != 0)
  492. ret += RegionName;
  493. return ret;
  494. }
  495. }
  496. // this needs to be set before get
  497. public bool IsLocalGrid
  498. {
  499. get { return (Flags & URIFlags.IsLocalGrid) != 0; }
  500. set
  501. {
  502. if(value)
  503. {
  504. Host = string.Empty;
  505. Flags &= ~URIFlags.HasHost;
  506. Flags |= URIFlags.IsLocalGrid;
  507. }
  508. }
  509. }
  510. }
  511. }