diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 3.0.12
+
+* Only conditionally produce HTTP 100 Continue
+
 ## 3.0.11
 
 * Better HEAD support for files [#357](https://github.com/yesodweb/wai/pull/357)
diff --git a/Network/Wai/Handler/Warp/Request.hs b/Network/Wai/Handler/Warp/Request.hs
--- a/Network/Wai/Handler/Warp/Request.hs
+++ b/Network/Wai/Handler/Warp/Request.hs
@@ -50,10 +50,12 @@
             -> Source -- ^ Where HTTP request comes from.
             -> IO (Request
                   ,Maybe (I.IORef Int)
-                  ,IndexedHeader) -- ^
+                  ,IndexedHeader
+                  ,IO ByteString) -- ^
             -- 'Request' passed to 'Application',
             -- how many bytes remain to be consumed, if known
             -- 'IndexedHeader' of HTTP request for internal use,
+            -- Body producing action used for flushing the request body
 
 recvRequest settings conn ii addr src = do
     hdrlines <- headerLines src
@@ -62,9 +64,12 @@
         expect = idxhdr ! idxExpect
         cl = idxhdr ! idxContentLength
         te = idxhdr ! idxTransferEncoding
-    handleExpect conn httpversion expect
+        handle100Continue = handleExpect conn httpversion expect
     (rbody, remainingRef, bodyLength) <- bodyAndSource src cl te
-    rbody' <- timeoutBody remainingRef th rbody
+    -- body producing function which will produce '100-continue', if needed
+    rbody' <- timeoutBody remainingRef th rbody handle100Continue
+    -- body producing function which will never produce 100-continue
+    rbodyFlush <- timeoutBody remainingRef th rbody (return ())
     let req = Request {
             requestMethod     = method
           , httpVersion       = httpversion
@@ -83,7 +88,7 @@
           , requestHeaderHost = idxhdr ! idxHost
           , requestHeaderRange = idxhdr ! idxRange
           }
-    return (req, remainingRef, idxhdr)
+    return (req, remainingRef, idxhdr, rbodyFlush)
   where
     th = threadHandle ii
 
@@ -145,8 +150,9 @@
 timeoutBody :: Maybe (I.IORef Int) -- ^ remaining
             -> Timeout.Handle
             -> IO ByteString
+            -> IO ()
             -> IO (IO ByteString)
-timeoutBody remainingRef timeoutHandle rbody = do
+timeoutBody remainingRef timeoutHandle rbody handle100Continue = do
     isFirstRef <- I.newIORef True
 
     let checkEmpty =
@@ -162,6 +168,9 @@
         isFirst <- I.readIORef isFirstRef
 
         when isFirst $ do
+            -- Only check if we need to produce the 100 Continue status
+            -- when asking for the first chunk of the body
+            handle100Continue
             -- Timeout handling was paused after receiving the full request
             -- headers. Now we need to resume it to avoid a slowloris
             -- attack during request body sending.
diff --git a/Network/Wai/Handler/Warp/Response.hs b/Network/Wai/Handler/Warp/Response.hs
--- a/Network/Wai/Handler/Warp/Response.hs
+++ b/Network/Wai/Handler/Warp/Response.hs
@@ -138,19 +138,20 @@
 --   There are three basic APIs to create 'Response':
 --
 --   ['responseFile' :: 'H.Status' -> 'H.ResponseHeaders' -> 'FilePath' -> 'Maybe' 'FilePart' -> 'Response']
---     HTTP response body is sent by sendfile().
+--     HTTP response body is sent by sendfile() for GET method.
+--     HTTP response body is not sent by HEAD method.
 --     Applications are categorized into simple and sophisticated.
 --     Simple applications should specify 'Nothing' to
 --     'Maybe' 'FilePart'. The size of the specified file is obtained
 --     by disk access. Then Range is handled.
 --     Sophisticated applications should specify 'Just' to
 --     'Maybe' 'FilePart'. They should treat Range (and If-Range) by
---     thierselves. In both cases,
+--     themselves. In both cases,
 --     Content-Length and Content-Range (if necessary) are automatically
 --     added into the HTTP response header.
 --     If Content-Length and Content-Range exist in the HTTP response header,
 --     they would cause inconsistency.
---     Status is also changed to 206 if necessary.
+--     Status is also changed to 206 (Partial Content) if necessary.
 --
 --   ['responseBuilder' :: 'H.Status' -> 'H.ResponseHeaders' -> 'Builder' -> 'Response']
 --     HTTP response body is created from 'Builder'.
diff --git a/Network/Wai/Handler/Warp/Run.hs b/Network/Wai/Handler/Warp/Run.hs
--- a/Network/Wai/Handler/Warp/Run.hs
+++ b/Network/Wai/Handler/Warp/Run.hs
@@ -355,9 +355,9 @@
     errorResponse e = settingsOnExceptionResponse settings e
 
     http1 addr istatus src = do
-        (req', mremainingRef, idxhdr) <- recvRequest settings conn ii addr src
+        (req', mremainingRef, idxhdr, nextBodyFlush) <- recvRequest settings conn ii addr src
         let req = req' { isSecure = isTransportSecure transport }
-        keepAlive <- processRequest istatus src req mremainingRef idxhdr
+        keepAlive <- processRequest istatus src req mremainingRef idxhdr nextBodyFlush
             `E.catch` \e -> do
                 -- Call the user-supplied exception handlers, passing the request.
                 sendErrorResponse addr istatus e
@@ -366,7 +366,7 @@
                 return False
         when keepAlive $ http1 addr istatus src
 
-    processRequest istatus src req mremainingRef idxhdr = do
+    processRequest istatus src req mremainingRef idxhdr nextBodyFlush = do
         -- Let the application run for as long as it wants
         T.pause th
 
@@ -405,13 +405,13 @@
             -- reading it all in to satisfy a keep-alive request.
             case settingsMaximumBodyFlush settings of
                 Nothing -> do
-                    flushEntireBody (requestBody req)
+                    flushEntireBody nextBodyFlush
                     T.resume th
                     return True
                 Just maxToRead -> do
                     let tryKeepAlive = do
                             -- flush the rest of the request body
-                            isComplete <- flushBody (requestBody req) maxToRead
+                            isComplete <- flushBody nextBodyFlush maxToRead
                             if isComplete then do
                                 T.resume th
                                 return True
diff --git a/warp.cabal b/warp.cabal
--- a/warp.cabal
+++ b/warp.cabal
@@ -1,5 +1,5 @@
 Name:                warp
-Version:             3.0.11
+Version:             3.0.12
 Synopsis:            A fast, light-weight web server for WAI applications.
 License:             MIT
 License-file:        LICENSE
