passenger 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (220) hide show
  1. data/NEWS +29 -0
  2. data/build/agents.rb +1 -0
  3. data/build/apache2.rb +2 -1
  4. data/build/cxx_tests.rb +7 -0
  5. data/build/rpm.rb +17 -22
  6. data/doc/cxxapi/Constants_8h_source.html +1 -1
  7. data/doc/cxxapi/Exceptions_8h_source.html +18 -4
  8. data/doc/cxxapi/Logging_8h_source.html +332 -262
  9. data/doc/cxxapi/annotated.html +1 -0
  10. data/doc/cxxapi/classes.html +4 -4
  11. data/doc/cxxapi/group__Exceptions.html +2 -0
  12. data/doc/cxxapi/hierarchy.html +1 -0
  13. data/doc/cxxapi/inherit__graph__35.map +1 -3
  14. data/doc/cxxapi/inherit__graph__35.md5 +1 -1
  15. data/doc/cxxapi/inherit__graph__35.png +0 -0
  16. data/doc/cxxapi/inherit__graph__36.map +3 -1
  17. data/doc/cxxapi/inherit__graph__36.md5 +1 -1
  18. data/doc/cxxapi/inherit__graph__36.png +0 -0
  19. data/doc/cxxapi/inherit__graph__37.map +1 -1
  20. data/doc/cxxapi/inherit__graph__37.md5 +1 -1
  21. data/doc/cxxapi/inherit__graph__37.png +0 -0
  22. data/doc/cxxapi/inherit__graph__38.map +1 -1
  23. data/doc/cxxapi/inherit__graph__38.md5 +1 -1
  24. data/doc/cxxapi/inherit__graph__38.png +0 -0
  25. data/doc/cxxapi/inherit__graph__39.map +1 -1
  26. data/doc/cxxapi/inherit__graph__39.md5 +1 -1
  27. data/doc/cxxapi/inherit__graph__39.png +0 -0
  28. data/doc/cxxapi/inherit__graph__40.map +1 -1
  29. data/doc/cxxapi/inherit__graph__40.md5 +1 -1
  30. data/doc/cxxapi/inherit__graph__40.png +0 -0
  31. data/doc/cxxapi/inherits.html +9 -6
  32. data/doc/cxxapi/namespacePassenger.html +2 -0
  33. data/doc/cxxapi/tree.html +2 -0
  34. data/doc/rdoc/classes/ConditionVariable.html +215 -0
  35. data/doc/rdoc/classes/Exception.html +120 -0
  36. data/doc/rdoc/classes/GC.html +113 -0
  37. data/doc/rdoc/classes/IO.html +221 -0
  38. data/doc/rdoc/classes/PhusionPassenger.html +397 -0
  39. data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +180 -0
  40. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +647 -0
  41. data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +654 -0
  42. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/InvalidPassword.html +92 -0
  43. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +97 -0
  44. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +96 -0
  45. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +97 -0
  46. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +96 -0
  47. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +619 -0
  48. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +142 -0
  49. data/doc/rdoc/classes/PhusionPassenger/AdminTools/MemoryStats.html +368 -0
  50. data/doc/rdoc/classes/PhusionPassenger/AdminTools/MemoryStats/Process.html +231 -0
  51. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance.html +588 -0
  52. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/CorruptedDirectoryError.html +92 -0
  53. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/GenerationsAbsentError.html +92 -0
  54. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/Group.html +147 -0
  55. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/Process.html +279 -0
  56. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/RoleDeniedError.html +92 -0
  57. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/StaleDirectoryError.html +92 -0
  58. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/Stats.html +123 -0
  59. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ServerInstance/UnsupportedGenerationStructureVersionError.html +92 -0
  60. data/doc/rdoc/classes/PhusionPassenger/AnalyticsLogger.html +368 -0
  61. data/doc/rdoc/classes/PhusionPassenger/AnalyticsLogger/Log.html +299 -0
  62. data/doc/rdoc/classes/PhusionPassenger/AnalyticsLogger/SharedData.html +206 -0
  63. data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +155 -0
  64. data/doc/rdoc/classes/PhusionPassenger/AppProcess.html +367 -0
  65. data/doc/rdoc/classes/PhusionPassenger/ClassicRails.html +95 -0
  66. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/ApplicationSpawner.html +351 -0
  67. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/ApplicationSpawner/Error.html +98 -0
  68. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/CGIFixed.html +200 -0
  69. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/FrameworkSpawner.html +410 -0
  70. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/FrameworkSpawner/Error.html +98 -0
  71. data/doc/rdoc/classes/PhusionPassenger/ClassicRails/RequestHandler.html +156 -0
  72. data/doc/rdoc/classes/PhusionPassenger/ClassicRailsExtensions.html +115 -0
  73. data/doc/rdoc/classes/PhusionPassenger/ClassicRailsExtensions/AnalyticsLogging.html +202 -0
  74. data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +172 -0
  75. data/doc/rdoc/classes/PhusionPassenger/DebugLogging.html +273 -0
  76. data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +145 -0
  77. data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +162 -0
  78. data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +141 -0
  79. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  80. data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +673 -0
  81. data/doc/rdoc/classes/PhusionPassenger/MessageChannel/InvalidHashError.html +92 -0
  82. data/doc/rdoc/classes/PhusionPassenger/MessageClient.html +415 -0
  83. data/doc/rdoc/classes/PhusionPassenger/NativeSupportLoader.html +134 -0
  84. data/doc/rdoc/classes/PhusionPassenger/Packaging.html +129 -0
  85. data/doc/rdoc/classes/PhusionPassenger/PlatformInfo.html +1972 -0
  86. data/doc/rdoc/classes/PhusionPassenger/Plugin.html +237 -0
  87. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  88. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +312 -0
  89. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner/Error.html +98 -0
  90. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +218 -0
  91. data/doc/rdoc/classes/PhusionPassenger/Rails3Extensions.html +114 -0
  92. data/doc/rdoc/classes/PhusionPassenger/Rails3Extensions/AnalyticsLogging.html +259 -0
  93. data/doc/rdoc/classes/PhusionPassenger/Rails3Extensions/AnalyticsLogging/ACExtension.html +139 -0
  94. data/doc/rdoc/classes/PhusionPassenger/Rails3Extensions/AnalyticsLogging/ASBenchmarkableExtension.html +118 -0
  95. data/doc/rdoc/classes/PhusionPassenger/Rails3Extensions/AnalyticsLogging/ExceptionLogger.html +135 -0
  96. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +378 -0
  97. data/doc/rdoc/classes/PhusionPassenger/Standalone.html +111 -0
  98. data/doc/rdoc/classes/PhusionPassenger/Standalone/AppFinder.html +252 -0
  99. data/doc/rdoc/classes/PhusionPassenger/Standalone/Command.html +161 -0
  100. data/doc/rdoc/classes/PhusionPassenger/Standalone/ConfigFile.html +368 -0
  101. data/doc/rdoc/classes/PhusionPassenger/Standalone/ConfigFile/DisallowedContextError.html +132 -0
  102. data/doc/rdoc/classes/PhusionPassenger/Standalone/HelpCommand.html +151 -0
  103. data/doc/rdoc/classes/PhusionPassenger/Standalone/Main.html +189 -0
  104. data/doc/rdoc/classes/PhusionPassenger/Standalone/PackageRuntimeCommand.html +177 -0
  105. data/doc/rdoc/classes/PhusionPassenger/Standalone/RuntimeInstaller.html +341 -0
  106. data/doc/rdoc/classes/PhusionPassenger/Standalone/StartCommand.html +203 -0
  107. data/doc/rdoc/classes/PhusionPassenger/Standalone/StatusCommand.html +156 -0
  108. data/doc/rdoc/classes/PhusionPassenger/Standalone/StopCommand.html +168 -0
  109. data/doc/rdoc/classes/PhusionPassenger/Standalone/Utils.html +86 -0
  110. data/doc/rdoc/classes/PhusionPassenger/Standalone/VersionCommand.html +135 -0
  111. data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +125 -0
  112. data/doc/rdoc/classes/PhusionPassenger/Utils.html +1543 -0
  113. data/doc/rdoc/classes/PhusionPassenger/Utils/FileSystemWatcher.html +204 -0
  114. data/doc/rdoc/classes/PhusionPassenger/Utils/FileSystemWatcher/DirInfo.html +171 -0
  115. data/doc/rdoc/classes/PhusionPassenger/Utils/FileSystemWatcher/FileInfo.html +140 -0
  116. data/doc/rdoc/classes/PhusionPassenger/Utils/HostsFileParser.html +260 -0
  117. data/doc/rdoc/classes/PhusionPassenger/Utils/PseudoIO.html +194 -0
  118. data/doc/rdoc/classes/PhusionPassenger/Utils/RewindableInput.html +265 -0
  119. data/doc/rdoc/classes/PhusionPassenger/Utils/RewindableInput/Tempfile.html +120 -0
  120. data/doc/rdoc/classes/PhusionPassenger/Utils/UnseekableSocket.html +561 -0
  121. data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +140 -0
  122. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  123. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +182 -0
  124. data/doc/rdoc/classes/Process.html +115 -0
  125. data/doc/rdoc/classes/Signal.html +139 -0
  126. data/doc/rdoc/created.rid +1 -0
  127. data/doc/rdoc/files/DEVELOPERS_TXT.html +280 -0
  128. data/doc/rdoc/files/README.html +157 -0
  129. data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +130 -0
  130. data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +135 -0
  131. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +126 -0
  132. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +128 -0
  133. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/memory_stats_rb.html +126 -0
  134. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/server_instance_rb.html +132 -0
  135. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +122 -0
  136. data/doc/rdoc/files/lib/phusion_passenger/analytics_logger_rb.html +129 -0
  137. data/doc/rdoc/files/lib/phusion_passenger/app_process_rb.html +127 -0
  138. data/doc/rdoc/files/lib/phusion_passenger/classic_rails/application_spawner_rb.html +141 -0
  139. data/doc/rdoc/files/lib/phusion_passenger/classic_rails/cgi_fixed_rb.html +126 -0
  140. data/doc/rdoc/files/lib/phusion_passenger/classic_rails/framework_spawner_rb.html +146 -0
  141. data/doc/rdoc/files/lib/phusion_passenger/classic_rails/request_handler_rb.html +125 -0
  142. data/doc/rdoc/files/lib/phusion_passenger/classic_rails_extensions/init_rb.html +132 -0
  143. data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +126 -0
  144. data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +122 -0
  145. data/doc/rdoc/files/lib/phusion_passenger/debug_logging_rb.html +122 -0
  146. data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +147 -0
  147. data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +122 -0
  148. data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +127 -0
  149. data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +120 -0
  150. data/doc/rdoc/files/lib/phusion_passenger/message_client_rb.html +127 -0
  151. data/doc/rdoc/files/lib/phusion_passenger/native_support_rb.html +132 -0
  152. data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +122 -0
  153. data/doc/rdoc/files/lib/phusion_passenger/platform_info/apache_rb.html +127 -0
  154. data/doc/rdoc/files/lib/phusion_passenger/platform_info/binary_compatibility_rb.html +129 -0
  155. data/doc/rdoc/files/lib/phusion_passenger/platform_info/compiler_rb.html +127 -0
  156. data/doc/rdoc/files/lib/phusion_passenger/platform_info/curl_rb.html +126 -0
  157. data/doc/rdoc/files/lib/phusion_passenger/platform_info/documentation_tools_rb.html +126 -0
  158. data/doc/rdoc/files/lib/phusion_passenger/platform_info/linux_rb.html +126 -0
  159. data/doc/rdoc/files/lib/phusion_passenger/platform_info/operating_system_rb.html +127 -0
  160. data/doc/rdoc/files/lib/phusion_passenger/platform_info/ruby_rb.html +128 -0
  161. data/doc/rdoc/files/lib/phusion_passenger/platform_info/zlib_rb.html +126 -0
  162. data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +122 -0
  163. data/doc/rdoc/files/lib/phusion_passenger/plugin_rb.html +127 -0
  164. data/doc/rdoc/files/lib/phusion_passenger/public_api_rb.html +127 -0
  165. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +137 -0
  166. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +125 -0
  167. data/doc/rdoc/files/lib/phusion_passenger/rails3_extensions/init_rb.html +127 -0
  168. data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +122 -0
  169. data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +160 -0
  170. data/doc/rdoc/files/lib/phusion_passenger/standalone/app_finder_rb.html +127 -0
  171. data/doc/rdoc/files/lib/phusion_passenger/standalone/command_rb.html +136 -0
  172. data/doc/rdoc/files/lib/phusion_passenger/standalone/config_file_rb.html +126 -0
  173. data/doc/rdoc/files/lib/phusion_passenger/standalone/help_command_rb.html +126 -0
  174. data/doc/rdoc/files/lib/phusion_passenger/standalone/main_rb.html +126 -0
  175. data/doc/rdoc/files/lib/phusion_passenger/standalone/package_runtime_command_rb.html +127 -0
  176. data/doc/rdoc/files/lib/phusion_passenger/standalone/runtime_installer_rb.html +133 -0
  177. data/doc/rdoc/files/lib/phusion_passenger/standalone/start_command_rb.html +136 -0
  178. data/doc/rdoc/files/lib/phusion_passenger/standalone/status_command_rb.html +126 -0
  179. data/doc/rdoc/files/lib/phusion_passenger/standalone/stop_command_rb.html +126 -0
  180. data/doc/rdoc/files/lib/phusion_passenger/standalone/utils_rb.html +126 -0
  181. data/doc/rdoc/files/lib/phusion_passenger/standalone/version_command_rb.html +127 -0
  182. data/doc/rdoc/files/lib/phusion_passenger/utils/file_system_watcher_rb.html +126 -0
  183. data/doc/rdoc/files/lib/phusion_passenger/utils/hosts_file_parser_rb.html +120 -0
  184. data/doc/rdoc/files/lib/phusion_passenger/utils/rewindable_input_rb.html +100 -0
  185. data/doc/rdoc/files/lib/phusion_passenger/utils/tmpdir_rb.html +122 -0
  186. data/doc/rdoc/files/lib/phusion_passenger/utils/unseekable_socket_rb.html +126 -0
  187. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +179 -0
  188. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +132 -0
  189. data/doc/rdoc/fr_class_index.html +139 -0
  190. data/doc/rdoc/fr_file_index.html +108 -0
  191. data/doc/rdoc/fr_method_index.html +439 -0
  192. data/doc/rdoc/index.html +26 -0
  193. data/doc/rdoc/rdoc-style.css +187 -0
  194. data/ext/apache2/Configuration.cpp +41 -0
  195. data/ext/apache2/Configuration.hpp +19 -0
  196. data/ext/apache2/Hooks.cpp +67 -5
  197. data/ext/common/Constants.h +1 -1
  198. data/ext/common/Exceptions.h +14 -0
  199. data/ext/common/Logging.h +76 -6
  200. data/ext/common/LoggingAgent/FilterSupport.h +1317 -0
  201. data/ext/common/LoggingAgent/LoggingServer.h +93 -4
  202. data/ext/common/LoggingAgent/RemoteSender.h +5 -5
  203. data/ext/common/Utils/StrIntUtils.cpp +12 -1
  204. data/ext/common/Utils/StrIntUtils.h +2 -1
  205. data/ext/common/Utils/StringMap.h +100 -0
  206. data/ext/nginx/Configuration.c +0 -1
  207. data/ext/nginx/ContentHandler.c +33 -7
  208. data/lib/phusion_passenger.rb +2 -2
  209. data/lib/phusion_passenger/abstract_request_handler.rb +5 -0
  210. data/lib/phusion_passenger/analytics_logger.rb +77 -11
  211. data/lib/phusion_passenger/dependencies.rb +11 -1
  212. data/lib/phusion_passenger/platform_info.rb +1 -1
  213. data/lib/phusion_passenger/utils.rb +9 -1
  214. data/test/cxx/FilterSupportTest.cpp +276 -0
  215. data/test/cxx/LoggingTest.cpp +28 -0
  216. data/test/cxx/StringMapTest.cpp +70 -0
  217. data/test/integration_tests/cgi_environment_spec.rb +10 -0
  218. metadata +170 -8
  219. data/ext/common/libboost_oxt/aggregate.cpp +0 -10
  220. data/ext/common/libpassenger_common/aggregate.cpp +0 -15
