mongrel 0.3.11 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. data/Rakefile +4 -2
  2. data/bin/mongrel_rails +65 -101
  3. data/bin/mongrel_rails_service +1 -1
  4. data/bin/mongrel_rails_svc +131 -115
  5. data/doc/rdoc/classes/Class.html +197 -0
  6. data/doc/rdoc/classes/Class.src/M000001.html +24 -0
  7. data/doc/rdoc/classes/Class.src/M000002.html +62 -0
  8. data/doc/rdoc/classes/Class.src/M000003.html +21 -0
  9. data/doc/rdoc/classes/Class.src/M000004.html +20 -0
  10. data/doc/rdoc/classes/IO.html +170 -0
  11. data/doc/rdoc/classes/IO.src/M000005.html +19 -0
  12. data/doc/rdoc/classes/IO.src/M000006.html +19 -0
  13. data/doc/rdoc/classes/Kernel.html +159 -0
  14. data/doc/rdoc/classes/Kernel.src/M000025.html +19 -0
  15. data/doc/rdoc/classes/Kernel.src/M000026.html +25 -0
  16. data/doc/rdoc/classes/Mongrel.html +181 -0
  17. data/doc/rdoc/classes/Mongrel/CGIWrapper.html +383 -0
  18. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000090.html +24 -0
  19. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000091.html +47 -0
  20. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000092.html +34 -0
  21. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000093.html +27 -0
  22. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000094.html +25 -0
  23. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000095.html +18 -0
  24. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000096.html +18 -0
  25. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000097.html +18 -0
  26. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000098.html +19 -0
  27. data/doc/rdoc/classes/Mongrel/Camping.html +177 -0
  28. data/doc/rdoc/classes/Mongrel/Camping.src/M000048.html +22 -0
  29. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.html +165 -0
  30. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/M000049.html +18 -0
  31. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/M000050.html +27 -0
  32. data/doc/rdoc/classes/Mongrel/Command.html +119 -0
  33. data/doc/rdoc/classes/Mongrel/Command/Base.html +337 -0
  34. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000029.html +24 -0
  35. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000030.html +41 -0
  36. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000031.html +18 -0
  37. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000032.html +18 -0
  38. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000033.html +18 -0
  39. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000034.html +22 -0
  40. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000035.html +18 -0
  41. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000036.html +18 -0
  42. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000037.html +18 -0
  43. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000038.html +18 -0
  44. data/doc/rdoc/classes/Mongrel/Command/Registry.html +192 -0
  45. data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000039.html +20 -0
  46. data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000040.html +25 -0
  47. data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000041.html +46 -0
  48. data/doc/rdoc/classes/Mongrel/Configurator.html +563 -0
  49. data/doc/rdoc/classes/Mongrel/Configurator.src/M000099.html +24 -0
  50. data/doc/rdoc/classes/Mongrel/Configurator.src/M000100.html +23 -0
  51. data/doc/rdoc/classes/Mongrel/Configurator.src/M000101.html +18 -0
  52. data/doc/rdoc/classes/Mongrel/Configurator.src/M000102.html +32 -0
  53. data/doc/rdoc/classes/Mongrel/Configurator.src/M000103.html +19 -0
  54. data/doc/rdoc/classes/Mongrel/Configurator.src/M000104.html +31 -0
  55. data/doc/rdoc/classes/Mongrel/Configurator.src/M000105.html +33 -0
  56. data/doc/rdoc/classes/Mongrel/Configurator.src/M000106.html +18 -0
  57. data/doc/rdoc/classes/Mongrel/Configurator.src/M000107.html +25 -0
  58. data/doc/rdoc/classes/Mongrel/Configurator.src/M000108.html +19 -0
  59. data/doc/rdoc/classes/Mongrel/Configurator.src/M000109.html +22 -0
  60. data/doc/rdoc/classes/Mongrel/Configurator.src/M000110.html +21 -0
  61. data/doc/rdoc/classes/Mongrel/Configurator.src/M000111.html +18 -0
  62. data/doc/rdoc/classes/Mongrel/Configurator.src/M000112.html +27 -0
  63. data/doc/rdoc/classes/Mongrel/Configurator.src/M000113.html +46 -0
  64. data/doc/rdoc/classes/Mongrel/Configurator.src/M000114.html +18 -0
  65. data/doc/rdoc/classes/Mongrel/Const.html +286 -0
  66. data/doc/rdoc/classes/Mongrel/DirHandler.html +288 -0
  67. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000058.html +20 -0
  68. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000059.html +42 -0
  69. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000060.html +40 -0
  70. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000061.html +51 -0
  71. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000062.html +40 -0
  72. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000063.html +18 -0
  73. data/doc/rdoc/classes/Mongrel/Error404Handler.html +171 -0
  74. data/doc/rdoc/classes/Mongrel/Error404Handler.src/M000115.html +18 -0
  75. data/doc/rdoc/classes/Mongrel/Error404Handler.src/M000116.html +18 -0
  76. data/doc/rdoc/classes/Mongrel/HeaderOut.html +185 -0
  77. data/doc/rdoc/classes/Mongrel/HeaderOut.src/M000072.html +18 -0
  78. data/doc/rdoc/classes/Mongrel/HeaderOut.src/M000073.html +18 -0
  79. data/doc/rdoc/classes/Mongrel/HttpHandler.html +152 -0
  80. data/doc/rdoc/classes/Mongrel/HttpHandler.src/M000074.html +17 -0
  81. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.html +169 -0
  82. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/M000027.html +18 -0
  83. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/M000028.html +17 -0
  84. data/doc/rdoc/classes/Mongrel/HttpParser.html +271 -0
  85. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000051.html +28 -0
  86. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000052.html +29 -0
  87. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000053.html +29 -0
  88. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000054.html +41 -0
  89. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000055.html +27 -0
  90. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000056.html +27 -0
  91. data/doc/rdoc/classes/Mongrel/HttpParser.src/M000057.html +28 -0
  92. data/doc/rdoc/classes/Mongrel/HttpRequest.html +222 -0
  93. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000117.html +28 -0
  94. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000118.html +20 -0
  95. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000119.html +20 -0
  96. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000120.html +32 -0
  97. data/doc/rdoc/classes/Mongrel/HttpResponse.html +371 -0
  98. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000075.html +26 -0
  99. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000076.html +20 -0
  100. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000077.html +25 -0
  101. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000078.html +22 -0
  102. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000079.html +22 -0
  103. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000080.html +23 -0
  104. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000081.html +18 -0
  105. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000082.html +20 -0
  106. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000083.html +18 -0
  107. data/doc/rdoc/classes/Mongrel/HttpServer.html +360 -0
  108. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000064.html +24 -0
  109. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000065.html +65 -0
  110. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000066.html +24 -0
  111. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000067.html +60 -0
  112. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000068.html +28 -0
  113. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000069.html +18 -0
  114. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000070.html +22 -0
  115. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000071.html +18 -0
  116. data/doc/rdoc/classes/Mongrel/Rails.html +112 -0
  117. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.html +223 -0
  118. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000042.html +35 -0
  119. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000043.html +25 -0
  120. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000044.html +32 -0
  121. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.html +250 -0
  122. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000045.html +22 -0
  123. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000046.html +48 -0
  124. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000047.html +23 -0
  125. data/doc/rdoc/classes/Mongrel/StopServer.html +117 -0
  126. data/doc/rdoc/classes/Mongrel/URIClassifier.html +301 -0
  127. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000084.html +18 -0
  128. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000085.html +18 -0
  129. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000086.html +39 -0
  130. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000087.html +51 -0
  131. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000088.html +36 -0
  132. data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000089.html +83 -0
  133. data/doc/rdoc/classes/MongrelDbg.html +209 -0
  134. data/doc/rdoc/classes/MongrelDbg.src/M000020.html +19 -0
  135. data/doc/rdoc/classes/MongrelDbg.src/M000021.html +20 -0
  136. data/doc/rdoc/classes/MongrelDbg.src/M000022.html +22 -0
  137. data/doc/rdoc/classes/MongrelDbg.src/M000023.html +21 -0
  138. data/doc/rdoc/classes/MongrelDbg.src/M000024.html +18 -0
  139. data/doc/rdoc/classes/ObjectTracker.html +176 -0
  140. data/doc/rdoc/classes/ObjectTracker.src/M000016.html +22 -0
  141. data/doc/rdoc/classes/ObjectTracker.src/M000017.html +18 -0
  142. data/doc/rdoc/classes/ObjectTracker.src/M000018.html +18 -0
  143. data/doc/rdoc/classes/ObjectTracker.src/M000019.html +46 -0
  144. data/doc/rdoc/classes/RequestLog.html +113 -0
  145. data/doc/rdoc/classes/RequestLog/Files.html +144 -0
  146. data/doc/rdoc/classes/RequestLog/Files.src/M000121.html +19 -0
  147. data/doc/rdoc/classes/RequestLog/Objects.html +144 -0
  148. data/doc/rdoc/classes/RequestLog/Objects.src/M000122.html +19 -0
  149. data/doc/rdoc/classes/RequestLog/Params.html +144 -0
  150. data/doc/rdoc/classes/RequestLog/Params.src/M000123.html +19 -0
  151. data/doc/rdoc/classes/Stats.html +306 -0
  152. data/doc/rdoc/classes/Stats.src/M000009.html +19 -0
  153. data/doc/rdoc/classes/Stats.src/M000010.html +23 -0
  154. data/doc/rdoc/classes/Stats.src/M000011.html +26 -0
  155. data/doc/rdoc/classes/Stats.src/M000012.html +18 -0
  156. data/doc/rdoc/classes/Stats.src/M000013.html +18 -0
  157. data/doc/rdoc/classes/Stats.src/M000014.html +19 -0
  158. data/doc/rdoc/classes/Stats.src/M000015.html +20 -0
  159. data/doc/rdoc/classes/TCPServer.html +173 -0
  160. data/doc/rdoc/classes/TCPServer.src/M000007.html +19 -0
  161. data/doc/rdoc/created.rid +1 -0
  162. data/doc/rdoc/files/COPYING.html +756 -0
  163. data/doc/rdoc/files/LICENSE.html +756 -0
  164. data/doc/rdoc/files/README.html +302 -0
  165. data/doc/rdoc/files/ext/http11/http11_c.html +101 -0
  166. data/doc/rdoc/files/lib/mongrel/camping_rb.html +108 -0
  167. data/doc/rdoc/files/lib/mongrel/cgi_rb.html +108 -0
  168. data/doc/rdoc/files/lib/mongrel/command_rb.html +111 -0
  169. data/doc/rdoc/files/lib/mongrel/debug_rb.html +110 -0
  170. data/doc/rdoc/files/lib/mongrel/handlers_rb.html +109 -0
  171. data/doc/rdoc/files/lib/mongrel/init_rb.html +109 -0
  172. data/doc/rdoc/files/lib/mongrel/rails_rb.html +111 -0
  173. data/doc/rdoc/files/lib/mongrel/stats_rb.html +117 -0
  174. data/doc/rdoc/files/lib/mongrel/tcphack_rb.html +109 -0
  175. data/doc/rdoc/files/lib/mongrel_rb.html +118 -0
  176. data/doc/rdoc/fr_class_index.html +60 -0
  177. data/doc/rdoc/fr_file_index.html +40 -0
  178. data/doc/rdoc/fr_method_index.html +149 -0
  179. data/doc/rdoc/index.html +24 -0
  180. data/doc/rdoc/rdoc-style.css +208 -0
  181. data/examples/builder.rb +29 -0
  182. data/examples/camping/blog.rb +11 -2
  183. data/examples/simpletest.rb +20 -7
  184. data/ext/http11/http11.c +71 -14
  185. data/ext/http11/http11_parser.c +27 -24
  186. data/ext/http11/http11_parser.h +2 -1
  187. data/lib/http11.bundle +0 -0
  188. data/lib/mongrel.rb +498 -135
  189. data/lib/mongrel/command.rb +1 -1
  190. data/lib/mongrel/debug.rb +259 -0
  191. data/lib/mongrel/handlers.rb +76 -22
  192. data/lib/mongrel/rails.rb +165 -72
  193. data/lib/mongrel/stats.rb +71 -0
  194. data/test/test_configurator.rb +67 -0
  195. data/test/test_debug.rb +31 -0
  196. data/test/test_http11.rb +16 -0
  197. data/test/test_response.rb +5 -0
  198. data/test/test_stats.rb +28 -0
  199. metadata +224 -2
