Ext.cs 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  1. #region MIT License
  2. /**
  3. * Ext.cs
  4. * IsPredefinedScheme and MaybeUri methods derived from System.Uri.cs
  5. * GetStatusDescription method derived from System.Net.HttpListenerResponse.cs
  6. *
  7. * The MIT License
  8. *
  9. * Copyright (c) 2010-2012 sta.blockhead
  10. *
  11. * System.Uri.cs
  12. * (C) 2001 Garrett Rooney
  13. * (C) 2003 Ian MacLean
  14. * (C) 2003 Ben Maurer
  15. * Copyright (C) 2003, 2005, 2009 Novell, Inc. (http://www.novell.com)
  16. * Copyright (c) 2009 Stephane Delcroix
  17. *
  18. * System.Net.HttpListenerResponse.cs
  19. * Copyright (C) 2003, 2005, 2009 Novell, Inc. (http://www.novell.com)
  20. *
  21. * Permission is hereby granted, free of charge, to any person obtaining a copy
  22. * of this software and associated documentation files (the "Software"), to deal
  23. * in the Software without restriction, including without limitation the rights
  24. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  25. * copies of the Software, and to permit persons to whom the Software is
  26. * furnished to do so, subject to the following conditions:
  27. *
  28. * The above copyright notice and this permission notice shall be included in
  29. * all copies or substantial portions of the Software.
  30. *
  31. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  32. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  33. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  34. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  35. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  36. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  37. * THE SOFTWARE.
  38. */
  39. #endregion
  40. using System;
  41. using System.Collections.Generic;
  42. using System.Collections.Specialized;
  43. using System.IO;
  44. using System.Net.Sockets;
  45. using System.Text;
  46. using WebSocketSharp.Net;
  47. using WebSocketSharp.Net.Sockets;
  48. namespace WebSocketSharp
  49. {
  50. public delegate void Action();
  51. public delegate void Action<T1, T2>(T1 t1, T2 t2);
  52. public delegate void Action<T1, T2, T3>(T1 t1, T2 t2, T3 t3);
  53. public delegate void Action<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4);
  54. public delegate TResult Func<T1, TResult>(T1 t1);
  55. /// <summary>Provides a set of static methods for the websocket-sharp.
  56. /// </summary>
  57. public static class Ext
  58. {
  59. #region Private Methods
  60. private static void times(ulong n, Action act)
  61. {
  62. for (ulong i = 0; i < n; i++)
  63. act();
  64. }
  65. private static void times(ulong n, Action<ulong> act)
  66. {
  67. for (ulong i = 0; i < n; i++)
  68. act(i);
  69. }
  70. private static byte[] Reverse(byte[] array)
  71. {
  72. Array.Reverse(array);
  73. return array;
  74. }
  75. #endregion
  76. #region Public Methods
  77. /// <summary>
  78. /// Accept a WebSocket connection by the <see cref="TcpListener"/>.
  79. /// </summary>
  80. /// <returns>
  81. /// A <see cref="WebSocketSharp.Net.Sockets.TcpListenerWebSocketContext"/> that contains a WebSocket connection.
  82. /// </returns>
  83. /// <param name="client">
  84. /// A <see cref="TcpClient"/> that contains a TCP connection to accept a WebSocket connection from.
  85. /// </param>
  86. /// <param name="secure">
  87. /// A <see cref="bool"/> that indicates a secure connection or not. (<c>true</c> indicates a secure connection.)
  88. /// </param>
  89. /// <exception cref="ArgumentNullException">
  90. /// Is thrown when the <paramref name="client"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  91. /// </exception>
  92. public static TcpListenerWebSocketContext AcceptWebSocket(TcpClient client, bool secure)
  93. {
  94. if (client == null)
  95. throw new ArgumentNullException("client");
  96. return new TcpListenerWebSocketContext(client, secure);
  97. }
  98. /// <summary>
  99. /// Emit the specified <see cref="EventHandler"/> delegate if is not <see langword="null"/>.
  100. /// </summary>
  101. /// <param name="eventHandler">
  102. /// An <see cref="EventHandler"/> to emit.
  103. /// </param>
  104. /// <param name="sender">
  105. /// An <see cref="object"/> that emits the <paramref name="eventHandler"/>.
  106. /// </param>
  107. /// <param name="e">
  108. /// An <see cref="EventArgs"/> that contains no event data.
  109. /// </param>
  110. public static void Emit(
  111. EventHandler eventHandler, object sender, EventArgs e)
  112. {
  113. if (eventHandler != null)
  114. eventHandler(sender, e);
  115. }
  116. /// <summary>
  117. /// Emit the specified <see cref="EventHandler&lt;TEventArgs&gt;"/> delegate if is not <see langword="null"/>.
  118. /// </summary>
  119. /// <param name="eventHandler">
  120. /// An <see cref="EventHandler&lt;TEventArgs&gt;"/> to emit.
  121. /// </param>
  122. /// <param name="sender">
  123. /// An <see cref="object"/> that emits the <paramref name="eventHandler"/>.
  124. /// </param>
  125. /// <param name="e">
  126. /// An <see cref="EventArgs"/> that contains the event data.
  127. /// </param>
  128. /// <typeparam name="TEventArgs">
  129. /// The type of the event data generated by the event.
  130. /// </typeparam>
  131. public static void Emit<TEventArgs>(
  132. EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e)
  133. where TEventArgs : EventArgs
  134. {
  135. if (eventHandler != null)
  136. eventHandler(sender, e);
  137. }
  138. /// <summary>
  139. /// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/> as <see cref="byte"/>.
  140. /// And save this specified <see cref="int"/> as <see cref="byte"/> to the specified <see cref="List&lt;byte&gt;"/>.
  141. /// </summary>
  142. /// <returns>
  143. /// <c>true</c> if the <paramref name="value"/> parameter equals the <paramref name="c"/> parameter as <see cref="byte"/>; otherwise, <c>false</c>.
  144. /// </returns>
  145. /// <param name="value">
  146. /// An <see cref="int"/> to compare.
  147. /// </param>
  148. /// <param name="c">
  149. /// A <see cref="char"/> to compare.
  150. /// </param>
  151. /// <param name="dest">
  152. /// A <see cref="List&lt;byte&gt;"/> to save the <paramref name="value"/> as <see cref="byte"/>.
  153. /// </param>
  154. /// <exception cref="ArgumentOutOfRangeException">
  155. /// Is thrown when the <paramref name="value"/> parameter passed to a method is invalid because it is outside the allowable range of values as <see cref="byte"/>.
  156. /// </exception>
  157. public static bool EqualsAndSaveTo(int value, char c, List<byte> dest)
  158. {
  159. if (value < 0 || value > 255)
  160. throw new ArgumentOutOfRangeException("value");
  161. var b = (byte)value;
  162. dest.Add(b);
  163. return b == Convert.ToByte(c);
  164. }
  165. /// <summary>
  166. /// Determines whether the entry with the specified key exists in the specified <see cref="NameValueCollection"/>.
  167. /// </summary>
  168. /// <returns>
  169. /// <c>true</c> if the entry with the <paramref name="name"/> exists in the <paramref name="collection"/>; otherwise, <c>false</c>.
  170. /// </returns>
  171. /// <param name="collection">
  172. /// A <see cref="NameValueCollection"/> that contains the entries.
  173. /// </param>
  174. /// <param name="name">
  175. /// A <see cref="string"/> that contains the key of the entry to find.
  176. /// </param>
  177. public static bool Exists(NameValueCollection collection, string name)
  178. {
  179. return collection == null
  180. ? false
  181. : collection[name] != null;
  182. }
  183. /// <summary>
  184. /// Determines whether the entry with the specified both key and value exists in the specified <see cref="NameValueCollection"/>.
  185. /// </summary>
  186. /// <returns>
  187. /// <c>true</c> if the entry with the both <paramref name="name"/> and <paramref name="value"/> exists in the <paramref name="collection"/>; otherwise, <c>false</c>.
  188. /// </returns>
  189. /// <param name="collection">
  190. /// A <see cref="NameValueCollection"/> that contains the entries.
  191. /// </param>
  192. /// <param name="name">
  193. /// A <see cref="string"/> that contains the key of the entry to find.
  194. /// </param>
  195. /// <param name="value">
  196. /// A <see cref="string"/> that contains the value of the entry to find.
  197. /// </param>
  198. public static bool Exists(NameValueCollection collection, string name, string value)
  199. {
  200. if (collection == null)
  201. return false;
  202. var values = collection[name];
  203. if (values == null)
  204. return false;
  205. foreach (string v in values.Split(','))
  206. if (String.Compare(v.Trim(), value, true) == 0)
  207. return true;
  208. return false;
  209. }
  210. /// <summary>
  211. /// Gets the absolute path from the specified <see cref="Uri"/>.
  212. /// </summary>
  213. /// <returns>
  214. /// A <see cref="string"/> that contains the absolute path if got successfully; otherwise, <see langword="null"/>.
  215. /// </returns>
  216. /// <param name="uri">
  217. /// A <see cref="Uri"/> that contains the URI to get the absolute path from.
  218. /// </param>
  219. public static string GetAbsolutePath(Uri uri)
  220. {
  221. if (uri == null)
  222. return null;
  223. if (uri.IsAbsoluteUri)
  224. return uri.AbsolutePath;
  225. var uriString = uri.OriginalString;
  226. var i = uriString.IndexOf('/');
  227. if (i != 0)
  228. return null;
  229. i = uriString.IndexOfAny(new[] { '?', '#' });
  230. return i > 0
  231. ? uriString.Substring(0, i)
  232. : uriString;
  233. }
  234. /// <summary>
  235. /// Gets the description of the HTTP status code using the specified code.
  236. /// </summary>
  237. /// <returns>
  238. /// A <see cref="string"/> that contains the description of the <paramref name="code"/>.
  239. /// </returns>
  240. /// <param name="code">
  241. /// One of <see cref="WebSocketSharp.Net.HttpStatusCode"/> values that contains the HTTP status code.
  242. /// </param>
  243. public static string GetDescription(HttpStatusCode code)
  244. {
  245. return GetStatusDescription((int)code);
  246. }
  247. /// <summary>
  248. /// Gets the name from the specified <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  249. /// </summary>
  250. /// <returns>
  251. /// A <see cref="string"/> that contains the name if any; otherwise, <c>null</c>.
  252. /// </returns>
  253. /// <param name="nameAndValue">
  254. /// A <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  255. /// </param>
  256. /// <param name="separator">
  257. /// A <see cref="string"/> that contains a separator string.
  258. /// </param>
  259. public static string GetName(string nameAndValue, string separator)
  260. {
  261. if (IsNullOrEmpty(nameAndValue))
  262. return null;
  263. if (IsNullOrEmpty(separator))
  264. return null;
  265. var i = nameAndValue.IndexOf(separator);
  266. return i > 0
  267. ? nameAndValue.Substring(0, i).Trim()
  268. : null;
  269. }
  270. /// <summary>
  271. /// Gets the name and value from the specified <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  272. /// </summary>
  273. /// <returns>
  274. /// A <see cref="KeyValuePair&lt;string, string&gt;"/> that contains the name and value if any.
  275. /// </returns>
  276. /// <param name="nameAndValue">
  277. /// A <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  278. /// </param>
  279. /// <param name="separator">
  280. /// A <see cref="string"/> that contains a separator string.
  281. /// </param>
  282. public static KeyValuePair<string, string> GetNameAndValue(string nameAndValue, string separator)
  283. {
  284. var name = GetName(nameAndValue, separator);
  285. var value = GetValue(nameAndValue, separator);
  286. return name != null
  287. ? new KeyValuePair<string, string>(name, value)
  288. : new KeyValuePair<string, string>(null, null);
  289. }
  290. /// <summary>
  291. /// Gets the description of the HTTP status code using the specified code.
  292. /// </summary>
  293. /// <returns>
  294. /// A <see cref="string"/> that contains the description of the <paramref name="code"/>.
  295. /// </returns>
  296. /// <param name="code">
  297. /// An <see cref="int"/> that contains the HTTP status code.
  298. /// </param>
  299. public static string GetStatusDescription(int code)
  300. {
  301. switch (code)
  302. {
  303. case 100: return "Continue";
  304. case 101: return "Switching Protocols";
  305. case 102: return "Processing";
  306. case 200: return "OK";
  307. case 201: return "Created";
  308. case 202: return "Accepted";
  309. case 203: return "Non-Authoritative Information";
  310. case 204: return "No Content";
  311. case 205: return "Reset Content";
  312. case 206: return "Partial Content";
  313. case 207: return "Multi-Status";
  314. case 300: return "Multiple Choices";
  315. case 301: return "Moved Permanently";
  316. case 302: return "Found";
  317. case 303: return "See Other";
  318. case 304: return "Not Modified";
  319. case 305: return "Use Proxy";
  320. case 307: return "Temporary Redirect";
  321. case 400: return "Bad Request";
  322. case 401: return "Unauthorized";
  323. case 402: return "Payment Required";
  324. case 403: return "Forbidden";
  325. case 404: return "Not Found";
  326. case 405: return "Method Not Allowed";
  327. case 406: return "Not Acceptable";
  328. case 407: return "Proxy Authentication Required";
  329. case 408: return "Request Timeout";
  330. case 409: return "Conflict";
  331. case 410: return "Gone";
  332. case 411: return "Length Required";
  333. case 412: return "Precondition Failed";
  334. case 413: return "Request Entity Too Large";
  335. case 414: return "Request-Uri Too Long";
  336. case 415: return "Unsupported Media Type";
  337. case 416: return "Requested Range Not Satisfiable";
  338. case 417: return "Expectation Failed";
  339. case 422: return "Unprocessable Entity";
  340. case 423: return "Locked";
  341. case 424: return "Failed Dependency";
  342. case 500: return "Internal Server Error";
  343. case 501: return "Not Implemented";
  344. case 502: return "Bad Gateway";
  345. case 503: return "Service Unavailable";
  346. case 504: return "Gateway Timeout";
  347. case 505: return "Http Version Not Supported";
  348. case 507: return "Insufficient Storage";
  349. }
  350. return String.Empty;
  351. }
  352. /// <summary>
  353. /// Gets the value from the specified <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  354. /// </summary>
  355. /// <returns>
  356. /// A <see cref="string"/> that contains the value if any; otherwise, <c>null</c>.
  357. /// </returns>
  358. /// <param name="nameAndValue">
  359. /// A <see cref="string"/> that contains a pair of name and value are separated by a separator string.
  360. /// </param>
  361. /// <param name="separator">
  362. /// A <see cref="string"/> that contains a separator string.
  363. /// </param>
  364. public static string GetValue(string nameAndValue, string separator)
  365. {
  366. if (IsNullOrEmpty(nameAndValue))
  367. return null;
  368. if (IsNullOrEmpty(separator))
  369. return null;
  370. var i = nameAndValue.IndexOf(separator);
  371. return i >= 0 && i < nameAndValue.Length - 1
  372. ? nameAndValue.Substring(i + 1).Trim()
  373. : null;
  374. }
  375. /// <summary>
  376. /// Determines whether the specified <see cref="string"/> is a <see cref="String.Empty"/>.
  377. /// </summary>
  378. /// <returns>
  379. /// <c>true</c> if the <paramref name="value"/> parameter is a <see cref="String.Empty"/>; otherwise, <c>false</c>.
  380. /// </returns>
  381. /// <param name="value">
  382. /// A <see cref="string"/> to test.
  383. /// </param>
  384. public static bool IsEmpty(string value)
  385. {
  386. return value == String.Empty ? true : false;
  387. }
  388. /// <summary>
  389. /// Determines whether the specified <see cref="WebSocketSharp.ByteOrder"/> is host (this computer architecture) byte order.
  390. /// </summary>
  391. /// <returns>
  392. /// <c>true</c> if the <paramref name="order"/> parameter is host byte order; otherwise, <c>false</c>.
  393. /// </returns>
  394. /// <param name="order">
  395. /// A <see cref="WebSocketSharp.ByteOrder"/> to test.
  396. /// </param>
  397. public static bool IsHostOrder(ByteOrder order)
  398. {
  399. // true : !(true ^ true) or !(false ^ false)
  400. // false: !(true ^ false) or !(false ^ true)
  401. return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.LITTLE));
  402. }
  403. /// <summary>
  404. /// Determines whether the specified object is <see langword="null"/>.
  405. /// </summary>
  406. /// <returns>
  407. /// <c>true</c> if the <paramref name="obj"/> parameter is <see langword="null"/>; otherwise, <c>false</c>.
  408. /// </returns>
  409. /// <param name="obj">
  410. /// A <see cref="class"/> to test.
  411. /// </param>
  412. /// <typeparam name="T">
  413. /// The type of the <paramref name="obj"/> parameter.
  414. /// </typeparam>
  415. public static bool IsNull<T>(T obj)
  416. where T : class
  417. {
  418. return obj == null ? true : false;
  419. }
  420. /// <summary>
  421. /// Determines whether the specified object is <see langword="null"/>.
  422. /// And invokes the specified <see cref="Action"/> delegate if the specified object is <see langword="null"/>.
  423. /// </summary>
  424. /// <returns>
  425. /// <c>true</c> if the <paramref name="obj"/> parameter is <see langword="null"/>; otherwise, <c>false</c>.
  426. /// </returns>
  427. /// <param name="obj">
  428. /// A <see cref="class"/> to test.
  429. /// </param>
  430. /// <param name="act">
  431. /// An <see cref="Action"/> delegate that contains the method(s) called if the <paramref name="obj"/> is <see langword="null"/>.
  432. /// </param>
  433. /// <typeparam name="T">
  434. /// The type of the <paramref name="obj"/> parameter.
  435. /// </typeparam>
  436. public static bool IsNullDo<T>(T obj, Action act)
  437. where T : class
  438. {
  439. if (obj == null)
  440. {
  441. act();
  442. return true;
  443. }
  444. return false;
  445. }
  446. /// <summary>
  447. /// Determines whether the specified <see cref="string"/> is <see langword="null"/> or <see cref="String.Empty"/>.
  448. /// </summary>
  449. /// <returns>
  450. /// <c>true</c> if the <paramref name="value"/> parameter is <see langword="null"/> or <see cref="String.Empty"/>; otherwise, <c>false</c>.
  451. /// </returns>
  452. /// <param name="value">
  453. /// A <see cref="string"/> to test.
  454. /// </param>
  455. public static bool IsNullOrEmpty(string value)
  456. {
  457. return String.IsNullOrEmpty(value);
  458. }
  459. /// <summary>
  460. /// Determines whether the specified <see cref="string"/> is predefined scheme.
  461. /// </summary>
  462. /// <returns>
  463. /// <c>true</c> if the <paramref name="scheme"/> parameter is the predefined scheme; otherwise, <c>false</c>.
  464. /// </returns>
  465. /// <param name="scheme">
  466. /// A <see cref="string"/> to test.
  467. /// </param>
  468. public static bool IsPredefinedScheme(string scheme)
  469. {
  470. if (scheme == null && scheme.Length < 2)
  471. return false;
  472. char c = scheme[0];
  473. if (c == 'h')
  474. return (scheme == "http" || scheme == "https");
  475. if (c == 'f')
  476. return (scheme == "file" || scheme == "ftp");
  477. if (c == 'w')
  478. return (scheme == "ws" || scheme == "wss");
  479. if (c == 'n')
  480. {
  481. c = scheme[1];
  482. if (c == 'e')
  483. return (scheme == "news" || scheme == "net.pipe" || scheme == "net.tcp");
  484. if (scheme == "nntp")
  485. return true;
  486. return false;
  487. }
  488. if ((c == 'g' && scheme == "gopher") || (c == 'm' && scheme == "mailto"))
  489. return true;
  490. return false;
  491. }
  492. /// <summary>
  493. /// Determines whether the specified <see cref="string"/> is valid absolute path.
  494. /// </summary>
  495. /// <returns>
  496. /// <c>true</c> if the <paramref name="absPath"/> parameter is valid absolute path; otherwise, <c>false</c>.
  497. /// </returns>
  498. /// <param name="absPath">
  499. /// A <see cref="string"/> to test.
  500. /// </param>
  501. /// <param name="message">
  502. /// A <see cref="string"/> that receives a message if the <paramref name="absPath"/> is invalid.
  503. /// </param>
  504. public static bool IsValidAbsolutePath(string absPath, out string message)
  505. {
  506. if (IsNullOrEmpty(absPath))
  507. {
  508. message = "Must not be null or empty.";
  509. return false;
  510. }
  511. var i = absPath.IndexOf('/');
  512. if (i != 0)
  513. {
  514. message = "Not absolute path: " + absPath;
  515. return false;
  516. }
  517. i = absPath.IndexOfAny(new[] { '?', '#' });
  518. if (i != -1)
  519. {
  520. message = "Must not contain either or both query and fragment components: " + absPath;
  521. return false;
  522. }
  523. message = String.Empty;
  524. return true;
  525. }
  526. /// <summary>
  527. /// Determines whether the specified <see cref="string"/> is a URI string.
  528. /// </summary>
  529. /// <returns>
  530. /// <c>true</c> if the <paramref name="uriString"/> parameter is maybe a URI string; otherwise, <c>false</c>.
  531. /// </returns>
  532. /// <param name="uriString">
  533. /// A <see cref="string"/> to test.
  534. /// </param>
  535. public static bool MaybeUri(string uriString)
  536. {
  537. if (IsNullOrEmpty(uriString))
  538. return false;
  539. int p = uriString.IndexOf(':');
  540. if (p == -1)
  541. return false;
  542. if (p >= 10)
  543. return false;
  544. return IsPredefinedScheme(uriString.Substring(0, p));
  545. }
  546. /// <summary>
  547. /// Determines whether two specified <see cref="string"/> objects don't have the same value.
  548. /// </summary>
  549. /// <returns>
  550. /// <c>true</c> if the value of <paramref name="expected"/> parameter isn't the same as the value of <paramref name="actual"/> parameter; otherwise, <c>false</c>.
  551. /// </returns>
  552. /// <param name="expected">
  553. /// The first <see cref="string"/> to compare.
  554. /// </param>
  555. /// <param name="actual">
  556. /// The second <see cref="string"/> to compare.
  557. /// </param>
  558. /// <param name="ignoreCase">
  559. /// A <see cref="bool"/> that indicates a case-sensitive or insensitive comparison. (<c>true</c> indicates a case-insensitive comparison.)
  560. /// </param>
  561. public static bool NotEqual(string expected, string actual, bool ignoreCase)
  562. {
  563. return String.Compare(expected, actual, ignoreCase) != 0
  564. ? true
  565. : false;
  566. }
  567. /// <summary>
  568. /// Reads a block of bytes from the specified stream and returns the read data in an array of <see cref="byte"/>.
  569. /// </summary>
  570. /// <returns>
  571. /// An array of <see cref="byte"/> that receives the read data.
  572. /// </returns>
  573. /// <param name="stream">
  574. /// A <see cref="Stream"/> that contains the data to read.
  575. /// </param>
  576. /// <param name="length">
  577. /// An <see cref="int"/> that contains the number of bytes to read.
  578. /// </param>
  579. public static byte[] ReadBytes(Stream stream, int length)
  580. {
  581. if (stream == null || length <= 0)
  582. return new byte[] { };
  583. var buffer = new byte[length];
  584. var readLen = stream.Read(buffer, 0, length);
  585. var temp = 0;
  586. while (readLen < length)
  587. {
  588. temp = stream.Read(buffer, readLen, length - readLen);
  589. if (temp < 1)
  590. break;
  591. readLen += temp;
  592. }
  593. return readLen == length
  594. ? buffer
  595. : readLen > 0
  596. ? SubArray(buffer, 0, readLen)
  597. : new byte[] { };
  598. }
  599. /// <summary>
  600. /// Reads a block of bytes from the specified stream and returns the read data in an array of <see cref="byte"/>.
  601. /// </summary>
  602. /// <returns>
  603. /// An array of <see cref="byte"/> that receives the read data.
  604. /// </returns>
  605. /// <param name="stream">
  606. /// A <see cref="Stream"/> that contains the data to read.
  607. /// </param>
  608. /// <param name="length">
  609. /// A <see cref="long"/> that contains the number of bytes to read.
  610. /// </param>
  611. public static byte[] ReadBytes(Stream stream, long length)
  612. {
  613. return ReadBytes(stream, length, 1024);
  614. }
  615. /// <summary>
  616. /// Reads a block of bytes from the specified stream and returns the read data in an array of <see cref="byte"/>.
  617. /// </summary>
  618. /// <returns>
  619. /// An array of <see cref="byte"/> that receives the read data.
  620. /// </returns>
  621. /// <param name="stream">
  622. /// A <see cref="Stream"/> that contains the data to read.
  623. /// </param>
  624. /// <param name="length">
  625. /// A <see cref="long"/> that contains the number of bytes to read.
  626. /// </param>
  627. /// <param name="bufferLength">
  628. /// An <see cref="int"/> that contains the buffer size in bytes of each internal read.
  629. /// </param>
  630. public static byte[] ReadBytes(Stream stream, long length, int bufferLength)
  631. {
  632. if (stream == null || length <= 0)
  633. return new byte[] { };
  634. if (bufferLength <= 0)
  635. bufferLength = 1024;
  636. var count = length / bufferLength;
  637. var rem = length % bufferLength;
  638. var readData = new List<byte>();
  639. var readBuffer = new byte[bufferLength];
  640. long readLen = 0;
  641. var tmpLen = 0;
  642. Action<byte[]> read = (buffer) =>
  643. {
  644. tmpLen = stream.Read(buffer, 0, buffer.Length);
  645. if (tmpLen > 0)
  646. {
  647. readLen += tmpLen;
  648. readData.AddRange(SubArray(buffer, 0, tmpLen));
  649. }
  650. };
  651. Times(count, () =>
  652. {
  653. read(readBuffer);
  654. });
  655. if (rem > 0)
  656. read(new byte[rem]);
  657. return readLen > 0
  658. ? readData.ToArray()
  659. : new byte[] { };
  660. }
  661. /// <summary>
  662. /// Retrieves a sub-array from the specified <paramref name="array"/>. A sub-array starts at the specified element position.
  663. /// </summary>
  664. /// <returns>
  665. /// An array of T that receives a sub-array, or an empty array of T if any problems with the parameters.
  666. /// </returns>
  667. /// <param name="array">
  668. /// An array of T that contains the data to retrieve a sub-array.
  669. /// </param>
  670. /// <param name="startIndex">
  671. /// An <see cref="int"/> that contains the zero-based starting position of a sub-array in the <paramref name="array"/>.
  672. /// </param>
  673. /// <param name="length">
  674. /// An <see cref="int"/> that contains the number of elements to retrieve a sub-array.
  675. /// </param>
  676. /// <typeparam name="T">
  677. /// The type of elements in the <paramref name="array"/>.
  678. /// </typeparam>
  679. public static T[] SubArray<T>(T[] array, int startIndex, int length)
  680. {
  681. if (array == null || array.Length == 0)
  682. return new T[] { };
  683. if (startIndex < 0 || length <= 0)
  684. return new T[] { };
  685. if (startIndex + length > array.Length)
  686. return new T[] { };
  687. if (startIndex == 0 && array.Length == length)
  688. return array;
  689. T[] subArray = new T[length];
  690. Array.Copy(array, startIndex, subArray, 0, length);
  691. return subArray;
  692. }
  693. /// <summary>
  694. /// Executes the specified <see cref="Action"/> delegate <paramref name="n"/> times.
  695. /// </summary>
  696. /// <param name="n">
  697. /// An <see cref="int"/> that contains the number of times to execute.
  698. /// </param>
  699. /// <param name="act">
  700. /// An <see cref="Action"/> delegate that contains the method(s) to execute.
  701. /// </param>
  702. public static void Times(int n, Action act)
  703. {
  704. if (n > 0 && act != null)
  705. times((ulong)n, act);
  706. }
  707. /// <summary>
  708. /// Executes the specified <see cref="Action"/> delegate <paramref name="n"/> times.
  709. /// </summary>
  710. /// <param name="n">
  711. /// A <see cref="long"/> that contains the number of times to execute.
  712. /// </param>
  713. /// <param name="act">
  714. /// An <see cref="Action"/> delegate that contains the method(s) to execute.
  715. /// </param>
  716. public static void Times(long n, Action act)
  717. {
  718. if (n > 0 && act != null)
  719. times((ulong)n, act);
  720. }
  721. /// <summary>
  722. /// Executes the specified <see cref="Action"/> delegate <paramref name="n"/> times.
  723. /// </summary>
  724. /// <param name="n">
  725. /// A <see cref="uint"/> that contains the number of times to execute.
  726. /// </param>
  727. /// <param name="act">
  728. /// An <see cref="Action"/> delegate that contains the method(s) to execute.
  729. /// </param>
  730. public static void Times(uint n, Action act)
  731. {
  732. if (n > 0 && act != null)
  733. times((ulong)n, act);
  734. }
  735. /// <summary>
  736. /// Executes the specified <see cref="Action"/> delegate <paramref name="n"/> times.
  737. /// </summary>
  738. /// <param name="n">
  739. /// A <see cref="ulong"/> that contains the number of times to execute.
  740. /// </param>
  741. /// <param name="act">
  742. /// An <see cref="Action"/> delegate that contains the method(s) to execute.
  743. /// </param>
  744. public static void Times(ulong n, Action act)
  745. {
  746. if (n > 0 && act != null)
  747. times((ulong)n, act);
  748. }
  749. /// <summary>
  750. /// Executes the specified <see cref="Action&lt;ulong&gt;"/> delegate <paramref name="n"/> times.
  751. /// </summary>
  752. /// <param name="n">
  753. /// An <see cref="int"/> that contains the number of times to execute.
  754. /// </param>
  755. /// <param name="act">
  756. /// An <see cref="Action&lt;ulong&gt;"/> delegate that contains the method(s) to execute.
  757. /// A <see cref="ulong"/> parameter to pass to this method(s) contains the zero-based count of iteration.
  758. /// </param>
  759. public static void Times(int n, Action<ulong> act)
  760. {
  761. if (n > 0 && act != null)
  762. times((ulong)n, act);
  763. }
  764. /// <summary>
  765. /// Executes the specified <see cref="Action&lt;ulong&gt;"/> delegate <paramref name="n"/> times.
  766. /// </summary>
  767. /// <param name="n">
  768. /// A <see cref="long"/> that contains the number of times to execute.
  769. /// </param>
  770. /// <param name="act">
  771. /// An <see cref="Action&lt;ulong&gt;"/> delegate that contains the method(s) to execute.
  772. /// A <see cref="ulong"/> parameter to pass to this method(s) contains the zero-based count of iteration.
  773. /// </param>
  774. public static void Times(long n, Action<ulong> act)
  775. {
  776. if (n > 0 && act != null)
  777. times((ulong)n, act);
  778. }
  779. /// <summary>
  780. /// Executes the specified <see cref="Action&lt;ulong&gt;"/> delegate <paramref name="n"/> times.
  781. /// </summary>
  782. /// <param name="n">
  783. /// A <see cref="uint"/> that contains the number of times to execute.
  784. /// </param>
  785. /// <param name="act">
  786. /// An <see cref="Action&lt;ulong&gt;"/> delegate that contains the method(s) to execute.
  787. /// A <see cref="ulong"/> parameter to pass to this method(s) contains the zero-based count of iteration.
  788. /// </param>
  789. public static void Times(uint n, Action<ulong> act)
  790. {
  791. if (n > 0 && act != null)
  792. times((ulong)n, act);
  793. }
  794. /// <summary>
  795. /// Executes the specified <see cref="Action&lt;ulong&gt;"/> delegate <paramref name="n"/> times.
  796. /// </summary>
  797. /// <param name="n">
  798. /// A <see cref="ulong"/> that contains the number of times to execute.
  799. /// </param>
  800. /// <param name="act">
  801. /// An <see cref="Action&lt;ulong&gt;"/> delegate that contains the method(s) to execute.
  802. /// A <see cref="ulong"/> parameter to pass to this method(s) contains the zero-based count of iteration.
  803. /// </param>
  804. public static void Times(ulong n, Action<ulong> act)
  805. {
  806. if (n > 0 && act != null)
  807. times((ulong)n, act);
  808. }
  809. /// <summary>
  810. /// Converts the specified array of <see cref="byte"/> to the specified type data.
  811. /// </summary>
  812. /// <returns>
  813. /// A T converted from the <paramref name="src"/>, or a default value of T
  814. /// if the <paramref name="src"/> is an empty array of <see cref="byte"/>
  815. /// or if the types of T aren't the <see cref="bool"/>, <see cref="char"/>, <see cref="double"/>,
  816. /// <see cref="float"/>, <see cref="int"/>, <see cref="long"/>, <see cref="short"/>,
  817. /// <see cref="uint"/>, <see cref="ulong"/>, <see cref="ushort"/>.
  818. /// </returns>
  819. /// <param name="src">
  820. /// An array of <see cref="byte"/> to convert.
  821. /// </param>
  822. /// <param name="srcOrder">
  823. /// A <see cref="WebSocketSharp.ByteOrder"/> that indicates the byte order of the <paramref name="src"/>.
  824. /// </param>
  825. /// <typeparam name="T">
  826. /// The type of the return value. The T must be a value type.
  827. /// </typeparam>
  828. /// <exception cref="ArgumentNullException">
  829. /// Is thrown when the <paramref name="src"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  830. /// </exception>
  831. public static T To<T>(byte[] src, ByteOrder srcOrder)
  832. where T : struct
  833. {
  834. if (src == null)
  835. throw new ArgumentNullException("src");
  836. if (src.Length == 0)
  837. return default(T);
  838. var type = typeof(T);
  839. var buffer = ToHostOrder(src, srcOrder);
  840. if (type == typeof(Boolean))
  841. return (T)(object)BitConverter.ToBoolean(buffer, 0);
  842. if (type == typeof(Char))
  843. return (T)(object)BitConverter.ToChar(buffer, 0);
  844. if (type == typeof(Double))
  845. return (T)(object)BitConverter.ToDouble(buffer, 0);
  846. if (type == typeof(Int16))
  847. return (T)(object)BitConverter.ToInt16(buffer, 0);
  848. if (type == typeof(Int32))
  849. return (T)(object)BitConverter.ToInt32(buffer, 0);
  850. if (type == typeof(Int64))
  851. return (T)(object)BitConverter.ToInt64(buffer, 0);
  852. if (type == typeof(Single))
  853. return (T)(object)BitConverter.ToSingle(buffer, 0);
  854. if (type == typeof(UInt16))
  855. return (T)(object)BitConverter.ToUInt16(buffer, 0);
  856. if (type == typeof(UInt32))
  857. return (T)(object)BitConverter.ToUInt32(buffer, 0);
  858. if (type == typeof(UInt64))
  859. return (T)(object)BitConverter.ToUInt64(buffer, 0);
  860. return default(T);
  861. }
  862. /// <summary>
  863. /// Converts the specified data to an array of <see cref="byte"/>.
  864. /// </summary>
  865. /// <returns>
  866. /// An array of <see cref="byte"/> converted from the <paramref name="value"/>.
  867. /// </returns>
  868. /// <param name="value">
  869. /// A T to convert.
  870. /// </param>
  871. /// <param name="order">
  872. /// A <see cref="WebSocketSharp.ByteOrder"/> that indicates the byte order of the return.
  873. /// </param>
  874. /// <typeparam name="T">
  875. /// The type of the <paramref name="value"/>. The T must be a value type.
  876. /// </typeparam>
  877. public static byte[] ToBytes<T>(T value, ByteOrder order)
  878. where T : struct
  879. {
  880. var type = typeof(T);
  881. byte[] buffer;
  882. if (type == typeof(Boolean))
  883. {
  884. buffer = BitConverter.GetBytes((Boolean)(object)value);
  885. }
  886. else if (type == typeof(Char))
  887. {
  888. buffer = BitConverter.GetBytes((Char)(object)value);
  889. }
  890. else if (type == typeof(Double))
  891. {
  892. buffer = BitConverter.GetBytes((Double)(object)value);
  893. }
  894. else if (type == typeof(Int16))
  895. {
  896. buffer = BitConverter.GetBytes((Int16)(object)value);
  897. }
  898. else if (type == typeof(Int32))
  899. {
  900. buffer = BitConverter.GetBytes((Int32)(object)value);
  901. }
  902. else if (type == typeof(Int64))
  903. {
  904. buffer = BitConverter.GetBytes((Int64)(object)value);
  905. }
  906. else if (type == typeof(Single))
  907. {
  908. buffer = BitConverter.GetBytes((Single)(object)value);
  909. }
  910. else if (type == typeof(UInt16))
  911. {
  912. buffer = BitConverter.GetBytes((UInt16)(object)value);
  913. }
  914. else if (type == typeof(UInt32))
  915. {
  916. buffer = BitConverter.GetBytes((UInt32)(object)value);
  917. }
  918. else if (type == typeof(UInt64))
  919. {
  920. buffer = BitConverter.GetBytes((UInt64)(object)value);
  921. }
  922. else
  923. {
  924. buffer = new byte[] { };
  925. }
  926. return buffer.Length == 0 || IsHostOrder(order)
  927. ? buffer
  928. : Reverse(buffer);
  929. }
  930. /// <summary>
  931. /// Converts the order of the specified array of <see cref="byte"/> to the host byte order.
  932. /// </summary>
  933. /// <returns>
  934. /// An array of <see cref="byte"/> converted from the <paramref name="src"/>.
  935. /// </returns>
  936. /// <param name="src">
  937. /// An array of <see cref="byte"/> to convert.
  938. /// </param>
  939. /// <param name="srcOrder">
  940. /// A <see cref="WebSocketSharp.ByteOrder"/> that indicates the byte order of the <paramref name="src"/>.
  941. /// </param>
  942. /// <exception cref="ArgumentNullException">
  943. /// Is thrown when the <paramref name="src"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  944. /// </exception>
  945. public static byte[] ToHostOrder(byte[] src, ByteOrder srcOrder)
  946. {
  947. if (src == null)
  948. throw new ArgumentNullException("src");
  949. return src.Length == 0 || IsHostOrder(srcOrder)
  950. ? src
  951. : Reverse(src);
  952. }
  953. /// <summary>
  954. /// Converts the specified array to a <see cref="string"/> concatenated the specified separator string
  955. /// between each element of this array.
  956. /// </summary>
  957. /// <returns>
  958. /// A <see cref="string"/> converted from the <paramref name="array"/> parameter, or a <see cref="String.Empty"/>
  959. /// if the length of the <paramref name="array"/> is zero.
  960. /// </returns>
  961. /// <param name="array">
  962. /// An array of T to convert.
  963. /// </param>
  964. /// <param name="separator">
  965. /// A <see cref="string"/> that contains a separator string.
  966. /// </param>
  967. /// <typeparam name="T">
  968. /// The type of elements in the <paramref name="array"/>.
  969. /// </typeparam>
  970. /// <exception cref="ArgumentNullException">
  971. /// Is thrown when the <paramref name="array"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  972. /// </exception>
  973. public static string ToString<T>(T[] array, string separator)
  974. {
  975. if (array == null)
  976. throw new ArgumentNullException("array");
  977. var len = array.Length;
  978. if (len == 0)
  979. return String.Empty;
  980. if (separator == null)
  981. separator = String.Empty;
  982. var sb = new StringBuilder();
  983. Times(len - 1, i =>
  984. sb.AppendFormat("{0}{1}", array[i].ToString(), separator)
  985. );
  986. sb.Append(array[len - 1].ToString());
  987. return sb.ToString();
  988. }
  989. /// <summary>
  990. /// Converts the specified <see cref="string"/> to a <see cref="Uri"/> object.
  991. /// </summary>
  992. /// <returns>
  993. /// A <see cref="Uri"/> converted from the <paramref name="uriString"/> parameter, or <see langword="null"/>
  994. /// if the <paramref name="uriString"/> is <see langword="null"/> or <see cref="String.Empty"/>.
  995. /// </returns>
  996. /// <param name="uriString">
  997. /// A <see cref="string"/> to convert.
  998. /// </param>
  999. public static Uri ToUri(string uriString)
  1000. {
  1001. return IsNullOrEmpty(uriString)
  1002. ? null
  1003. : MaybeUri(uriString)
  1004. ? new Uri(uriString)
  1005. : new Uri(uriString, UriKind.Relative);
  1006. }
  1007. /// <summary>
  1008. /// Tries to create a new WebSocket <see cref="Uri"/> using the specified <paramref name="uriString"/>.
  1009. /// </summary>
  1010. /// <returns>
  1011. /// <c>true</c> if the WebSocket <see cref="Uri"/> was successfully created; otherwise, <c>false</c>.
  1012. /// </returns>
  1013. /// <param name="uriString">
  1014. /// A <see cref="string"/> that contains a WebSocket URI.
  1015. /// </param>
  1016. /// <param name="result">
  1017. /// When this method returns, contains a created WebSocket <see cref="Uri"/> if the <paramref name="uriString"/> parameter is valid WebSocket URI; otherwise, <see langword="null"/>.
  1018. /// </param>
  1019. /// <param name="message">
  1020. /// When this method returns, contains a error message <see cref="string"/> if the <paramref name="uriString"/> parameter is invalid WebSocket URI; otherwise, <c>String.Empty</c>.
  1021. /// </param>
  1022. /// <exception cref="ArgumentNullException">
  1023. /// Is thrown when the <paramref name="uriString"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  1024. /// </exception>
  1025. public static bool TryCreateWebSocketUri(string uriString, out Uri result, out string message)
  1026. {
  1027. if (uriString == null)
  1028. throw new ArgumentNullException("uriString");
  1029. result = null;
  1030. if (uriString == String.Empty)
  1031. {
  1032. message = "Must not be empty.";
  1033. return false;
  1034. }
  1035. var uri = ToUri(uriString);
  1036. if (!uri.IsAbsoluteUri)
  1037. {
  1038. message = "Not absolute URI: " + uriString;
  1039. return false;
  1040. }
  1041. var scheme = uri.Scheme;
  1042. if (scheme != "ws" && scheme != "wss")
  1043. {
  1044. message = "Unsupported scheme: " + scheme;
  1045. return false;
  1046. }
  1047. var fragment = uri.Fragment;
  1048. if (!String.IsNullOrEmpty(fragment))
  1049. {
  1050. message = "Must not contain the fragment component: " + uriString;
  1051. return false;
  1052. }
  1053. var port = uri.Port;
  1054. if (port > 0)
  1055. {
  1056. if ((scheme == "ws" && port == 443) ||
  1057. (scheme == "wss" && port == 80))
  1058. {
  1059. message = String.Format(
  1060. "Invalid pair of scheme and port: {0}, {1}", scheme, port);
  1061. return false;
  1062. }
  1063. }
  1064. result = uri;
  1065. message = String.Empty;
  1066. return true;
  1067. }
  1068. /// <summary>
  1069. /// URL-decodes the specified <see cref="string"/>.
  1070. /// </summary>
  1071. /// <returns>
  1072. /// A <see cref="string"/> that receives a decoded string, or the <paramref name="s"/> parameter
  1073. /// if the <paramref name="s"/> is <see langword="null"/> or <see cref="String.Empty"/>.
  1074. /// </returns>
  1075. /// <param name="s">
  1076. /// A <see cref="string"/> to decode.
  1077. /// </param>
  1078. public static string UrlDecode(string s)
  1079. {
  1080. return IsNullOrEmpty(s)
  1081. ? s
  1082. : HttpUtility.UrlDecode(s);
  1083. }
  1084. /// <summary>
  1085. /// URL-encodes the specified <see cref="string"/>.
  1086. /// </summary>
  1087. /// <returns>
  1088. /// A <see cref="string"/> that receives a encoded string, or the <paramref name="s"/> parameter
  1089. /// if the <paramref name="s"/> is <see langword="null"/> or <see cref="String.Empty"/>.
  1090. /// </returns>
  1091. /// <param name="s">
  1092. /// A <see cref="string"/> to encode.
  1093. /// </param>
  1094. public static string UrlEncode(string s)
  1095. {
  1096. return IsNullOrEmpty(s)
  1097. ? s
  1098. : HttpUtility.UrlEncode(s);
  1099. }
  1100. /// <summary>
  1101. /// Writes the specified content data using the specified <see cref="WebSocketSharp.Net.HttpListenerResponse"/>.
  1102. /// </summary>
  1103. /// <param name="response">
  1104. /// A <see cref="WebSocketSharp.Net.HttpListenerResponse"/> that contains a network stream to write a content data.
  1105. /// </param>
  1106. /// <param name="content">
  1107. /// An array of <see cref="byte"/> that contains a content data to write.
  1108. /// </param>
  1109. /// <exception cref="ArgumentNullException">
  1110. /// Is thrown when the <paramref name="response"/> parameter passed to a method is invalid because it is <see langword="null"/>.
  1111. /// </exception>
  1112. public static void WriteContent(HttpListenerResponse response, byte[] content)
  1113. {
  1114. if (response == null)
  1115. throw new ArgumentNullException("response");
  1116. if (content == null || content.Length == 0)
  1117. return;
  1118. var output = response.OutputStream;
  1119. response.ContentLength64 = content.Length;
  1120. output.Write(content, 0, content.Length);
  1121. output.Close();
  1122. }
  1123. #endregion
  1124. }
  1125. }