@@ -25,9 +25,9 @@ module PhusionPassenger
25
25
  ###### Version numbers ######
26
26
 
27
27
  # Phusion Passenger version number. Don't forget to edit ext/common/Constants.h too.
28
- VERSION_STRING = '3.0.2'
28
+ VERSION_STRING = '3.0.3'
29
29
 
30
- PREFERRED_NGINX_VERSION = '0.8.53'
30
+ PREFERRED_NGINX_VERSION = '0.8.54'
31
31
  PREFERRED_PCRE_VERSION = '8.10'
32
32
  STANDALONE_INTERFACE_VERSION = 1
33
33
 
@@ -704,6 +704,11 @@ private
704
704
  end
705
705
  Thread.current[PASSENGER_ANALYTICS_WEB_LOG] = nil
706
706
  ensure
707
+ # It is important that the following call receives an ACK
708
+ # from the logging server and that we don't close the socket
709
+ # connection until the ACK has been received, otherwise
710
+ # the helper agent may close the transaction before this
711
+ # process's openTransaction command is processed.
707
712
  log.close
708
713
  end
709
714
  end
@@ -107,8 +107,13 @@ class AnalyticsLogger
107
107
 
108
108
  def close(flush_to_disk = false)
109
109
  @shared_data.synchronize do
