HttpUtility.cs 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. #region License
  2. /*
  3. * HttpUtility.cs
  4. *
  5. * This code is derived from HttpUtility.cs (System.Net) of Mono
  6. * (http://www.mono-project.com).
  7. *
  8. * The MIT License
  9. *
  10. * Copyright (c) 2005-2009 Novell, Inc. (http://www.novell.com)
  11. * Copyright (c) 2012-2019 sta.blockhead
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a copy
  14. * of this software and associated documentation files (the "Software"), to deal
  15. * in the Software without restriction, including without limitation the rights
  16. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. * copies of the Software, and to permit persons to whom the Software is
  18. * furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice shall be included in
  21. * all copies or substantial portions of the Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  29. * THE SOFTWARE.
  30. */
  31. #endregion
  32. #region Authors
  33. /*
  34. * Authors:
  35. * - Patrik Torstensson <Patrik.Torstensson@labs2.com>
  36. * - Wictor Wilén (decode/encode functions) <wictor@ibizkit.se>
  37. * - Tim Coleman <tim@timcoleman.com>
  38. * - Gonzalo Paniagua Javier <gonzalo@ximian.com>
  39. */
  40. #endregion
  41. using System;
  42. using System.Collections;
  43. using System.Collections.Generic;
  44. using System.Collections.Specialized;
  45. using System.Globalization;
  46. using System.IO;
  47. using System.Security.Principal;
  48. using System.Text;
  49. namespace WebSocketSharp.Net
  50. {
  51. internal static class HttpUtility
  52. {
  53. #region Private Fields
  54. private static Dictionary<string, char> _entities;
  55. private static char[] _hexChars;
  56. private static object _sync;
  57. #endregion
  58. #region Static Constructor
  59. static HttpUtility ()
  60. {
  61. _hexChars = "0123456789ABCDEF".ToCharArray ();
  62. _sync = new object ();
  63. }
  64. #endregion
  65. #region Private Methods
  66. private static Dictionary<string, char> getEntities ()
  67. {
  68. lock (_sync) {
  69. if (_entities == null)
  70. initEntities ();
  71. return _entities;
  72. }
  73. }
  74. private static int getNumber (char c)
  75. {
  76. return c >= '0' && c <= '9'
  77. ? c - '0'
  78. : c >= 'A' && c <= 'F'
  79. ? c - 'A' + 10
  80. : c >= 'a' && c <= 'f'
  81. ? c - 'a' + 10
  82. : -1;
  83. }
  84. private static int getNumber (byte[] bytes, int offset, int count)
  85. {
  86. var ret = 0;
  87. var end = offset + count - 1;
  88. for (var i = offset; i <= end; i++) {
  89. var num = getNumber ((char) bytes[i]);
  90. if (num == -1)
  91. return -1;
  92. ret = (ret << 4) + num;
  93. }
  94. return ret;
  95. }
  96. private static int getNumber (string s, int offset, int count)
  97. {
  98. var ret = 0;
  99. var end = offset + count - 1;
  100. for (var i = offset; i <= end; i++) {
  101. var num = getNumber (s[i]);
  102. if (num == -1)
  103. return -1;
  104. ret = (ret << 4) + num;
  105. }
  106. return ret;
  107. }
  108. private static string htmlDecode (string s)
  109. {
  110. var buff = new StringBuilder ();
  111. // 0: None
  112. // 1: Right after '&'
  113. // 2: Between '&' and ';' but no NCR
  114. // 3: '#' found after '&' and getting numbers
  115. // 4: 'x' found after '#' and getting numbers
  116. var state = 0;
  117. var reference = new StringBuilder ();
  118. var num = 0;
  119. foreach (var c in s) {
  120. if (state == 0) {
  121. if (c == '&') {
  122. reference.Append ('&');
  123. state = 1;
  124. continue;
  125. }
  126. buff.Append (c);
  127. continue;
  128. }
  129. if (c == '&') {
  130. buff.Append (reference.ToString ());
  131. reference.Length = 0;
  132. reference.Append ('&');
  133. state = 1;
  134. continue;
  135. }
  136. reference.Append (c);
  137. if (state == 1) {
  138. if (c == ';') {
  139. buff.Append (reference.ToString ());
  140. reference.Length = 0;
  141. state = 0;
  142. continue;
  143. }
  144. num = 0;
  145. state = c == '#' ? 3 : 2;
  146. continue;
  147. }
  148. if (state == 2) {
  149. if (c == ';') {
  150. var entity = reference.ToString ();
  151. var name = entity.Substring (1, entity.Length - 2);
  152. var entities = getEntities ();
  153. if (entities.ContainsKey (name))
  154. buff.Append (entities[name]);
  155. else
  156. buff.Append (entity);
  157. reference.Length = 0;
  158. state = 0;
  159. continue;
  160. }
  161. continue;
  162. }
  163. if (state == 3) {
  164. if (c == ';') {
  165. if (reference.Length > 3 && num < 65536)
  166. buff.Append ((char) num);
  167. else
  168. buff.Append (reference.ToString ());
  169. reference.Length = 0;
  170. state = 0;
  171. continue;
  172. }
  173. if (c == 'x') {
  174. state = reference.Length == 3 ? 4 : 2;
  175. continue;
  176. }
  177. if (!isNumeric (c)) {
  178. state = 2;
  179. continue;
  180. }
  181. num = num * 10 + (c - '0');
  182. continue;
  183. }
  184. if (state == 4) {
  185. if (c == ';') {
  186. if (reference.Length > 4 && num < 65536)
  187. buff.Append ((char) num);
  188. else
  189. buff.Append (reference.ToString ());
  190. reference.Length = 0;
  191. state = 0;
  192. continue;
  193. }
  194. var n = getNumber (c);
  195. if (n == -1) {
  196. state = 2;
  197. continue;
  198. }
  199. num = (num << 4) + n;
  200. }
  201. }
  202. if (reference.Length > 0)
  203. buff.Append (reference.ToString ());
  204. return buff.ToString ();
  205. }
  206. /// <summary>
  207. /// Converts the specified string to an HTML-encoded string.
  208. /// </summary>
  209. /// <remarks>
  210. /// <para>
  211. /// This method starts encoding with a NCR from the character code 160
  212. /// but does not stop at the character code 255.
  213. /// </para>
  214. /// <para>
  215. /// One reason is the unicode characters &#65308; and &#65310; that
  216. /// look like &lt; and &gt;.
  217. /// </para>
  218. /// </remarks>
  219. /// <returns>
  220. /// A <see cref="string"/> that represents an encoded string.
  221. /// </returns>
  222. /// <param name="s">
  223. /// A <see cref="string"/> to encode.
  224. /// </param>
  225. /// <param name="minimal">
  226. /// A <see cref="bool"/>: <c>true</c> if encodes without a NCR;
  227. /// otherwise, <c>false</c>.
  228. /// </param>
  229. private static string htmlEncode (string s, bool minimal)
  230. {
  231. var buff = new StringBuilder ();
  232. foreach (var c in s) {
  233. buff.Append (
  234. c == '"'
  235. ? "&quot;"
  236. : c == '&'
  237. ? "&amp;"
  238. : c == '<'
  239. ? "&lt;"
  240. : c == '>'
  241. ? "&gt;"
  242. : !minimal && c > 159
  243. ? String.Format ("&#{0};", (int) c)
  244. : c.ToString ()
  245. );
  246. }
  247. return buff.ToString ();
  248. }
  249. /// <summary>
  250. /// Initializes the _entities field.
  251. /// </summary>
  252. /// <remarks>
  253. /// This method builds a dictionary of HTML character entity references.
  254. /// This dictionary comes from the HTML 4.01 W3C recommendation.
  255. /// </remarks>
  256. private static void initEntities ()
  257. {
  258. _entities = new Dictionary<string, char> ();
  259. _entities.Add ("nbsp", '\u00A0');
  260. _entities.Add ("iexcl", '\u00A1');
  261. _entities.Add ("cent", '\u00A2');
  262. _entities.Add ("pound", '\u00A3');
  263. _entities.Add ("curren", '\u00A4');
  264. _entities.Add ("yen", '\u00A5');
  265. _entities.Add ("brvbar", '\u00A6');
  266. _entities.Add ("sect", '\u00A7');
  267. _entities.Add ("uml", '\u00A8');
  268. _entities.Add ("copy", '\u00A9');
  269. _entities.Add ("ordf", '\u00AA');
  270. _entities.Add ("laquo", '\u00AB');
  271. _entities.Add ("not", '\u00AC');
  272. _entities.Add ("shy", '\u00AD');
  273. _entities.Add ("reg", '\u00AE');
  274. _entities.Add ("macr", '\u00AF');
  275. _entities.Add ("deg", '\u00B0');
  276. _entities.Add ("plusmn", '\u00B1');
  277. _entities.Add ("sup2", '\u00B2');
  278. _entities.Add ("sup3", '\u00B3');
  279. _entities.Add ("acute", '\u00B4');
  280. _entities.Add ("micro", '\u00B5');
  281. _entities.Add ("para", '\u00B6');
  282. _entities.Add ("middot", '\u00B7');
  283. _entities.Add ("cedil", '\u00B8');
  284. _entities.Add ("sup1", '\u00B9');
  285. _entities.Add ("ordm", '\u00BA');
  286. _entities.Add ("raquo", '\u00BB');
  287. _entities.Add ("frac14", '\u00BC');
  288. _entities.Add ("frac12", '\u00BD');
  289. _entities.Add ("frac34", '\u00BE');
  290. _entities.Add ("iquest", '\u00BF');
  291. _entities.Add ("Agrave", '\u00C0');
  292. _entities.Add ("Aacute", '\u00C1');
  293. _entities.Add ("Acirc", '\u00C2');
  294. _entities.Add ("Atilde", '\u00C3');
  295. _entities.Add ("Auml", '\u00C4');
  296. _entities.Add ("Aring", '\u00C5');
  297. _entities.Add ("AElig", '\u00C6');
  298. _entities.Add ("Ccedil", '\u00C7');
  299. _entities.Add ("Egrave", '\u00C8');
  300. _entities.Add ("Eacute", '\u00C9');
  301. _entities.Add ("Ecirc", '\u00CA');
  302. _entities.Add ("Euml", '\u00CB');
  303. _entities.Add ("Igrave", '\u00CC');
  304. _entities.Add ("Iacute", '\u00CD');
  305. _entities.Add ("Icirc", '\u00CE');
  306. _entities.Add ("Iuml", '\u00CF');
  307. _entities.Add ("ETH", '\u00D0');
  308. _entities.Add ("Ntilde", '\u00D1');
  309. _entities.Add ("Ograve", '\u00D2');
  310. _entities.Add ("Oacute", '\u00D3');
  311. _entities.Add ("Ocirc", '\u00D4');
  312. _entities.Add ("Otilde", '\u00D5');
  313. _entities.Add ("Ouml", '\u00D6');
  314. _entities.Add ("times", '\u00D7');
  315. _entities.Add ("Oslash", '\u00D8');
  316. _entities.Add ("Ugrave", '\u00D9');
  317. _entities.Add ("Uacute", '\u00DA');
  318. _entities.Add ("Ucirc", '\u00DB');
  319. _entities.Add ("Uuml", '\u00DC');
  320. _entities.Add ("Yacute", '\u00DD');
  321. _entities.Add ("THORN", '\u00DE');
  322. _entities.Add ("szlig", '\u00DF');
  323. _entities.Add ("agrave", '\u00E0');
  324. _entities.Add ("aacute", '\u00E1');
  325. _entities.Add ("acirc", '\u00E2');
  326. _entities.Add ("atilde", '\u00E3');
  327. _entities.Add ("auml", '\u00E4');
  328. _entities.Add ("aring", '\u00E5');
  329. _entities.Add ("aelig", '\u00E6');
  330. _entities.Add ("ccedil", '\u00E7');
  331. _entities.Add ("egrave", '\u00E8');
  332. _entities.Add ("eacute", '\u00E9');
  333. _entities.Add ("ecirc", '\u00EA');
  334. _entities.Add ("euml", '\u00EB');
  335. _entities.Add ("igrave", '\u00EC');
  336. _entities.Add ("iacute", '\u00ED');
  337. _entities.Add ("icirc", '\u00EE');
  338. _entities.Add ("iuml", '\u00EF');
  339. _entities.Add ("eth", '\u00F0');
  340. _entities.Add ("ntilde", '\u00F1');
  341. _entities.Add ("ograve", '\u00F2');
  342. _entities.Add ("oacute", '\u00F3');
  343. _entities.Add ("ocirc", '\u00F4');
  344. _entities.Add ("otilde", '\u00F5');
  345. _entities.Add ("ouml", '\u00F6');
  346. _entities.Add ("divide", '\u00F7');
  347. _entities.Add ("oslash", '\u00F8');
  348. _entities.Add ("ugrave", '\u00F9');
  349. _entities.Add ("uacute", '\u00FA');
  350. _entities.Add ("ucirc", '\u00FB');
  351. _entities.Add ("uuml", '\u00FC');
  352. _entities.Add ("yacute", '\u00FD');
  353. _entities.Add ("thorn", '\u00FE');
  354. _entities.Add ("yuml", '\u00FF');
  355. _entities.Add ("fnof", '\u0192');
  356. _entities.Add ("Alpha", '\u0391');
  357. _entities.Add ("Beta", '\u0392');
  358. _entities.Add ("Gamma", '\u0393');
  359. _entities.Add ("Delta", '\u0394');
  360. _entities.Add ("Epsilon", '\u0395');
  361. _entities.Add ("Zeta", '\u0396');
  362. _entities.Add ("Eta", '\u0397');
  363. _entities.Add ("Theta", '\u0398');
  364. _entities.Add ("Iota", '\u0399');
  365. _entities.Add ("Kappa", '\u039A');
  366. _entities.Add ("Lambda", '\u039B');
  367. _entities.Add ("Mu", '\u039C');
  368. _entities.Add ("Nu", '\u039D');
  369. _entities.Add ("Xi", '\u039E');
  370. _entities.Add ("Omicron", '\u039F');
  371. _entities.Add ("Pi", '\u03A0');
  372. _entities.Add ("Rho", '\u03A1');
  373. _entities.Add ("Sigma", '\u03A3');
  374. _entities.Add ("Tau", '\u03A4');
  375. _entities.Add ("Upsilon", '\u03A5');
  376. _entities.Add ("Phi", '\u03A6');
  377. _entities.Add ("Chi", '\u03A7');
  378. _entities.Add ("Psi", '\u03A8');
  379. _entities.Add ("Omega", '\u03A9');
  380. _entities.Add ("alpha", '\u03B1');
  381. _entities.Add ("beta", '\u03B2');
  382. _entities.Add ("gamma", '\u03B3');
  383. _entities.Add ("delta", '\u03B4');
  384. _entities.Add ("epsilon", '\u03B5');
  385. _entities.Add ("zeta", '\u03B6');
  386. _entities.Add ("eta", '\u03B7');
  387. _entities.Add ("theta", '\u03B8');
  388. _entities.Add ("iota", '\u03B9');
  389. _entities.Add ("kappa", '\u03BA');
  390. _entities.Add ("lambda", '\u03BB');
  391. _entities.Add ("mu", '\u03BC');
  392. _entities.Add ("nu", '\u03BD');
  393. _entities.Add ("xi", '\u03BE');
  394. _entities.Add ("omicron", '\u03BF');
  395. _entities.Add ("pi", '\u03C0');
  396. _entities.Add ("rho", '\u03C1');
  397. _entities.Add ("sigmaf", '\u03C2');
  398. _entities.Add ("sigma", '\u03C3');
  399. _entities.Add ("tau", '\u03C4');
  400. _entities.Add ("upsilon", '\u03C5');
  401. _entities.Add ("phi", '\u03C6');
  402. _entities.Add ("chi", '\u03C7');
  403. _entities.Add ("psi", '\u03C8');
  404. _entities.Add ("omega", '\u03C9');
  405. _entities.Add ("thetasym", '\u03D1');
  406. _entities.Add ("upsih", '\u03D2');
  407. _entities.Add ("piv", '\u03D6');
  408. _entities.Add ("bull", '\u2022');
  409. _entities.Add ("hellip", '\u2026');
  410. _entities.Add ("prime", '\u2032');
  411. _entities.Add ("Prime", '\u2033');
  412. _entities.Add ("oline", '\u203E');
  413. _entities.Add ("frasl", '\u2044');
  414. _entities.Add ("weierp", '\u2118');
  415. _entities.Add ("image", '\u2111');
  416. _entities.Add ("real", '\u211C');
  417. _entities.Add ("trade", '\u2122');
  418. _entities.Add ("alefsym", '\u2135');
  419. _entities.Add ("larr", '\u2190');
  420. _entities.Add ("uarr", '\u2191');
  421. _entities.Add ("rarr", '\u2192');
  422. _entities.Add ("darr", '\u2193');
  423. _entities.Add ("harr", '\u2194');
  424. _entities.Add ("crarr", '\u21B5');
  425. _entities.Add ("lArr", '\u21D0');
  426. _entities.Add ("uArr", '\u21D1');
  427. _entities.Add ("rArr", '\u21D2');
  428. _entities.Add ("dArr", '\u21D3');
  429. _entities.Add ("hArr", '\u21D4');
  430. _entities.Add ("forall", '\u2200');
  431. _entities.Add ("part", '\u2202');
  432. _entities.Add ("exist", '\u2203');
  433. _entities.Add ("empty", '\u2205');
  434. _entities.Add ("nabla", '\u2207');
  435. _entities.Add ("isin", '\u2208');
  436. _entities.Add ("notin", '\u2209');
  437. _entities.Add ("ni", '\u220B');
  438. _entities.Add ("prod", '\u220F');
  439. _entities.Add ("sum", '\u2211');
  440. _entities.Add ("minus", '\u2212');
  441. _entities.Add ("lowast", '\u2217');
  442. _entities.Add ("radic", '\u221A');
  443. _entities.Add ("prop", '\u221D');
  444. _entities.Add ("infin", '\u221E');
  445. _entities.Add ("ang", '\u2220');
  446. _entities.Add ("and", '\u2227');
  447. _entities.Add ("or", '\u2228');
  448. _entities.Add ("cap", '\u2229');
  449. _entities.Add ("cup", '\u222A');
  450. _entities.Add ("int", '\u222B');
  451. _entities.Add ("there4", '\u2234');
  452. _entities.Add ("sim", '\u223C');
  453. _entities.Add ("cong", '\u2245');
  454. _entities.Add ("asymp", '\u2248');
  455. _entities.Add ("ne", '\u2260');
  456. _entities.Add ("equiv", '\u2261');
  457. _entities.Add ("le", '\u2264');
  458. _entities.Add ("ge", '\u2265');
  459. _entities.Add ("sub", '\u2282');
  460. _entities.Add ("sup", '\u2283');
  461. _entities.Add ("nsub", '\u2284');
  462. _entities.Add ("sube", '\u2286');
  463. _entities.Add ("supe", '\u2287');
  464. _entities.Add ("oplus", '\u2295');
  465. _entities.Add ("otimes", '\u2297');
  466. _entities.Add ("perp", '\u22A5');
  467. _entities.Add ("sdot", '\u22C5');
  468. _entities.Add ("lceil", '\u2308');
  469. _entities.Add ("rceil", '\u2309');
  470. _entities.Add ("lfloor", '\u230A');
  471. _entities.Add ("rfloor", '\u230B');
  472. _entities.Add ("lang", '\u2329');
  473. _entities.Add ("rang", '\u232A');
  474. _entities.Add ("loz", '\u25CA');
  475. _entities.Add ("spades", '\u2660');
  476. _entities.Add ("clubs", '\u2663');
  477. _entities.Add ("hearts", '\u2665');
  478. _entities.Add ("diams", '\u2666');
  479. _entities.Add ("quot", '\u0022');
  480. _entities.Add ("amp", '\u0026');
  481. _entities.Add ("lt", '\u003C');
  482. _entities.Add ("gt", '\u003E');
  483. _entities.Add ("OElig", '\u0152');
  484. _entities.Add ("oelig", '\u0153');
  485. _entities.Add ("Scaron", '\u0160');
  486. _entities.Add ("scaron", '\u0161');
  487. _entities.Add ("Yuml", '\u0178');
  488. _entities.Add ("circ", '\u02C6');
  489. _entities.Add ("tilde", '\u02DC');
  490. _entities.Add ("ensp", '\u2002');
  491. _entities.Add ("emsp", '\u2003');
  492. _entities.Add ("thinsp", '\u2009');
  493. _entities.Add ("zwnj", '\u200C');
  494. _entities.Add ("zwj", '\u200D');
  495. _entities.Add ("lrm", '\u200E');
  496. _entities.Add ("rlm", '\u200F');
  497. _entities.Add ("ndash", '\u2013');
  498. _entities.Add ("mdash", '\u2014');
  499. _entities.Add ("lsquo", '\u2018');
  500. _entities.Add ("rsquo", '\u2019');
  501. _entities.Add ("sbquo", '\u201A');
  502. _entities.Add ("ldquo", '\u201C');
  503. _entities.Add ("rdquo", '\u201D');
  504. _entities.Add ("bdquo", '\u201E');
  505. _entities.Add ("dagger", '\u2020');
  506. _entities.Add ("Dagger", '\u2021');
  507. _entities.Add ("permil", '\u2030');
  508. _entities.Add ("lsaquo", '\u2039');
  509. _entities.Add ("rsaquo", '\u203A');
  510. _entities.Add ("euro", '\u20AC');
  511. }
  512. private static bool isAlphabet (char c)
  513. {
  514. return (c >= 'A' && c <= 'Z')
  515. || (c >= 'a' && c <= 'z');
  516. }
  517. private static bool isNumeric (char c)
  518. {
  519. return c >= '0' && c <= '9';
  520. }
  521. private static bool isUnreserved (char c)
  522. {
  523. return c == '*'
  524. || c == '-'
  525. || c == '.'
  526. || c == '_';
  527. }
  528. private static bool isUnreservedInRfc2396 (char c)
  529. {
  530. return c == '!'
  531. || c == '\''
  532. || c == '('
  533. || c == ')'
  534. || c == '*'
  535. || c == '-'
  536. || c == '.'
  537. || c == '_'
  538. || c == '~';
  539. }
  540. private static bool isUnreservedInRfc3986 (char c)
  541. {
  542. return c == '-'
  543. || c == '.'
  544. || c == '_'
  545. || c == '~';
  546. }
  547. private static byte[] urlDecodeToBytes (byte[] bytes, int offset, int count)
  548. {
  549. using (var buff = new MemoryStream ()) {
  550. var end = offset + count - 1;
  551. for (var i = offset; i <= end; i++) {
  552. var b = bytes[i];
  553. var c = (char) b;
  554. if (c == '%') {
  555. if (i > end - 2)
  556. break;
  557. var num = getNumber (bytes, i + 1, 2);
  558. if (num == -1)
  559. break;
  560. buff.WriteByte ((byte) num);
  561. i += 2;
  562. continue;
  563. }
  564. if (c == '+') {
  565. buff.WriteByte ((byte) ' ');
  566. continue;
  567. }
  568. buff.WriteByte (b);
  569. }
  570. buff.Close ();
  571. return buff.ToArray ();
  572. }
  573. }
  574. private static void urlEncode (byte b, Stream output)
  575. {
  576. if (b > 31 && b < 127) {
  577. var c = (char) b;
  578. if (c == ' ') {
  579. output.WriteByte ((byte) '+');
  580. return;
  581. }
  582. if (isNumeric (c)) {
  583. output.WriteByte (b);
  584. return;
  585. }
  586. if (isAlphabet (c)) {
  587. output.WriteByte (b);
  588. return;
  589. }
  590. if (isUnreserved (c)) {
  591. output.WriteByte (b);
  592. return;
  593. }
  594. }
  595. var i = (int) b;
  596. var bytes = new byte[] {
  597. (byte) '%',
  598. (byte) _hexChars[i >> 4],
  599. (byte) _hexChars[i & 0x0F]
  600. };
  601. output.Write (bytes, 0, 3);
  602. }
  603. private static byte[] urlEncodeToBytes (byte[] bytes, int offset, int count)
  604. {
  605. using (var buff = new MemoryStream ()) {
  606. var end = offset + count - 1;
  607. for (var i = offset; i <= end; i++)
  608. urlEncode (bytes[i], buff);
  609. buff.Close ();
  610. return buff.ToArray ();
  611. }
  612. }
  613. #endregion
  614. #region Internal Methods
  615. internal static Uri CreateRequestUrl (
  616. string requestUri, string host, bool websocketRequest, bool secure
  617. )
  618. {
  619. if (requestUri == null || requestUri.Length == 0)
  620. return null;
  621. if (host == null || host.Length == 0)
  622. return null;
  623. string schm = null;
  624. string path = null;
  625. if (requestUri.IndexOf ('/') == 0) {
  626. path = requestUri;
  627. }
  628. else if (requestUri.MaybeUri ()) {
  629. Uri uri;
  630. if (!Uri.TryCreate (requestUri, UriKind.Absolute, out uri))
  631. return null;
  632. schm = uri.Scheme;
  633. var valid = websocketRequest
  634. ? schm == "ws" || schm == "wss"
  635. : schm == "http" || schm == "https";
  636. if (!valid)
  637. return null;
  638. host = uri.Authority;
  639. path = uri.PathAndQuery;
  640. }
  641. else if (requestUri == "*") {
  642. }
  643. else {
  644. // As the authority form.
  645. host = requestUri;
  646. }
  647. if (schm == null) {
  648. schm = websocketRequest
  649. ? (secure ? "wss" : "ws")
  650. : (secure ? "https" : "http");
  651. }
  652. if (host.IndexOf (':') == -1)
  653. host = String.Format ("{0}:{1}", host, secure ? 443 : 80);
  654. var url = String.Format ("{0}://{1}{2}", schm, host, path);
  655. Uri ret;
  656. return Uri.TryCreate (url, UriKind.Absolute, out ret) ? ret : null;
  657. }
  658. internal static IPrincipal CreateUser (
  659. string response,
  660. AuthenticationSchemes scheme,
  661. string realm,
  662. string method,
  663. Func<IIdentity, NetworkCredential> credentialsFinder
  664. )
  665. {
  666. if (response == null || response.Length == 0)
  667. return null;
  668. if (scheme == AuthenticationSchemes.Digest) {
  669. if (realm == null || realm.Length == 0)
  670. return null;
  671. if (method == null || method.Length == 0)
  672. return null;
  673. }
  674. else {
  675. if (scheme != AuthenticationSchemes.Basic)
  676. return null;
  677. }
  678. if (credentialsFinder == null)
  679. return null;
  680. var compType = StringComparison.OrdinalIgnoreCase;
  681. if (response.IndexOf (scheme.ToString (), compType) != 0)
  682. return null;
  683. var res = AuthenticationResponse.Parse (response);
  684. if (res == null)
  685. return null;
  686. var id = res.ToIdentity ();
  687. if (id == null)
  688. return null;
  689. NetworkCredential cred = null;
  690. try {
  691. cred = credentialsFinder (id);
  692. }
  693. catch {
  694. }
  695. if (cred == null)
  696. return null;
  697. if (scheme == AuthenticationSchemes.Basic) {
  698. var basicId = (HttpBasicIdentity) id;
  699. return basicId.Password == cred.Password
  700. ? new GenericPrincipal (id, cred.Roles)
  701. : null;
  702. }
  703. var digestId = (HttpDigestIdentity) id;
  704. return digestId.IsValid (cred.Password, realm, method, null)
  705. ? new GenericPrincipal (id, cred.Roles)
  706. : null;
  707. }
  708. internal static Encoding GetEncoding (string contentType)
  709. {
  710. var name = "charset=";
  711. var compType = StringComparison.OrdinalIgnoreCase;
  712. foreach (var elm in contentType.SplitHeaderValue (';')) {
  713. var part = elm.Trim ();
  714. if (!part.StartsWith (name, compType))
  715. continue;
  716. var val = part.GetValue ('=', true);
  717. if (val == null || val.Length == 0)
  718. return null;
  719. return Encoding.GetEncoding (val);
  720. }
  721. return null;
  722. }
  723. internal static bool TryGetEncoding (
  724. string contentType, out Encoding result
  725. )
  726. {
  727. result = null;
  728. try {
  729. result = GetEncoding (contentType);
  730. }
  731. catch {
  732. return false;
  733. }
  734. return result != null;
  735. }
  736. #endregion
  737. #region Public Methods
  738. public static string HtmlAttributeEncode (string s)
  739. {
  740. if (s == null)
  741. throw new ArgumentNullException ("s");
  742. return s.Length > 0 ? htmlEncode (s, true) : s;
  743. }
  744. public static void HtmlAttributeEncode (string s, TextWriter output)
  745. {
  746. if (s == null)
  747. throw new ArgumentNullException ("s");
  748. if (output == null)
  749. throw new ArgumentNullException ("output");
  750. if (s.Length == 0)
  751. return;
  752. output.Write (htmlEncode (s, true));
  753. }
  754. public static string HtmlDecode (string s)
  755. {
  756. if (s == null)
  757. throw new ArgumentNullException ("s");
  758. return s.Length > 0 ? htmlDecode (s) : s;
  759. }
  760. public static void HtmlDecode (string s, TextWriter output)
  761. {
  762. if (s == null)
  763. throw new ArgumentNullException ("s");
  764. if (output == null)
  765. throw new ArgumentNullException ("output");
  766. if (s.Length == 0)
  767. return;
  768. output.Write (htmlDecode (s));
  769. }
  770. public static string HtmlEncode (string s)
  771. {
  772. if (s == null)
  773. throw new ArgumentNullException ("s");
  774. return s.Length > 0 ? htmlEncode (s, false) : s;
  775. }
  776. public static void HtmlEncode (string s, TextWriter output)
  777. {
  778. if (s == null)
  779. throw new ArgumentNullException ("s");
  780. if (output == null)
  781. throw new ArgumentNullException ("output");
  782. if (s.Length == 0)
  783. return;
  784. output.Write (htmlEncode (s, false));
  785. }
  786. public static string UrlDecode (string s)
  787. {
  788. return UrlDecode (s, Encoding.UTF8);
  789. }
  790. public static string UrlDecode (byte[] bytes, Encoding encoding)
  791. {
  792. if (bytes == null)
  793. throw new ArgumentNullException ("bytes");
  794. var len = bytes.Length;
  795. return len > 0
  796. ? (encoding ?? Encoding.UTF8).GetString (
  797. urlDecodeToBytes (bytes, 0, len)
  798. )
  799. : String.Empty;
  800. }
  801. public static string UrlDecode (string s, Encoding encoding)
  802. {
  803. if (s == null)
  804. throw new ArgumentNullException ("s");
  805. if (s.Length == 0)
  806. return s;
  807. var bytes = Encoding.ASCII.GetBytes (s);
  808. return (encoding ?? Encoding.UTF8).GetString (
  809. urlDecodeToBytes (bytes, 0, bytes.Length)
  810. );
  811. }
  812. public static string UrlDecode (
  813. byte[] bytes, int offset, int count, Encoding encoding
  814. )
  815. {
  816. if (bytes == null)
  817. throw new ArgumentNullException ("bytes");
  818. var len = bytes.Length;
  819. if (len == 0) {
  820. if (offset != 0)
  821. throw new ArgumentOutOfRangeException ("offset");
  822. if (count != 0)
  823. throw new ArgumentOutOfRangeException ("count");
  824. return String.Empty;
  825. }
  826. if (offset < 0 || offset >= len)
  827. throw new ArgumentOutOfRangeException ("offset");
  828. if (count < 0 || count > len - offset)
  829. throw new ArgumentOutOfRangeException ("count");
  830. return count > 0
  831. ? (encoding ?? Encoding.UTF8).GetString (
  832. urlDecodeToBytes (bytes, offset, count)
  833. )
  834. : String.Empty;
  835. }
  836. public static byte[] UrlDecodeToBytes (byte[] bytes)
  837. {
  838. if (bytes == null)
  839. throw new ArgumentNullException ("bytes");
  840. var len = bytes.Length;
  841. return len > 0
  842. ? urlDecodeToBytes (bytes, 0, len)
  843. : bytes;
  844. }
  845. public static byte[] UrlDecodeToBytes (string s)
  846. {
  847. if (s == null)
  848. throw new ArgumentNullException ("s");
  849. if (s.Length == 0)
  850. return new byte[0];
  851. var bytes = Encoding.ASCII.GetBytes (s);
  852. return urlDecodeToBytes (bytes, 0, bytes.Length);
  853. }
  854. public static byte[] UrlDecodeToBytes (byte[] bytes, int offset, int count)
  855. {
  856. if (bytes == null)
  857. throw new ArgumentNullException ("bytes");
  858. var len = bytes.Length;
  859. if (len == 0) {
  860. if (offset != 0)
  861. throw new ArgumentOutOfRangeException ("offset");
  862. if (count != 0)
  863. throw new ArgumentOutOfRangeException ("count");
  864. return bytes;
  865. }
  866. if (offset < 0 || offset >= len)
  867. throw new ArgumentOutOfRangeException ("offset");
  868. if (count < 0 || count > len - offset)
  869. throw new ArgumentOutOfRangeException ("count");
  870. return count > 0
  871. ? urlDecodeToBytes (bytes, offset, count)
  872. : new byte[0];
  873. }
  874. public static string UrlEncode (byte[] bytes)
  875. {
  876. if (bytes == null)
  877. throw new ArgumentNullException ("bytes");
  878. var len = bytes.Length;
  879. return len > 0
  880. ? Encoding.ASCII.GetString (urlEncodeToBytes (bytes, 0, len))
  881. : String.Empty;
  882. }
  883. public static string UrlEncode (string s)
  884. {
  885. return UrlEncode (s, Encoding.UTF8);
  886. }
  887. public static string UrlEncode (string s, Encoding encoding)
  888. {
  889. if (s == null)
  890. throw new ArgumentNullException ("s");
  891. var len = s.Length;
  892. if (len == 0)
  893. return s;
  894. if (encoding == null)
  895. encoding = Encoding.UTF8;
  896. var bytes = new byte[encoding.GetMaxByteCount (len)];
  897. var realLen = encoding.GetBytes (s, 0, len, bytes, 0);
  898. return Encoding.ASCII.GetString (urlEncodeToBytes (bytes, 0, realLen));
  899. }
  900. public static string UrlEncode (byte[] bytes, int offset, int count)
  901. {
  902. if (bytes == null)
  903. throw new ArgumentNullException ("bytes");
  904. var len = bytes.Length;
  905. if (len == 0) {
  906. if (offset != 0)
  907. throw new ArgumentOutOfRangeException ("offset");
  908. if (count != 0)
  909. throw new ArgumentOutOfRangeException ("count");
  910. return String.Empty;
  911. }
  912. if (offset < 0 || offset >= len)
  913. throw new ArgumentOutOfRangeException ("offset");
  914. if (count < 0 || count > len - offset)
  915. throw new ArgumentOutOfRangeException ("count");
  916. return count > 0
  917. ? Encoding.ASCII.GetString (
  918. urlEncodeToBytes (bytes, offset, count)
  919. )
  920. : String.Empty;
  921. }
  922. public static byte[] UrlEncodeToBytes (byte[] bytes)
  923. {
  924. if (bytes == null)
  925. throw new ArgumentNullException ("bytes");
  926. var len = bytes.Length;
  927. return len > 0 ? urlEncodeToBytes (bytes, 0, len) : bytes;
  928. }
  929. public static byte[] UrlEncodeToBytes (string s)
  930. {
  931. return UrlEncodeToBytes (s, Encoding.UTF8);
  932. }
  933. public static byte[] UrlEncodeToBytes (string s, Encoding encoding)
  934. {
  935. if (s == null)
  936. throw new ArgumentNullException ("s");
  937. if (s.Length == 0)
  938. return new byte[0];
  939. var bytes = (encoding ?? Encoding.UTF8).GetBytes (s);
  940. return urlEncodeToBytes (bytes, 0, bytes.Length);
  941. }
  942. public static byte[] UrlEncodeToBytes (byte[] bytes, int offset, int count)
  943. {
  944. if (bytes == null)
  945. throw new ArgumentNullException ("bytes");
  946. var len = bytes.Length;
  947. if (len == 0) {
  948. if (offset != 0)
  949. throw new ArgumentOutOfRangeException ("offset");
  950. if (count != 0)
  951. throw new ArgumentOutOfRangeException ("count");
  952. return bytes;
  953. }
  954. if (offset < 0 || offset >= len)
  955. throw new ArgumentOutOfRangeException ("offset");
  956. if (count < 0 || count > len - offset)
  957. throw new ArgumentOutOfRangeException ("count");
  958. return count > 0 ? urlEncodeToBytes (bytes, offset, count) : new byte[0];
  959. }
  960. #endregion
  961. }
  962. }