Changeset 300
- Timestamp:
- 08/03/06 15:49:37 (2 years ago)
- Files:
-
- branches/mongrel-0.4/doc/site/src/default.template (modified) (1 diff)
- branches/mongrel-0.4/doc/site/src/docs/howto.page (modified) (5 diffs)
- branches/mongrel-0.4/doc/site/src/docs/pound.page (modified) (2 diffs)
- branches/mongrel-0.4/doc/site/src/faq.page (modified) (2 diffs)
- branches/mongrel-0.4/doc/site/src/news.page (modified) (1 diff)
- branches/mongrel-0.4/ext/http11/http11.c (modified) (2 diffs)
- branches/mongrel-0.4/lib/mongrel.rb (modified) (6 diffs)
- branches/mongrel-0.4/lib/mongrel/handlers.rb (modified) (2 diffs)
- branches/mongrel-0.4/test/test_conditional.rb (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/mongrel-0.4/doc/site/src/default.template
r260 r300 49 49 <dt>Jun-25-2006</dt> 50 50 <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> 51 60 <h5><a href="{relocatable: news.html}">Mongrel 0.3.13.2 -- RailsConf 2006 Release</a></h5> 52 61 branches/mongrel-0.4/doc/site/src/docs/howto.page
r243 r300 34 34 <dd> 35 35 Configures your Rails environment to what you need. 36 <ul><li><b>Default:</b> de bug</li></ul>36 <ul><li><b>Default:</b> development</li></ul> 37 37 </dd> 38 38 </dl> … … 66 66 <dt>-l, --log (:log_file)</dt> 67 67 <dd> 68 Where to dump log messages in daemon mode. Use an *absolute* path s.68 Where to dump log messages in daemon mode. Use an *absolute* path. 69 69 <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> 71 71 </dd> 72 72 </dl> … … 78 78 <b>stop</b> commands know the Process ID. Use *absolute* paths. 79 79 <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> 81 81 </dd> 82 82 </dl> … … 148 148 reading about right now. Read "Command Line Settings" below 149 149 for 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> 151 151 </dd> 152 152 </dl> … … 175 175 </dl> 176 176 177 <dl> 178 <dt>--prefix uri</dt> 179 <dd> 180 A URI to mount your Rails application at rather than the default 181 /. This URI is stripped off all requests by Rails (not Mongrel) 182 so 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> 192 The user to change to right after creating the listening socket. 193 Use this if you have to bind Mongrel to a low port like port 80, 194 but 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> 204 The 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> 177 209 178 210 h2. Configuration Files branches/mongrel-0.4/doc/site/src/docs/pound.page
r247 r300 60 60 Port 8000 61 61 End 62 End63 Service64 62 BackEnd 65 63 Address 127.0.0.1 66 64 Port 8001 67 65 End 68 End69 Service70 66 BackEnd 71 67 Address 127.0.0.1 … … 87 83 Port 8000 88 84 End 89 End90 Service91 85 BackEnd 92 86 Address 127.0.0.1 93 87 Port 8001 94 88 End 95 End96 Service97 89 BackEnd 98 90 Address 127.0.0.1 branches/mongrel-0.4/doc/site/src/faq.page
r165 r300 62 62 h3. Q: Is it multi-threaded or can it handle concurrent requests? 63 63 64 Mongrel is uses a pool of thread workers to do it's processing. This means that65 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.64 Mongrel uses one thread per request, but it will start closing connections 65 when it gets "overloaded". While Mongrel is processing HTTP requests and 66 sending responses it uses Ruby's threading system (which is more like 67 Java's original green threads and uses select). 68 68 69 69 Camping and Og+Nitro are supposed to be thread safe and work with Mongrel directly. … … 74 74 to Dispatcher.dispatch. This means that everything is threaded right before and 75 75 right after Rails runs. While Rails is running there is only one controller 76 in operation at a time. 76 in operation at a time. This is why people typically have to run a small 77 set of Mongrel processes (a "Pack of Mongrels") to get good concurrency. 78 79 If you have long running actions then you'll most likely have performance 80 problems. You should look at "BackgrounDRB":http://backgroundrb.rubyforge.org/ 81 as a very nice way to offload work to another process so that your Rails 82 app can keep working. 77 83 78 84 branches/mongrel-0.4/doc/site/src/news.page
r266 r300 8 8 h1. Latest News 9 9 10 h2. Jun 30: Mongrel 0.3.13.3 -- Ruby Licensed Now10 h2. Jun 30: Mongrel 0.3.13.3 -- Ruby Licensed Release 11 11 12 12 After talking with various people deep inside the Ruby machine, I've decided 13 13 to release Mongrel Ruby licensed as of 0.3.13.3. This release should make 14 quite a few people happy. 14 quite a few people happy. It also means that contributors will hopefully 15 feel better about their contibutions and people using Mongrel have more freedom. 16 17 This release also fixes a problem with the -B option not actually logging 18 object counts. The object count logging isn't perfect, but some folks use 19 it. 20 21 This release also will print the access log to the screen when you run it in 22 your console. This was requested by a few folks, but I'm not convinced I like 23 it. Try it out and if you do or don't then mention it in the mailing list. 24 25 As usual, do your: 26 27 gem install mongrel 28 29 To get the release, and if it doesn't show up then you have to wait 30 for the ruby gems mirror to sync up. 15 31 16 32 h2. Jun 25: Mongrel 0.3.13.2 -- RailsConf 2006 Release branches/mongrel-0.4/ext/http11/http11.c
r298 r300 40 40 41 41 /** 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." 43 43 44 44 /** Validates the max length of given input and throws an HttpParserError exception if over. */ … … 46 46 47 47 /** 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) 49 49 50 50 branches/mongrel-0.4/lib/mongrel.rb
r296 r300 129 129 130 130 # A frozen format for this is about 15% faster 131 STATUS_FORMAT = "HTTP/1.1 %d %s\r\nCon tent-Length: %d\r\nConnection: close\r\n".freeze131 STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze 132 132 CONTENT_TYPE = "Content-Type".freeze 133 133 LAST_MODIFIED = "Last-Modified".freeze … … 143 143 REMOTE_ADDR="REMOTE_ADDR".freeze 144 144 HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze 145 HTTP_IF_ UNMODIFIED_SINCE="HTTP_IF_UNMODIFIED_SINCE".freeze145 HTTP_IF_MODIFIED_SINCE="HTTP_IF_MODIFIED_SINCE".freeze 146 146 HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze 147 147 REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze … … 382 382 end 383 383 384 def send_status(content_length= nil)384 def send_status(content_length=@body.length) 385 385 if not @status_sent 386 content_length ||= @body.length387 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]]) 388 388 @status_sent = true 389 389 end … … 509 509 # TODO: Find out if anyone actually uses the timeout option since it seems to cause problems on FBSD. 510 510 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 512 514 @classifier = URIClassifier.new 513 515 @host = host … … 622 624 end 623 625 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 624 633 625 634 # Runs the thing. It returns the thread used so you can "join" it. You can also … … 628 637 BasicSocket.do_not_reverse_lookup=true 629 638 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 630 643 @acceptor = Thread.new do 631 644 while true 632 645 begin 633 646 client = @socket.accept 647 client.setsockopt(Socket::SOL_TCP, $tcp_cork_opts[0], $tcp_cork_opts[1]) if $tcp_cork_opts 648 634 649 worker_list = @workers.list 635 636 650 if worker_list.length >= @num_processors 637 651 STDERR.puts "Server overloaded with #{worker_list.length} processors (#@num_processors max). Dropping connection." branches/mongrel-0.4/lib/mongrel/handlers.rb
r268 r300 204 204 etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino] 205 205 206 unmodified_since = request.params[Const::HTTP_IF_UNMODIFIED_SINCE]206 modified_since = request.params[Const::HTTP_IF_MODIFIED_SINCE] 207 207 none_match = request.params[Const::HTTP_IF_NONE_MATCH] 208 208 … … 210 210 # the response would be identical to the last response 211 211 same_response = case 212 when unmodified_since && !last_response_time = Time.httpdate(unmodified_since) rescue nil : false213 when unmodified_since && last_response_time > Time.now: false214 when unmodified_since && mtime > last_response_time: false215 when none_match && none_match == '*': false216 when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag): false217 else unmodified_since || none_match # validation successful if we get this far and at least one of the header exists212 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 218 218 end 219 219 branches/mongrel-0.4/test/test_conditional.rb
r282 r300 24 24 assert_not_nil @etag = res['ETag'] 25 25 assert_not_nil @last_modified = res['Last-Modified'] 26 assert_not_nil @content_length = res['Content-Length'] 26 27 end 27 28 … … 47 48 end 48 49 49 # status should be 304 Not Modified when If- Unmodified-Since is the matching Last-Modified date50 def test_not_modified_via_if_ unmodified_since51 assert_status_for_get_and_head Net::HTTPNotModified, 'If- Unmodified-Since' => @last_modified50 # 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 52 53 end 53 54 54 55 # status should be 304 Not Modified when If-None-Match is the matching ETag 55 # and If- Unmodified-Since is the matching Last-Modified date56 def test_not_modified_via_if_none_match_and_if_ unmodified_since57 assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If- Unmodified-Since' => @last_modified56 # 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 58 59 end 59 60 … … 61 62 def test_invalid_if_none_match 62 63 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_modified64 assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Modified-Since' => @last_modified 64 65 end 65 66 66 # status should be 200 OK when If- Unmodified-Since is invalid67 def test_invalid_if_ unmodified_since68 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' 70 71 end 71 72 72 # status should be 304 Not Modified when If- Unmodified-Since is greater than the Last-Modified header, but less than the system time73 def test_if_ unmodified_since_greater_than_last_modified73 # 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 74 75 sleep 2 75 76 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_177 assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If- Unmodified-Since' => last_modified_plus_177 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 78 79 end 79 80 80 # status should be 200 OK when If- Unmodified-Since is less than the Last-Modified header81 def test_if_ unmodified_since_less_than_last_modified81 # 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 82 83 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_184 assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If- Unmodified-Since' => last_modified_minus_184 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 85 86 end 86 87 87 # status should be 200 OK when If- Unmodified-Since is a date in the future88 def test_future_if_ unmodified_since88 # status should be 200 OK when If-Modified-Since is a date in the future 89 def test_future_if_modified_since 89 90 the_future = Time.at(2**31-1).httpdate 90 assert_status_for_get_and_head Net::HTTPOK, 'If- Unmodified-Since' => the_future91 assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If- Unmodified-Since' => the_future91 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 92 93 end 93 94 … … 95 96 def test_wildcard_match 96 97 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_modified98 assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Modified-Since' => @last_modified 98 99 end 99 100 … … 101 102 102 103 # 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 = {}) 104 105 %w{ get head }.each do |method| 105 106 res = @http.send(method, @path, headers) 106 assert_kind_of status_class, res107 assert_kind_of response_class, res 107 108 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}" 111 118 end 112 119 end