110
+ # We need an ACK here. See abstract_request_handler.rb finalize_request.
110
111
  @shared_data.client.write("closeTransaction", @txn_id,
111
- AnalyticsLogger.timestamp_string)
112
+ AnalyticsLogger.timestamp_string, true)
113
+ result = @shared_data.client.read
114
+ if result != ["ok"]
115
+ raise "Expected logging server to respond with 'ok', but got #{result.inspect} instead"
116
+ end
112
117
  if flush_to_disk
113
118
  @shared_data.client.write("flush")
114
119
  result = @shared_data.client.read
@@ -152,6 +157,11 @@ class AnalyticsLogger
152
157
  @node_name = `hostname`.strip
153
158
  end
154
159
  @random_dev = File.open("/dev/urandom")
160
+
161
+ # This mutex protects the following instance variables, but
162
+ # not the contents of @shared_data.
163
+ @mutex = Mutex.new
164
+
155
165
  @shared_data = SharedData.new
156
166
  if @server_address && local_socket_address?(@server_address)
157
167
  @max_connect_tries = 10
@@ -163,18 +173,22 @@ class AnalyticsLogger
163
173
  end
164
174
 
165
175
  def clear_connection
166
- @shared_data.synchronize do
167
- @random_dev = File.open("/dev/urandom") if @random_dev.closed?
168
- @shared_data.unref
169
- @shared_data = SharedData.new
176
+ @mutex.synchronize do
177
+ @shared_data.synchronize do
178
+ @random_dev = File.open("/dev/urandom") if @random_dev.closed?
179
+ @shared_data.unref
180
+ @shared_data = SharedData.new
181
+ end
170
182
  end
