about summary refs log tree commit homepage
path: root/lib/unicorn/http_request.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-02-06 22:12:55 -0800
committerEric Wong <normalperson@yhbt.net>2009-02-09 19:52:15 -0800
commit8c176fa571511d0a4dc5fa04777db4565a9d453d (patch)
tree0b6d5abfcbff7bac1792896a426f7388464b1ca6 /lib/unicorn/http_request.rb
parent8ebc0c9fcd941b8e8b31db9237c5d50b082aff0d (diff)
downloadunicorn-8c176fa571511d0a4dc5fa04777db4565a9d453d.tar.gz
Since we handle signals, read(2) syscalls can fail on sockets
with EINTR.  Restart the call if we hit this.
Diffstat (limited to 'lib/unicorn/http_request.rb')
-rw-r--r--lib/unicorn/http_request.rb24
1 files changed, 18 insertions, 6 deletions
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index 1f95abf..0a8c5b1 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -35,7 +35,7 @@ module Unicorn
     # This does minimal exception trapping and it is up to the caller
     # to handle any socket errors (e.g. user aborted upload).
     def read(socket)
-      data = String.new(socket.sysread(Const::CHUNK_SIZE, @buffer))
+      data = String.new(read_socket(socket))
       nparsed = 0
 
       # Assumption: nparsed will always be less since data will get
@@ -61,7 +61,7 @@ module Unicorn
         else
           # Parser is not done, queue up more data to read and continue
           # parsing
-          data << socket.sysread(Const::CHUNK_SIZE, @buffer)
+          data << read_socket(socket)
           if data.length >= Const::MAX_HEADER
             raise HttpParserError.new("HEADER is longer than allowed, " \
                                       "aborting client early.")
@@ -107,6 +107,11 @@ module Unicorn
       end
       @body.rewind
       @body.sysseek(0) if @body.respond_to?(:sysseek)
+
+      # in case read_body overread because the client tried to pipeline
+      # another request, we'll truncate it.  Again, we don't do pipelining
+      # or keepalive
+      @body.truncate(content_length)
       true
     end
 
@@ -139,13 +144,10 @@ module Unicorn
     # It also expects any initial part of the body that has been read to be in
     # the @body already.  It will return true if successful and false if not.
     def read_body(socket, remain)
-      buf = @buffer
       while remain > 0
-        socket.sysread(remain, buf) # short read if it's a socket
-
         # ASSUME: we are writing to a disk and these writes always write the
         # requested amount.  This is true on Linux.
-        remain -= @body.syswrite(buf)
+        remain -= @body.syswrite(read_socket(socket))
       end
       true # success!
     rescue Object => e
@@ -157,5 +159,15 @@ module Unicorn
       reset
       false
     end
+
+    # read(2) on "slow" devices like sockets can be interrupted by signals
+    def read_socket(socket)
+      begin
+        socket.sysread(Const::CHUNK_SIZE, @buffer)
+      rescue Errno::EINTR
+        retry
+      end
+    end
+
   end
 end