ngx-export 1.6.4 → 1.7.0
raw patch · 3 files changed
+86/−44 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ NgxExport: type HTTPHeaders = [(ByteString, ByteString)]
- NgxExport: type ContentHandlerResult = (ByteString, ByteString, Int)
+ NgxExport: type ContentHandlerResult = (ByteString, ByteString, Int, HTTPHeaders)
Files
- Changelog.md +11/−0
- NgxExport.hs +74/−43
- ngx-export.cabal +1/−1
Changelog.md view
@@ -1,3 +1,14 @@+### 1.7.0++- Now basic synchronous and all asynchronous content handlers are expected to+ return a list of custom response headers in the *4th* field of the+ *ContentHandlerResult*.+- All asynchronous handlers get proper masking against asynchronous exceptions,+ which is especially important for service handlers in presence of asynchronous+ exceptions from service hooks.+- Now a new StablePtr for the content type gets returned only when its value is+ not empty.+ ### 1.6.4 - Added exception *WorkerProcessIsExiting* to signal services that Nginx is
NgxExport.hs view
@@ -20,6 +20,7 @@ -- * Type declarations ContentHandlerResult ,UnsafeContentHandlerResult+ ,HTTPHeaders -- * Exporters -- *** Synchronous handlers ,ngxExportSS@@ -116,8 +117,9 @@ {-# COMPLETE ToBool :: CUInt #-} #endif --- | The /3-tuple/ contains /(content, content-type, HTTP-status)/.-type ContentHandlerResult = (L.ByteString, B.ByteString, Int)+-- | The /4-tuple/ contains+-- /(content, content-type, HTTP-status, response-headers)/.+type ContentHandlerResult = (L.ByteString, B.ByteString, Int, HTTPHeaders) -- | The /3-tuple/ contains /(content, content-type, HTTP-status)/. --@@ -126,6 +128,9 @@ -- termination and must not be garbage-collected in the Haskell RTS. type UnsafeContentHandlerResult = (B.ByteString, B.ByteString, Int) +-- | A list of HTTP headers comprised of /name-value/ pairs.+type HTTPHeaders = [(B.ByteString, B.ByteString)]+ data NgxExport = SS (String -> String) | SSS (String -> String -> String) | SLS ([String] -> String)@@ -143,17 +148,17 @@ | AsyncHandlerRB (L.ByteString -> B.ByteString -> IO ContentHandlerResult) -data NgxExportDisambiguation = Unambiguous- | YYSync- | YYDefHandler- | IOYYSync- | IOYYAsync+data NgxExportTypeAmbiguityTag = Unambiguous+ | YYSync+ | YYDefHandler+ | IOYYSync+ | IOYYAsync do TyConI (DataD _ _ _ EXTRA_WILDCARD_BEFORE_CON tCs _) <- reify ''NgxExport TyConI (DataD _ _ _ EXTRA_WILDCARD_BEFORE_CON aCs _) <-- reify ''NgxExportDisambiguation+ reify ''NgxExportTypeAmbiguityTag let tName = mkName "exportType" aName = mkName "exportTypeAmbiguity" tCons = map (\(NormalC con [(_, typ)]) -> (con, typ)) tCs@@ -164,7 +169,7 @@ map (\(fst -> c, i) -> clause [conP c [wildP]] (normalB [|return i|]) [] ) (zip tCons [1 ..] :: [((Name, Type), Int)])- ,sigD aName [t|NgxExportDisambiguation -> IO CInt|]+ ,sigD aName [t|NgxExportTypeAmbiguityTag -> IO CInt|] ,funD aName $ map (\(c, i) -> clause [conP c []] (normalB [|return i|]) []@@ -386,6 +391,7 @@ ngxExport 'Handler 'Unambiguous 'handler [t|CString -> CInt -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (StablePtr L.ByteString) -> IO CUInt|] -- | Exports a function of type@@ -428,6 +434,7 @@ ngxExport 'AsyncHandler 'Unambiguous 'asyncHandler [t|CString -> CInt -> CInt -> CUInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CUInt -> Ptr (StablePtr L.ByteString) -> IO (StablePtr (Async ()))|] @@ -447,6 +454,7 @@ [t|Ptr NgxStrType -> Ptr NgxStrType -> CInt -> CString -> CInt -> CInt -> CUInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CUInt -> Ptr (StablePtr L.ByteString) -> IO (StablePtr (Async ()))|] @@ -589,7 +597,7 @@ return (nullPtr, 0) toBuffers s p = do let n = L.foldlChunks (const . succ) 0 s- if n == 1+ if n == 1 && p /= nullPtr then do B.unsafeUseAsCStringLen (head $ L.toChunks s) $ \(x, I l) -> poke p $ NgxStrType l x@@ -617,10 +625,11 @@ when (t /= nullPtr) $ newStablePtr s >>= poke spd pokeContentTypeAndStatus :: B.ByteString ->- Ptr CString -> Ptr CSize -> Ptr CInt -> CInt -> IO ()+ Ptr CString -> Ptr CSize -> Ptr CInt -> CInt -> IO CSize pokeContentTypeAndStatus ct pct plct pst st = do PtrLen sct lct <- B.unsafeUseAsCStringLen ct return pokeCStringLen sct lct pct plct >> poke pst st+ return lct peekRequestBodyChunks :: Ptr NgxStrType -> Ptr NgxStrType -> Int -> IO L.ByteString@@ -634,10 +643,12 @@ else peekNgxStringArrayLenY b m pokeAsyncHandlerData :: B.ByteString -> Ptr CString -> Ptr CSize ->- Ptr (StablePtr B.ByteString) -> Ptr CInt -> CInt -> IO ()-pokeAsyncHandlerData ct pct plct spct pst st = do- pokeContentTypeAndStatus ct pct plct pst st- newStablePtr ct >>= poke spct+ Ptr (StablePtr B.ByteString) -> Ptr CInt -> CInt -> HTTPHeaders ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> IO ()+pokeAsyncHandlerData ct pct plct spct pst st rhs prhs plrhs sprhs = do+ lct <- pokeContentTypeAndStatus ct pct plct pst st+ when (lct > 0) $ newStablePtr ct >>= poke spct+ pokeLazyByteString (fromHTTPHeaders rhs) prhs plrhs sprhs safeHandler :: Ptr CString -> Ptr CInt -> IO CUInt -> IO CUInt safeHandler p pl = handle $ \e -> do@@ -645,9 +656,14 @@ pokeCStringLen x l p pl return 1 -safeYYHandler :: IO (L.ByteString, (CUInt, Bool)) ->- IO (L.ByteString, (CUInt, Bool))+safeYYHandler :: IO (L.ByteString, CUInt) -> IO (L.ByteString, CUInt) safeYYHandler = handle $ \e ->+ return (C8L.pack $ show (e :: SomeException), 1)+{-# INLINE safeYYHandler #-}++safeAsyncYYHandler :: IO (L.ByteString, (CUInt, Bool)) ->+ IO (L.ByteString, (CUInt, Bool))+safeAsyncYYHandler = handle $ \e -> return (C8L.pack $ show e, (case fromException e of Just ServiceHookInterrupt -> 2@@ -666,8 +682,13 @@ _ -> False ) )-{-# INLINE safeYYHandler #-}+{-# INLINE safeAsyncYYHandler #-} +fromHTTPHeaders :: HTTPHeaders -> L.ByteString+fromHTTPHeaders = L.fromChunks . foldr (\(z -> a, z -> b) -> ([a, b] ++)) []+ where z s | B.null s = B.singleton 0+ | otherwise = s+ isEINTR :: IOError -> Bool isEINTR = (Just ((\(Errno i) -> i) eINTR) ==) . ioe_errno {-# INLINE isEINTR #-}@@ -704,9 +725,9 @@ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> IO CUInt yY f x (I n) p pl spd = do- (s, (r, _)) <- safeYYHandler $ do+ (s, r) <- safeYYHandler $ do s <- f <$> B.unsafePackCStringLen (x, n)- fmap (, (0, False)) $ return $!! s+ fmap (, 0) $ return $!! s pokeLazyByteString s p pl spd return r @@ -715,9 +736,9 @@ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> IO CUInt ioyYCommon pack f x (I n) p pl spd = do- (s, (r, _)) <- safeYYHandler $ do+ (s, r) <- safeYYHandler $ do s <- pack (x, n) >>= flip f False- fmap (, (0, False)) $ return $!! s+ fmap (, 0) $ return $!! s pokeLazyByteString s p pl spd return r @@ -740,12 +761,13 @@ asyncIOCommon :: IO (L.ByteString, Bool) -> CInt -> Bool -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CUInt -> Ptr (StablePtr L.ByteString) -> IO (StablePtr (Async ()))-asyncIOCommon a (I fd) efd p pl pr spd =+asyncIOCommon a (I fd) efd p pl pr spd = mask $ \restore -> async (do- (s, (r, exiting)) <- safeYYHandler $ do- (s, exiting) <- a- fmap (, (0, exiting)) $ return $!! s+ (s, (r, exiting)) <- safeAsyncYYHandler $+ restore $ do+ (s, exiting) <- a+ fmap (, (0, exiting)) $ return $!! s pokeLazyByteString s p pl spd poke pr r if exiting@@ -768,11 +790,11 @@ writeFlag1b = B.unsafeUseAsCString asyncIOFlag1b $ writeBufN 1 writeFlag8b = B.unsafeUseAsCString asyncIOFlag8b $ writeBufN 8 closeChannel = closeFd fd `catchIOError` const (return ())- -- FIXME: cleanupOnWriteError should free contents of p, spd,- -- and spct. However, leaving this not implemented seems to be safe- -- because Nginx won't close the event channel or delete the request- -- object (for request-driven handlers) regardless of the Haskell- -- handler's duration.+ -- FIXME: cleanupOnWriteError should free all previously allocated+ -- data and stable pointers. However, leaving this not implemented+ -- seems to be safe because Nginx won't close the event channel or+ -- delete the request object (for request-driven handlers)+ -- regardless of the Haskell handler's duration. cleanupOnWriteError = return () asyncIOYY :: IOYY -> CString -> CInt ->@@ -818,29 +840,35 @@ asyncHandler :: AsyncHandler -> CString -> CInt -> CInt -> CUInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CUInt -> Ptr (StablePtr L.ByteString) -> IO (StablePtr (Async ()))-asyncHandler f x (I n) fd (ToBool efd) pct plct spct pst =+asyncHandler f x (I n) fd (ToBool efd) pct plct spct pst+ prhs plrhs sprhs = asyncIOCommon (do x' <- B.unsafePackCStringLen (x, n)- (s, ct, I st) <- f x'- (return $!! s) >> pokeAsyncHandlerData ct pct plct spct pst st+ v@(s, ct, I st, rhs) <- f x'+ (return $!! v) >> mask_+ (pokeAsyncHandlerData ct pct plct spct pst st rhs prhs plrhs sprhs) return (s, False) ) fd efd asyncHandlerRB :: AsyncHandlerRB -> Ptr NgxStrType -> Ptr NgxStrType -> CInt -> CString -> CInt -> CInt -> CUInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CUInt -> Ptr (StablePtr L.ByteString) -> IO (StablePtr (Async ()))-asyncHandlerRB f tmpf b (I m) x (I n) fd (ToBool efd) pct plct spct pst =+asyncHandlerRB f tmpf b (I m) x (I n) fd (ToBool efd) pct plct spct pst+ prhs plrhs sprhs = asyncIOCommon (do b' <- peekRequestBodyChunks tmpf b m x' <- B.unsafePackCStringLen (x, n)- (s, ct, I st) <- f b' x'- (return $!! s) >> pokeAsyncHandlerData ct pct plct spct pst st+ v@(s, ct, I st, rhs) <- f b' x'+ (return $!! v) >> mask_+ (pokeAsyncHandlerData ct pct plct spct pst st rhs prhs plrhs sprhs) return (s, False) ) fd efd @@ -879,13 +907,16 @@ handler :: Handler -> CString -> CInt -> Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr CString -> Ptr CSize -> Ptr (StablePtr B.ByteString) -> Ptr CInt ->+ Ptr (Ptr NgxStrType) -> Ptr CInt -> Ptr (StablePtr L.ByteString) -> Ptr (StablePtr L.ByteString) -> IO CUInt-handler f x (I n) p pl pct plct spct pst spd =+handler f x (I n) p pl pct plct spct pst prhs plrhs sprhs spd = safeHandler pct pst $ do- (s, ct, I st) <- f <$> B.unsafePackCStringLen (x, n)- (return $!! s) >> pokeContentTypeAndStatus ct pct plct pst st+ v@(s, ct, I st, rhs) <- f <$> B.unsafePackCStringLen (x, n)+ lct <- (return $!! v) >> pokeContentTypeAndStatus ct pct plct pst st+ (return $!! lct) >>+ pokeLazyByteString (fromHTTPHeaders rhs) prhs plrhs sprhs pokeLazyByteString s p pl spd- newStablePtr ct >>= poke spct+ when (lct > 0) $ newStablePtr ct >>= poke spct return 0 defHandler :: YY -> CString -> CInt ->@@ -901,8 +932,8 @@ Ptr CString -> Ptr CSize -> Ptr CInt -> IO CUInt unsafeHandler f x (I n) p pl pct plct pst = safeHandler pct pst $ do- (s, ct, I st) <- f <$> B.unsafePackCStringLen (x, n)- (return $!! s) >> pokeContentTypeAndStatus ct pct plct pst st+ v@(s, ct, I st) <- f <$> B.unsafePackCStringLen (x, n)+ (return $!! v) >> void (pokeContentTypeAndStatus ct pct plct pst st) PtrLen t l <- B.unsafeUseAsCStringLen s return pokeCStringLen t l p pl return 0
ngx-export.cabal view
@@ -1,5 +1,5 @@ name: ngx-export-version: 1.6.4+version: 1.7.0 synopsis: Helper module for Nginx haskell module description: Helper module for <http://github.com/lyokha/nginx-haskell-module Nginx haskell module>.