]> gitweb @ CieloNegro.org - Lucu.git/commitdiff
Lucu 0.7 RELEASE-0_7
authorpho <pho@cielonegro.org>
Mon, 19 Apr 2010 16:37:17 +0000 (01:37 +0900)
committerpho <pho@cielonegro.org>
Mon, 19 Apr 2010 16:37:17 +0000 (01:37 +0900)
Ignore-this: 79590876fded88d2fe488665cce4c0ce

Changes from 0.6 to 0.7
-----------------------
* Network.HTTP.Lucu.Resource: (Suggested by Voker57)

    - getQueryForm and inputForm now return [(name :: String,
      FormData)] instead of [FormData] to ease field lookup by
      name. The reason why it's not 'Map String FormData' is that
      there is a possibility where multiple fields have the same name.

    - Removed field fdName from FormData type as it's now redundant.

darcs-hash:20100419163717-62b54-747b74a5884a16becba1f9408b954c9b202909d3.gz

Lucu.cabal
NEWS
Network/HTTP/Lucu.hs
Network/HTTP/Lucu/MultipartForm.hs
Network/HTTP/Lucu/Resource.hs
examples/Multipart.hs

index c0c5660f21907d1604613c19ed50472b9578b884..ddb7e3c1adbe2a57075224ee17c5f64975b44668 100644 (file)
@@ -2,13 +2,13 @@ Name: Lucu
 Synopsis: HTTP Daemonic Library
 Description:
         Lucu is an HTTP daemonic library. It can be embedded in any
-        Haskell program and runs in an independent thread.
-        Lucu is not a replacement for Apache. It is intended to be
-        used to create an efficient web-based application without
-        messing around FastCGI. It is also intended to be run behind a
-        reverse-proxy so it doesn't have some facilities like logging,
-        client filtering or such like.
-Version: 0.6
+        Haskell program and runs in an independent thread.  Lucu is
+        not a replacement for Apache or lighttpd. It is intended to be
+        used to create an efficient web-based RESTful application
+        without messing around FastCGI. It is also intended to be run
+        behind a reverse-proxy so it doesn't have some facilities like
+        logging, client filtering or such like.
+Version: 0.7
 License: PublicDomain
 License-File: COPYING
 Author: PHO <pho at cielonegro dot org>
diff --git a/NEWS b/NEWS
index aa4edb3879693226afe487ba357dbf62e352f459..6c88db1e965deae91153832cfc2870d185dfe33f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+Changes from 0.6 to 0.7
+-----------------------
+* Network.HTTP.Lucu.Resource: (Suggested by Voker57)
+
+    - getQueryForm and inputForm now return [(name :: String,
+      FormData)] instead of [FormData] to ease field lookup by
+      name. The reason why it's not 'Map String FormData' is that
+      there is a possibility where multiple fields have the same name.
+
+    - Removed field fdName from FormData type as it's now redundant.
+
 Changes from 0.5 to 0.6
 -----------------------
 * New dependency: time-http == 0.1.*
index e6ae3ee33111cd6f0938442f081dc71e9c54f89a..52315d6952afdce4e2c0e07600627b8a03dfd8ab 100644 (file)
 --   [/SSL connections/] Lucu can handle HTTP connections over SSL
 --   layer.
 --
--- Lucu is not a replacement for Apache. It is intended to be used to
--- create an efficient web-based application without messing around
--- FastCGI. It is also intended to be run behind a reverse-proxy so it
--- doesn't have the following (otherwise essential) facilities:
+-- Lucu is not a replacement for Apache or lighttpd. It is intended to
+-- be used to create an efficient web-based RESTful application
+-- without messing around FastCGI. It is also intended to be run
+-- behind a reverse-proxy so it doesn't have the following (otherwise
+-- essential) facilities:
 --
 --   [/Logging/] Lucu doesn't log any requests from any clients.
 --
index c9684b18892e3e2259e1818a13385f91cfa98b8c..a2ee492bbb401c1268b74be37dbf5a7d90220046 100644 (file)
@@ -18,12 +18,11 @@ import           Network.HTTP.Lucu.Utils
 
 data Part = Part Headers L8.ByteString
 
--- |This data type represents a form entry name, form value and
--- possibly an uploaded file name.
+-- |This data type represents a form value and possibly an uploaded
+-- file name.
 data FormData
     = FormData {
-        fdName     :: String
-      , fdFileName :: Maybe String
+        fdFileName :: Maybe String
       , fdContent  :: L8.ByteString
       }
 
@@ -50,7 +49,7 @@ instance Show ContDispo where
                                    value
 
 
-multipartFormP :: String -> Parser [FormData]
+multipartFormP :: String -> Parser [(String, FormData)]
 multipartFormP boundary
     = do parts <- many (partP boundary)
          _     <- string "--"
@@ -58,7 +57,7 @@ multipartFormP boundary
          _     <- string "--"
          _     <- crlf
          eof
-         return $ map partToFormData parts
+         return $ map partToFormPair parts
 
 
 partP :: String -> Parser Part
