From 1f901943e34247d08029f4fa9ba6e8226578669d Mon Sep 17 00:00:00 2001 From: juju2143 Date: Sun, 8 Oct 2023 22:27:47 -0400 Subject: [PATCH] add FTP handler + mime type guesser --- Protocols/FileProtoHandler.cs | 6 +- Protocols/FtpProtoHandler.cs | 116 ++++++++++++++++++++++++++++++++++ Protocols/ResProtoHandler.cs | 3 +- 3 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 Protocols/FtpProtoHandler.cs diff --git a/Protocols/FileProtoHandler.cs b/Protocols/FileProtoHandler.cs index 9d525ec..75945e3 100644 --- a/Protocols/FileProtoHandler.cs +++ b/Protocols/FileProtoHandler.cs @@ -1,5 +1,6 @@ using System.Text; using System.Web; +using HeyRed.Mime; namespace Shoko; @@ -13,17 +14,18 @@ class FileProtoHandler : ProtoHandler public override void Load() { - var file = HttpUtility.UrlDecode(new UriBuilder(URL).Path); + var file = HttpUtility.UrlDecode(URL.AbsolutePath); if(URL.Host.Length > 0) file = "//" + URL.Host + file; - MediaType = "text/plain"; // TODO: magic numbers + MediaType = "text/plain"; Status = "OK"; if(File.Exists(file)) { var stream = new FileStream(file, FileMode.Open); + MediaType = MimeGuesser.GuessMimeType(stream); Content = stream; } else if(Directory.Exists(file)) diff --git a/Protocols/FtpProtoHandler.cs b/Protocols/FtpProtoHandler.cs new file mode 100644 index 0000000..a723051 --- /dev/null +++ b/Protocols/FtpProtoHandler.cs @@ -0,0 +1,116 @@ +using System.Net; +using System.Text; +using FluentFTP; +using HeyRed.Mime; + +namespace Shoko; + +[Protocol("ftp")] +[Protocol("ftps")] +class FtpProtoHandler : ProtoHandler +{ + public FtpProtoHandler(Uri url) + { + URL = url; + } + + public override void Load() + { + var file = URL.AbsolutePath; + + var conn = new FtpClient + { + Host = URL.Host, + Port = URL.Port + }; + + if (URL.UserInfo.Length > 0) + { + var userinfo = URL.UserInfo.Split(":",2); + var user = userinfo[0]; + var pass = userinfo.Length > 1 ? userinfo[1] : ""; + conn.Credentials = new NetworkCredential(user, pass); + } + + if(URL.Scheme == "ftps") + { + conn.Config.EncryptionMode = FtpEncryptionMode.Explicit; + conn.Config.ValidateAnyCertificate = true; + } + + conn.Config.LogToConsole = true; + conn.Config.LogHost = true; + conn.Config.LogUserName = true; + conn.Config.LogPassword = true; + + conn.Connect(); + + MediaType = "text/plain"; // TODO: magic numbers + Status = "OK"; + + var info = conn.GetObjectInfo(file); + + if(info is not null) + { + switch(info.Type) + { + case FtpObjectType.File: + //Content = conn.OpenRead(file); + if(conn.DownloadBytes(out byte[] bytes, info.FullName)) + { + Content = new MemoryStream(bytes); + MediaType = MimeGuesser.GuessMimeType(Content); + } + break; + case FtpObjectType.Directory: + MediaType = "text/gemini"; + var entries = conn.GetListing(info.FullName); + var str = "# "+file+"\r\n"; + + foreach(var entry in entries) + { + var path = entry.Name; + if(entry.Type == FtpObjectType.Directory) path += "/"; + var target = new Uri(URL, path).ToString(); + if(entry.Type == FtpObjectType.Link) target = new Uri(URL, info.LinkTarget).ToString(); + str += string.Format("=>{0} {1}\r\n", target, path); + } + + Content = new MemoryStream(Encoding.UTF8.GetBytes(str)); + break; + case FtpObjectType.Link: + MediaType = "text/gemini"; + Content = new MemoryStream(Encoding.UTF8.GetBytes("=>"+new Uri(URL, info.LinkTarget).ToString())); + break; + } + } + else + { + if(conn.DirectoryExists(file)) + { + MediaType = "text/gemini"; + var entries = conn.GetListing(file); + var str = "# "+file+"\r\n"; + + foreach(var entry in entries) + { + var path = entry.Name; + if(entry.Type == FtpObjectType.Directory) path += "/"; + str += string.Format("=>{0} {1}\r\n", new Uri(URL, path).ToString(), path); + } + + Content = new MemoryStream(Encoding.UTF8.GetBytes(str)); + } + else + { + Content = new MemoryStream(Encoding.UTF8.GetBytes("file not found")); + Status = "not found"; + } + } + + Loaded = true; + } + public override void Render() + { + } +} \ No newline at end of file diff --git a/Protocols/ResProtoHandler.cs b/Protocols/ResProtoHandler.cs index e90d33e..b45e483 100644 --- a/Protocols/ResProtoHandler.cs +++ b/Protocols/ResProtoHandler.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Web; +using HeyRed.Mime; namespace Shoko; @@ -16,10 +17,10 @@ class ResProtoHandler : ProtoHandler var path = HttpUtility.HtmlDecode(new UriBuilder(URL).Path); Status = "OK"; Loaded = true; - MediaType = "text/plain"; try { Content = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); + MediaType = MimeGuesser.GuessMimeType(Content); } catch {