using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.Text; using System.IO; using System.Reflection; using System.Configuration; using System.Xml; using WebSockets.Common; namespace WebSockets.Server.Http { public class HttpService : IService { private readonly Stream _stream; private readonly string _path; private readonly string _webRoot; private readonly IWebSocketLogger _logger; private readonly MimeTypes _mimeTypes; public HttpService(Stream stream, string path, string webRoot, IWebSocketLogger logger) { _stream = stream; _path = path; _webRoot = webRoot; _logger = logger; _mimeTypes = MimeTypesFactory.GetMimeTypes(webRoot); } private static bool IsDirectory(string file) { if (Directory.Exists(file)) { //detect whether its a directory or file FileAttributes attr = File.GetAttributes(file); return ((attr & FileAttributes.Directory) == FileAttributes.Directory); } return false; } public void Respond() { _logger.Information(this.GetType(), "Request: {0}", _path); string file = GetSafePath(_path); // default to index.html is path is supplied if (IsDirectory(file)) { file += "index.html"; } FileInfo fi = new FileInfo(file); if (fi.Exists) { string ext = fi.Extension.ToLower(); string contentType; if (_mimeTypes.TryGetValue(ext, out contentType)) { Byte[] bytes = File.ReadAllBytes(fi.FullName); RespondSuccess(contentType, bytes.Length); _stream.Write(bytes, 0, bytes.Length); _logger.Information(this.GetType(), "Served file: {0}", file); } else { RespondMimeTypeFailure(file); } } else { RespondNotFoundFailure(file); } } /// /// I am not convinced that this function is indeed safe from hacking file path tricks /// /// The relative path /// The file system path private string GetSafePath(string path) { path = path.Trim().Replace("/", "\\"); if (path.Contains("..") || !path.StartsWith("\\") || path.Contains(":")) { return string.Empty; } string file = _webRoot + path; return file; } public void RespondMimeTypeFailure(string file) { HttpHelper.WriteHttpHeader("415 Unsupported Media Type", _stream); _logger.Warning(this.GetType(), "File extension not found MimeTypes.config: {0}", file); } public void RespondNotFoundFailure(string file) { HttpHelper.WriteHttpHeader("HTTP/1.1 404 Not Found", _stream); _logger.Information(this.GetType(), "File not found: {0}", file); } public void RespondSuccess(string contentType, int contentLength) { string response = "HTTP/1.1 200 OK" + Environment.NewLine + "Content-Type: " + contentType + Environment.NewLine + "Content-Length: " + contentLength + Environment.NewLine + "Connection: close"; HttpHelper.WriteHttpHeader(response, _stream); } public void Dispose() { // do nothing. The network stream will be closed by the WebServer } } }