171
183
  end
172
184
 
173
185
  def close
174
- @shared_data.synchronize do
175
- @random_dev.close
176
- @shared_data.unref
177
- @shared_data = nil
186
+ @mutex.synchronize do
187
+ @shared_data.synchronize do
188
+ @random_dev.close
189
+ @shared_data.unref
190
+ @shared_data = nil
191
+ end
178
192
  end
179
193
  end
180
194
 
@@ -187,7 +201,8 @@ class AnalyticsLogger
187
201
 
188
202
  txn_id = (AnalyticsLogger.current_time.to_i / 60).to_s(36)
189
203
  txn_id << "-#{random_token(11)}"
190
- @shared_data.synchronize do
204
+ Lock.new(@mutex).synchronize do |lock|
205
+ Lock.new(@shared_data.mutex).synchronize do |shared_data_lock|
191
206
  try_count = 0
192
207
  if current_time >= @next_reconnect_time
193
208
  while try_count < @max_connect_tries
@@ -197,12 +212,21 @@ class AnalyticsLogger
197
212
  txn_id, group_name, "", category,
198
213
  AnalyticsLogger.timestamp_string,
199
214
  union_station_key,
215
+ true,
200
216
  true)
217
+ result = @shared_data.client.read
218
+ if result != ["ok"]
219
+ raise "Expected logging server to respond with 'ok', but got #{result.inspect} instead"
220
+ end
201
221
  return Log.new(@shared_data, txn_id)