@@ -15,7 +15,7 @@ module Mongrel
15
15
  # user's bidding.
16
16
  module Base
17
17
 
18
- attr_reader :valid, :done_validating
18
+ attr_reader :valid, :done_validating, :original_args
19
19
 
20
20
  # Called by the implemented command to set the options for that command.
21
21
  # Every option has a short and long version, a description, a variable to
@@ -0,0 +1,259 @@
1
+ require 'logger'
2
+ require 'set'
3
+ require 'socket'
4
+
5
+ $mongrel_debugging=true
6
+
7
+ module MongrelDbg
8
+ SETTINGS = { :tracing => {}}
9
+ LOGGING = { }
10
+
11
+ def MongrelDbg::configure(log_dir = "log/mongrel_debug")
12
+ Dir.mkdir(log_dir) if not File.exist?(log_dir)
13
+ @log_dir = log_dir
14
+ end
15
+
16
+
17
+ def MongrelDbg::trace(target, message)
18
+ if SETTINGS[:tracing][target] and LOGGING[target]
19
+ LOGGING[target].log(Logger::DEBUG, message)
20
+ end
21
+ end
22
+
23
+ def MongrelDbg::begin_trace(target)
24
+ SETTINGS[:tracing][target] = true
25
+ if not LOGGING[target]
26
+ LOGGING[target] = Logger.new(File.join(@log_dir, "#{target.to_s}.log"))
27
+ end
28
+ MongrelDbg::trace(target, "TRACING ON #{Time.now}")
29
+ end
30
+
31
+ def MongrelDbg::end_trace(target)
32
+ SETTINGS[:tracing][target] = false
33
+ MongrelDbg::trace(target, "TRACING OFF #{Time.now}")
34
+ LOGGING[target].close
35
+ LOGGING[target] = nil
36
+ end
37
+
38
+ def MongrelDbg::tracing?(target)
39
+ SETTINGS[:tracing][target]
40
+ end
41
+ end
42
+
43
+
44
+ module ObjectTracker
45
+ @active_objects = nil
46
+ @live_object_tracking = true
47
+
48
+ def ObjectTracker.configure
49
+ @active_objects = Set.new
50
+
51
+ ObjectSpace.each_object do |obj|
52
+ @active_objects << obj.object_id
53
+ end
54
+ end
55
+
56
+
57
+ def ObjectTracker.start
58
+ @live_object_tracking = true
59
+ end
60
+
61
+ def ObjectTracker.stop
62
+ @live_object_tracking = false
63
+ end
64
+
65
+ def ObjectTracker.sample
66
+ Class.stopit do
67
+ ospace = Set.new
68
+ counts = {}
69
+
70
+ # Strings can't be tracked easily and are so numerous that they drown out all else
71
+ # so we just ignore them in the counts.
72
+ ObjectSpace.each_object do |obj|
73
+ if not obj.kind_of? String
74
+ ospace << obj.object_id
75
+ counts[obj.class] ||= 0
76
+ counts[obj.class] += 1
77
+ end
78
+ end
79
+
80
+ dead_objects = @active_objects - ospace
81
+ new_objects = ospace - @active_objects
82
+ live_objects = ospace & @active_objects
83
+
84
+ MongrelDbg::trace(:objects, "COUNTS: #{dead_objects.length},#{new_objects.length},#{live_objects.length}")
85
+
86
+ if MongrelDbg::tracing? :objects
87
+ top_20 = counts.sort{|a,b| b[1] <=> a[1]}[0..20]
88
+ MongrelDbg::trace(:objects,"TOP 20: #{top_20.inspect}")
89
+ end
90
+
91
+ @active_objects = live_objects + new_objects
92
+
93
+ [@active_objects, top_20]
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ $open_files = {}
100
+
101
+ class IO
102
+ alias_method :orig_open, :open
103
+ alias_method :orig_close, :close
104
+
105
+ def open(*arg, &blk)
106
+ $open_files[self] = args.inspect
107
+ orig_open(*arg,&blk)
108
+ end
109
+
110
+ def close(*arg,&blk)
111
+ $open_files.delete self
112
+ orig_close(*arg,&blk)
113
+ end
114
+ end
115
+
116
+
117
+ module Kernel
118
+ alias_method :orig_open, :open
119
+
120
+ def open(*arg, &blk)
121
+ $open_files[self] = arg[0]
122
+ orig_open(*arg,&blk)
123
+ end
124
+
125
+ def log_open_files
126
+ Class.stopit do
127
+ open_counts = {}
128
+ $open_files.each do |f,args|
129
+ open_counts[args] ||= 0
130
+ open_counts[args] += 1
131
+ end
132
+ MongrelDbg::trace(:files, open_counts.to_yaml)
133
+ end
134
+ end
135
+ end
136
+
137
+
138
+
139
+ class Class
140
+ alias_method :orig_new, :new
141
+
142
+ @@count = 0
143
+ @@stopit = false
144
+ @@class_caller_count = Hash.new{|hash,key| hash[key] = Hash.new(0)}
145
+
146
+ def new(*arg,&blk)
147
+ unless @@stopit
148
+ @@stopit = true
149
+ @@count += 1
150
+ @@class_caller_count[self][caller.join("\n\t")] += 1
151
+ @@stopit = false
152
+ end
153
+ orig_new(*arg,&blk)
154
+ end
155
+
156
+
157
+ def Class.report_object_creations(out=$stderr, more_than=20)
158
+ Class.stopit do
159
+ out.puts "Number of objects created = #{@@count}"
160
+
161
+ total = Hash.new(0)
162
+
163
+ @@class_caller_count.each_key do |klass|
164
+ caller_count = @@class_caller_count[klass]
165
+ caller_count.each_value do |count|
166
+ total[klass] += count
167
+ end
168
+ end
169
+
170
+ klass_list = total.keys.sort{|klass_a, klass_b|
171
+ a = total[klass_a]
172
+ b = total[klass_b]
173
+ if a != b
174
+ -1* (a <=> b)
175
+ else
176
+ klass_a.to_s <=> klass_b.to_s
177
+ end
178
+ }
179
+
180
+ below_count = 0
181
+
182
+ klass_list.each do |klass|
183
+ below_calls = 0
184
+ if total[klass] > more_than
185
+ out.puts "#{total[klass]}\t#{klass} objects created."
186
+ caller_count = @@class_caller_count[ klass]
187
+ caller_count.keys.sort_by{|call| -1*caller_count[call]}.each do |call|
188
+ if caller_count[call] > more_than
189
+ out.puts "\t** #{caller_count[call]} #{klass} objects AT:"
190
+ out.puts "\t#{call}\n\n"
191
+ else
192
+ below_calls += 1
193
+ end
194
+ end
195
+ out.puts "\t#{below_calls} more objects had calls less that #{more_than} limit.\n\n" if below_calls > 0
196
+ else
197
+ below_count += 1
198
+ end
199
+ end
200
+
201
+ out.puts "\t** #{below_count} More objects were created but the count was below the #{more_than} limit." if below_count > 0
202
+ end
203
+ end
204
+
205
+ def Class.reset_object_creations
206
+ Class.stopit do
207
+ @@count = 0
208
+ @@class_caller_count = Hash.new{|hash,key| hash[key] = Hash.new(0)}
209
+ end
210
+ end
211
+
212
+ def Class.stopit
213
+ @@stopit = true
214
+ yield
215
+ @@stopit = false
216
+ end
217
+
218
+ end
219
+
220
+
221
+ module RequestLog
222
+ class Files < GemPlugin::Plugin "/handlers"
223
+ include Mongrel::HttpHandlerPlugin
224
+
225
+ def process(request, response)
226
+ MongrelDbg::trace(:files, "#{Time.now} FILES OPEN BEFORE REQUEST #{request.params['PATH_INFO']}")
227
+ log_open_files
228
+ end
229
+
230
+ end
231
+
232
+ class Objects < GemPlugin::Plugin "/handlers"
233
+ include Mongrel::HttpHandlerPlugin
234
+
235
+ def process(request, response)
236
+ MongrelDbg::trace(:objects, "#{Time.now} OBJECT STATS BEFORE REQUEST #{request.params['PATH_INFO']}")
237
+ ObjectTracker.sample
238
+ end
239
+
240
+ end
241
+
242
+
243
+ class Params < GemPlugin::Plugin "/handlers"
244
+ include Mongrel::HttpHandlerPlugin
245
+
246
+ def process(request, response)
247
+ MongrelDbg::trace(:rails, "#{Time.now} REQUEST #{request.params['PATH_INFO']}")
248
+ MongrelDbg::trace(:rails, request.params.to_yaml)
249
+ end
250
+
251
+ end
252
+ end
253
+
254
+
255
+ END {
256
+ open("log/mongrel_debug/object_tracking.log", "w") {|f| Class.report_object_creations(f) }
257
+ MongrelDbg::trace(:files, "FILES OPEN AT EXIT")
258
+ log_open_files
259
+ }
@@ -1,3 +1,11 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'sendfile'
4
+ $mongrel_has_sendfile = true
5
+ STDERR.puts "** You have sendfile installed, will use that to serve files."
6
+ rescue Object
7
+ $mongrel_has_sendfile = false
8
+ end
1
9
 
