gopher-proxy 0.1.0.2 → 0.1.1.0
raw patch · 5 files changed
+82/−28 lines, 5 files
Files
- ChangeLog.md +10/−0
- README.md +12/−13
- gopher-proxy.cabal +23/−2
- src/GopherProxy/Params.hs +16/−2
- src/Main.hs +21/−11
ChangeLog.md view
@@ -1,5 +1,15 @@ # Revision history for gopher-proxy +## 0.1.1.0 -- 2017-01-06++* Add two options: `--title` and `--server-name`+* Fix the README on hackage+* Elaborate the package description++## 0.1.0.2 -- 2017-01-05++* Fixed a build issue+ ## 0.1.0.1 -- 2017-01-04 * Updated package metadata
README.md view
@@ -8,26 +8,25 @@ gopher-proxy --host foo.org --http-port 8080 -In this particular example, gopher-proxy would proxy the foo.org gopher server and bind its http service on `127.0.0.1:8080` (to be proxied to by another web server like `nginx`).+In this particular example, gopher-proxy would proxy the `foo.org` gopher server and bind its http service on `127.0.0.1:8080` (to be proxied to by another web server like `nginx`). -There are these additional flags which allow tweaking of exact behavior as well:+These are all optional flags which allow to change default behavior: -option | meaning-----------------------|---------------------------------------------------------------------------------------------------------`--port` | The port of the gopher server, defaults to `70`-`--css-url` | Use some specific css file instead of the default one.-`--css-url` | The http path of the css file, defaults to `/gopher-proxy.css` (should be changed, if your gopher server has a file with the same name-`--base-url` | The path of the directory which will appear as root directory of gopher-proxy to the user, defaults to `/`. Should be changed if you configured your proxying web server to expose gopher-proxy as, say `/gopher-space/`.-`--listen-public` | If this flag is set, gopher-proxy will accept connections on its public IP address(es).-`--default-mime-type` | Mime type to use if spacecookie can't guess it, defaults to "application/octet-stream"-`--timeout` | Timeout when connecting in milliseconds, defaults to 10 seconds.+* `--port`: The port of the gopher server, defaults to `70`+* `--css-url`: Use some specific css file instead of the default one.+* `--css-url`: The http path of the css file, defaults to `/gopher-proxy.css` (should be changed, if your gopher server has a file with the same name+* `--base-url`: The path of the directory which will appear as root directory of gopher-proxy to the user, defaults to `/`. Should be changed if you configured your proxying web server to expose gopher-proxy as, say `/gopher-space/`.+* `--listen-public`: If this flag is set, gopher-proxy will accept connections on its public IP address(es).+* `--default-mime-type`: Mime type to use if spacecookie can't guess it, defaults to "application/octet-stream"+* `--timeout`: connection timeout in milliseconds, defaults to 10 seconds.+* `--server-name`: The server name of the server to proxy, defaults to the host name. This value is used to detect wether a menu item is pointing to another gopher server than the proxied one. This is particularly useful, if you use e. g. `127.0.0.1` instead of the public host name. ## Things to keep in mind -* Your gopher server must send UTF-8-encoded gopher menus+* Your gopher server must send UTF-8-encoded gopher responses * gopher-proxy might misinterpret certain content, because of the context-sensitive nature of gopher * gopher-proxy does not support Gopher+ ## Roadmap -[ ] Add Logging+- [ ] Add Logging
gopher-proxy.cabal view
@@ -2,9 +2,30 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: gopher-proxy-version: 0.1.0.2+version: 0.1.1.0 synopsis: proxy gopher over http-description: A simple gopher-over-http proxy to http-ify gopher spaces.+description:+ @gopher-proxy@ allows to proxy gopher over HTTP, which is mainly useful for HTTP-ifying a specific gopher space.+ .+ A simple invocation looks like this:+ .+ @+ gopher-proxy --host example.org --http-port 8080+ @+ .++ In this particular example @gopher-proxy@ does the following things:+ .+ * Takes HTTP requests on @127.0.0.1:8080@ (to be used by a proxying web server, like nginx), converts those to gopher requests to @example.org@ and returns the gopher responses as HTTP responses+ .+ * Links menu items pointing to external servers to @gopher://@ URLs (this ensures that only one gopher server is proxied) and recognizes <https://en.wikipedia.org/wiki/Gopher_(protocol)#URL_links URL links> which are converted to normal HTML links+ .+ * Tries to guess the correct mime-type for every gopher-served file (as it is not included in the response) and wraps text files in a HTML container.+ .+ * And generally works hard to offer the best HTTP equivalent of a given gopher space :)+ .+ To learn about the other parameters for tweaking the behavior of @gopher-proxy@ <#readme see the readme>.+ license: GPL-3 license-file: LICENSE author: sternenseemann
src/GopherProxy/Params.hs view
@@ -9,7 +9,8 @@ import qualified Data.ByteString as BS import Data.Maybe (fromMaybe) import Data.Monoid ((<>))-import Data.Text (Text ())+import Data.Text (Text (), pack)+import Data.Text.Encoding import Network.Mime (MimeType (), defaultMimeType) import Network.Socket (HostName (), PortNumber ()) import Options.Applicative@@ -25,6 +26,8 @@ , listenPublic :: Bool , defaultMime :: MimeType , timeoutms :: Int+ , serverName :: Maybe HostName+ , title :: String } helpfulParams :: ParserInfo Params@@ -48,7 +51,7 @@ (long "css-path" <> metavar "PATH" <> help "path of the css to be used"))- <*> optionalWithDefault "/gopher-proxy.css" (option auto+ <*> optionalWithDefault "/gopher-proxy.css" (option utf8ByteString (long "css-url" <> metavar "PATH" <> help "absolute location of the css on the web server, defaults to \"/gopher-proxy.css\""))@@ -67,7 +70,18 @@ (long "timeout" <> metavar "MILLISECONDS" <> help "timeout for connecting to the specified gopher server, defaults to 10s."))+ <*> optional (strOption+ (long "server-name"+ <> metavar "HOSTNAME"+ <> help "The server name of the target gopher server, it sends in gopher menus. Defaults to hostname."))+ <*> optionalWithDefault "gopher-proxy" (strOption+ (long "title"+ <> metavar "STRING"+ <> help "title of the resulting html page")) ++utf8ByteString :: ReadM BS.ByteString+utf8ByteString = encodeUtf8 . pack <$> str optionalWithDefault :: a -> Parser a -> Parser a optionalWithDefault def p = fromMaybe def <$> optional p
src/Main.hs view
@@ -64,8 +64,9 @@ gopherResponse :: Params -> Application gopherResponse cfg r respond = do+ let req = rawPathInfo r (resp, mime) <- (flip fmap)- (makeGopherRequest cfg (B.fromStrict (rawPathInfo r))) $+ (makeGopherRequest cfg (B.fromStrict req)) $ \case Just r -> r Nothing -> ( MenuResponse [ MenuItem '3' "An error occured while retrieving server's response." "" "" 0 ]@@ -80,11 +81,11 @@ respond $ uncurry (responseLBS status) $ case resp of MenuResponse _ ->- ([("Content-type", "text/html")], renderBS (gResponseToHtml cfg resp))+ ([("Content-type", "text/html")], renderBS (gResponseToHtml cfg req resp)) FileResponse b -> case mimeTuple mime of ("text", "html") -> ([("Content-type", mime)], b)- ("text", _) -> ([("Content-type", "text/html")], renderBS (gResponseToHtml cfg resp))+ ("text", _) -> ([("Content-type", "text/html")], renderBS (gResponseToHtml cfg req resp)) _ -> ([("Content-type", mime)], b) mimeTuple :: MimeType -> (BS.ByteString, BS.ByteString)@@ -132,16 +133,17 @@ | T.last base == '/' = base <> path | otherwise = base <> "/" <> path --- we generally assume that everything is utf-8 encoded-gResponseToHtml :: Params -> GopherResponse -> Html ()-gResponseToHtml cfg res+gResponseToHtml :: Params -> BS.ByteString -> GopherResponse -> Html ()+gResponseToHtml cfg req res = doctype_ <> html_ (head_ (meta_ [charset_ "utf-8"] <> meta_ [term "viewport" "width=device-width"]- <> title_ "gopher-proxy"- <> link_ [rel_ "stylesheet", type_ "text/css", href_ . decodeUtf8 . cssUrl $ cfg])+ <> title_ title'+ <> link_ [rel_ "stylesheet", type_ "text/css", href_ cssUrl']) <> body_ bodyContent)- where bodyContent = case res of+ where cssUrl' = decodeUtf8 . cssUrl $ cfg+ title' = (toHtml (title cfg)) <> (toHtml (" – " :: Text)) <> (toHtml req)+ bodyContent = case res of FileResponse bytes -> pre_ (toHtml bytes) MenuResponse items -> ul_ $ foldl (itemChain cfg) mempty items @@ -153,11 +155,19 @@ 'i' -> toHtml desc '3' -> span_ [class_ "error"] (toHtml desc) _ -> a_ [href_ url] (toHtml desc)+ serverName' = case serverName cfg of+ Just s -> s+ Nothing -> hostname cfg url = if "URL:" `T.isPrefixOf` path then T.drop 4 path- else if host' == hostname cfg && port' == port cfg+ else if host' == serverName' && port' == port cfg then prependBaseUrl (baseUrl cfg) path- else prependBaseUrl ("gopher://" <> (T.pack host') <> ":" <> (T.pack (show port'))) path+ else gopherUrl host' port' typec path++gopherUrl :: HostName -> PortNumber -> Char -> Text -> Text+gopherUrl host port typeChar path = prependBaseUrl+ ("gopher://" <> (T.pack host) <> ":" <> (T.pack (show port)) <> "/" <> (T.singleton typeChar) <> "/")+ path main :: IO () main = do