about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--projects/mongrel_upload_progress/lib/mongrel_upload_progress/progress.rb87
-rw-r--r--test/mongrel.conf1
-rw-r--r--test/test_handlers.rb124
3 files changed, 212 insertions, 0 deletions
diff --git a/projects/mongrel_upload_progress/lib/mongrel_upload_progress/progress.rb b/projects/mongrel_upload_progress/lib/mongrel_upload_progress/progress.rb
new file mode 100644
index 0000000..533bd19
--- /dev/null
+++ b/projects/mongrel_upload_progress/lib/mongrel_upload_progress/progress.rb
@@ -0,0 +1,87 @@
+module Mongrel
+  class Uploads
+    include Singleton
+    
+    def initialize
+      @guard = Mutex.new
+      @counters = {}
+    end
+    
+    def check(upid)
+      @counters[upid]
+    end
+    
+    def add(upid, size)
+      stats = {'size' => size, 'received' => 0}
+      @guard.synchronize do
+        @counters[upid] = stats
+      end
+    end
+    
+    def mark(upid, len)
+      upload = @counters[upid]
+      recvd = upload['size'] - len
+      @guard.synchronize do
+        upload['received'] = recvd
+      end
+    end
+    
+    def finish(upid)
+      upload = @counters[upid]
+      recvd = upload['size']
+      @guard.synchronize do
+        upload['received'] = recvd
+      end
+    end
+  end
+  
+  class HttpRequest
+    def initialize(params, initial_body, socket)
+      @params = params
+      @socket = socket
+
+      clen = params[Const::CONTENT_LENGTH].to_i - initial_body.length
+      upload_id = nil
+      
+      if params[Const::REQUEST_METHOD] == 'POST'
+        qs = self.class.query_parse(params['QUERY_STRING'])
+        if qs['upload_id'] and not qs['upload_id'].empty?
+          upload_id = qs['upload_id']
+          Uploads.instance.add(upload_id, clen) if upload_id
+        end
+      end
+
+      if clen > Const::MAX_BODY
+        @body = Tempfile.new(self.class.name)
+        @body.binmode
+      else
+        @body = StringIO.new
+      end
+
+      begin
+        @body.write(initial_body)
+
+        # write the odd sized chunk first
+        clen -= @body.write(@socket.read(clen % Const::CHUNK_SIZE))
+        
+        # then stream out nothing but perfectly sized chunks
+        while clen > 0
+          data = @socket.read(Const::CHUNK_SIZE)
+          # have to do it this way since @socket.eof? causes it to block
+          raise "Socket closed or read failure" if not data or data.length != Const::CHUNK_SIZE
+          clen -= @body.write(data)
+          Uploads.instance.mark(upload_id, clen) if upload_id
+        end
+
+        # rewind to keep the world happy
+        Uploads.instance.finish(upload_id) if upload_id
+        @body.rewind
+      rescue Object
+        # any errors means we should delete the file, including if the file is dumped
+        STDERR.puts "Error reading request: #$!"
+        @body.delete if @body.class == Tempfile
+        @body = nil # signals that there was a problem
+      end
+    end
+  end
+end \ No newline at end of file
diff --git a/test/mongrel.conf b/test/mongrel.conf
new file mode 100644
index 0000000..3daa23a
--- /dev/null
+++ b/test/mongrel.conf
@@ -0,0 +1 @@
+uri "/fromconf", :handler => Mongrel::Error404Handler.new("test")
diff --git a/test/test_handlers.rb b/test/test_handlers.rb
new file mode 100644
index 0000000..234ef26
--- /dev/null
+++ b/test/test_handlers.rb
@@ -0,0 +1,124 @@
+# Mongrel Web Server - A Mostly Ruby Webserver and Library
+#
+# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+require 'test/unit'
+require 'net/http'
+require 'mongrel'
+require 'timeout'
+
+
+class SimpleHandler < Mongrel::HttpHandler
+  def process(request, response)
+    response.start do |head,out|
+      head["Content-Type"] = "text/html"
+      results = "<html><body>Your request:<br /><pre>#{request.params.to_yaml}</pre><a href=\"/files\">View the files.</a></body></html>"
+      out << results
+    end
+  end
+end
+
+class DumbHandler < Mongrel::HttpHandler
+  def process(request, response)
+    response.start do |head,out|
+      head["Content-Type"] = "text/html"
+      out.write("test")
+    end
+  end
+end
+
+# Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
+# HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
+def hit(uris)
+  results = []
+  uris.each do |u|
+    res = nil
+
+    if u.kind_of? String
+      res = Net::HTTP.get(URI.parse(u))
+    else
+      url = URI.parse(u[0])
+      res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) }
+    end
+
+    assert res != nil, "Didn't get a response: #{u}"
+    results << res
+  end
+
+  return results
+end
+
+def check_status(results, expecting)
+  results.each do |res|
+    assert(res.kind_of?(expecting), "Didn't get #{expecting}, got: #{res.class}")
+  end
+end
+
+class HandlersTest < Test::Unit::TestCase
+
+  def setup
+    stats = Mongrel::StatisticsFilter.new(:sample_rate => 1)
+
+    @config = Mongrel::Configurator.new :host => '127.0.0.1', :port => 9998 do
+      listener do
+        uri "/", :handler => SimpleHandler.new
+        uri "/", :handler => stats
+        uri "/404", :handler => Mongrel::Error404Handler.new("Not found")
+        uri "/dumb", :handler => Mongrel::DeflateFilter.new(:always_deflate => true)
+        uri "/dumb", :handler => DumbHandler.new, :in_front => true
+        uri "/files", :handler => Mongrel::DirHandler.new("doc")
+        uri "/files_nodir", :handler => Mongrel::DirHandler.new("doc",listing_allowed=false, index_html="none")
+        uri "/status", :handler => Mongrel::StatusHandler.new(:stats_filter => stats)
+      end
+    end
+    @config.run
+  end
+
+  def teardown
+    @config.stop
+  end
+
+  def test_more_web_server
+    res = hit([ "http://localhost:9998/test",
+          "http://localhost:9998/dumb",
+          "http://localhost:9998/404",
+          "http://localhost:9998/files/rdoc/index.html",
+          "http://localhost:9998/files/rdoc/nothere.html",
+          "http://localhost:9998/files/rdoc/",
+          "http://localhost:9998/files_nodir/rdoc/",
+          "http://localhost:9998/status",
+    ])
+
+    check_status res, String
+  end
+
+  def test_deflate_access
+    req = Net::HTTP::Get.new("http://localhost:9998/dumb")
+  end
+
+  def test_posting_fails_dirhandler
+    req = Net::HTTP::Post.new("http://localhost:9998/files/rdoc/")
+    req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')
+    res = hit [["http://localhost:9998/files/rdoc/",req]]
+    check_status res, Net::HTTPNotFound
+  end
+
+  def test_unregister
+    @config.listeners["127.0.0.1:9998"].unregister("/")
+  end
+end
+