2
10
  module Mongrel
3
11
 
@@ -5,12 +13,35 @@ module Mongrel
5
13
  # just the minimum necessary for you to handle a request and shoot back
6
14
  # a response. Look at the HttpRequest and HttpResponse objects for how
7
15
  # to use them.
16
+ #
17
+ # This is used for very simple handlers that don't require much to operate.
18
+ # More extensive plugins or those you intend to distribute as GemPlugins
19
+ # should be implemented using the HttpHandlerPlugin mixin.
20
+ #
8
21
  class HttpHandler
22
+
9
23
  def process(request, response)
10
24
  end
11
25
  end
12
26
 
13
27
 
28
+ # This is used when your handler is implemented as a GemPlugin.
29
+ # The plugin always takes an options hash which you can modify
30
+ # and then access later. They are stored by default for
31
+ # the process method later.
32
+ module HttpHandlerPlugin
33
+ attr_reader :options
34
+
35
+ def initialize(options={})
36
+ @options = options
37
+ end
38
+
39
+ def process(request, response)
40
+ end
41
+
42
+ end
43
+
44
+
14
45
  # The server normally returns a 404 response if an unknown URI is requested, but it
15
46
  # also returns a lame empty message. This lets you do a 404 response
16
47
  # with a custom message for special URIs.
