PageRenderTime 28ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Hosts/IronRuby.Rack/Src/Cassini/Connection.cs

http://github.com/IronLanguages/main
C# | 309 lines | 239 code | 56 blank | 14 comment | 42 complexity | f0b76c79b9c9117df44071ff28fa621a MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* **********************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation. All rights reserved.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public
  6. * License (Ms-PL). A copy of the license can be found in the license.htm file
  7. * included in this distribution.
  8. *
  9. * You must not remove this notice, or any other, from this software.
  10. *
  11. * **********************************************************************************/
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Diagnostics;
  15. using System.Globalization;
  16. using System.IO;
  17. using System.Net;
  18. using System.Net.Sockets;
  19. using System.Text;
  20. using System.Threading;
  21. using System.Web;
  22. using System.Web.Hosting;
  23. namespace Cassini {
  24. internal class Connection : MarshalByRefObject {
  25. Server _server;
  26. Socket _socket;
  27. string _localServerIP;
  28. internal Connection(Server server, Socket socket) {
  29. _server = server;
  30. _socket = socket;
  31. }
  32. public override object InitializeLifetimeService() {
  33. // never expire the license
  34. return null;
  35. }
  36. public bool Connected { get { return _socket.Connected; } }
  37. public bool IsLocal {
  38. get {
  39. string remoteIP = RemoteIP;
  40. if (remoteIP == "127.0.0.1" || remoteIP == "::1")
  41. return true;
  42. return LocalServerIP.Equals(remoteIP);
  43. }
  44. }
  45. string LocalServerIP {
  46. get {
  47. if (_localServerIP == null) {
  48. var hostEntry = Dns.GetHostEntry(Environment.MachineName);
  49. var localAddress = hostEntry.AddressList[0];
  50. _localServerIP = localAddress.ToString();
  51. }
  52. return _localServerIP;
  53. }
  54. }
  55. public string LocalIP {
  56. get {
  57. IPEndPoint ep = (IPEndPoint)_socket.LocalEndPoint;
  58. return (ep != null && ep.Address != null)? ep.Address.ToString() : "127.0.0.1";
  59. }
  60. }
  61. public string RemoteIP {
  62. get {
  63. IPEndPoint ep = (IPEndPoint)_socket.RemoteEndPoint;
  64. return (ep != null && ep.Address != null) ? ep.Address.ToString() : "127.0.0.1";
  65. }
  66. }
  67. public void Close() {
  68. try {
  69. _socket.Shutdown(SocketShutdown.Both);
  70. _socket.Close();
  71. }
  72. catch {
  73. }
  74. finally {
  75. _socket = null;
  76. }
  77. }
  78. static string MakeResponseHeaders(int statusCode, string moreHeaders, int contentLength, bool keepAlive) {
  79. var sb = new StringBuilder();
  80. sb.Append("HTTP/1.1 " + statusCode + " " + HttpWorkerRequest.GetStatusDescription(statusCode) + "\r\n");
  81. sb.Append("Server: Cassini/" + Messages.VersionString + "\r\n");
  82. sb.Append("Date: " + DateTime.Now.ToUniversalTime().ToString("R", DateTimeFormatInfo.InvariantInfo) + "\r\n");
  83. if (contentLength >= 0)
  84. sb.Append("Content-Length: " + contentLength + "\r\n");
  85. if (moreHeaders != null)
  86. sb.Append(moreHeaders);
  87. if (!keepAlive)
  88. sb.Append("Connection: Close\r\n");
  89. sb.Append("\r\n");
  90. return sb.ToString();
  91. }
  92. static String MakeContentTypeHeader(string fileName) {
  93. Debug.Assert(File.Exists(fileName));
  94. string contentType = null;
  95. var info = new FileInfo(fileName);
  96. string extension = info.Extension.ToLowerInvariant();
  97. switch (extension) {
  98. case ".bmp":
  99. contentType = "image/bmp";
  100. break;
  101. case ".css":
  102. contentType = "text/css";
  103. break;
  104. case ".gif":
  105. contentType = "image/gif";
  106. break;
  107. case ".ico":
  108. contentType = "image/x-icon";
  109. break;
  110. case ".htm" :
  111. case ".html":
  112. contentType = "text/html";
  113. break;
  114. case ".jpe":
  115. case ".jpeg":
  116. case ".jpg":
  117. contentType = "image/jpeg";
  118. break;
  119. case ".js":
  120. contentType = "application/x-javascript";
  121. break;
  122. default:
  123. break;
  124. }
  125. if (contentType == null) {
  126. return null;
  127. }
  128. return "Content-Type: " + contentType + "\r\n";
  129. }
  130. string GetErrorResponseBody(int statusCode, string message) {
  131. string body = Messages.FormatErrorMessageBody(statusCode, _server.VirtualPath);
  132. if (message != null && message.Length > 0) {
  133. body += "\r\n<!--\r\n" + message + "\r\n-->";
  134. }
  135. return body;
  136. }
  137. public byte[] ReadRequestBytes(int maxBytes) {
  138. try {
  139. if (WaitForRequestBytes() == 0) {
  140. return null;
  141. }
  142. int numBytes = _socket.Available;
  143. if (numBytes > maxBytes)
  144. numBytes = maxBytes;
  145. int numReceived = 0;
  146. byte[] buffer = new byte[numBytes];
  147. if (numBytes > 0) {
  148. numReceived = _socket.Receive(buffer, 0, numBytes, SocketFlags.None);
  149. }
  150. if (numReceived < numBytes) {
  151. byte[] tempBuffer = new byte[numReceived];
  152. if (numReceived > 0) {
  153. Buffer.BlockCopy(buffer, 0, tempBuffer, 0, numReceived);
  154. }
  155. buffer = tempBuffer;
  156. }
  157. return buffer;
  158. }
  159. catch {
  160. return null;
  161. }
  162. }
  163. public void Write100Continue() {
  164. WriteEntireResponseFromString(100, null, null, true);
  165. }
  166. public void WriteBody(byte[] data, int offset, int length) {
  167. try {
  168. _socket.Send(data, offset, length, SocketFlags.None);
  169. }
  170. catch (SocketException) {
  171. }
  172. }
  173. public void WriteEntireResponseFromString(int statusCode, String extraHeaders, String body, bool keepAlive) {
  174. try {
  175. int bodyLength = (body != null) ? Encoding.UTF8.GetByteCount(body) : 0;
  176. string headers = MakeResponseHeaders(statusCode, extraHeaders, bodyLength, keepAlive);
  177. _socket.Send(Encoding.UTF8.GetBytes(headers + body));
  178. }
  179. catch (SocketException) {
  180. }
  181. finally {
  182. if (!keepAlive) {
  183. Close();
  184. }
  185. }
  186. }
  187. public void WriteEntireResponseFromFile(String fileName, bool keepAlive) {
  188. if (!File.Exists(fileName)) {
  189. WriteErrorAndClose(404);
  190. return;
  191. }
  192. // Deny the request if the contentType cannot be recognized.
  193. string contentTypeHeader = MakeContentTypeHeader(fileName);
  194. if (contentTypeHeader == null) {
  195. WriteErrorAndClose(403);
  196. return;
  197. }
  198. bool completed = false;
  199. FileStream fs = null;
  200. try {
  201. fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
  202. int len = (int)fs.Length;
  203. byte[] fileBytes = new byte[len];
  204. int bytesRead = fs.Read(fileBytes, 0, len);
  205. String headers = MakeResponseHeaders(200, contentTypeHeader, bytesRead, keepAlive);
  206. _socket.Send(Encoding.UTF8.GetBytes(headers));
  207. _socket.Send(fileBytes, 0, bytesRead, SocketFlags.None);
  208. completed = true;
  209. }
  210. catch (SocketException) {
  211. }
  212. finally {
  213. if (!keepAlive || !completed)
  214. Close();
  215. if (fs != null)
  216. fs.Close();
  217. }
  218. }
  219. public void WriteErrorAndClose(int statusCode, string message) {
  220. WriteEntireResponseFromString(statusCode, null, GetErrorResponseBody(statusCode, message), false);
  221. }
  222. public void WriteErrorAndClose(int statusCode) {
  223. WriteErrorAndClose(statusCode, null);
  224. }
  225. public void WriteErrorWithExtraHeadersAndKeepAlive(int statusCode, string extraHeaders) {
  226. WriteEntireResponseFromString(statusCode, extraHeaders, GetErrorResponseBody(statusCode, null), true);
  227. }
  228. public int WaitForRequestBytes() {
  229. int availBytes = 0;
  230. try {
  231. if (_socket.Available == 0) {
  232. // poll until there is data
  233. _socket.Poll(100000 /* 100ms */, SelectMode.SelectRead);
  234. if (_socket.Available == 0 && _socket.Connected) {
  235. _socket.Poll(30000000 /* 30sec */, SelectMode.SelectRead);
  236. }
  237. }
  238. availBytes = _socket.Available;
  239. }
  240. catch {
  241. }
  242. return availBytes;
  243. }
  244. public void WriteHeaders(int statusCode, String extraHeaders) {
  245. string headers = MakeResponseHeaders(statusCode, extraHeaders, -1, false);
  246. try {
  247. _socket.Send(Encoding.UTF8.GetBytes(headers));
  248. }
  249. catch (SocketException) {
  250. }
  251. }
  252. }
  253. }