HttpRequest.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #region License
  2. /*
  3. * HttpRequest.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2012-2022 sta.blockhead
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #endregion
  28. #region Contributors
  29. /*
  30. * Contributors:
  31. * - David Burhans
  32. */
  33. #endregion
  34. using System;
  35. using System.Collections.Specialized;
  36. using System.IO;
  37. using System.Text;
  38. using WebSocketSharp.Net;
  39. namespace WebSocketSharp
  40. {
  41. internal class HttpRequest : HttpBase
  42. {
  43. #region Private Fields
  44. private CookieCollection _cookies;
  45. private string _method;
  46. private string _target;
  47. #endregion
  48. #region Private Constructors
  49. private HttpRequest (
  50. string method,
  51. string target,
  52. Version version,
  53. NameValueCollection headers
  54. )
  55. : base (version, headers)
  56. {
  57. _method = method;
  58. _target = target;
  59. }
  60. #endregion
  61. #region Internal Constructors
  62. internal HttpRequest (string method, string target)
  63. : this (method, target, HttpVersion.Version11, new NameValueCollection ())
  64. {
  65. Headers["User-Agent"] = "websocket-sharp/1.0";
  66. }
  67. #endregion
  68. #region Internal Properties
  69. internal string RequestLine {
  70. get {
  71. return String.Format (
  72. "{0} {1} HTTP/{2}{3}", _method, _target, ProtocolVersion, CrLf
  73. );
  74. }
  75. }
  76. #endregion
  77. #region Public Properties
  78. public AuthenticationResponse AuthenticationResponse {
  79. get {
  80. var val = Headers["Authorization"];
  81. return val != null && val.Length > 0
  82. ? AuthenticationResponse.Parse (val)
  83. : null;
  84. }
  85. }
  86. public CookieCollection Cookies {
  87. get {
  88. if (_cookies == null)
  89. _cookies = Headers.GetCookies (false);
  90. return _cookies;
  91. }
  92. }
  93. public string HttpMethod {
  94. get {
  95. return _method;
  96. }
  97. }
  98. public bool IsWebSocketRequest {
  99. get {
  100. return _method == "GET"
  101. && ProtocolVersion > HttpVersion.Version10
  102. && Headers.Upgrades ("websocket");
  103. }
  104. }
  105. public override string MessageHeader {
  106. get {
  107. return RequestLine + HeaderSection;
  108. }
  109. }
  110. public string RequestTarget {
  111. get {
  112. return _target;
  113. }
  114. }
  115. #endregion
  116. #region Internal Methods
  117. internal static HttpRequest CreateConnectRequest (Uri targetUri)
  118. {
  119. var host = targetUri.DnsSafeHost;
  120. var port = targetUri.Port;
  121. var authority = String.Format ("{0}:{1}", host, port);
  122. var ret = new HttpRequest ("CONNECT", authority);
  123. ret.Headers["Host"] = port != 80 ? authority : host;
  124. return ret;
  125. }
  126. internal static HttpRequest CreateWebSocketHandshakeRequest (Uri targetUri)
  127. {
  128. var ret = new HttpRequest ("GET", targetUri.PathAndQuery);
  129. var headers = ret.Headers;
  130. var port = targetUri.Port;
  131. var schm = targetUri.Scheme;
  132. var defaultPort = (port == 80 && schm == "ws")
  133. || (port == 443 && schm == "wss");
  134. headers["Host"] = !defaultPort
  135. ? targetUri.Authority
  136. : targetUri.DnsSafeHost;
  137. headers["Upgrade"] = "websocket";
  138. headers["Connection"] = "Upgrade";
  139. return ret;
  140. }
  141. internal HttpResponse GetResponse (Stream stream, int millisecondsTimeout)
  142. {
  143. WriteTo (stream);
  144. return HttpResponse.ReadResponse (stream, millisecondsTimeout);
  145. }
  146. internal static HttpRequest Parse (string[] messageHeader)
  147. {
  148. var len = messageHeader.Length;
  149. if (len == 0) {
  150. var msg = "An empty request header.";
  151. throw new ArgumentException (msg);
  152. }
  153. var rlParts = messageHeader[0].Split (new[] { ' ' }, 3);
  154. if (rlParts.Length != 3) {
  155. var msg = "It includes an invalid request line.";
  156. throw new ArgumentException (msg);
  157. }
  158. var method = rlParts[0];
  159. var target = rlParts[1];
  160. var ver = rlParts[2].Substring (5).ToVersion ();
  161. var headers = new WebHeaderCollection ();
  162. for (var i = 1; i < len; i++)
  163. headers.InternalSet (messageHeader[i], false);
  164. return new HttpRequest (method, target, ver, headers);
  165. }
  166. internal static HttpRequest ReadRequest (
  167. Stream stream, int millisecondsTimeout
  168. )
  169. {
  170. return Read<HttpRequest> (stream, Parse, millisecondsTimeout);
  171. }
  172. #endregion
  173. #region Public Methods
  174. public void SetCookies (CookieCollection cookies)
  175. {
  176. if (cookies == null || cookies.Count == 0)
  177. return;
  178. var buff = new StringBuilder (64);
  179. foreach (var cookie in cookies.Sorted) {
  180. if (cookie.Expired)
  181. continue;
  182. buff.AppendFormat ("{0}; ", cookie);
  183. }
  184. var len = buff.Length;
  185. if (len <= 2)
  186. return;
  187. buff.Length = len - 2;
  188. Headers["Cookie"] = buff.ToString ();
  189. }
  190. #endregion
  191. }
  192. }