@@ -53,6 +84,7 @@ module Mongrel
53
84
  ".txt" => "text/plain"
54
85
  }
55
86
 
87
+ ONLY_HEAD_GET="Only HEAD and GET allowed.".freeze
56
88
 
57
89
  attr_reader :path
58
90
 
@@ -103,7 +135,7 @@ module Mongrel
103
135
 
104
136
  if @listing_allowed
105
137
  response.start(200) do |head,out|
106
- head['Content-Type'] = "text/html"
138
+ head[Const::CONTENT_TYPE] = "text/html"
107
139
  out << "<html><head><title>Directory Listing</title></head><body>"
108
140
  Dir.entries(dir).each do |child|
109
141
  next if child == "."
@@ -126,20 +158,40 @@ module Mongrel
126
158
 
127
159
  # Sends the contents of a file back to the user. Not terribly efficient since it's
128
160
  # opening and closing the file for each read.
129
- def send_file(req, response)
130
- response.start(200) do |head,out|
131
- # set the mime type from our map based on the ending
132
- dot_at = req.rindex(".")
133
- if dot_at
134
- ext = req[dot_at .. -1]
135
- if MIME_TYPES[ext]
136
- head['Content-Type'] = MIME_TYPES[ext]
137
- end
161
+ def send_file(req, response, header_only=false)
162
+
163
+ # first we setup the headers and status then we do a very fast send on the socket directly
164
+ response.status = 200
165
+
166
+ # set the mime type from our map based on the ending
167
+ dot_at = req.rindex(".")
168
+ if dot_at
169
+ ext = req[dot_at .. -1]
170
+ if MIME_TYPES[ext]
171
+ stat = File.stat(req)
172
+ response.header[Const::CONTENT_TYPE] = MIME_TYPES[ext]
173
+ # TODO: Confirm this works for rfc 1123
174
+ response.header[Const::LAST_MODIFIED] = HttpServer.httpdate(stat.mtime)
175
+ # TODO that this is a valid way to calculate an etag
176
+ response.header[Const::ETAG] = Const::ETAG_FORMAT % [stat.mtime.to_i, stat.size, stat.ino]
138
177
  end
