import Control.Concurrent
import Network
+import qualified Network.Socket as So
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 System.IO
import System.Posix.Signals
-- | This is the entry point of Lucu httpd. It listens to a socket and
where
loop :: Socket -> IO ()
loop so
- = do (h, host, _) <- accept so
- tQueue <- newInteractionQueue
- readerTID <- forkIO $ requestReader cnf tree h host tQueue
- writerTID <- forkIO $ responseWriter cnf h tQueue readerTID
+ -- 本當は Network.accept を使ひたいが、このアクションは勝手に
+ -- リモートのIPを逆引きするので、使へない。
+ = do (h, addr) <- accept' so
+ tQueue <- newInteractionQueue
+ readerTID <- forkIO $ requestReader cnf tree h addr tQueue
+ writerTID <- forkIO $ responseWriter cnf h tQueue readerTID
loop so
+
+ accept' :: Socket -> IO (Handle, So.SockAddr)
+ accept' soSelf
+ = do (soPeer, addr) <- So.accept soSelf
+ hPeer <- So.socketToHandle soPeer ReadWriteMode
+ return (hPeer, addr)
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.Sequence as S
import Data.Sequence (Seq)
-import Network
+import Network.Socket
import Network.HTTP.Lucu.Config
import Network.HTTP.Lucu.HttpVersion
import Network.HTTP.Lucu.Request
data Interaction = Interaction {
itrConfig :: Config
- , itrRemoteHost :: HostName
+ , itrRemoteAddr :: SockAddr
, itrResourcePath :: Maybe [String]
, itrRequest :: TVar (Maybe Request)
, itrResponse :: TVar Response
defaultPageContentType = "application/xhtml+xml"
-newInteraction :: Config -> HostName -> Maybe Request -> IO Interaction
-newInteraction conf host req
+newInteraction :: Config -> SockAddr -> Maybe Request -> IO Interaction
+newInteraction conf addr req
= do request <- newTVarIO $ req
responce <- newTVarIO $ Response {
resVersion = HttpVersion 1 1
return $ Interaction {
itrConfig = conf
- , itrRemoteHost = host
+ , itrRemoteAddr = addr
, itrResourcePath = Nothing
, itrRequest = request
, itrResponse = responce
import Data.Maybe
import qualified Data.Sequence as S
import Data.Sequence (Seq, (<|), ViewR(..))
-import Network
+import Network.Socket
import Network.HTTP.Lucu.Config
import Network.HTTP.Lucu.Chunk
import Network.HTTP.Lucu.DefaultPage
import System.IO
-requestReader :: Config -> ResTree -> Handle -> HostName -> InteractionQueue -> IO ()
-requestReader cnf tree h host tQueue
+requestReader :: Config -> ResTree -> Handle -> SockAddr -> InteractionQueue -> IO ()
+requestReader cnf tree h addr tQueue
= do catch (do input <- B.hGetContents h
acceptRequest input) $ \ exc ->
case exc of
acceptNonparsableRequest :: StatusCode -> IO ()
acceptNonparsableRequest status
- = do itr <- newInteraction cnf host Nothing
+ = do itr <- newInteraction cnf addr Nothing
atomically $ do updateItr itr itrResponse
$ \ res -> res {
resStatus = status
acceptParsableRequest :: Request -> ByteString -> IO ()
acceptParsableRequest req input
- = do itr <- newInteraction cnf host (Just req)
+ = do itr <- newInteraction cnf addr (Just req)
action
<- atomically $
do preprocess itr
-- |These actions can be computed regardless of the current state,
-- and they don't change the state.
, getConfig
+ , getRemoteAddr
+ , getRemoteAddr'
, getRequest
, getMethod
, getRequestURI
import Control.Concurrent.STM
import Control.Monad.Reader
+import Data.Bits
import qualified Data.ByteString.Lazy.Char8 as B
import Data.ByteString.Lazy.Char8 (ByteString)
import Data.List
import Network.HTTP.Lucu.Response
import Network.HTTP.Lucu.MIMEType
import Network.HTTP.Lucu.Utils
+import Network.Socket
import Network.URI
import System.Time
getConfig = do itr <- ask
return $ itrConfig itr
+
+-- |Get the SockAddr of the remote host. If you want a string
+-- representation instead of SockAddr, use 'getRemoteAddr''.
+getRemoteAddr :: Resource SockAddr
+getRemoteAddr = do itr <- ask
+ return $ itrRemoteAddr itr
+
+
+-- |Get the string representation of the address of remote host. If
+-- you want a SockAddr instead of String, use 'getRemoteAddr'.
+getRemoteAddr' :: Resource String
+getRemoteAddr' = do addr <- getRemoteAddr
+ case addr of
+ -- Network.Socket は IPv6 を考慮してゐないやうだ…
+ (SockAddrInet _ v4addr)
+ -> let b1 = (v4addr `shiftR` 24) .&. 0xFF
+ b2 = (v4addr `shiftR` 16) .&. 0xFF
+ b3 = (v4addr `shiftR` 8) .&. 0xFF
+ b4 = v4addr .&. 0xFF
+ in
+ return $ concat $ intersperse "." $ map show [b1, b2, b3, b4]
+ (SockAddrUnix path)
+ -> return path
+
+
-- |Get the 'Network.HTTP.Lucu.Request.Request' value which represents
-- the request header. In general you don't have to use this action.
getRequest :: Resource Request