2011-05-27 19 views
13

El módulo Network.HTTP expone las funciones y receiveHTTPrespondHTTP la que me gustaría utilizar para un servidor web muy básico. Escribí un código auxiliar que sólo espera para los clientes:Cómo escribir un servidor HTTP simple en Haskell usando Network.HTTP.receiveHTTP

{-# 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) 

Aquí accpet me da un Handle, y ahora no puedo encontrar la manera de utilizar un Handle con receiveHTTP.

Encontré an example con Google, pero es de 2008 y ya no funciona. Y no pude portarlo.

¿Alguna idea?

+0

No puedo responder directamente a esto, pero es posible que pueda encontrar algunos ejemplos útiles con [Búsqueda de códigos de Google] (http://www.google.com/codesearch). –

Respuesta

5

Quizás espere que use the accept function from Network.Socket en lugar de Network? Eso le da un Socket en lugar de un Handle, que debe ser capaz de convertir a un formulario que receiveHTTP puede usar.

Normalmente sería mejor trabajar directamente con Handle, pero aquí la biblioteca HTTP se está ocupando de usted, por lo que espera la interfaz de nivel inferior.

EDIT: Después de mirar un poco más allá, parece que la función socketConnection en Network.TCP hace lo que necesita. La parte divertida es que hace que el socket se convierta en un Handle internamente antes de leerlo, pero no parece proporcionar una manera de leer desde un Handle proporcionado por un proveedor externo. El parámetro de cadena para la función se supone que es el nombre del host remoto, pero parece que simplemente se guarda como referencia; en realidad, no está iniciando una conexión con ese host ni nada.

4

Puedes hacer esto, pero realmente creo que no deberías. HTTP puede actuar como un servidor, pero está diseñado para ser utilizado por el lado del cliente. Busqué en Google un poco y no puedo encontrar ningún ejemplo de alguien realmente usando respondHTTP. Si está haciendo HTTP del lado del cliente en 2016, use http-conduit. En el lado del servidor, warp o algo que depende de él es probablemente lo que quiere.

Sin embargo, aquí está el código.

#!/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 

Lo anterior utiliza el soporte de Stack para scripts shebang. chmod +x o ejecutarlo con stack foo.hs.

El módulo Network está en desuso. Siempre use Network.Socket si necesita una API de socket. Para algo de nivel superior, use connection.

haces lo normal de sockets POSIX, a continuación, convertir el enchufe conectado a un HandleStream con socketConnection y ejecutar respondHTTP y receiveHTTP en él. socketConnection es una función extraña. Los primeros dos parámetros son un nombre de host y un puerto que AFAICT no se utilizan cuando se ejecuta un servidor.

Utilicé la extensión RecordWildCards. Me permite escribir Right (Request {..}) en un patrón y tener todos los campos del registro en el alcance en el lado derecho.