178
+ end
139
179
 
140
- open(req, "rb") do |f|
141
- out.write(f.read)
142
- end
180
+ response.send_status(File.size(req))
181
+ response.send_header
182
+
183
+ if not header_only
184
+ begin
185
+ if $mongrel_has_sendfile
186
+ File.open(req, "rb") { |f| response.socket.sendfile(f) }
187
+ else
188
+ File.open(req, "rb") { |f| response.socket.write(f.read) }
189
+ end
190
+ rescue EOFError,Errno::ECONNRESET,Errno::EPIPE
191
+ # ignore these since it means the client closed off early
192
+ end
193
+ else
194
+ response.send_body # should send nothing
143
195
  end
144
196
  end
145
197
 
@@ -147,7 +199,8 @@ module Mongrel
147
199
  # Process the request to either serve a file or a directory listing
148
200
  # if allowed (based on the listing_allowed paramter to the constructor).
149
201
  def process(request, response)
150
- req = can_serve request.params['PATH_INFO']
202
+ req_method = request.params[Const::REQUEST_METHOD] || Const::GET
203
+ req = can_serve request.params[Const::PATH_INFO]
151
204
  if not req
152
205
  # not found, return a 404
153
206
  response.start(404) do |head,out|
@@ -156,16 +209,17 @@ module Mongrel
156
209
  else
