diff --git a/Data/Csv/Conversion.hs b/Data/Csv/Conversion.hs
--- a/Data/Csv/Conversion.hs
+++ b/Data/Csv/Conversion.hs
@@ -32,7 +32,7 @@
     ) where
 
 import Control.Applicative (Alternative, Applicative, (<*>), (<$>), (<|>),
-                            empty, pure)
+                            (<*), (*>), empty, pure)
 import Control.Monad (MonadPlus, mplus, mzero)
 import Data.Attoparsec.Char8 (double)
 import qualified Data.Attoparsec.Char8 as A8
@@ -429,7 +429,7 @@
     toField = toField . T.encodeUtf8 . T.singleton
     {-# INLINE toField #-}
 
--- | Accepts same syntax as 'rational'.
+-- | Accepts same syntax as 'rational'. Ignores whitespace.
 instance FromField Double where
     parseField = parseDouble
     {-# INLINE parseField #-}
@@ -440,7 +440,7 @@
     toField = realFloat
     {-# INLINE toField #-}
 
--- | Accepts same syntax as 'rational'.
+-- | Accepts same syntax as 'rational'. Ignores whitespace.
 instance FromField Float where
     parseField s = double2Float <$> parseDouble s
     {-# INLINE parseField #-}
@@ -452,12 +452,12 @@
     {-# INLINE toField #-}
 
 parseDouble :: B.ByteString -> Parser Double
-parseDouble s = case parseOnly double s of
+parseDouble s = case parseOnly (ws *> double <* ws) s of
     Left err -> typeError "Double" s (Just err)
     Right n  -> pure n
 {-# INLINE parseDouble #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Int where
     parseField = parseSigned "Int"
     {-# INLINE parseField #-}
@@ -467,7 +467,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Integer where
     parseField = parseSigned "Integer"
     {-# INLINE parseField #-}
@@ -477,7 +477,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Int8 where
     parseField = parseSigned "Int8"
     {-# INLINE parseField #-}
@@ -487,7 +487,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Int16 where
     parseField = parseSigned "Int16"
     {-# INLINE parseField #-}
@@ -497,7 +497,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Int32 where
     parseField = parseSigned "Int32"
     {-# INLINE parseField #-}
@@ -507,7 +507,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts a signed decimal number.
+-- | Accepts a signed decimal number. Ignores whitespace.
 instance FromField Int64 where
     parseField = parseSigned "Int64"
     {-# INLINE parseField #-}
@@ -517,7 +517,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts an unsigned decimal number.
+-- | Accepts an unsigned decimal number. Ignores whitespace.
 instance FromField Word where
     parseField = parseUnsigned "Word"
     {-# INLINE parseField #-}
@@ -527,7 +527,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts an unsigned decimal number.
+-- | Accepts an unsigned decimal number. Ignores whitespace.
 instance FromField Word8 where
     parseField = parseUnsigned "Word8"
     {-# INLINE parseField #-}
@@ -537,7 +537,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts an unsigned decimal number.
+-- | Accepts an unsigned decimal number. Ignores whitespace.
 instance FromField Word16 where
     parseField = parseUnsigned "Word16"
     {-# INLINE parseField #-}
@@ -547,7 +547,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts an unsigned decimal number.
+-- | Accepts an unsigned decimal number. Ignores whitespace.
 instance FromField Word32 where
     parseField = parseUnsigned "Word32"
     {-# INLINE parseField #-}
@@ -557,7 +557,7 @@
     toField = decimal
     {-# INLINE toField #-}
 
--- | Accepts an unsigned decimal number.
+-- | Accepts an unsigned decimal number. Ignores whitespace.
 instance FromField Word64 where
     parseField = parseUnsigned "Word64"
     {-# INLINE parseField #-}
@@ -614,16 +614,21 @@
     {-# INLINE toField #-}
 
 parseSigned :: (Integral a, Num a) => String -> B.ByteString -> Parser a
-parseSigned typ s = case parseOnly (A8.signed A8.decimal) s of
+parseSigned typ s = case parseOnly (ws *> A8.signed A8.decimal <* ws) s of
     Left err -> typeError typ s (Just err)
     Right n  -> pure n
 {-# INLINE parseSigned #-}
 
 parseUnsigned :: Integral a => String -> B.ByteString -> Parser a
-parseUnsigned typ s = case parseOnly A8.decimal s of
+parseUnsigned typ s = case parseOnly (ws *> A8.decimal <* ws) s of
     Left err -> typeError typ s (Just err)
     Right n  -> pure n
 {-# INLINE parseUnsigned #-}
+
+ws :: A8.Parser ()
+ws = A8.skipWhile (\c -> c == ' ' || c == '\t')
+
+
 
 ------------------------------------------------------------------------
 -- Custom version of attoparsec @parseOnly@ function which fails if
diff --git a/Data/Csv/Encoding.hs b/Data/Csv/Encoding.hs
--- a/Data/Csv/Encoding.hs
+++ b/Data/Csv/Encoding.hs
@@ -33,7 +33,7 @@
                                  toLazyByteString, toByteString)
 import Blaze.ByteString.Builder.Char8 (fromString)
 import Control.Applicative ((*>), (<|>), optional, pure)
-import Data.Attoparsec.Char8 (endOfInput, endOfLine)
+import Data.Attoparsec.Char8 (endOfInput)
 import qualified Data.Attoparsec.ByteString.Lazy as AL
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as B8
@@ -54,7 +54,7 @@
 import qualified Data.Csv.Parser as Parser
 import Data.Csv.Types hiding (toNamedRecord)
 import qualified Data.Csv.Types as Types
-import Data.Csv.Util (blankLine)
+import Data.Csv.Util (blankLine, endOfLine)
 
 -- TODO: 'encode' isn't as efficient as it could be.
 
diff --git a/Data/Csv/Incremental.hs b/Data/Csv/Incremental.hs
--- a/Data/Csv/Incremental.hs
+++ b/Data/Csv/Incremental.hs
@@ -29,7 +29,7 @@
 
 import Control.Applicative ((<*), (<|>))
 import qualified Data.Attoparsec as A
-import Data.Attoparsec.Char8 (endOfInput, endOfLine)
+import Data.Attoparsec.Char8 (endOfInput)
 import qualified Data.ByteString as B
 import qualified Data.Vector as V
 
@@ -37,6 +37,7 @@
 import qualified Data.Csv.Conversion as Conversion
 import Data.Csv.Parser
 import Data.Csv.Types
+import Data.Csv.Util (endOfLine)
 
 -- $feed-header
 --
diff --git a/Data/Csv/Parser.hs b/Data/Csv/Parser.hs
--- a/Data/Csv/Parser.hs
+++ b/Data/Csv/Parser.hs
@@ -27,7 +27,7 @@
 import Blaze.ByteString.Builder (fromByteString, toByteString)
 import Blaze.ByteString.Builder.Char.Utf8 (fromChar)
 import Control.Applicative ((*>), (<$>), (<*), optional, pure)
-import Data.Attoparsec.Char8 (char, endOfInput, endOfLine)
+import Data.Attoparsec.Char8 (char, endOfInput)
 import qualified Data.Attoparsec as A
 import qualified Data.Attoparsec.Lazy as AL
 import qualified Data.Attoparsec.Zepto as Z
@@ -38,7 +38,7 @@
 import Data.Word (Word8)
 
 import Data.Csv.Types
-import Data.Csv.Util ((<$!>), blankLine, liftM2')
+import Data.Csv.Util ((<$!>), blankLine, endOfLine, liftM2', cr, newline, doubleQuote)
 
 -- | Options that controls how data is decoded. These options can be
 -- used to e.g. decode tab-separated data instead of comma-separated
@@ -186,8 +186,3 @@
     if done
       then return (acc `mappend` fromByteString h)
       else rest
-
-doubleQuote, newline, cr :: Word8
-doubleQuote = 34
-newline = 10
-cr = 13
diff --git a/Data/Csv/Util.hs b/Data/Csv/Util.hs
--- a/Data/Csv/Util.hs
+++ b/Data/Csv/Util.hs
@@ -1,13 +1,22 @@
-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BangPatterns, OverloadedStrings #-}
 
 module Data.Csv.Util
     ( (<$!>)
     , blankLine
     , liftM2'
+    , endOfLine
+    , doubleQuote
+    , newline
+    , cr
     ) where
 
+import Control.Applicative ((<|>), (*>))
+import Data.Word (Word8)
+import Data.Attoparsec.ByteString.Char8 (string)
+import qualified Data.Attoparsec as A
 import qualified Data.ByteString as B
 import qualified Data.Vector as V
+import Data.Attoparsec (Parser)
 
 -- | A strict version of 'Data.Functor.<$>' for monads.
 (<$!>) :: Monad m => (a -> b) -> m a -> m b
@@ -30,3 +39,16 @@
     y <- b
     return (f x y)
 {-# INLINE liftM2' #-}
+
+
+-- | Match either a single newline character @\'\\n\'@, or a carriage
+-- return followed by a newline character @\"\\r\\n\"@, or a single
+-- carriage return @\'\\r\'@.
+endOfLine :: Parser ()
+endOfLine = (A.word8 newline *> return ()) <|> (string "\r\n" *> return ()) <|> (A.word8 cr *> return ())
+{-# INLINE endOfLine #-}
+
+doubleQuote, newline, cr :: Word8
+doubleQuote = 34
+newline = 10
+cr = 13
diff --git a/cassava.cabal b/cassava.cabal
--- a/cassava.cabal
+++ b/cassava.cabal
@@ -1,5 +1,5 @@
 Name:                cassava
-Version:             0.4.0.0
+Version:             0.4.1.0
 Synopsis:            A CSV parsing and encoding library
 Description:
   A CSV parsing and encoding library optimized for ease of use and high
@@ -36,7 +36,7 @@
 
   Build-depends:
     array < 0.6,
-    attoparsec >= 0.10.2 && < 0.12,
+    attoparsec >= 0.10.2 && < 0.13,
     base < 5,
     blaze-builder < 0.4,
     bytestring < 0.11,
diff --git a/tests/UnitTests.hs b/tests/UnitTests.hs
--- a/tests/UnitTests.hs
+++ b/tests/UnitTests.hs
@@ -192,6 +192,9 @@
            [[("field1", "abc"), ("field2", "def")]])
         , ("twoRecords", "field\r\nabc\r\ndef\r\n", ["field"],
            [[("field", "abc")], [("field", "def")]])
+        , ("cr header", "field\rabc", ["field"], [[("field", "abc")]])
+        , ("cr trailing", "field\rabc\r", ["field"], [[("field", "abc")]])
+        , ("cr separator", "field\rabc\rdef", ["field"], [[("field", "abc")],[("field","def")]])
         ]
 
     encodeTest (name, hdr, input, expected) =
@@ -241,6 +244,12 @@
   Left _  -> return ()
   Right _ -> assertFailure "expected partial field decode"
 
+expect :: (Eq a, Show a) => Parser a -> a -> Assertion
+expect p a0 =
+  case runParser p of
+    Right a -> a @=? a0
+    Left  e -> assertFailure e
+
 conversionTests :: [TF.Test]
 conversionTests =
     [ testGroup "roundTrip"
@@ -290,6 +299,17 @@
                             (parseField "1.0+" :: Parser Double))
       , testCase "Integer" (partialDecode
                             (parseField "1e6"  :: Parser Integer))
+      ]
+    , testGroup "Space trimming"
+      [ testCase "_Int"     (expect (parseField " 12"     :: Parser Int)    12)
+      , testCase "Int_"     (expect (parseField "12 "     :: Parser Int)    12)
+      , testCase "_Int_"    (expect (parseField " 12 "    :: Parser Int)    12)
+      , testCase "_Word"    (expect (parseField " 12"     :: Parser Word)   12)
+      , testCase "Word_"    (expect (parseField "12 "     :: Parser Word)   12)
+      , testCase "_Word_"   (expect (parseField " 12 "    :: Parser Word)   12)
+      , testCase "_Double"  (expect (parseField " 1.2e1"  :: Parser Double) 12)
+      , testCase "Double_"  (expect (parseField "1.2e1 "  :: Parser Double) 12)
+      , testCase "_Double_" (expect (parseField " 1.2e1 " :: Parser Double) 12)
       ]
     ]
 
