diff options
-rw-r--r-- | projects/mongrel_upload_progress/lib/mongrel_upload_progress/progress.rb | 87 | ||||
-rw-r--r-- | test/mongrel.conf | 1 | ||||
-rw-r--r-- | test/test_handlers.rb | 124 |
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 + |