157
210
  begin
158
211
  if File.directory? req
159
- send_dir_listing(request.params["REQUEST_URI"],req, response)
160
- else
161
- send_file(req, response)
212
+ send_dir_listing(request.params[Const::REQUEST_URI],req, response)
213
+ elsif req_method == Const::HEAD
214
+ send_file(req, response, true)
215
+ elsif req_method == Const::GET
216
+ send_file(req, response, false)
217
+ else
218
+ response.start(403) {|head,out| out.write(ONLY_HEAD_GET) }
162
219
  end
163
220
  rescue => details
164
- response.reset
165
- response.start(403) do |head,out|
166
- out << "Error accessing file: #{details}"
167
- out << details.backtrace.join("\n")
168
- end
221
+ STDERR.puts "Error accessing file #{req}: #{details}"
222
+ STDERR.puts details.backtrace.join("\n")
169
223
  end
170
224
  end
171
225
  end
@@ -1,85 +1,178 @@
1
1
  require 'mongrel'
2
2
  require 'cgi'
3
3
 
4
- # Implements a handler that can run Rails and serve files out of the
5
- # Rails application's public directory. This lets you run your Rails
6
- # application with Mongrel during development and testing, then use it
7
- # also in production behind a server that's better at serving the
8
- # static files.
9
- #
10
- # The RailsHandler takes a mime_map parameter which is a simple suffix=mimetype
11
- # mapping that it should add to the list of valid mime types.
12
- #
13
- # It also supports page caching directly and will try to resolve a request
14
- # in the following order:
15
- #
16
- # * If the requested exact PATH_INFO exists as a file then serve it.
17
- # * If it exists at PATH_INFO+".html" exists then serve that.
18
- # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
19
- #
20
- # This means that if you are using page caching it will actually work with Mongrel
21
- # and you should see a decent speed boost (but not as fast as if you use lighttpd).
22
- #
23
- # An additional feature you can use is
24
- class RailsHandler < Mongrel::HttpHandler
25
- attr_reader :files
26
- attr_reader :guard
27
-
28
- def initialize(dir, mime_map = {})
29
- @files = Mongrel::DirHandler.new(dir,false)
30
- @guard = Mutex.new
4
+ module Mongrel
5
+ module Rails
31
6
 
