1
0
Fork 0
GalleryShare/GalleryShare/GalleryServer.cs

140 lines
3.8 KiB
C#

using System;
using System.Net;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Xml;
using System.Reflection;
using System.Drawing;
using GalleryShare.RequestRouter;
namespace GalleryShare
{
public class GalleryServer
{
int port;
string servingDirectory = Environment.CurrentDirectory;
HttpListener server = new HttpListener();
MasterHttpRouter router;
string prefix;
Dictionary<string, string> pathReplacements = new Dictionary<string, string>()
{
["%20"] = " "
};
public int Port { get { return port; } }
public string ServingDirectory { get { return servingDirectory; } }
public GalleryServer(string inServingDirectory, int inPort)
{
port = inPort;
servingDirectory = inServingDirectory;
string homeDir = Environment.GetEnvironmentVariable("HOME");
if (homeDir != null)
servingDirectory = servingDirectory.Replace("~", homeDir);
prefix = string.Format("http://*:{0}/", Port);
server.Prefixes.Add(prefix);
}
/// <summary>
/// Synchronously starrts the server listening for requests.
/// </summary>
public void StartSync()
{
Task.WaitAll(Start());
}
/// <summary>
/// Asynchronously starts the server listening for requests.
/// </summary>
public async Task Start()
{
Console.Write("Setting up router...");
router = new MasterHttpRouter(this, "GalleryShare");
router.UrlTransformer = GetFullReqestedPath;
Console.WriteLine("done.");
try
{
server.Start();
}
catch(HttpListenerException error)
{
if (error.Message.Contains("denied") && Environment.OSVersion.Platform == PlatformID.Win32NT && !Utilities.IsAdministrator())
{
Console.Error.WriteLine("Error starting HttpListener: {0}", error.Message);
Console.Error.WriteLine("You are using Windows and have attempted to bind to a non-localhost address, and aren't running GalleryShare as an administrator.");
Console.Error.WriteLine("Please restart GalleryShare with administrative privileges in order to bind to this address.");
Console.Error.WriteLine("Please see http://stackoverflow.com/questions/4019466/httplistener-access-denied for more information.");
return;
}
throw;
}
Console.WriteLine("Listening for requests on {0}.", prefix);
Console.WriteLine("Serving from {0}. Browser url: http://localhost:{1}/", servingDirectory, Port);
while (true)
{
Utilities.ForgetTask(Handle(await server.GetContextAsync()));
}
}
/// <summary>
/// Handles the specified Http request.
/// </summary>
/// <param name="cycle">The Http request to handle.</param>
private async Task Handle(HttpListenerContext cycle)
{
IPEndPoint remoteEndpoint = cycle.Request.RemoteEndPoint;
try
{
await router.RouteRequest(cycle);
logCycle(cycle);
}
catch(Exception error)
{
Console.WriteLine("[{0}] [{1}] [Error] {2} ({3})",
DateTime.Now.ToString("hh:m tt"),
remoteEndpoint,
cycle.Request.RawUrl,
error.Message
);
}
finally
{
cycle.Response.Close();
}
}
private string GetFullReqestedPath(string rawUrl)
{
string result = Path.GetFullPath(Path.Combine(servingDirectory, "." + rawUrl));
if(result.IndexOf("?") != -1)
result = result.Substring(0, result.IndexOf("?"));
result = Uri.UnescapeDataString(result);
foreach (KeyValuePair<string, string> replacePair in pathReplacements)
result = result.Replace(replacePair.Key, replacePair.Value);
return result;
}
private void logCycle(HttpListenerContext cycle)
{
Console.WriteLine("[{0}] [{1}] [{2}] {3} {4}",
DateTime.Now.ToString("hh:mm tt"),
cycle.Request.RemoteEndPoint,
cycle.Response.StatusCode,
cycle.Request.HttpMethod,
cycle.Request.RawUrl
);
}
}
}