HttpRequest.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #region License
  2. /*
  3. * HttpRequest.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2012-2015 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 _uri;
  47. #endregion
  48. #region Private Constructors
  49. private HttpRequest (string method, string uri, Version version, NameValueCollection headers)
  50. : base (version, headers)
  51. {
  52. _method = method;
  53. _uri = uri;
  54. }
  55. #endregion
  56. #region Internal Constructors
  57. internal HttpRequest (string method, string uri)
  58. : this (method, uri, HttpVersion.Version11, new NameValueCollection ())
  59. {
  60. Headers["User-Agent"] = "websocket-sharp/1.0";
  61. }
  62. #endregion
  63. #region Public Properties
  64. public AuthenticationResponse AuthenticationResponse {
  65. get {
  66. var res = Headers["Authorization"];
  67. return res != null && res.Length > 0
  68. ? AuthenticationResponse.Parse (res)
  69. : null;
  70. }
  71. }
  72. public CookieCollection Cookies {
  73. get {
  74. if (_cookies == null)
  75. _cookies = Headers.GetCookies (false);
  76. return _cookies;
  77. }
  78. }
  79. public string HttpMethod {
  80. get {
  81. return _method;
  82. }
  83. }
  84. public bool IsWebSocketRequest {
  85. get {
  86. return _method == "GET"
  87. && ProtocolVersion > HttpVersion.Version10
  88. && Headers.Upgrades ("websocket");
  89. }
  90. }
  91. public string RequestUri {
  92. get {
  93. return _uri;
  94. }
  95. }
  96. #endregion
  97. #region Internal Methods
  98. internal static HttpRequest CreateConnectRequest (Uri uri)
  99. {
  100. var host = uri.DnsSafeHost;
  101. var port = uri.Port;
  102. var authority = String.Format ("{0}:{1}", host, port);
  103. var req = new HttpRequest ("CONNECT", authority);
  104. req.Headers["Host"] = port == 80 ? host : authority;
  105. return req;
  106. }
  107. internal static HttpRequest CreateWebSocketRequest (Uri uri)
  108. {
  109. var req = new HttpRequest ("GET", uri.PathAndQuery);
  110. var headers = req.Headers;
  111. // Only includes a port number in the Host header value if it's non-default.
  112. // See: https://tools.ietf.org/html/rfc6455#page-17
  113. var port = uri.Port;
  114. var schm = uri.Scheme;
  115. headers["Host"] = (port == 80 && schm == "ws") || (port == 443 && schm == "wss")
  116. ? uri.DnsSafeHost
  117. : uri.Authority;
  118. headers["Upgrade"] = "websocket";
  119. headers["Connection"] = "Upgrade";
  120. return req;
  121. }
  122. internal HttpResponse GetResponse (Stream stream, int millisecondsTimeout)
  123. {
  124. var buff = ToByteArray ();
  125. stream.Write (buff, 0, buff.Length);
  126. return Read<HttpResponse> (stream, HttpResponse.Parse, millisecondsTimeout);
  127. }
  128. internal static HttpRequest Parse (string[] headerParts)
  129. {
  130. var requestLine = headerParts[0].Split (new[] { ' ' }, 3);
  131. if (requestLine.Length != 3)
  132. throw new ArgumentException ("Invalid request line: " + headerParts[0]);
  133. var headers = new WebHeaderCollection ();
  134. for (int i = 1; i < headerParts.Length; i++)
  135. headers.InternalSet (headerParts[i], false);
  136. return new HttpRequest (
  137. requestLine[0], requestLine[1], new Version (requestLine[2].Substring (5)), headers);
  138. }
  139. internal static HttpRequest Read (Stream stream, int millisecondsTimeout)
  140. {
  141. return Read<HttpRequest> (stream, Parse, millisecondsTimeout);
  142. }
  143. #endregion
  144. #region Public Methods
  145. public void SetCookies (CookieCollection cookies)
  146. {
  147. if (cookies == null || cookies.Count == 0)
  148. return;
  149. var buff = new StringBuilder (64);
  150. foreach (var cookie in cookies.Sorted)
  151. if (!cookie.Expired)
  152. buff.AppendFormat ("{0}; ", cookie.ToString ());
  153. var len = buff.Length;
  154. if (len > 2) {
  155. buff.Length = len - 2;
  156. Headers["Cookie"] = buff.ToString ();
  157. }
  158. }
  159. public override string ToString ()
  160. {
  161. var output = new StringBuilder (64);
  162. output.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _uri, ProtocolVersion, CrLf);
  163. var headers = Headers;
  164. foreach (var key in headers.AllKeys)
  165. output.AppendFormat ("{0}: {1}{2}", key, headers[key], CrLf);
  166. output.Append (CrLf);
  167. var entity = EntityBody;
  168. if (entity.Length > 0)
  169. output.Append (entity);
  170. return output.ToString ();
  171. }
  172. #endregion
  173. }
  174. }