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.
精彩评论