32
- # register the requested mime types
33
- mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
34
- end
35
-
36
- # Attempts to resolve the request as follows:
37
- #
38
- #
39
- # * If the requested exact PATH_INFO exists as a file then serve it.
40
- # * If it exists at PATH_INFO+".html" exists then serve that.
41
- # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
42
- def process(request, response)
43
- return if response.socket.closed?
44
-
45
- path_info = request.params[Mongrel::Const::PATH_INFO]
46
- page_cached = request.params[Mongrel::Const::PATH_INFO] + ".html"
47
-
48
- if @files.can_serve(path_info)
49
- # File exists as-is so serve it up
50
- @files.process(request,response)
51
- elsif @files.can_serve(page_cached)
52
- # possible cached page, serve it up
53
- request.params[Mongrel::Const::PATH_INFO] = page_cached
54
- @files.process(request,response)
55
- else
56
- begin
57
- cgi = Mongrel::CGIWrapper.new(request, response)
58
- cgi.handler = self
59
7
 
8
+ # Implements a handler that can run Rails and serve files out of the
9
+ # Rails application's public directory. This lets you run your Rails
10
+ # application with Mongrel during development and testing, then use it
11
+ # also in production behind a server that's better at serving the
12
+ # static files.
13
+ #
14
+ # The RailsHandler takes a mime_map parameter which is a simple suffix=mimetype
15
+ # mapping that it should add to the list of valid mime types.
16
+ #
17
+ # It also supports page caching directly and will try to resolve a request
18
+ # in the following order:
19
+ #
20
+ # * If the requested exact PATH_INFO exists as a file then serve it.
21
+ # * If it exists at PATH_INFO+".html" exists then serve that.
22
+ # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
23
+ #
24
+ # This means that if you are using page caching it will actually work with Mongrel
25
+ # and you should see a decent speed boost (but not as fast as if you use lighttpd).
26
+ #
27
+ # An additional feature you can use is
28
+ class RailsHandler < Mongrel::HttpHandler
29
+ attr_reader :files
30
+ attr_reader :guard
31
+
32
+ def initialize(dir, mime_map = {})
33
+ @files = Mongrel::DirHandler.new(dir,false)
34
+ @guard = Mutex.new
35
+
36
+ # register the requested mime types
37
+ mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
38
+ end
39
+
40
+ # Attempts to resolve the request as follows:
41
+ #
42
+ #
43
+ # * If the requested exact PATH_INFO exists as a file then serve it.
44
+ # * If it exists at PATH_INFO+".html" exists then serve that.
45
+ # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
46
+ def process(request, response)
47
+ return if response.socket.closed?
48
+
49
+ path_info = request.params[Mongrel::Const::PATH_INFO]
50
+ page_cached = request.params[Mongrel::Const::PATH_INFO] + ".html"
51
+
52
+ if @files.can_serve(path_info)
53
+ # File exists as-is so serve it up
54
+ @files.process(request,response)
55
+ elsif @files.can_serve(page_cached)
56
+ # possible cached page, serve it up
57
+ request.params[Mongrel::Const::PATH_INFO] = page_cached
58
+ @files.process(request,response)
59
+ else
60
+ begin
61
+ cgi = Mongrel::CGIWrapper.new(request, response)
62
+ cgi.handler = self
63
+
64
+ @guard.synchronize do
65
+ # Rails is not thread safe so must be run entirely within synchronize
66
+ Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
67
+ end
68
+
69
+ # This finalizes the output using the proper HttpResponse way
70
+ cgi.out {""}
71
+ rescue Errno::EPIPE
72
+ # ignored
73
+ rescue Object => rails_error
74
+ STDERR.puts "Error calling Dispatcher.dispatch #{rails_error.inspect}"
75
+ STDERR.puts rails_error.backtrace.join("\n")
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ # Does the internal reload for Rails. It might work for most cases, but
82
+ # sometimes you get exceptions. In that case just do a real restart.
83
+ def reload!
60
84
  @guard.synchronize do