202
222
  rescue Errno::ENOENT, *NETWORK_ERRORS
203
223
  try_count += 1
204
224
  disconnect(true)
225
+ shared_data_lock.reset(@shared_data.mutex, false)
226
+ lock.unlock
205
227
  sleep RETRY_SLEEP if try_count < @max_connect_tries
228
+ lock.lock
229
+ shared_data_lock.lock
206
230
  rescue Exception => e
207
231
  disconnect
208
232
  raise e
@@ -215,6 +239,7 @@ class AnalyticsLogger
215
239
  end
216
240
  return Log.new
217
241
  end
242
+ end
218
243
  end
219
244
 
220
245
  def continue_transaction(txn_id, group_name, category = :requests, union_station_key = nil)
@@ -224,7 +249,8 @@ class AnalyticsLogger
224
249
  raise ArgumentError, "Transaction ID may not be empty"
225
250
  end
226
251
 
227
- @shared_data.synchronize do
252
+ Lock.new(@mutex).synchronize do |lock|
253
+ Lock.new(@shared_data.mutex).synchronize do |shared_data_lock|
228
254
  try_count = 0
229
255
  if current_time >= @next_reconnect_time
230
256
  while try_count < @max_connect_tries
@@ -239,7 +265,11 @@ class AnalyticsLogger
239
265
  rescue Errno::ENOENT, *NETWORK_ERRORS
240
266
  try_count += 1
241
267
  disconnect(true)
268
+ shared_data_lock.reset(@shared_data.mutex, false)
269
+ lock.unlock
242
270
  sleep RETRY_SLEEP if try_count < @max_connect_tries
271
+ lock.lock
272
+ shared_data_lock.lock
243
273
  rescue Exception => e
244
274
  disconnect
245
275
  raise e
@@ -252,6 +282,7 @@ class AnalyticsLogger
252
282
  end
253
283
  return Log.new
254
284
  end
285
+ end
255
286
  end
256
287
 
257
288
  private
@@ -261,7 +292,42 @@ private
261
292
  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
262
293
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
263
294
 
