]> gitweb @ CieloNegro.org - Lucu.git/commitdiff
Honor cnfServerV4Addr and cnfServerV6Addr.
authorpho <pho@cielonegro.org>
Wed, 3 Mar 2010 14:30:16 +0000 (23:30 +0900)
committerpho <pho@cielonegro.org>
Wed, 3 Mar 2010 14:30:16 +0000 (23:30 +0900)
Ignore-this: 63735347206de657c2c095e677a52f4e

darcs-hash:20100303143016-62b54-82d8627a3e3222f5cca265710cb7e9e1da6d60b7.gz

12 files changed:
Network/HTTP/Lucu/Config.hs
Network/HTTP/Lucu/DefaultPage.hs
Network/HTTP/Lucu/Httpd.hs
Network/HTTP/Lucu/Interaction.hs
Network/HTTP/Lucu/Preprocess.hs
Network/HTTP/Lucu/RequestReader.hs
examples/HelloWorld.hs
examples/Implanted.hs
examples/ImplantedSmall.hs
examples/Makefile
examples/Multipart.hs
examples/SSL.hs

index 847b737ad200e0ef42a7740e608eed5caba9207d..29c560891ebec2f9d13b38bca91f9ce2d77436ae 100644 (file)
@@ -26,8 +26,8 @@ data Config = Config {
     -- built-in pages like \"404 Not Found\".
     , cnfServerHost :: !Strict.ByteString
 
-    -- |A port ID to listen to HTTP clients.
-    , cnfServerPort :: !PortID
+    -- |A port number (or service name) to listen to HTTP clients.
+    , cnfServerPort :: !ServiceName
 
     -- |Local IPv4 address to listen to HTTP clients. Set this to
     -- @('Just' "0.0.0.0")@ if you want to accept any IPv4
@@ -88,7 +88,7 @@ data SSLConfig
         -- |A port ID to listen to HTTPS clients. Local addresses
         -- (both for IPv4 and IPv6) will be derived from the parent
         -- 'Config'.
-        sslServerPort :: !PortID
+        sslServerPort :: !ServiceName
 
         -- |An SSL context for accepting connections.
       , sslContext    :: !SSLContext
@@ -101,7 +101,7 @@ defaultConfig :: Config
 defaultConfig = Config {
                   cnfServerSoftware              = C8.pack "Lucu/1.0"
                 , cnfServerHost                  = C8.pack (unsafePerformIO getHostName)
-                , cnfServerPort                  = Service "http"
+                , cnfServerPort                  = "http"
                 , cnfServerV4Addr                = Just "0.0.0.0"
                 , cnfServerV6Addr                = Just "::"
                 , cnfSSLConfig                   = Nothing
index cbbf674718e922957ce57389ae32aa8454b9b87a..2220c7fca408d5b416ec324103dbe0ed646b4e02 100644 (file)
@@ -12,7 +12,6 @@ import           Control.Monad
 import qualified Data.ByteString.Char8 as C8
 import qualified Data.ByteString.Lazy.Char8 as L8
 import           Data.Maybe
-import           Network
 import           Network.HTTP.Lucu.Config
 import           Network.HTTP.Lucu.Format
 import           Network.HTTP.Lucu.Headers
@@ -60,11 +59,6 @@ mkDefaultPage !conf !status !msgA
           sig               = C8.unpack (cnfServerSoftware conf)
                               ++ " at "
                               ++ C8.unpack (cnfServerHost conf)
-                              ++ ( case cnfServerPort conf of
-                                     Service    serv -> ", service " ++ serv
-                                     PortNumber num  -> ", port " ++ show num
-                                     UnixSocket path -> ", unix socket " ++ show path
-                                 )
       in ( eelem "/"
            += ( eelem "html"
                 += sattr "xmlns" "http://www.w3.org/1999/xhtml"
index 1d0f2b8a5c626d3aa8175c7d07927b88fdeff1cc..d9f28f110e5f1c668a3fc9f539b9f2c4981e3959 100644 (file)
@@ -6,13 +6,16 @@ module Network.HTTP.Lucu.Httpd
     where
 
 import           Control.Concurrent
-import           Network hiding (accept)
+import           Control.Exception
+import           Control.Monad
+import           Network.BSD
+import           Network.Socket
 import           Network.HTTP.Lucu.Config
 import           Network.HTTP.Lucu.Interaction
 import           Network.HTTP.Lucu.RequestReader
 import           Network.HTTP.Lucu.Resource.Tree
 import           Network.HTTP.Lucu.ResponseWriter
-import           Network.HTTP.Lucu.SocketLike
+import           Network.HTTP.Lucu.SocketLike as SL
 import           System.Posix.Signals
 
 -- |This is the entry point of Lucu httpd. It listens to a socket and
@@ -53,20 +56,83 @@ runHttpd cnf tree fbs
     = withSocketsDo $
       do _ <- installHandler sigPIPE Ignore Nothing
 
+         -- FIXME: TERRIBLE CODE. NEED MAJOR REWRITE.
          case cnfSSLConfig cnf of
            Nothing
                -> return ()
            Just scnf
-               -> do so       <- listenOn (sslServerPort scnf)
-                     _loopTID <- forkIO $ httpLoop (sslContext scnf, so)
-                     return ()
+               -> do case cnfServerV4Addr cnf of
+                       Nothing
+                           -> return ()
+                       Just v4addr
+                           -> do so <- listenOn AF_INET v4addr (sslServerPort scnf)
+                                 p  <- socketPort so
+                                 -- FIXME: Don't throw away the thread
+                                 -- ID as we can't kill it later
+                                 -- then. [1]
+                                 _  <- forkIO $ httpLoop p (sslContext scnf, so)
+                                 return ()
+
+                     case cnfServerV6Addr cnf of
+                       Nothing
+                           -> return ()
+                       Just v6addr
+                           -> do so <- listenOn AF_INET6 v6addr (sslServerPort scnf)
+                                 p  <- socketPort so
+                                 -- FIXME: [1]
+                                 _  <- forkIO $ httpLoop p (sslContext scnf, so)
+                                 return ()
          
-         httpLoop =<< listenOn (cnfServerPort cnf)
+         case cnfServerV4Addr cnf of
+           Nothing
+               -> return ()
+           Just v4addr
+               -> do so <- listenOn AF_INET v4addr (cnfServerPort cnf)
+                     p  <- socketPort so
+                     -- FIXME: [1]
+                     _  <- forkIO $ httpLoop p so
+                     return ()
+
+         case cnfServerV6Addr cnf of
+           Nothing
+               -> return ()
+           Just v6addr
+               -> do so <- listenOn AF_INET6 v6addr (cnfServerPort cnf)
+                     p  <- socketPort so
+                     -- FIXME: [1]
+                     _  <- forkIO $ httpLoop p so
+                     return ()
+
+         waitForever
     where
-      httpLoop :: SocketLike s => s -> IO ()
-      httpLoop so
-          = do (h, addr)  <- accept so
+      listenOn :: Family -> HostName -> ServiceName -> IO Socket
+      listenOn fam host srv
+          = do proto <- getProtocolNumber "tcp"
+               let hints = defaultHints {
+                             addrFlags      = [AI_PASSIVE]
+                           , addrFamily     = fam
+                           , addrSocketType = Stream
+                           , addrProtocol   = proto
+                           }
+               addrs <- getAddrInfo (Just hints) (Just host) (Just srv)
+               let addr = head addrs
+               bracketOnError
+                   (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))
+                   (sClose)
+                   (\ sock ->
+                        do setSocketOption sock ReuseAddr 1
+                           bindSocket sock (addrAddress addr)
+                           listen sock maxListenQueue
+                           return sock
+                   )
+
+      httpLoop :: SocketLike s => PortNumber -> s -> IO ()
+      httpLoop port so
+          = do (h, addr)  <- SL.accept so
                tQueue     <- newInteractionQueue
-               readerTID  <- forkIO $ requestReader cnf tree fbs h addr tQueue
+               readerTID  <- forkIO $ requestReader cnf tree fbs h port addr tQueue
                _writerTID <- forkIO $ responseWriter cnf h tQueue readerTID
-               httpLoop so
+               httpLoop port so
+
+      waitForever :: IO ()
+      waitForever = forever (threadDelay 1000000)
index 5da428d4968ff225e31ac84fa003f013fbdf3d77..4c93b41abf258999aa329121c98d90b43d666ffa 100644 (file)
@@ -31,6 +31,7 @@ import           OpenSSL.X509
 
 data Interaction = Interaction {
       itrConfig       :: !Config
+    , itrLocalPort    :: !PortNumber
     , itrRemoteAddr   :: !SockAddr
     , itrRemoteCert   :: !(Maybe X509)
     , itrResourcePath :: !(Maybe [String])
@@ -82,8 +83,8 @@ defaultPageContentType :: Strict.ByteString
 defaultPageContentType = C8.pack "application/xhtml+xml"
 
 
-newInteraction :: Config -> SockAddr -> Maybe X509 -> Maybe Request -> IO Interaction
-newInteraction !conf !addr !cert !req
+newInteraction :: Config -> PortNumber -> SockAddr -> Maybe X509 -> Maybe Request -> IO Interaction
+newInteraction !conf !port !addr !cert !req
     = do request  <- newTVarIO req
          responce <- newTVarIO Response {
                        resVersion = HttpVersion 1 1
@@ -117,6 +118,7 @@ newInteraction !conf !addr !cert !req
 
          return Interaction {
                       itrConfig       = conf
+                    , itrLocalPort    = port
                     , itrRemoteAddr   = addr
                     , itrRemoteCert   = cert
                     , itrResourcePath = Nothing
index de5efaae4ac5bce5d23bab1658609092a95f8df4..fc3fcbdfcde6cd01ce13cf36d3df3b44ddd9a45c 100644 (file)
@@ -15,7 +15,6 @@ import           Network.HTTP.Lucu.HttpVersion
 import           Network.HTTP.Lucu.Interaction
 import           Network.HTTP.Lucu.Request
 import           Network.HTTP.Lucu.Response
-import           Network
 import           Network.URI
 
 {-
@@ -79,36 +78,25 @@ preprocess itr
                 preprocessHeader req
     where
       setStatus :: StatusCode -> STM ()
-      setStatus status
-          = status `seq`
-            updateItr itr itrResponse
+      setStatus !status
+          = updateItr itr itrResponse
             $! \ res -> res {
                           resStatus = status
                         }
 
       completeAuthority :: Request -> STM ()
-      completeAuthority req
-          = req `seq`
-            when (uriAuthority (reqURI req) == Nothing)
+      completeAuthority !req
+          = when (uriAuthority (reqURI req) == Nothing)
             $ if reqVersion req == HttpVersion 1 0 then
                   -- HTTP/1.0 なので Config から補完
                   do let conf = itrConfig itr
                          host = cnfServerHost conf
-                         port = case cnfServerPort conf of
-                                  PortNumber n -> Just (fromIntegral n :: Int)
-                                  _            -> Nothing
+                         port = itrLocalPort itr
                          portStr
                               = case port of
-                                  Just 80 -> Just ""
-                                  Just n  -> Just $ ':' : show n
-                                  Nothing -> Nothing
-                     case portStr of
-                       Just str -> updateAuthority host (C8.pack str)
-                       -- FIXME: このエラーの原因は、listen してゐるソ
-                       -- ケットが INET でない故にポート番號が分からな
-                       -- い事だが、その事をどうにかして通知した方が良
-                       -- いと思ふ。stderr?
-                       Nothing  -> setStatus InternalServerError
+                                  80 -> ""
+                                  n  -> ':' : show n
+                     updateAuthority host (C8.pack portStr)
               else
                   case getHeader (C8.pack "Host") req of
                     Just str -> let (host, portStr) = parseHost str
index e7244896d30f98c434ae43d4653da5f10b1cf686..cfc991a1ef5a70f415daf08ac40f6f4a10d17134 100644 (file)
@@ -28,8 +28,8 @@ import           Prelude hiding (catch)
 import           System.IO (stderr)
 
 
-requestReader :: HandleLike h => Config -> ResTree -> [FallbackHandler] -> h -> SockAddr -> InteractionQueue -> IO ()
-requestReader !cnf !tree !fbs !h !addr !tQueue
+requestReader :: HandleLike h => Config -> ResTree -> [FallbackHandler] -> h -> PortNumber -> SockAddr -> InteractionQueue -> IO ()
+requestReader !cnf !tree !fbs !h !port !addr !tQueue
     = do input <- hGetLBS h
          acceptRequest input
       `catches`
@@ -59,7 +59,7 @@ requestReader !cnf !tree !fbs !h !addr !tQueue
       acceptNonparsableRequest :: StatusCode -> IO ()
       acceptNonparsableRequest status
           = {-# SCC "acceptNonparsableRequest" #-}
-            do itr <- newInteraction cnf addr Nothing Nothing
+            do itr <- newInteraction cnf port addr Nothing Nothing
                atomically $ do updateItr itr itrResponse
                                              $ \ res -> res {
                                                           resStatus = status
@@ -74,7 +74,7 @@ requestReader !cnf !tree !fbs !h !addr !tQueue
       acceptParsableRequest req input
           = {-# SCC "acceptParsableRequest" #-}
             do cert <- hGetPeerCert h
-               itr  <- newInteraction cnf addr cert (Just req)
+               itr  <- newInteraction cnf port addr cert (Just req)
                action
                    <- atomically $
                       do preprocess itr
index 187bd349415539228c5cc425b260551e2ab5aa72..71916f3203bf0e3bdf8a30073a74376a92550d9a 100644 (file)
@@ -1,8 +1,7 @@
-import Network
 import Network.HTTP.Lucu
 
 main :: IO ()
-main = let config    = defaultConfig { cnfServerPort = PortNumber 9999 }
+main = let config    = defaultConfig { cnfServerPort = "9999" }
            resources = mkResTree [ ( []
                                    , helloWorld )
 
index 390a572873b00119ca8f3c690ced9441e9a6b101..68423086a2472ac51fa1d777ecf9ac412fbe2a97 100644 (file)
@@ -1,9 +1,8 @@
 import MiseRafturai
-import Network
 import Network.HTTP.Lucu
 
 main :: IO ()
-main = let config    = defaultConfig { cnfServerPort = PortNumber 9999 }
+main = let config    = defaultConfig { cnfServerPort = "9999" }
            resources = mkResTree [ ([], miseRafturai) ]
        in
          do putStrLn "Access http://localhost:9999/ with your browser."
index 9ee3466e1217c39fb4bbda99fa611137310a5452..af35b6320979db7d247649b90e3041e66ee1e4bb 100644 (file)
@@ -1,9 +1,8 @@
-import Network
 import Network.HTTP.Lucu
 import SmallFile
 
 main :: IO ()
-main = let config    = defaultConfig { cnfServerPort = PortNumber 9999 }
+main = let config    = defaultConfig { cnfServerPort = "9999" }
            resources = mkResTree [ ([], smallFile) ]
        in
          do putStrLn "Access http://localhost:9999/ with your browser."
index 002f48177b9e72c6c5a9bf3548623ae3e93844dd..3e2c6f02245cc2faacf0930bbaf86cb13df6e05b 100644 (file)
@@ -5,7 +5,6 @@ TARGETS = \
        ImplantedSmall \
        Multipart \
        SSL \
-       StaticDir \
        $(NULL)
 
 build: $(TARGETS)
@@ -22,6 +21,8 @@ clean:
 MiseRafturai.hs: mise-rafturai.html
        lucu-implant-file -m MiseRafturai -o $@ $<
 
+ImplantedSmall.hs: SmallFile.hs
+
 SmallFile.hs: small-file.txt
        lucu-implant-file -m SmallFile -o $@ $<
 
index f8c1c7bc218d76a1f8322fb3475f87d67296ef04..3897dfb2a1f62359c44206c113ba60cf0314b5e4 100644 (file)
@@ -1,11 +1,10 @@
 import qualified Data.ByteString.Lazy.Char8 as L8
 import Data.List
 import Data.Maybe
-import Network
 import Network.HTTP.Lucu
 
 main :: IO ()
-main = let config    = defaultConfig { cnfServerPort = PortNumber 9999 }
+main = let config    = defaultConfig { cnfServerPort = "9999" }
            resources = mkResTree [ ([], resMain) ]
        in
          do putStrLn "Access http://localhost:9999/ with your browser."
index 129316eba787f1e26ed7fbe88667bb6d96e7abd5..436749fdc01fe7a2a081fec88831414d815c5fe5 100644 (file)
@@ -2,7 +2,6 @@
 import           Control.Monad
 import "mtl"     Control.Monad.Trans
 import           Data.Time.Clock
-import           Network
 import           Network.HTTP.Lucu
 import           OpenSSL
 import           OpenSSL.EVP.PKey
@@ -21,9 +20,9 @@ main = withOpenSSL $
           SSL.contextSetDefaultCiphers ctx
 
           let config    = defaultConfig {
-                            cnfServerPort = PortNumber 9000
+                            cnfServerPort = "9000"
                           , cnfSSLConfig  = Just SSLConfig {
-                                              sslServerPort = PortNumber 9001
+                                              sslServerPort = "9001"
                                             , sslContext    = ctx
                                             }
                           }