The module Network.HTTP exposes the functions receiveHTTP and respondHTTP which I'd like to use for a very basic web server. I wrote a stub that just waits for clients:
{-# LANGUAGE OverloadedStrings #-} module Main where import Network.HTTP import Network import Control.Monad main = withSocketsDo $ do socket <- listenOn $ PortNumber 8080 forever $ do (handle, host, port) <- accept socket print (host, port) Here accpet gives me a Handle, and now I can't figure out how to use a Handle with receiveHTTP.
I found an example with Google, but it is from 2008 and does not work anymore. And I was not able to port it.
Any ideas?
2 Answers
Answers 1
Perhaps it expects you to use the accept function from Network.Socket instead of Network? That gives you a Socket instead of a Handle, which you should be able to convert to a form that receiveHTTP can use.
Normally a Handle would be nicer to work with directly, but here the HTTP library is taking care of it for you so it expects the lower-level interface instead.
EDIT: After looking at it a bit further, it seems the socketConnection function in Network.TCP does what you need. The funny part is it's actually making the socket into a Handle internally before it reads from it, but doesn't seem to provide a way to read from an externally-provided Handle. The string parameter to the function is supposed to be the name of the remote host, but it looks like that's merely kept for reference; it's not actually initiating a connection to that host or anything.
Answers 2
You can do this, but I really think you shouldn't. HTTP can act as a server, but is designed to be used client side. I Googled a little and I can't find any examples of someone actually using respondHTTP. If you're doing client side HTTP in 2016 use http-conduit. On the server side, warp or something that depends upon it is probably what you want.
Nevertheless, here's the code.
#!/usr/bin/env stack -- stack --resolver lts-6.3 --install-ghc runghc --package HTTP {-# LANGUAGE RecordWildCards #-} import Control.Monad import qualified Data.ByteString as B import Network.HTTP import Network.Socket import Network.URI main = do lsock <- socket AF_INET Stream defaultProtocol bind lsock (SockAddrInet 8080 iNADDR_ANY) listen lsock 1 forever $ do (csock, _) <- accept lsock hs <- socketConnection "" 8080 csock req <- receiveHTTP hs case req of Left _ -> error "Receiving request failed" Right (Request {..}) -> if uriPath rqURI == "/" then do respondHTTP hs $ Response (2,0,0) "OK" [] "Hello HTTP" Network.HTTP.close hs else do respondHTTP hs $ Response (4,0,4) "Not found" [] "Nothing here" Network.HTTP.close hs The above uses Stack's support for shebang scripts. chmod +x it or run it with stack foo.hs.
The Network module is deprecated. Always use Network.Socket if you need a socket API. For something higher level, use connection.
You do the normal POSIX socket thing, then convert the connected socket to a HandleStream with socketConnection and run respondHTTP and receiveHTTP on it. socketConnection is a weird function. The first two parameters are a hostname and a port which AFAICT aren't used when running a server.
I used the RecordWildCards extension. It lets me write Right (Request {..}) in a pattern and have all the fields of the record in scope on the right hand side.
0 comments:
Post a Comment