Changeset 300

Show
Ignore:
Timestamp:
08/03/06 15:49:37 (2 years ago)
Author:
zedshaw
Message:

Dan Kubb's conditional response patch.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/mongrel-0.4/doc/site/src/default.template

    r260 r300  
    4949            <dt>Jun-25-2006</dt> 
    5050            <dd> 
     51            <h5><a href="{relocatable: news.html}">Mongrel 0.3.13.3 -- Ruby Licensed Release</a></h5> 
     52 
     53            <p>This release is now licensed under the Ruby license.  Enjoy!</p> 
     54            <a href="{relocatable: news.html}" title="Read About It">Read About It</a> 
     55            <a href="{relocatable: news.html}"><img src="{relocatable: images/li4.gif}" alt="more" /><br /></a></p> 
     56            </dd> 
     57             
     58            <dt>Jun-25-2006</dt> 
     59            <dd> 
    5160            <h5><a href="{relocatable: news.html}">Mongrel 0.3.13.2 -- RailsConf 2006 Release</a></h5> 
    5261 
  • branches/mongrel-0.4/doc/site/src/docs/howto.page

    r243 r300  
    3434<dd> 
    3535Configures your Rails environment to what you need. 
    36 <ul><li><b>Default:</b> debug</li></ul> 
     36<ul><li><b>Default:</b> development</li></ul> 
    3737</dd> 
    3838</dl> 
     
    6666<dt>-l, --log (:log_file)</dt> 
    6767<dd> 
    68 Where to dump log messages in daemon mode.  Use an *absolute* paths
     68Where to dump log messages in daemon mode.  Use an *absolute* path
    6969<b>No Win32.</b> 
    70 <ul><li><b>Default:</b> log/mongrel.log</li></ul> 
     70<ul><li><b>Default:</b> $PWD/log/mongrel.log</li></ul> 
    7171</dd> 
    7272</dl> 
     
    7878<b>stop</b> commands know the Process ID.  Use *absolute* paths. 
    7979<b>No Win32.</b> 
    80 <ul><li><b>Default:</b> log/mongrel.pid</li></ul> 
     80<ul><li><b>Default:</b> $PWD/log/mongrel.pid</li></ul> 
    8181</dd> 
    8282</dl> 
     
    148148reading about right now.  Read "Command Line Settings" below 
    149149for more information.  Use *absolute* paths. 
    150 <ul><li><b>Default:</b> You can't set this.</li></ul> 
     150<ul><li><b>Default:</b> no default</li></ul> 
    151151</dd> 
    152152</dl> 
     
    175175</dl> 
    176176 
     177<dl> 
     178<dt>--prefix uri</dt> 
     179<dd> 
     180A URI to mount your Rails application at rather than the default 
     181/.  This URI is stripped off all requests by Rails (not Mongrel) 
     182so it <b>cannot</b> end in /. 
     183<ul><li><b>Default:</b> not set</li></ul> 
     184</dd> 
     185</dl> 
     186 
     187 
     188<dl> 
     189<dt>--user USER</dt> 
     190<dd> 
     191<b>Must have --group too.</b> 
     192The user to change to right after creating the listening socket. 
     193Use this if you have to bind Mongrel to a low port like port 80, 
     194but don't want Mongrel to run as root.  <b>Not useful in Windows.</b> 
     195<ul><li><b>Default:</b> not set</li></ul> 
     196</dd> 
     197</dl> 
     198 
     199 
     200<dl> 
     201<dt>--group GROUP</dt> 
     202<dd> 
     203<b>Must have --user too.</b> 
     204The group to change to right after creating the listening socket. 
     205<b>Not userful in Windows.</b> 
     206<ul><li><b>Default:</b> not set</li></ul> 
     207</dd> 
     208</dl> 
    177209 
    178210h2.  Configuration Files 
  • branches/mongrel-0.4/doc/site/src/docs/pound.page

    r247 r300  
    6060      Port    8000 
    6161    End 
    62   End 
    63   Service 
    6462    BackEnd 
    6563      Address 127.0.0.1 
    6664      Port    8001 
    6765    End 
    68   End 
    69   Service 
    7066    BackEnd 
    7167      Address 127.0.0.1 
     
    8783      Port    8000 
    8884    End 
    89   End 
    90   Service 
    9185    BackEnd 
    9286      Address 127.0.0.1 
    9387      Port    8001 
    9488    End 
    95   End 
    96   Service 
    9789    BackEnd 
    9890      Address 127.0.0.1 
  • branches/mongrel-0.4/doc/site/src/faq.page

    r165 r300  
    6262h3. Q: Is it multi-threaded or can it handle concurrent requests? 
    6363 
    64 Mongrel is uses a pool of thread workers to do it's processing.  This means that 
    65 it is able to handle concurrent access and should be thread safe.  This also 
    66 means that you have to be more careful about how you use Mongrel.  You can't 
    67 just write your application assuming that there are no threads involved
     64Mongrel uses one thread per request, but it will start closing connections 
     65when it gets "overloaded".  While Mongrel is processing HTTP requests and 
     66sending responses it uses Ruby's threading system (which is more like 
     67Java's original green threads and uses select)
    6868 
    6969Camping and Og+Nitro are supposed to be thread safe and work with Mongrel directly. 
     
    7474to Dispatcher.dispatch.  This means that everything is threaded right before and 
    7575right after Rails runs.  While Rails is running there is only one controller 
    76 in operation at a time. 
     76in operation at a time.  This is why people typically have to run a small 
     77set of Mongrel processes (a "Pack of Mongrels") to get good concurrency. 
     78 
     79If you have long running actions then you'll most likely have performance 
     80problems.  You should look at "BackgrounDRB":http://backgroundrb.rubyforge.org/ 
     81as a very nice way to offload work to another process so that your Rails 
     82app can keep working. 
    7783 
    7884 
  • branches/mongrel-0.4/doc/site/src/news.page

    r266 r300  
    88h1. Latest News 
    99 
    10 h2. Jun 30: Mongrel 0.3.13.3 -- Ruby Licensed Now 
     10h2. Jun 30: Mongrel 0.3.13.3 -- Ruby Licensed Release 
    1111 
    1212After talking with various people deep inside the Ruby machine, I've decided 
    1313to release Mongrel Ruby licensed as of 0.3.13.3.  This release should make 
    14 quite a few people happy. 
     14quite a few people happy.  It also means that contributors will hopefully 
     15feel better about their contibutions and people using Mongrel have more freedom. 
     16 
     17This release also fixes a problem with the -B option not actually logging  
     18object counts.  The object count logging isn't perfect, but some folks use 
     19it. 
     20 
     21This release also will print the access log to the screen when you run it in 
     22your console.  This was requested by a few folks, but I'm not convinced I like 
     23it.  Try it out and if you do or don't then mention it in the mailing list. 
     24 
     25As usual, do your: 
     26 
     27  gem install mongrel 
     28 
     29To get the release, and if it doesn't show up then you have to wait 
     30for the ruby gems mirror to sync up. 
    1531 
    1632h2. Jun 25: Mongrel 0.3.13.2 -- RailsConf 2006 Release 
  • branches/mongrel-0.4/ext/http11/http11.c

    r298 r300  
    4040 
    4141/** Defines common length and error messages for input length validation. */ 
    42 #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N  " is longer than the " # length " allowed length."; 
     42#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N  " is longer than the " # length " allowed length." 
    4343 
    4444/** Validates the max length of given input and throws an HttpParserError exception if over. */ 
     
    4646 
    4747/** Defines global strings in the init method. */ 
    48 #define DEF_GLOBAL(N, val)   global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N); 
     48#define DEF_GLOBAL(N, val)   global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N) 
    4949 
    5050 
  • branches/mongrel-0.4/lib/mongrel.rb

    r296 r300  
    129129 
    130130    # A frozen format for this is about 15% faster 
    131     STATUS_FORMAT = "HTTP/1.1 %d %s\r\nContent-Length: %d\r\nConnection: close\r\n".freeze 
     131    STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze 
    132132    CONTENT_TYPE = "Content-Type".freeze 
    133133    LAST_MODIFIED = "Last-Modified".freeze 
     
    143143    REMOTE_ADDR="REMOTE_ADDR".freeze 
    144144    HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze 
    145     HTTP_IF_UNMODIFIED_SINCE="HTTP_IF_UNMODIFIED_SINCE".freeze 
     145    HTTP_IF_MODIFIED_SINCE="HTTP_IF_MODIFIED_SINCE".freeze 
    146146    HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze 
    147147    REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze 
     
    382382    end 
    383383 
    384     def send_status(content_length=nil
     384    def send_status(content_length=@body.length
    385385      if not @status_sent 
    386         content_length ||= @body.length 
    387         write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status], content_length]) 
     386        @header['Content-Length'] = content_length unless @status == 304 
     387        write(Const::STATUS_FORMAT % [@status, HTTP_STATUS_CODES[@status]]) 
    388388        @status_sent = true 
    389389      end 
     
    509509    # TODO: Find out if anyone actually uses the timeout option since it seems to cause problems on FBSD. 
    510510    def initialize(host, port, num_processors=(2**30-1), timeout=0) 
    511       @socket = TCPServer.new(host, port)  
     511      @socket = TCPServer.new(host, port) 
     512 
     513 
    512514      @classifier = URIClassifier.new 
    513515      @host = host 
     
    622624    end 
    623625 
     626    def configure_socket_options 
     627      if /linux/ === RUBY_PLATFORM 
     628        # 9 is currently TCP_DEFER_ACCEPT 
     629        $tcp_defer_accept_opts = [9,1] 
     630        $tcp_cork_opts = [3,1] 
     631      end 
     632    end 
    624633 
    625634    # Runs the thing.  It returns the thread used so you can "join" it.  You can also 
     
    628637      BasicSocket.do_not_reverse_lookup=true 
    629638 
     639      configure_socket_options 
     640 
     641      @socket.setsockopt(Socket::SOL_TCP, $tcp_defer_accept_opts[0], $tcp_defer_accept_opts[1]) if $tcp_defer_accept_opts 
     642 
    630643      @acceptor = Thread.new do 
    631644        while true 
    632645          begin 
    633646            client = @socket.accept 
     647            client.setsockopt(Socket::SOL_TCP, $tcp_cork_opts[0], $tcp_cork_opts[1]) if $tcp_cork_opts 
     648 
    634649            worker_list = @workers.list 
    635  
    636650            if worker_list.length >= @num_processors 
    637651              STDERR.puts "Server overloaded with #{worker_list.length} processors (#@num_processors max). Dropping connection." 
  • branches/mongrel-0.4/lib/mongrel/handlers.rb

    r268 r300  
    204204      etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino] 
    205205 
    206       unmodified_since = request.params[Const::HTTP_IF_UNMODIFIED_SINCE] 
     206      modified_since = request.params[Const::HTTP_IF_MODIFIED_SINCE] 
    207207      none_match = request.params[Const::HTTP_IF_NONE_MATCH] 
    208208 
     
    210210      # the response would be identical to the last response 
    211211      same_response = case 
    212                       when unmodified_since && !last_response_time = Time.httpdate(unmodified_since) rescue nil : false 
    213                       when unmodified_since && last_response_time > Time.now                                    : false 
    214                       when unmodified_since && mtime > last_response_time                                       : false 
    215                       when none_match       && none_match == '*'                                                : false 
    216                       when none_match       && !none_match.strip.split(/\s*,\s*/).include?(etag)                : false 
    217                       else unmodified_since || none_match  # validation successful if we get this far and at least one of the header exists 
     212                      when modified_since && !last_response_time = Time.httpdate(modified_since) rescue nil : false 
     213                      when modified_since && last_response_time > Time.now                                  : false 
     214                      when modified_since && mtime > last_response_time                                     : false 
     215                      when none_match     && none_match == '*'                                              : false 
     216                      when none_match     && !none_match.strip.split(/\s*,\s*/).include?(etag)              : false 
     217                      else modified_since || none_match  # validation successful if we get this far and at least one of the header exists 
    218218                      end 
    219219 
  • branches/mongrel-0.4/test/test_conditional.rb

    r282 r300  
    2424    assert_not_nil @etag = res['ETag'] 
    2525    assert_not_nil @last_modified = res['Last-Modified'] 
     26    assert_not_nil @content_length = res['Content-Length'] 
    2627  end 
    2728 
     
    4748  end 
    4849 
    49   # status should be 304 Not Modified when If-Unmodified-Since is the matching Last-Modified date 
    50   def test_not_modified_via_if_unmodified_since 
    51     assert_status_for_get_and_head Net::HTTPNotModified, 'If-Unmodified-Since' => @last_modified 
     50  # status should be 304 Not Modified when If-Modified-Since is the matching Last-Modified date 
     51  def test_not_modified_via_if_modified_since 
     52    assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => @last_modified 
    5253  end 
    5354 
    5455  # status should be 304 Not Modified when If-None-Match is the matching ETag 
    55   # and If-Unmodified-Since is the matching Last-Modified date 
    56   def test_not_modified_via_if_none_match_and_if_unmodified_since 
    57     assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Unmodified-Since' => @last_modified 
     56  # and If-Modified-Since is the matching Last-Modified date 
     57  def test_not_modified_via_if_none_match_and_if_modified_since 
     58    assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => @last_modified 
    5859  end 
    5960 
     
    6162  def test_invalid_if_none_match 
    6263    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid' 
    63     assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Unmodified-Since' => @last_modified 
     64    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Modified-Since' => @last_modified 
    6465  end 
    6566 
    66   # status should be 200 OK when If-Unmodified-Since is invalid 
    67   def test_invalid_if_unmodified_since 
    68     assert_status_for_get_and_head Net::HTTPOK,                           'If-Unmodified-Since' => 'invalid' 
    69     assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Unmodified-Since' => 'invalid' 
     67  # status should be 200 OK when If-Modified-Since is invalid 
     68  def test_invalid_if_modified_since 
     69    assert_status_for_get_and_head Net::HTTPOK,                           'If-Modified-Since' => 'invalid' 
     70    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => 'invalid' 
    7071  end 
    7172 
    72   # status should be 304 Not Modified when If-Unmodified-Since is greater than the Last-Modified header, but less than the system time 
    73   def test_if_unmodified_since_greater_than_last_modified 
     73  # status should be 304 Not Modified when If-Modified-Since is greater than the Last-Modified header, but less than the system time 
     74  def test_if_modified_since_greater_than_last_modified 
    7475    sleep 2 
    7576    last_modified_plus_1 = (Time.httpdate(@last_modified) + 1).httpdate 
    76     assert_status_for_get_and_head Net::HTTPNotModified,                           'If-Unmodified-Since' => last_modified_plus_1 
    77     assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Unmodified-Since' => last_modified_plus_1 
     77    assert_status_for_get_and_head Net::HTTPNotModified,                           'If-Modified-Since' => last_modified_plus_1 
     78    assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_plus_1 
    7879  end 
    7980 
    80   # status should be 200 OK when If-Unmodified-Since is less than the Last-Modified header 
    81   def test_if_unmodified_since_less_than_last_modified 
     81  # status should be 200 OK when If-Modified-Since is less than the Last-Modified header 
     82  def test_if_modified_since_less_than_last_modified 
    8283    last_modified_minus_1 = (Time.httpdate(@last_modified) - 1).httpdate 
    83     assert_status_for_get_and_head Net::HTTPOK,                           'If-Unmodified-Since' => last_modified_minus_1 
    84     assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Unmodified-Since' => last_modified_minus_1 
     84    assert_status_for_get_and_head Net::HTTPOK,                           'If-Modified-Since' => last_modified_minus_1 
     85    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_minus_1 
    8586  end 
    8687 
    87   # status should be 200 OK when If-Unmodified-Since is a date in the future 
    88   def test_future_if_unmodified_since 
     88  # status should be 200 OK when If-Modified-Since is a date in the future 
     89  def test_future_if_modified_since 
    8990    the_future = Time.at(2**31-1).httpdate 
    90     assert_status_for_get_and_head Net::HTTPOK,                           'If-Unmodified-Since' => the_future 
    91     assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Unmodified-Since' => the_future 
     91    assert_status_for_get_and_head Net::HTTPOK,                           'If-Modified-Since' => the_future 
     92    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => the_future 
    9293  end 
    9394 
     
    9596  def test_wildcard_match 
    9697    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*' 
    97     assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Unmodified-Since' => @last_modified 
     98    assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Modified-Since' => @last_modified 
    9899  end 
    99100 
     
    101102 
    102103    # assert the response status is correct for GET and HEAD 
    103     def assert_status_for_get_and_head(status_class, headers = {}) 
     104    def assert_status_for_get_and_head(response_class, headers = {}) 
    104105      %w{ get head }.each do |method| 
    105106        res = @http.send(method, @path, headers) 
    106         assert_kind_of status_class, res 
     107        assert_kind_of response_class, res 
    107108        assert_equal @etag, res['ETag'] 
    108         case status_class 
    109           when Net::HTTPNotModified : assert_nil res['Last-Modified'] 
    110           when Net::HTTPOK          : assert_equal @last_modified, res['Last-Modified'] 
     109        case response_class.to_s 
     110          when 'Net::HTTPNotModified' then 
     111            assert_nil res['Last-Modified'] 
     112            assert_nil res['Content-Length'] 
     113          when 'Net::HTTPOK' then 
     114            assert_equal @last_modified, res['Last-Modified'] 
     115            assert_equal @content_length, res['Content-Length'] 
     116          else 
     117            fail "Incorrect response class: #{response_class}" 
    111118        end 
    112119      end