@@ -82,17 +81,15 @@ bodyP boundary
          return body
 
 
-partToFormData :: Part -> FormData
-partToFormData part@(Part _ body)
+partToFormPair :: Part -> (String, FormData)
+partToFormPair part@(Part _ body)
     = let name  = partName part
-          fName = partFileName part
-      in
-        FormData {
-          fdName     = name
-        , fdFileName = fName
-        , fdContent  = body
-        }
-
+          fname = partFileName part
+          fd    = FormData {
+                    fdFileName = fname
+                  , fdContent  = body
+                  }
+      in (name, fd)
 
 partName :: Part -> String
 partName = getName' . getContDispoFormData
index 08fb6f19ce50b434457d42f0deef09710f6c31f1..34c1a725634b6485df32d7e5e302238e44cf78b4 100644 (file)
@@ -301,20 +301,26 @@ getPathInfo = do rsrcPath <- getResourcePath
                  -- rsrcPath の長さの分だけ削除すれば良い。
                  return $! drop (length rsrcPath) reqPath
 
--- | Assume the query part of request URI as
--- application\/x-www-form-urlencoded, and parse it. This action
--- doesn't parse the request body. See 'inputForm'.
-getQueryForm :: Resource [FormData]
-getQueryForm = do uri <- getRequestURI
-                  return $! map pairToFormData $ parseWWWFormURLEncoded $ snd $ splitAt 1 $ uriQuery uri
-
-pairToFormData :: (String, String) -> FormData
-pairToFormData (name, value)
-    = FormData {
-        fdName     = name
-      , fdFileName = Nothing
-      , fdContent  = L8.pack value
-      }
+-- |Assume the query part of request URI as
+-- application\/x-www-form-urlencoded, and parse it to pairs of
+-- @(name, formData)@. This action doesn't parse the request body. See
+-- 'inputForm'.
+getQueryForm :: Resource [(String, FormData)]
+getQueryForm = liftM parse' getRequestURI
+    where
+      parse' = map toPairWithFormData .
+               parseWWWFormURLEncoded .
+               snd .
+               splitAt 1 .
+               uriQuery
+
+toPairWithFormData :: (String, String) -> (String, FormData)
+toPairWithFormData (name, value)
+    = let fd = FormData {
+                 fdFileName = Nothing
+               , fdContent  = L8.pack value
+               }
+      in (name, fd)
 
 -- |Get a value of given request header. Comparison of header name is
 -- case-insensitive. Note that this action is not intended to be used
@@ -726,7 +732,7 @@ inputChunkLBS limit
 -- makes 'Resource' abort with status \"415 Unsupported Media
 -- Type\". If the request has no \"Content-Type\", it aborts with
 -- \"400 Bad Request\".
-inputForm :: Int -> Resource [FormData]
+inputForm :: Int -> Resource [(String, FormData)]
 inputForm limit
     = limit `seq` 
       do cTypeM <- getContentType
@@ -742,8 +748,7 @@ inputForm limit
                                                           ++ show cType)
     where
       readWWWFormURLEncoded
-          = do src <- input limit
-               return $ map pairToFormData $ parseWWWFormURLEncoded src
+          = liftM (map toPairWithFormData . parseWWWFormURLEncoded) (input limit)
 
       readMultipartFormData params
           = do case find ((== "boundary") . map toLower . fst) params of
@@ -752,7 +757,8 @@ inputForm limit
                  Just (_, boundary)
                      -> do src <- inputLBS limit
                            case parse (multipartFormP boundary) src of
-                             (# Success fdList, _ #) -> return fdList
+                             (# Success formList, _ #)
+                                 -> return formList
                              (# _, _ #)
                                  -> abort BadRequest [] (Just "Unparsable multipart/form-data")
 
index 3897dfb2a1f62359c44206c113ba60cf0314b5e4..69c4125accd5a97c54f909dea9141fd5866062c8 100644 (file)
@@ -1,5 +1,4 @@
 import qualified Data.ByteString.Lazy.Char8 as L8
-import Data.List
 import Data.Maybe
 import Network.HTTP.Lucu
 
@@ -28,9 +27,9 @@ resMain
       , resHead   = Nothing
       , resPost
           = Just $ do form <- inputForm defaultLimit
-                      let text     = fromMaybe L8.empty $ fmap fdContent $ find ((== "text") . fdName) form
-                          file     = fromMaybe L8.empty $ fmap fdContent $ find ((== "file") . fdName) form
-                          fileName = fdFileName =<< find ((== "file") . fdName) form
+                      let text     = fromMaybe L8.empty $ fmap fdContent $ lookup "text" form
+                          file     = fromMaybe L8.empty $ fmap fdContent $ lookup "file" form
+                          fileName = fdFileName =<< lookup "file" form
                       setContentType $ read "text/plain"
                       outputChunk ("You entered \"" ++ L8.unpack text ++ "\".\n")
                       outputChunk ("You uploaded a " ++ show (L8.length file) ++ " bytes long file.\n")