2016-07-05 20:22:34 +00:00
using System ;
using System.Net ;
using System.Threading.Tasks ;
using System.Runtime.InteropServices ;
using System.IO ;
2016-07-06 10:04:02 +00:00
using System.Collections.Generic ;
using System.Threading ;
using System.Xml ;
using System.Reflection ;
2016-07-05 20:22:34 +00:00
2016-07-09 20:34:09 +00:00
using System.Drawing ;
2016-07-16 14:46:53 +00:00
using GalleryShare.RequestRouter ;
2016-07-08 16:12:57 +00:00
2016-07-05 20:22:34 +00:00
namespace GalleryShare
{
2016-07-16 14:46:53 +00:00
public class GalleryServer
2016-07-06 19:03:03 +00:00
{
2016-07-05 20:22:34 +00:00
int port ;
2016-07-06 10:04:02 +00:00
string servingDirectory = Environment . CurrentDirectory ;
2016-07-05 20:22:34 +00:00
2016-07-06 18:20:05 +00:00
HttpListener server = new HttpListener ( ) ;
2016-07-16 14:46:53 +00:00
MasterHttpRouter router ;
2016-07-06 18:20:05 +00:00
string prefix ;
2016-07-08 08:50:53 +00:00
Dictionary < string , string > pathReplacements = new Dictionary < string , string > ( )
{
2016-08-10 16:46:43 +00:00
["%20"] = " "
2016-07-08 08:50:53 +00:00
} ;
2016-07-06 10:04:02 +00:00
public int Port { get { return port ; } }
2016-07-06 18:20:05 +00:00
public string ServingDirectory { get { return servingDirectory ; } }
2016-07-05 20:22:34 +00:00
2016-07-06 18:20:05 +00:00
public GalleryServer ( string inServingDirectory , int inPort )
2016-07-05 20:22:34 +00:00
{
port = inPort ;
2016-07-06 18:20:05 +00:00
servingDirectory = inServingDirectory ;
2016-07-05 20:22:34 +00:00
2016-07-08 08:12:59 +00:00
string homeDir = Environment . GetEnvironmentVariable ( "HOME" ) ;
if ( homeDir ! = null )
servingDirectory = servingDirectory . Replace ( "~" , homeDir ) ;
2016-07-05 20:22:34 +00:00
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 ( )
{
2016-07-16 14:46:53 +00:00
Console . Write ( "Setting up router..." ) ;
router = new MasterHttpRouter ( this , "GalleryShare" ) ;
router . UrlTransformer = GetFullReqestedPath ;
Console . WriteLine ( "done." ) ;
2016-07-18 14:47:07 +00:00
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 ;
}
2016-07-05 20:22:34 +00:00
Console . WriteLine ( "Listening for requests on {0}." , prefix ) ;
2016-07-08 08:12:59 +00:00
Console . WriteLine ( "Serving from {0}. Browser url: http://localhost:{1}/" , servingDirectory , Port ) ;
2016-07-05 20:22:34 +00:00
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 )
{
2016-07-17 15:17:43 +00:00
IPEndPoint remoteEndpoint = cycle . Request . RemoteEndPoint ;
2016-07-16 19:57:59 +00:00
try
{
await router . RouteRequest ( cycle ) ;
logCycle ( cycle ) ;
}
catch ( Exception error )
{
Console . WriteLine ( "[{0}] [{1}] [Error] {2} ({3})" ,
DateTime . Now . ToString ( "hh:m tt" ) ,
2016-07-17 15:17:43 +00:00
remoteEndpoint ,
2016-07-16 19:57:59 +00:00
cycle . Request . RawUrl ,
error . Message
) ;
}
finally
{
cycle . Response . Close ( ) ;
}
2016-07-06 10:04:02 +00:00
}
2016-07-06 19:03:03 +00:00
private string GetFullReqestedPath ( string rawUrl )
{
2016-07-08 08:50:53 +00:00
string result = Path . GetFullPath ( Path . Combine ( servingDirectory , "." + rawUrl ) ) ;
if ( result . IndexOf ( "?" ) ! = - 1 )
result = result . Substring ( 0 , result . IndexOf ( "?" ) ) ;
2016-08-10 16:46:43 +00:00
result = Uri . UnescapeDataString ( result ) ;
2016-07-08 08:50:53 +00:00
foreach ( KeyValuePair < string , string > replacePair in pathReplacements )
result = result . Replace ( replacePair . Key , replacePair . Value ) ;
return result ;
2016-07-06 19:03:03 +00:00
}
2016-07-06 10:04:02 +00:00
private void logCycle ( HttpListenerContext cycle )
{
2016-07-05 20:22:34 +00:00
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
) ;
}
}
}