295
+ class Lock
296
+ def initialize(mutex)
297
+ @mutex = mutex
298
+ @locked = false
299
+ end
300
+
301
+ def reset(mutex, lock_now = true)
302
+ unlock if @locked
303
+ @mutex = mutex
304
+ lock if lock_now
305
+ end
306
+
307
+ def synchronize
308
+ lock if !@locked
309
+ begin
310
+ yield(self)
311
+ ensure
312
+ unlock if @locked
313
+ end
314
+ end
315
+
316
+ def lock
317
+ raise if @locked
318
+ @mutex.lock
319
+ @locked = true
320
+ end
321
+
322
+ def unlock
323
+ raise if !@locked
324
+ @mutex.unlock
325
+ @locked = false
326
+ end
327
+ end
328
+
264
329
  class SharedData
330
+ attr_reader :mutex
265
331
  attr_accessor :client
266
332
 
267
333
  def initialize
@@ -492,7 +492,17 @@ module Dependencies # :nodoc: all
492
492
  "<b>apt-get install libcurl4-openssl-dev</b> " +
493
493
  "or <b>libcurl4-gnutls-dev</b>, whichever you prefer."
494
494
  elsif tags.include?(:redhat)
495
- dep.install_command = "yum install curl-devel"
495
+ begin
496
+ release = File.read("/etc/redhat-release")
497
+ rescue
498
+ release = nil
499
+ end
500
+ if release =~ /release 4/
501
+ # http://code.google.com/p/phusion-passenger/issues/detail?id=554
502
+ dep.install_command = "yum install zlib-devel e2fsprogs-devel krb5-devel libidn-devel"
503
+ else
504
+ dep.install_command = "yum install curl-devel"
505
+ end
496
506
  end
497
507
  end
498
508
  end
@@ -145,7 +145,7 @@ public
145
145
  def self.find_command(name)
146
146
  ENV['PATH'].split(File::PATH_SEPARATOR).detect do |directory|
147
147
  path = File.join(directory, name.to_s)
148
- if File.executable?(path)
148
+ if File.file?(path) && File.executable?(path)
149
149
  return path
150
150
  end
151
151
  end
@@ -57,7 +57,7 @@ protected
57
57
  raise ArgumentError, "The 'path' argument may not be nil" if path.nil?
58
58
  return Pathname.new(path).realpath.to_s
59
59
  rescue Errno::ENOENT => e
60
- raise InvalidAPath, e.message
60
+ raise InvalidPath, e.message
61
61
  end
62
62
 
63
63
  # Assert that +path+ is a directory. Raises +InvalidPath+ if it isn't.
@@ -511,6 +511,10 @@ protected
511
511
  end
512
512
  module_function :process_is_alive?
513
513
 
514
+ # Wraps another IO object. Everything written to the PseudoIO will
515
+ # not only be immediately forwarded to the underlying IO object but
516
+ # will also be captured in a buffer. The contents of the buffer
517
+ # can be retrieved by calling #done!.
514
518
  class PseudoIO
515
519
  def initialize(sink)
516
520
  @sink = sink || File.open("/dev/null", "w")
@@ -523,6 +527,10 @@ protected
523
527
  return result
524
528
  end
525
529
 
530
+ def to_io
531
+ return self
532
+ end
533
+
526
534
  def method_missing(*args, &block)
527
535
  @buffer.send(*args, &block) if @buffer && args.first != :reopen
528
536
  return @sink.send(*args, &block)
@@ -0,0 +1,276 @@
1
+ #include "TestSupport.h"
2
+ #include "LoggingAgent/FilterSupport.h"
3
+
4
+ #include <boost/bind.hpp>
5
+ #include <boost/shared_ptr.hpp>
6
+ #include <oxt/thread.hpp>
7
+ #include <set>
8
+
9
+ using namespace Passenger;
10
+ using namespace Passenger::FilterSupport;
11
+ using namespace std;
12
+ using namespace oxt;
13
+
14
+ namespace tut {
15
+ struct FilterSupportTest {
16
+ SimpleContext ctx;
17
+ };
18
+
19
+ DEFINE_TEST_GROUP_WITH_LIMIT(FilterSupportTest, 100);
20
+
21
+ /******** Generic tests *******/
22
+
23
+ TEST_METHOD(1) {
24
+ // Filter source cannot be blank.
25
+
26
+ try {
27
+ Filter f("");
28
+ fail("SyntaxError expected for empty filter source");
29
+ } catch (const SyntaxError &) {
30
+ // Success.
31
+ }
32
+
33
+ try {
34
+ Filter f(" ");
35
+ fail("SyntaxError expected for blank filter source");
36
+ } catch (const SyntaxError &) {
37
+ // Success.
38
+ }
39
+ }
40
+
41
+
42
+ /******** String tests *******/
43
+
44
+ TEST_METHOD(5) {
45
+ // Test string comparison
46
+ Filter f("uri == \"hello world\"");
47
+ ctx.uri = "hello world";
48
+ ensure("(1)", f.run(ctx));
49
+ ctx.uri = "something else";
50
+ ensure("(2)", !f.run(ctx));
51
+ }
52
+
53
+ TEST_METHOD(6) {
54
+ // Test string negative comparison
55
+ Filter f("uri != \"hello world\"");
56
+ ctx.uri = "hello world";
57
+ ensure("(1)", !f.run(ctx));
58
+ ctx.uri = "something else";
59
+ ensure("(2)", f.run(ctx));
60
+ }
61
+
62
+ TEST_METHOD(7) {
63
+ // Test string regexp matching
64
+ Filter f("uri =~ /hello world/");
65
+ ctx.uri = "hello world";
66
+ ensure("(1)", f.run(ctx));
67
+ ctx.uri = "hello";
68
+ ensure("(2)", !f.run(ctx));
69
+ }
70
+
71
+ TEST_METHOD(8) {
72
+ // Test advanced string regexp matching
73
+ Filter f("uri =~ /(hello|world)\\nhi/");
74
+ ctx.uri = "hello\nhi";
75
+ ensure("(1)", f.run(ctx));
76
+ ctx.uri = "world\nhi";
77
+ ensure("(2)", f.run(ctx));
78
+ ctx.uri = "hello\n";
79
+ ensure("(3)", !f.run(ctx));
80
+ }
81
+
82
+ TEST_METHOD(9) {
83
+ // Regexp matching is case-sensitive by default.
84
+ Filter f("uri =~ /Hello World/");
85
+ ctx.uri = "hello world";
86
+ ensure(!f.run(ctx));
87
+ }
88
+
89
+ TEST_METHOD(10) {
90
+ // Regexp matching can be made case-insensitive.
91
+ Filter f("uri =~ /Hello World/i");
92
+ ctx.uri = "hello world";
93
+ ensure(f.run(ctx));
94
+ }
95
+
96
+ TEST_METHOD(11) {
97
+ // Left operand may be a literal.
98
+ Filter f("\"hello\" == \"hello\"");
99
+ ensure("(1)", f.run(ctx));
100
+
101
+ f = Filter("\"hello\" == \"world\"");
102
+ ensure("(2)", !f.run(ctx));
103
+ }
104
+
105
+ TEST_METHOD(12) {
106
+ // Right operand may be a field.
107
+ Filter f("\"hello\" == uri");
108
+ ctx.uri = "hello";
109
+ ensure("(1)", f.run(ctx));
110
+
111
+ f = Filter("\"hello\" == uri");
112
+ ctx.uri = "world";
113
+ ensure("(2)", !f.run(ctx));
114
+ }
115
+
116
+ TEST_METHOD(13) {
117
+ // String syntax supports \n, \r, \t
118
+ ctx.uri = "hello\r\n\tworld";
119
+ ensure(Filter("uri == \"hello\\r\\n\\tworld\"").run(ctx));
120
+ }
121
+
122
+
123
+ /******** Integer tests *******/
124
+
125
+ TEST_METHOD(20) {
126
+ // Test integer equality comparison
127
+ Filter f("response_time == 10");
128
+ ctx.responseTime = 10;
129
+ ensure("(1)", f.run(ctx));
130
+ ctx.responseTime = 11;
131
+ ensure("(2)", !f.run(ctx));
132
+ }
133
+
134
+ TEST_METHOD(21) {
135
+ // Test integer inequality comparison
136
+ Filter f("response_time != 10");
137
+ ctx.responseTime = 10;
138
+ ensure("(1)", !f.run(ctx));
139
+ ctx.responseTime = 11;
140
+ ensure("(2)", f.run(ctx));
141
+ }
142
+
143
+ TEST_METHOD(22) {
144
+ // Test integer larger than comparison
145
+ Filter f("response_time > 10");
146
+ ctx.responseTime = 11;
147
+ ensure("(1)", f.run(ctx));
148
+ ctx.responseTime = 10;
149
+ ensure("(2)", !f.run(ctx));
150
+ }
151
+
152
+ TEST_METHOD(23) {
153
+ // Test integer larger than or equals comparison
154
+ Filter f("response_time >= 10");
155
+ ctx.responseTime = 10;
156
+ ensure("(1)", f.run(ctx));
157
+ ctx.responseTime = 9;
158
+ ensure("(2)", !f.run(ctx));
159
+ }
160
+
161
+ TEST_METHOD(24) {
162
+ // Test integer smaller than comparison
163
+ Filter f("response_time < 10");
164
+ ctx.responseTime = 9;
165
+ ensure("(1)", f.run(ctx));
166
+ ctx.responseTime = 10;
167
+ ensure("(2)", !f.run(ctx));
168
+ }
169
+
170
+ TEST_METHOD(25) {
171
+ // Test integer smaller than or equals comparison
172
+ Filter f("response_time <= 10");
173
+ ctx.responseTime = 10;
174
+ ensure("(1)", f.run(ctx));
175
+ ctx.responseTime = 11;
176
+ ensure("(2)", !f.run(ctx));
177
+ }
178
+
179
+ TEST_METHOD(26) {
180
+ // Negative integers work
181
+ ctx.responseTime = -23;
182
+ ensure(Filter("response_time == -23").run(ctx));
183
+ }
184
+
185
+ TEST_METHOD(27) {
186
+ // Left operand may be a literal.
187
+ ensure("(1)", Filter("2 == 2").run(ctx));
188
+ ensure("(2)", !Filter("2 != 2").run(ctx));
189
+ ensure("(3)", Filter("1 < 2").run(ctx));
190
+ ensure("(4)", !Filter("1 < 0").run(ctx));
191
+ ensure("(5)", Filter("1 <= 1").run(ctx));
192
+ ensure("(6)", !Filter("1 <= 0").run(ctx));
193
+ ensure("(7)", Filter("2 > 1").run(ctx));
194
+ ensure("(8)", !Filter("2 > 2").run(ctx));
195
+ ensure("(9)", Filter("2 >= 2").run(ctx));
196
+ ensure("(10)", !Filter("2 >= 3").run(ctx));
197
+ }
198
+
199
+ TEST_METHOD(28) {
200
+ // Right operand may be a field.
201
+ ctx.responseTime = 2;
202
+ ensure("(1)", Filter("2 == response_time").run(ctx));
203
+ ensure("(2)", !Filter("2 != 2").run(ctx));
204
+
205
+ ensure("(3)", Filter("1 < response_time").run(ctx));
206
+ ctx.responseTime = 0;
207
+ ensure("(4)", !Filter("1 < response_time").run(ctx));
208
+
209
+ ctx.responseTime = 1;
210
+ ensure("(5)", Filter("1 <= response_time").run(ctx));
211
+ ctx.responseTime = 0;
212
+ ensure("(6)", !Filter("1 <= response_time").run(ctx));
213
+
214
+ ctx.responseTime = 1;
215
+ ensure("(7)", Filter("2 > response_time").run(ctx));
216
+ ctx.responseTime = 2;
217
+ ensure("(8)", !Filter("2 > response_time").run(ctx));
218
+
219
+ ensure("(9)", Filter("2 >= response_time").run(ctx));
220
+ ctx.responseTime = 3;
221
+ ensure("(10)", !Filter("2 >= response_time").run(ctx));
222
+ }
223
+
224
+
225
+ /******** Error tests *******/
226
+
227
+ TEST_METHOD(40) {
228
+ // < does not work if left operand is a string
229
+ // < does not work if right operand is a string
230
+ // <= does not work if left operand is a string
231
+ // <= does not work if right operand is a string
232
+ // > does not work if left operand is a string
233
+ // < does not work if right operand is a string
234
+ // >= does not work if left operand is a string
235
+ // >= does not work if right operand is a string
236
+ // =~ does not work if left operand is not a string
237
+ // =~ does not work if right operand is not a regexp
238
+ }
239
+
240
+
241
+ /******** ContextFromLog tests *******/
242
+
243
+ TEST_METHOD(50) {
244
+ // It extracts information from the logs
245
+ ContextFromLog ctx(
246
+ "1234-abcd 1234 0 BEGIN: request processing (1235, 10, 10)\n"
247
+ "1234-abcd 1240 1 URI: /foo\n"
248
+ "1234-abcd 1241 2 Controller action: HomeController#index\n"
249
+ "1234-abcd 2234 3 END: request processing (2234, 10, 10)\n"
250
+ );
251
+ ensure_equals(ctx.getURI(), "/foo");
252
+ ensure_equals(ctx.getController(), "HomeController");
253
+ ensure_equals(ctx.getResponseTime(), 46655);
254
+ }
255
+
256
+ TEST_METHOD(51) {
257
+ // It ignores empty lines and invalid lines
258
+ ContextFromLog ctx(
259
+ "\n"
260
+ "\n"
261
+ " \n"
262
+ "1234-abcd 1234 0 URI: /foo\n"
263
+ "URI: /bar\n"
264
+ "\n"
265
+ );
266
+ ensure_equals(ctx.getURI(), "/foo");
267
+ }
268
+
269
+ TEST_METHOD(52) {
270
+ // It does only extracts the response time if both the begin and end events are available
271
+ ContextFromLog ctx(
272
+ "1234-abcd 1234 0 BEGIN: request processing (1235, 10, 10)\n"
273
+ );
274
+ ensure_equals(ctx.getResponseTime(), 0);
275
+ }
276
+ }