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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With