61
- # Rails is not thread safe so must be run entirely within synchronize
62
- Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
85
+ $".replace $orig_dollar_quote
86
+ GC.start
87
+ Dispatcher.reset_application!
88
+ ActionController::Routing::Routes.reload
63
89
  end
64
-
65
- # This finalizes the output using the proper HttpResponse way
66
- cgi.out {""}
67
- rescue Errno::EPIPE
68
- # ignored
69
- rescue Object => rails_error
70
- STDERR.puts "Error calling Dispatcher.dispatch #{rails_error.inspect}"
71
- STDERR.puts rails_error.backtrace.join("\n")
72
90
  end
73
91
  end
74
- end
75
-
76
92
 
77
- def reload!
78
- @guard.synchronize do
79
- $".replace $orig_dollar_quote
80
- GC.start
81
- Dispatcher.reset_application!
82
- ActionController::Routing::Routes.reload
93
+ # Creates Rails specific configuration options for people to use
94
+ # instead of the base Configurator.
95
+ class RailsConfigurator < Mongrel::Configurator
96
+
97
+ # Creates a single rails handler and returns it so you
98
+ # can add it to a uri. You can actually attach it to
99
+ # as many URIs as you want, but this returns the
100
+ # same RailsHandler for each call.
101
+ #
102
+ # Requires the following options:
103
+ #
104
+ # * :docroot => The public dir to serve from.
105
+ # * :environment => Rails environment to use.
106
+ # * :cwd => The change to working directory
107
+ #
108
+ # And understands the following optional settings:
109
+ #
110
+ # * :mime => A map of mime types.
111
+ #
112
+ # Because of how Rails is designed you can only have
113
+ # one installed per Ruby interpreter (talk to them
114
+ # about thread safety). Because of this the first
115
+ # time you call this function it does all the config
116
+ # needed to get your rails working. After that
117
+ # it returns the one handler you've configured.
118
+ # This lets you attach Rails to any URI (and mulitple)
119
+ # you want, but still protects you from threads destroying
120
+ # your handler.
121
+ def rails(options={})
122
+
123
+ return @rails_handler if @rails_handler
124
+
125
+ ops = resolve_defaults(options)
126
+
127
+ # fix up some defaults
128
+ ops[:environment] ||= "development"
129
+ ops[:docroot] ||= "public"
130
+ ops[:mime] ||= {}
131
+
132
+
133
+ $orig_dollar_quote = $".clone
134
+ ENV['RAILS_ENV'] = ops[:environment]
135
+ require "#{ops[:cwd]}/config/environment"
136
+ require 'dispatcher'
137
+ require 'mongrel/rails'
138
+
139
+ @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime])
140
+ end
141
+
142
+
143
+ # Reloads rails. This isn't too reliable really, but
144
+ # should work for most minimal reload purposes. Only reliable
145
+ # way it so stop then start the process.
146
+ def reload!
147
+ if not @rails_handler
148
+ raise "Rails was not configured. Read the docs for RailsConfigurator."
149
+ end
150
+
151
+ log "Reloading rails..."
152
+ @rails_handler.reload!
153
+ log "Done reloading rails."
154
+
155
+ end
156
+
157
+ # Takes the exact same configuration as Mongrel::Configurator (and actually calls that)
158
+ # but sets up the additional HUP handler to call reload!.
159
+ def setup_rails_signals(options={})
160
+ ops = resolve_defaults(options)
161
+
162
+ if RUBY_PLATFORM !~ /mswin/
163
+ setup_signals(options)
164
+
165
+ # rails reload
166
+ trap("HUP") {
167
+ log "HUP signal received."
168
+ reload!
169
+ }
170
+
171
+ log "Rails signals registered. HUP => reload (without restart). It might not work well."
172
+ else
173
+ log "WARNING: Rails does not support signals on Win32."
174
+ end
175
+ end
83
176
  end
84
177
  end
85
178
  end