mirror of
https://gitlab.com/sbrl/GalleryShare.git
synced 2018-06-12 22:45:16 +00:00
Initial routing rewrite.
The routes aren't functioning correctly yet.
This commit is contained in:
parent
de2117f9bf
commit
60b7560d21
10 changed files with 408 additions and 143 deletions
|
@ -10,26 +10,17 @@ using System.Xml;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using GalleryShare.RequestRouter;
|
||||||
|
|
||||||
namespace GalleryShare
|
namespace GalleryShare
|
||||||
{
|
{
|
||||||
enum OutputFunction
|
public class GalleryServer
|
||||||
{
|
{
|
||||||
None,
|
|
||||||
SpecialFile,
|
|
||||||
DirectoryListing,
|
|
||||||
SendFile
|
|
||||||
}
|
|
||||||
|
|
||||||
class GalleryServer
|
|
||||||
{
|
|
||||||
static MimeSharp.Mime mimeDB = new MimeSharp.Mime();
|
|
||||||
|
|
||||||
int port;
|
int port;
|
||||||
string servingDirectory = Environment.CurrentDirectory;
|
string servingDirectory = Environment.CurrentDirectory;
|
||||||
Size thumbnailSize = new Size(300, 200);
|
|
||||||
|
|
||||||
HttpListener server = new HttpListener();
|
HttpListener server = new HttpListener();
|
||||||
|
MasterHttpRouter router;
|
||||||
string prefix;
|
string prefix;
|
||||||
|
|
||||||
Dictionary<string, string> pathReplacements = new Dictionary<string, string>()
|
Dictionary<string, string> pathReplacements = new Dictionary<string, string>()
|
||||||
|
@ -66,6 +57,11 @@ namespace GalleryShare
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task Start()
|
public async Task Start()
|
||||||
{
|
{
|
||||||
|
Console.Write("Setting up router...");
|
||||||
|
router = new MasterHttpRouter(this, "GalleryShare");
|
||||||
|
router.UrlTransformer = GetFullReqestedPath;
|
||||||
|
Console.WriteLine("done.");
|
||||||
|
|
||||||
server.Start();
|
server.Start();
|
||||||
Console.WriteLine("Listening for requests on {0}.", prefix);
|
Console.WriteLine("Listening for requests on {0}.", prefix);
|
||||||
Console.WriteLine("Serving from {0}. Browser url: http://localhost:{1}/", servingDirectory, Port);
|
Console.WriteLine("Serving from {0}. Browser url: http://localhost:{1}/", servingDirectory, Port);
|
||||||
|
@ -82,36 +78,7 @@ namespace GalleryShare
|
||||||
/// <param name="cycle">The Http request to handle.</param>
|
/// <param name="cycle">The Http request to handle.</param>
|
||||||
private async Task Handle(HttpListenerContext cycle)
|
private async Task Handle(HttpListenerContext cycle)
|
||||||
{
|
{
|
||||||
OutputFunction outFunction = OutputFunction.None;
|
await router.RouteRequest(cycle);
|
||||||
|
|
||||||
if (cycle.Request.RawUrl.StartsWith("/!"))
|
|
||||||
outFunction = OutputFunction.SpecialFile;
|
|
||||||
|
|
||||||
string requestedPath = GetFullReqestedPath(cycle.Request.RawUrl);
|
|
||||||
if (Directory.Exists(requestedPath))
|
|
||||||
outFunction = OutputFunction.DirectoryListing;
|
|
||||||
if (File.Exists(requestedPath))
|
|
||||||
outFunction = OutputFunction.SendFile;
|
|
||||||
|
|
||||||
switch(outFunction)
|
|
||||||
{
|
|
||||||
case OutputFunction.SpecialFile:
|
|
||||||
await sendSpecialFile(cycle);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OutputFunction.DirectoryListing:
|
|
||||||
cycle.Response.ContentType = "application/xml";
|
|
||||||
await sendDirectoryListing(cycle.Response.OutputStream, cycle.Request.RawUrl, requestedPath);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OutputFunction.SendFile:
|
|
||||||
await sendFile(cycle, requestedPath);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
await sendMessage(cycle, 404, "Error: File or directory '{0}' not found.", requestedPath);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
logCycle(cycle);
|
logCycle(cycle);
|
||||||
cycle.Response.Close();
|
cycle.Response.Close();
|
||||||
|
@ -127,16 +94,6 @@ namespace GalleryShare
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task sendMessage(HttpListenerContext cycle, int statusCode, string message, params object[] paramObjects)
|
|
||||||
{
|
|
||||||
StreamWriter responseData = new StreamWriter(cycle.Response.OutputStream);
|
|
||||||
|
|
||||||
cycle.Response.StatusCode = statusCode;
|
|
||||||
await responseData.WriteLineAsync(string.Format(message, paramObjects));
|
|
||||||
/*responseData.Close();
|
|
||||||
cycle.Response.Close();*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logCycle(HttpListenerContext cycle)
|
private void logCycle(HttpListenerContext cycle)
|
||||||
{
|
{
|
||||||
Console.WriteLine("[{0}] [{1}] [{2}] {3} {4}",
|
Console.WriteLine("[{0}] [{1}] [{2}] {3} {4}",
|
||||||
|
@ -147,97 +104,6 @@ namespace GalleryShare
|
||||||
cycle.Request.RawUrl
|
cycle.Request.RawUrl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task sendDirectoryListing(Stream outgoingData, string rawUrl, string requestedPath)
|
|
||||||
{
|
|
||||||
List<string> dirFiles = new List<string>(Directory.GetFiles(requestedPath));
|
|
||||||
List<string> dirDirectories = new List<string>(Directory.GetDirectories(requestedPath));
|
|
||||||
|
|
||||||
XmlWriterSettings writerSettings = new XmlWriterSettings();
|
|
||||||
writerSettings.Async = true;
|
|
||||||
writerSettings.Indent = true;
|
|
||||||
writerSettings.IndentChars = "\t";
|
|
||||||
XmlWriter xmlData = XmlWriter.Create(outgoingData, writerSettings);
|
|
||||||
|
|
||||||
await xmlData.WriteStartDocumentAsync();
|
|
||||||
await xmlData.WriteProcessingInstructionAsync("xml-stylesheet", "type=\"text/xsl\" href=\"/!Transform-DirListing.xslt\"");
|
|
||||||
await xmlData.WriteStartElementAsync(null, "DirectoryListing", null);
|
|
||||||
await xmlData.WriteElementStringAsync(null, "CurrentDirectory", null, rawUrl);
|
|
||||||
await xmlData.WriteStartElementAsync(null, "Contents", null);
|
|
||||||
|
|
||||||
foreach (string directoryName in dirDirectories)
|
|
||||||
{
|
|
||||||
await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
|
|
||||||
await xmlData.WriteAttributeStringAsync(null, "Type", null, "Directory");
|
|
||||||
|
|
||||||
await xmlData.WriteElementStringAsync(null, "Name", null, "/" + directoryName.Substring(servingDirectory.Length));
|
|
||||||
await xmlData.WriteElementStringAsync(null, "ItemCount", null, Directory.GetFileSystemEntries(directoryName).Length.ToString());
|
|
||||||
|
|
||||||
// TODO: Write out thumbnail url
|
|
||||||
|
|
||||||
await xmlData.WriteEndElementAsync();
|
|
||||||
}
|
|
||||||
foreach (string filename in dirFiles)
|
|
||||||
{
|
|
||||||
await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
|
|
||||||
await xmlData.WriteAttributeStringAsync(null, "Type", null, "File");
|
|
||||||
|
|
||||||
await xmlData.WriteElementStringAsync(null, "Name", null, "/" + filename.Substring(servingDirectory.Length));
|
|
||||||
|
|
||||||
await xmlData.WriteEndElementAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
await xmlData.WriteEndDocumentAsync();
|
|
||||||
await xmlData.FlushAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task sendSpecialFile(HttpListenerContext cycle)
|
|
||||||
{
|
|
||||||
string specialFileName = cycle.Request.RawUrl.Substring(2);
|
|
||||||
string outputFileName = string.Empty;
|
|
||||||
|
|
||||||
switch(specialFileName)
|
|
||||||
{
|
|
||||||
case "Transform-DirListing.xslt":
|
|
||||||
cycle.Response.ContentType = "text/xsl";
|
|
||||||
outputFileName = @"GalleryShare.Embed.DirectoryListing.xslt";
|
|
||||||
break;
|
|
||||||
case "Theme.css":
|
|
||||||
cycle.Response.ContentType = "text/css";
|
|
||||||
outputFileName = @"GalleryShare.Embed.Theme.css";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputFileName == string.Empty)
|
|
||||||
{
|
|
||||||
await sendMessage(cycle, 404, "Error: Unknown special file '{0}' requested.", specialFileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*string[] resNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
|
||||||
foreach (string resName in resNames)
|
|
||||||
Console.WriteLine(resName);*/
|
|
||||||
byte[] xsltData = await Utilities.GetEmbeddedResourceContent(outputFileName);
|
|
||||||
await cycle.Response.OutputStream.WriteAsync(xsltData, 0, xsltData.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task sendFile(HttpListenerContext cycle, string requestedPath)
|
|
||||||
{
|
|
||||||
if(cycle.Request.QueryString["type"] == "thumbnail")
|
|
||||||
{
|
|
||||||
// Send a thumbnail!
|
|
||||||
Console.WriteLine("Sending thumbnail for '{0}'", requestedPath);
|
|
||||||
await ThumbnailGenerator.SendThumbnailPng(requestedPath, thumbnailSize, cycle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the raw file
|
|
||||||
|
|
||||||
cycle.Response.ContentType = mimeDB.Lookup(requestedPath);
|
|
||||||
|
|
||||||
Stream fileData = File.OpenRead(requestedPath);
|
|
||||||
await fileData.CopyToAsync(cycle.Response.OutputStream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,11 +44,19 @@
|
||||||
<Compile Include="GalleryServer.cs" />
|
<Compile Include="GalleryServer.cs" />
|
||||||
<Compile Include="Utilities.cs" />
|
<Compile Include="Utilities.cs" />
|
||||||
<Compile Include="ThumbnailGenerator.cs" />
|
<Compile Include="ThumbnailGenerator.cs" />
|
||||||
|
<Compile Include="RequestRouter\IRequestRoute.cs" />
|
||||||
|
<Compile Include="RequestRouter\MasterHttpRouter.cs" />
|
||||||
|
<Compile Include="RequestRouter\HttpRequestRouteAttribute.cs" />
|
||||||
|
<Compile Include="RequestRouter\RouteSendFile.cs" />
|
||||||
|
<Compile Include="RequestRouter\RouteSpecialFile.cs" />
|
||||||
|
<Compile Include="RequestRouter\RouteDirectoryListing.cs" />
|
||||||
|
<Compile Include="RequestRouter\RouteDefault.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="packages\Magick.NET-Q8-x64.7.0.2.100\build\net40-client\Magick.NET-Q8-x64.targets" Condition="Exists('packages\Magick.NET-Q8-x64.7.0.2.100\build\net40-client\Magick.NET-Q8-x64.targets')" />
|
<Import Project="packages\Magick.NET-Q8-x64.7.0.2.100\build\net40-client\Magick.NET-Q8-x64.targets" Condition="Exists('packages\Magick.NET-Q8-x64.7.0.2.100\build\net40-client\Magick.NET-Q8-x64.targets')" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Embed\" />
|
<Folder Include="Embed\" />
|
||||||
|
<Folder Include="RequestRouter\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Embed\**" />
|
<EmbeddedResource Include="Embed\**" />
|
||||||
|
|
22
GalleryShare/RequestRouter/HttpRequestRouteAttribute.cs
Normal file
22
GalleryShare/RequestRouter/HttpRequestRouteAttribute.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a class to be a http reqeust router that's part of the given routing group.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class is an attribute. Please don't try to inherit from it.
|
||||||
|
/// To create a new request router, please implement GalleryShare.RequestRouter.IRequestRoute, not this class.
|
||||||
|
/// </remarks>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||||
|
public sealed class HttpRequestRoute : Attribute
|
||||||
|
{
|
||||||
|
public string RoutingGroup;
|
||||||
|
|
||||||
|
public HttpRequestRoute(string inRoutingGroup)
|
||||||
|
{
|
||||||
|
RoutingGroup = inRoutingGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
GalleryShare/RequestRouter/IRequestRoute.cs
Normal file
34
GalleryShare/RequestRouter/IRequestRoute.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using System.Dynamic;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
public interface IRequestRoute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The priority of the request route.
|
||||||
|
/// Higher priority routes will always be chosen to handle requests over lower priority ones.
|
||||||
|
/// Note that only 1 route may handle any given request.
|
||||||
|
/// </summary>
|
||||||
|
int Priority { get; }
|
||||||
|
|
||||||
|
void SetParentServer(GalleryServer inGalleryServer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Works out whether the request route hander can handle a request to the given path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urlPath">The path to check to see if it can be handled.</param>
|
||||||
|
/// <returns>Whether the request route can handle a request to the given path.</returns>
|
||||||
|
bool CanHandle(string rawUrl, string requestedPath);
|
||||||
|
/// <summary>
|
||||||
|
/// Handles a HTTP request asynchronously.
|
||||||
|
/// Note that the master request router will close the request for you, so you don't need to bother.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cycle">The Http request to handle.</param>
|
||||||
|
/// <param name="requestedPath">The transformed url path of the given request.</param>
|
||||||
|
Task HandleRequestAsync(HttpListenerContext cycle, string requestedPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
78
GalleryShare/RequestRouter/MasterHttpRouter.cs
Normal file
78
GalleryShare/RequestRouter/MasterHttpRouter.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
public delegate string UrlPathTransformer(string rawUrl);
|
||||||
|
|
||||||
|
public class MasterHttpRouter
|
||||||
|
{
|
||||||
|
public bool DebugMode = true;
|
||||||
|
|
||||||
|
List<IRequestRoute> requestRoutes = new List<IRequestRoute>();
|
||||||
|
UrlPathTransformer urlTransformer;
|
||||||
|
|
||||||
|
public UrlPathTransformer UrlTransformer
|
||||||
|
{
|
||||||
|
get { return urlTransformer; }
|
||||||
|
set { urlTransformer = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterHttpRouter(GalleryServer parentServer, string routingGroup)
|
||||||
|
{
|
||||||
|
// Add the default route
|
||||||
|
requestRoutes.Add(new RouteDefault());
|
||||||
|
// Search for and add the rest of the routes
|
||||||
|
foreach(Type currentType in getRequestRouters(routingGroup))
|
||||||
|
{
|
||||||
|
IRequestRoute nextRoute = (IRequestRoute)Activator.CreateInstance(currentType);
|
||||||
|
nextRoute.SetParentServer(parentServer);
|
||||||
|
requestRoutes.Add(nextRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the request reoutes by priority
|
||||||
|
requestRoutes.Sort((routeA, routeB) => -routeA.Priority.CompareTo(routeB.Priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RouteRequest(HttpListenerContext cycle)
|
||||||
|
{
|
||||||
|
foreach(IRequestRoute currentRoute in requestRoutes)
|
||||||
|
{
|
||||||
|
if (DebugMode) Console.Write("Trying {0} (Priority {1}) - ", currentRoute.GetType(), currentRoute.Priority);
|
||||||
|
string transformedUrl = UrlTransformer(cycle.Request.RawUrl);
|
||||||
|
|
||||||
|
if (!currentRoute.CanHandle(cycle.Request.RawUrl, transformedUrl))
|
||||||
|
{
|
||||||
|
if(DebugMode) Console.WriteLine("false. Trying next route.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(DebugMode) Console.WriteLine("true. Sending to route.");
|
||||||
|
await currentRoute.HandleRequestAsync(cycle, transformedUrl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Type> getRequestRouters(string routingGroup)
|
||||||
|
{
|
||||||
|
foreach(Type requestRoute in Assembly.GetCallingAssembly().GetExportedTypes().Where(cType =>
|
||||||
|
cType.GetInterfaces().Contains(typeof(IRequestRoute))))
|
||||||
|
{
|
||||||
|
foreach(HttpRequestRoute attr in requestRoute.GetCustomAttributes())
|
||||||
|
{
|
||||||
|
if(attr.RoutingGroup == routingGroup)
|
||||||
|
{
|
||||||
|
yield return requestRoute;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
39
GalleryShare/RequestRouter/RouteDefault.cs
Normal file
39
GalleryShare/RequestRouter/RouteDefault.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using GalleryShare.RequestRouter;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace GalleryShare
|
||||||
|
{
|
||||||
|
public class RouteDefault : IRequestRoute
|
||||||
|
{
|
||||||
|
public int Priority { get; } = 0;
|
||||||
|
|
||||||
|
public string DefaultResponse { get; set; } = "Error: 404 - No route was found to handle the specified url.\n";
|
||||||
|
|
||||||
|
public RouteDefault()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(string rawUrl, string requestedPath)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParentServer(GalleryServer inParentServer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleRequestAsync(HttpListenerContext cycle, string requestedPath)
|
||||||
|
{
|
||||||
|
cycle.Response.StatusCode = 404;
|
||||||
|
cycle.Response.ContentType = "text/plain";
|
||||||
|
cycle.Response.ContentLength64 = DefaultResponse.Length;
|
||||||
|
|
||||||
|
StreamWriter responseData = new StreamWriter(cycle.Response.OutputStream) { AutoFlush = true };
|
||||||
|
await responseData.WriteLineAsync(DefaultResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
79
GalleryShare/RequestRouter/RouteDirectoryListing.cs
Normal file
79
GalleryShare/RequestRouter/RouteDirectoryListing.cs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
[HttpRequestRoute("GalleryShare")]
|
||||||
|
public class RouteDirectoryListing : IRequestRoute
|
||||||
|
{
|
||||||
|
GalleryServer parentServer;
|
||||||
|
|
||||||
|
public int Priority { get; } = 5;
|
||||||
|
|
||||||
|
public RouteDirectoryListing()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(string rawUrl, string requestedPath)
|
||||||
|
{
|
||||||
|
if(Directory.Exists(requestedPath))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParentServer(GalleryServer inParentServer)
|
||||||
|
{
|
||||||
|
parentServer = inParentServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleRequestAsync(HttpListenerContext cycle, string requestedPath)
|
||||||
|
{
|
||||||
|
cycle.Response.ContentType = "application/xml";
|
||||||
|
|
||||||
|
List<string> dirFiles = new List<string>(Directory.GetFiles(requestedPath));
|
||||||
|
List<string> dirDirectories = new List<string>(Directory.GetDirectories(requestedPath));
|
||||||
|
|
||||||
|
XmlWriterSettings writerSettings = new XmlWriterSettings();
|
||||||
|
writerSettings.Async = true;
|
||||||
|
writerSettings.Indent = true;
|
||||||
|
writerSettings.IndentChars = "\t";
|
||||||
|
XmlWriter xmlData = XmlWriter.Create(cycle.Response.OutputStream, writerSettings);
|
||||||
|
|
||||||
|
await xmlData.WriteStartDocumentAsync();
|
||||||
|
await xmlData.WriteProcessingInstructionAsync("xml-stylesheet", "type=\"text/xsl\" href=\"/!Transform-DirListing.xslt\"");
|
||||||
|
await xmlData.WriteStartElementAsync(null, "DirectoryListing", null);
|
||||||
|
await xmlData.WriteElementStringAsync(null, "CurrentDirectory", null, cycle.Request.RawUrl);
|
||||||
|
await xmlData.WriteStartElementAsync(null, "Contents", null);
|
||||||
|
|
||||||
|
foreach (string directoryName in dirDirectories)
|
||||||
|
{
|
||||||
|
await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
|
||||||
|
await xmlData.WriteAttributeStringAsync(null, "Type", null, "Directory");
|
||||||
|
|
||||||
|
await xmlData.WriteElementStringAsync(null, "Name", null, "/" + directoryName.Substring(parentServer.ServingDirectory.Length));
|
||||||
|
await xmlData.WriteElementStringAsync(null, "ItemCount", null, Directory.GetFileSystemEntries(directoryName).Length.ToString());
|
||||||
|
|
||||||
|
// TODO: Write out thumbnail url
|
||||||
|
|
||||||
|
await xmlData.WriteEndElementAsync();
|
||||||
|
}
|
||||||
|
foreach (string filename in dirFiles)
|
||||||
|
{
|
||||||
|
await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
|
||||||
|
await xmlData.WriteAttributeStringAsync(null, "Type", null, "File");
|
||||||
|
|
||||||
|
await xmlData.WriteElementStringAsync(null, "Name", null, "/" + filename.Substring(parentServer.ServingDirectory.Length));
|
||||||
|
|
||||||
|
await xmlData.WriteEndElementAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
await xmlData.WriteEndDocumentAsync();
|
||||||
|
await xmlData.FlushAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
GalleryShare/RequestRouter/RouteSendFile.cs
Normal file
56
GalleryShare/RequestRouter/RouteSendFile.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
[HttpRequestRoute("GalleryShare")]
|
||||||
|
public class RouteSendFile : IRequestRoute
|
||||||
|
{
|
||||||
|
static MimeSharp.Mime mimeDB = new MimeSharp.Mime();
|
||||||
|
|
||||||
|
|
||||||
|
Size thumbnailSize = new Size(300, 200);
|
||||||
|
|
||||||
|
public int Priority { get; } = 5;
|
||||||
|
|
||||||
|
public RouteSendFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParentServer(GalleryServer inParentServer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// The SendFile route can only handle requests to paths that are a valid file on disk.
|
||||||
|
/// </remarks>
|
||||||
|
public bool CanHandle(string rawUrl, string requestedPath)
|
||||||
|
{
|
||||||
|
if (File.Exists(requestedPath))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleRequestAsync(HttpListenerContext cycle, string requestedPath)
|
||||||
|
{
|
||||||
|
if(cycle.Request.QueryString["type"] == "thumbnail")
|
||||||
|
{
|
||||||
|
// Send a thumbnail!
|
||||||
|
Console.WriteLine("Sending thumbnail for '{0}'", requestedPath);
|
||||||
|
await ThumbnailGenerator.SendThumbnailPng(requestedPath, thumbnailSize, cycle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the raw file
|
||||||
|
|
||||||
|
cycle.Response.ContentType = mimeDB.Lookup(requestedPath);
|
||||||
|
|
||||||
|
Stream fileData = File.OpenRead(requestedPath);
|
||||||
|
await fileData.CopyToAsync(cycle.Response.OutputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
71
GalleryShare/RequestRouter/RouteSpecialFile.cs
Normal file
71
GalleryShare/RequestRouter/RouteSpecialFile.cs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace GalleryShare.RequestRouter
|
||||||
|
{
|
||||||
|
[HttpRequestRoute("GalleryShare")]
|
||||||
|
public class RouteSpecialFile : IRequestRoute
|
||||||
|
{
|
||||||
|
public int Priority { get; } = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dictionary mapping special file names to their actual filenames and content types.
|
||||||
|
/// </summary>
|
||||||
|
Dictionary<string, SpecialFileEntry> specialFileMap = new Dictionary<string, SpecialFileEntry>()
|
||||||
|
{
|
||||||
|
{ "Transform-DirListing.xslt", new SpecialFileEntry(@"GalleryShare.Embed.DirectoryListing.xslt", "text/xsl") },
|
||||||
|
{ "Theme.css", new SpecialFileEntry(@"GalleryShare.Embed.Theme.css", "text/css") }
|
||||||
|
};
|
||||||
|
|
||||||
|
public RouteSpecialFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParentServer(GalleryServer inParentServer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(string rawUrl, string requestedPath)
|
||||||
|
{
|
||||||
|
if (rawUrl.StartsWith("/!"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleRequestAsync(HttpListenerContext cycle, string requestedPath)
|
||||||
|
{
|
||||||
|
string specialFileName = cycle.Request.RawUrl.Substring(2);
|
||||||
|
string outputFileName = string.Empty;
|
||||||
|
|
||||||
|
if(specialFileMap.ContainsKey(specialFileName))
|
||||||
|
{
|
||||||
|
outputFileName = specialFileMap[specialFileName].FileName;
|
||||||
|
cycle.Response.ContentType = specialFileMap[specialFileName].ContentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputFileName == string.Empty)
|
||||||
|
{
|
||||||
|
await Utilities.SendMessage(cycle, 404, "Error: Unknown special file '{0}' requested.", specialFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] xsltData = await Utilities.GetEmbeddedResourceContent(outputFileName);
|
||||||
|
await cycle.Response.OutputStream.WriteAsync(xsltData, 0, xsltData.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpecialFileEntry
|
||||||
|
{
|
||||||
|
public string FileName;
|
||||||
|
public string ContentType;
|
||||||
|
|
||||||
|
|
||||||
|
public SpecialFileEntry(string inFileName, string inContentType)
|
||||||
|
{
|
||||||
|
FileName = inFileName;
|
||||||
|
ContentType = inContentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace GalleryShare
|
namespace GalleryShare
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,17 @@ namespace GalleryShare
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
return embeddedContent;
|
return embeddedContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async Task SendMessage(HttpListenerContext cycle, int statusCode, string message, params object[] paramObjects)
|
||||||
|
{
|
||||||
|
StreamWriter responseData = new StreamWriter(cycle.Response.OutputStream);
|
||||||
|
|
||||||
|
cycle.Response.StatusCode = statusCode;
|
||||||
|
await responseData.WriteLineAsync(string.Format(message, paramObjects));
|
||||||
|
/*responseData.Close();
|
||||||
|
cycle.Response.Close();*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue