passenger 5.2.3 → 5.3.0

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 (241) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +13 -0
  3. data/CONTRIBUTORS +5 -1
  4. data/build/agent.rb +22 -2
  5. data/build/cxx_tests.rb +41 -5
  6. data/build/misc.rb +4 -1
  7. data/build/support/cxx_dependency_map.rb +1746 -908
  8. data/build/support/vendor/cxx_hinted_parser/CxxHintedParser.sublime-project +8 -0
  9. data/build/support/vendor/cxx_hinted_parser/Gemfile +5 -0
  10. data/build/support/vendor/cxx_hinted_parser/Gemfile.lock +30 -0
  11. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core → build/support/vendor/cxx_hinted_parser}/LICENSE.md +1 -1
  12. data/build/support/vendor/cxx_hinted_parser/README.md +95 -0
  13. data/build/support/vendor/cxx_hinted_parser/Rakefile +4 -0
  14. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/initialize.rb → build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser.rb} +2 -9
  15. data/build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser/parser.rb +239 -0
  16. data/dev/ci/README.md +15 -2
  17. data/dev/ci/lib/set-container-envvars.sh +6 -0
  18. data/dev/ci/lib/setup-container.sh +4 -1
  19. data/dev/ci/scripts/debug-console-wrapper.sh +3 -1
  20. data/dev/ci/setup-host +5 -0
  21. data/dev/ci/tests/binaries/Jenkinsfile +105 -0
  22. data/dev/ci/tests/binaries/build-linux +38 -0
  23. data/dev/ci/tests/binaries/build-macos +40 -0
  24. data/dev/ci/tests/binaries/prepare-macos +38 -0
  25. data/dev/ci/tests/binaries/test-linux +45 -0
  26. data/dev/ci/tests/binaries/test-macos +38 -0
  27. data/dev/ci/tests/debian/Jenkinsfile +2 -2
  28. data/dev/ci/tests/rpm/Jenkinsfile +1 -1
  29. data/dev/configkit-schemas/index.json +3 -24
  30. data/dev/vagrant/nginx_rakefile +0 -1
  31. data/package.json +15 -5
  32. data/resources/templates/error_renderer/.editorconfig +19 -0
  33. data/resources/templates/error_renderer/with_details/README.md +9 -0
  34. data/resources/templates/error_renderer/with_details/dist/bundle.js +33 -0
  35. data/resources/templates/error_renderer/with_details/dist/styles.css +17 -0
  36. data/resources/templates/error_renderer/with_details/src/DetailsView.jsx +52 -0
  37. data/resources/templates/error_renderer/with_details/src/GetHelpView.jsx +61 -0
  38. data/resources/templates/error_renderer/with_details/src/JourneyView.css +50 -0
  39. data/resources/templates/error_renderer/with_details/src/JourneyView.jsx +621 -0
  40. data/resources/templates/error_renderer/with_details/src/PageMain.css +114 -0
  41. data/resources/templates/error_renderer/with_details/src/PageMain.jsx +136 -0
  42. data/resources/templates/error_renderer/with_details/src/ProblemDescriptionView.jsx +14 -0
  43. data/resources/templates/error_renderer/with_details/src/ProcessDetailsView.jsx +56 -0
  44. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.css +5 -0
  45. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.jsx +15 -0
  46. data/resources/templates/error_renderer/with_details/src/SummaryView.jsx +35 -0
  47. data/resources/templates/error_renderer/with_details/src/SystemComponentView.css +34 -0
  48. data/resources/templates/error_renderer/with_details/src/SystemComponentView.jsx +168 -0
  49. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.css +13 -0
  50. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.jsx +116 -0
  51. data/resources/templates/error_renderer/with_details/src/Tab.jsx +12 -0
  52. data/resources/templates/error_renderer/with_details/src/Tabs.jsx +104 -0
  53. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.css +3446 -0
  54. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.js +293 -0
  55. data/resources/templates/error_renderer/with_details/src/bootstrap/config.json +401 -0
  56. data/resources/templates/error_renderer/with_details/src/index.html.template +22 -0
  57. data/resources/templates/error_renderer/with_details/src/index.jsx +23 -0
  58. data/resources/templates/error_renderer/with_details/webpack.config.js +47 -0
  59. data/resources/templates/error_renderer/without_details/dist/bundle.js +1 -0
  60. data/resources/templates/error_renderer/without_details/dist/styles.css +1 -0
  61. data/resources/templates/{undisclosed_error.html.template → error_renderer/without_details/src/index.html.template} +7 -11
  62. data/resources/templates/error_renderer/without_details/src/index.js +1 -0
  63. data/resources/templates/{error_layout.css → error_renderer/without_details/src/main.css} +5 -2
  64. data/resources/templates/error_renderer/without_details/webpack.config.js +42 -0
  65. data/src/agent/AgentMain.cpp +3 -3
  66. data/src/agent/Core/ApplicationPool/BasicProcessInfo.h +13 -0
  67. data/src/agent/Core/ApplicationPool/Common.h +3 -4
  68. data/src/agent/Core/ApplicationPool/Context.h +27 -17
  69. data/src/agent/Core/ApplicationPool/Group.h +3 -1
  70. data/src/agent/Core/ApplicationPool/Group/InitializationAndShutdown.cpp +2 -12
  71. data/src/agent/Core/ApplicationPool/Group/InternalUtils.cpp +55 -10
  72. data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +1 -1
  73. data/src/agent/Core/ApplicationPool/Group/OutOfBandWork.cpp +1 -1
  74. data/src/agent/Core/ApplicationPool/Group/SpawningAndRestarting.cpp +13 -6
  75. data/src/agent/Core/ApplicationPool/Implementation.cpp +16 -100
  76. data/src/agent/Core/ApplicationPool/Options.h +8 -65
  77. data/src/agent/Core/ApplicationPool/Pool.h +4 -21
  78. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +1 -60
  79. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +10 -13
  80. data/src/agent/Core/ApplicationPool/Pool/InitializationAndShutdown.cpp +3 -8
  81. data/src/agent/Core/ApplicationPool/Pool/Miscellaneous.cpp +2 -34
  82. data/src/agent/Core/ApplicationPool/Pool/StateInspection.cpp +1 -1
  83. data/src/agent/Core/ApplicationPool/Process.cpp +17 -12
  84. data/src/agent/Core/ApplicationPool/Process.h +146 -93
  85. data/src/agent/Core/ApplicationPool/Session.h +2 -2
  86. data/src/agent/Core/ApplicationPool/Socket.h +28 -27
  87. data/src/agent/Core/Config.h +1 -3
  88. data/src/agent/Core/ConfigChange.cpp +2 -4
  89. data/src/agent/Core/Controller.h +2 -8
  90. data/src/agent/Core/Controller/BufferBody.cpp +0 -2
  91. data/src/agent/Core/Controller/CheckoutSession.cpp +12 -24
  92. data/src/agent/Core/Controller/Config.h +1 -9
  93. data/src/agent/Core/Controller/ForwardResponse.cpp +0 -34
  94. data/src/agent/Core/Controller/Hooks.cpp +0 -7
  95. data/src/agent/Core/Controller/InitRequest.cpp +0 -43
  96. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +0 -4
  97. data/src/agent/Core/Controller/Request.h +1 -35
  98. data/src/agent/Core/Controller/SendRequest.cpp +0 -32
  99. data/src/agent/Core/CoreMain.cpp +19 -32
  100. data/src/agent/Core/SpawningKit/Config.h +329 -55
  101. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h +369 -0
  102. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h.cxxcodebuilder +307 -0
  103. data/src/agent/Core/SpawningKit/Context.h +211 -0
  104. data/src/agent/Core/SpawningKit/DirectSpawner.h +112 -122
  105. data/src/agent/Core/SpawningKit/DummySpawner.h +59 -20
  106. data/src/agent/Core/SpawningKit/ErrorRenderer.h +117 -0
  107. data/src/agent/Core/SpawningKit/Exceptions.h +1157 -0
  108. data/src/agent/Core/SpawningKit/Factory.h +24 -17
  109. data/src/agent/Core/SpawningKit/{BackgroundIOCapturer.h → Handshake/BackgroundIOCapturer.h} +48 -18
  110. data/src/agent/Core/SpawningKit/Handshake/Perform.h +1650 -0
  111. data/src/agent/Core/SpawningKit/Handshake/Prepare.h +582 -0
  112. data/src/agent/Core/SpawningKit/Handshake/Session.h +91 -0
  113. data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +100 -0
  114. data/src/agent/Core/SpawningKit/Journey.h +561 -0
  115. data/src/agent/Core/SpawningKit/PipeWatcher.h +41 -18
  116. data/src/agent/Core/SpawningKit/README.md +534 -0
  117. data/src/agent/Core/SpawningKit/Result.h +182 -7
  118. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h +69 -0
  119. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h.cxxcodebuilder +110 -0
  120. data/src/agent/Core/SpawningKit/SmartSpawner.h +1027 -562
  121. data/src/agent/Core/SpawningKit/Spawner.h +70 -1134
  122. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +3 -33
  123. data/src/agent/README.md +2 -3
  124. data/src/agent/Shared/ApiServerUtils.h +2 -3
  125. data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +932 -0
  126. data/src/agent/Watchdog/Config.h +1 -3
  127. data/src/agent/Watchdog/WatchdogMain.cpp +2 -1
  128. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
  129. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  130. data/src/apache2_module/ConfigGeneral/ManifestGeneration.h +22 -13
  131. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +5 -0
  132. data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +3 -0
  133. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +13 -0
  134. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
  135. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +13 -0
  136. data/src/cxx_supportlib/Constants.h +3 -1
  137. data/src/cxx_supportlib/Exceptions.h +0 -121
  138. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +7 -6
  139. data/src/cxx_supportlib/LoggingKit/Logging.h +3 -1
  140. data/src/cxx_supportlib/Utils.cpp +42 -0
  141. data/src/cxx_supportlib/Utils.h +7 -0
  142. data/src/cxx_supportlib/Utils/IOUtils.cpp +58 -0
  143. data/src/cxx_supportlib/Utils/IOUtils.h +13 -0
  144. data/src/cxx_supportlib/Utils/JsonUtils.h +130 -23
  145. data/src/cxx_supportlib/Utils/ScopeGuard.h +9 -4
  146. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +7 -0
  147. data/src/cxx_supportlib/Utils/StrIntUtils.h +1 -0
  148. data/src/cxx_supportlib/Utils/SystemTime.h +1 -1
  149. data/src/cxx_supportlib/Utils/Timer.h +1 -1
  150. data/src/cxx_supportlib/WebSocketCommandReverseServer.h +6 -4
  151. data/src/cxx_supportlib/vendor-copy/adhoc_lve.h +1 -0
  152. data/src/helper-scripts/node-loader.js +54 -59
  153. data/src/helper-scripts/rack-loader.rb +63 -60
  154. data/src/helper-scripts/rack-preloader.rb +125 -72
  155. data/src/helper-scripts/wsgi-loader.py +100 -43
  156. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +120 -112
  157. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +15 -8
  158. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +142 -142
  159. data/src/nginx_module/ConfigGeneral/ManifestGeneration.c +26 -15
  160. data/src/nginx_module/ConfigGeneral/ManifestGeneration.h +3 -0
  161. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +76 -70
  162. data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +114 -99
  163. data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +170 -156
  164. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +38 -35
  165. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +5 -1
  166. data/src/ruby_supportlib/phusion_passenger.rb +5 -5
  167. data/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb +14 -1
  168. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +8 -0
  169. data/src/ruby_supportlib/phusion_passenger/common_library.rb +0 -3
  170. data/src/ruby_supportlib/phusion_passenger/config/nginx_engine_compiler.rb +0 -1
  171. data/src/ruby_supportlib/phusion_passenger/constants.rb +2 -0
  172. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +646 -238
  173. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +117 -95
  174. data/src/ruby_supportlib/phusion_passenger/packaging.rb +0 -1
  175. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +5 -1
  176. data/src/ruby_supportlib/phusion_passenger/preloader_shared_helpers.rb +92 -69
  177. data/src/ruby_supportlib/phusion_passenger/public_api.rb +0 -17
  178. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +0 -3
  179. data/src/ruby_supportlib/phusion_passenger/request_handler.rb +4 -5
  180. data/src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb +0 -22
  181. metadata +64 -67
  182. data/resources/templates/error_layout.html.template +0 -86
  183. data/resources/templates/general_error.html.template +0 -1
  184. data/resources/templates/general_error_with_html.html.template +0 -1
  185. data/src/agent/Core/ApplicationPool/ErrorRenderer.h +0 -131
  186. data/src/agent/Core/SpawningKit/Options.h +0 -41
  187. data/src/agent/Core/UnionStation/Connection.h +0 -173
  188. data/src/agent/Core/UnionStation/Context.h +0 -536
  189. data/src/agent/Core/UnionStation/StopwatchLog.h +0 -147
  190. data/src/agent/Core/UnionStation/Transaction.h +0 -249
  191. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +0 -208
  192. data/src/cxx_supportlib/UnionStationFilterSupport.cpp +0 -67
  193. data/src/cxx_supportlib/UnionStationFilterSupport.h +0 -1622
  194. data/src/nodejs_supportlib/phusion_passenger/log_express.js +0 -106
  195. data/src/nodejs_supportlib/phusion_passenger/log_mongodb.js +0 -202
  196. data/src/nodejs_supportlib/phusion_passenger/ustreporter.js +0 -227
  197. data/src/nodejs_supportlib/phusion_passenger/ustrouter_connector.js +0 -448
  198. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/CONFIG.md +0 -37
  199. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile +0 -17
  200. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile.lock +0 -59
  201. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README-API.md +0 -5
  202. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README.md +0 -117
  203. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Rakefile +0 -115
  204. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +0 -423
  205. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +0 -238
  206. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/connection.rb +0 -67
  207. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +0 -281
  208. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/lock.rb +0 -62
  209. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/log.rb +0 -66
  210. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/message_channel.rb +0 -157
  211. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +0 -150
  212. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/basics.rb +0 -199
  213. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/controllers.rb +0 -187
  214. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/misc.rb +0 -303
  215. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/view_rendering.rb +0 -91
  216. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +0 -396
  217. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +0 -279
  218. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +0 -39
  219. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +0 -173
  220. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +0 -177
  221. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version.rb +0 -32
  222. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version_data.rb +0 -44
  223. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.example +0 -16
  224. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis +0 -20
  225. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis-with-sudo +0 -18
  226. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/union_station_hooks_core.gemspec +0 -23
  227. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile +0 -14
  228. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile.lock +0 -45
  229. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/LICENSE.md +0 -19
  230. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/README.md +0 -104
  231. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Rakefile +0 -160
  232. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails.rb +0 -200
  233. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_controller_extension.rb +0 -45
  234. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_view_subscriber.rb +0 -55
  235. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_record_subscriber.rb +0 -41
  236. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_benchmarkable_extension.rb +0 -47
  237. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_cache_subscriber.rb +0 -79
  238. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/exception_logger.rb +0 -57
  239. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version.rb +0 -32
  240. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version_data.rb +0 -44
  241. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/union_station_hooks_rails.gemspec +0 -34
@@ -1,67 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2017 Phusion Holding B.V.
4
- *
5
- * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
- * trademarks of Phusion Holding B.V.
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in
16
- * all copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
- * THE SOFTWARE.
25
- */
26
- #include <UnionStationFilterSupport.h>
27
- #include <cstring>
28
- #include <cstdlib>
29
-
30
- using namespace Passenger;
31
-
32
- extern "C" {
33
-
34
- PassengerFilter *
35
- passenger_filter_create(const char *source, int size, char **error) {
36
- if (size == -1) {
37
- size = strlen(source);
38
- }
39
- try {
40
- return (PassengerFilter *) new FilterSupport::Filter(StaticString(source, size));
41
- } catch (const SyntaxError &e) {
42
- if (error != NULL) {
43
- *error = strdup(e.what());
44
- }
45
- return NULL;
46
- }
47
- }
48
-
49
- void
50
- passenger_filter_free(PassengerFilter *filter) {
51
- delete (FilterSupport::Filter *) filter;
52
- }
53
-
54
- char *
55
- passenger_filter_validate(const char *source, int size) {
56
- if (size == -1) {
57
- size = strlen(source);
58
- }
59
- try {
60
- (void) FilterSupport::Filter(StaticString(source, size));
61
- return NULL;
62
- } catch (const SyntaxError &e) {
63
- return strdup(e.what());
64
- }
65
- }
66
-
67
- } // extern "C"
@@ -1,1622 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2017 Phusion Holding B.V.
4
- *
5
- * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
- * trademarks of Phusion Holding B.V.
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in
16
- * all copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
- * THE SOFTWARE.
25
- */
26
- #ifndef _PASSENGER_FILTER_SUPPORT_H_
27
- #define _PASSENGER_FILTER_SUPPORT_H_
28
-
29
- #ifdef __cplusplus
30
-
31
- #include <boost/shared_ptr.hpp>
32
- #include <boost/make_shared.hpp>
33
- #include <oxt/tracable_exception.hpp>
34
-
35
- #include <string>
36
- #include <set>
37
- // Checking for _PCREPOSIX_H avoids conflicts with headers provided by Apache.
38
- // https://code.google.com/p/phusion-passenger/issues/detail?id=651
39
- #ifndef _PCREPOSIX_H
40
- #include <boost/regex.h>
41
- #endif
42
- #include <cstdio>
43
- #include <cstring>
44
- #include <string.h>
45
- #include <stdlib.h>
46
-
47
- #include <StaticString.h>
48
- #include <Exceptions.h>
49
- #include <Utils/StrIntUtils.h>
50
- #include <Utils/ReleaseableScopedPointer.h>
51
-
52
- namespace Passenger {
53
- namespace FilterSupport {
54
-
55
- using namespace std;
56
- using namespace boost;
57
- using namespace oxt;
58
-
59
-
60
- class Tokenizer {
61
- public:
62
- enum TokenType {
63
- NONE,
64
- NOT,
65
- AND,
66
- OR,
67
- MATCHES,
68
- NOT_MATCHES,
69
- EQUALS,
70
- NOT_EQUALS,
71
- GREATER_THAN,
72
- GREATER_THAN_OR_EQUALS,
73
- LESS_THAN,
74
- LESS_THAN_OR_EQUALS,
75
- LPARENTHESIS,
76
- RPARENTHESIS,
77
- COMMA,
78
- REGEXP,
79
- STRING,
80
- INTEGER,
81
- TRUE_LIT,
82
- FALSE_LIT,
83
- IDENTIFIER,
84
- END_OF_DATA
85
- };
86
-
87
- enum TokenOptions {
88
- NO_OPTIONS = 0,
89
- REGEXP_OPTION_CASE_INSENSITIVE = 1
90
- };
91
-
92
- struct Token {
93
- TokenType type;
94
- int options;
95
- unsigned int pos;
96
- unsigned int size;
97
- StaticString rawValue;
98
-
99
- Token() {
100
- type = NONE;
101
- }
102
-
103
- Token(TokenType _type, unsigned int _pos, unsigned int _size, const StaticString &_rawValue)
104
- : type(_type),
105
- options(NO_OPTIONS),
106
- pos(_pos),
107
- size(_size),
108
- rawValue(_rawValue)
109
- { }
110
-
111
- string toString() const {
112
- return Tokenizer::typeToString(type);
113
- }
114
- };
115
-
116
- private:
117
- StaticString data;
118
- bool debug;
119
- unsigned int pos;
120
-
121
- static bool isWhitespace(char ch) {
122
- return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
123
- }
124
-
125
- void skipWhitespaces() {
126
- while (pos < data.size() && isWhitespace(data[pos])) {
127
- pos++;
128
- }
129
- }
130
-
131
- unsigned int available() const {
132
- return data.size() - pos;
133
- }
134
-
135
- char current() const {
136
- return data[pos];
137
- }
138
-
139
- char next() const {
140
- return data[pos + 1];
141
- }
142
-
143
- static bool isIdentifierChar(char ch) {
144
- return (ch >= 'a' && ch <= 'z')
145
- || (ch >= 'A' && ch <= 'Z')
146
- || (ch >= '0' && ch <= '9')
147
- || ch == '_';
148
- }
149
-
150
- static bool isDigit(char ch) {
151
- return ch >= '0' && ch <= '9';
152
- }
153
-
154
- Token logToken(const Token &token) const {
155
- if (debug) {
156
- printf("# Token: %s\n", token.toString().c_str());
157
- }
158
- return token;
159
- }
160
-
161
- void raiseSyntaxError(const string &message = "") {
162
- string msg = "Syntax error at character " + toString(pos + 1);
163
- if (!message.empty()) {
164
- msg.append(": ");
165
- msg.append(message);
166
- }
167
- throw SyntaxError(msg);
168
- }
169
-
170
- void expectingAtLeast(unsigned int size) {
171
- if (available() < size) {
172
- raiseSyntaxError("at least " + toString(size) +
173
- " more characters expected");
174
- }
175
- }
176
-
177
- void expectingNextChar(char ch) {
178
- expectingAtLeast(2);
179
- if (next() != ch) {
180
- raiseSyntaxError("expected '" + toString(ch) +
181
- "', but found '" + toString(next()) +
182
- "'");
183
- }
184
- }
185
-
186
- Token matchToken(TokenType type, unsigned int size = 0) {
187
- unsigned int oldPos = pos;
188
- pos += size;
189
- return Token(type, oldPos, size, data.substr(oldPos, size));
190
- }
191
-
192
- Token matchTokensStartingWithNegation() {
193
- expectingAtLeast(2);
194
- switch (next()) {
195
- case '~':
196
- return matchToken(NOT_MATCHES, 2);
197
- case '=':
198
- return matchToken(NOT_EQUALS, 2);
199
- default:
200
- return matchToken(NOT, 1);
201
- };
202
- }
203
-
204
- Token matchAnd() {
205
- expectingNextChar('&');
206
- return matchToken(AND, 2);
207
- }
208
-
209
- Token matchOr() {
210
- expectingNextChar('|');
211
- return matchToken(OR, 2);
212
- }
213
-
214
- Token matchTokensStartingWithEquals() {
215
- expectingAtLeast(2);
216
- switch (next()) {
217
- case '~':
218
- return matchToken(MATCHES, 2);
219
- case '=':
220
- return matchToken(EQUALS, 2);
221
- default:
222
- raiseSyntaxError("unrecognized operator '" + data.substr(pos, 2) + "'");
223
- return Token(); // Shut up compiler warning.
224
- }
225
- }
226
-
227
- Token matchTokensStartingWithGreaterThan() {
228
- if (available() == 0 || next() != '=') {
229
- return matchToken(GREATER_THAN, 1);
230
- } else {
231
- return matchToken(GREATER_THAN_OR_EQUALS, 2);
232
- }
233
- }
234
-
235
- Token matchTokensStartingWithLessThan() {
236
- if (available() == 0 || next() != '=') {
237
- return matchToken(LESS_THAN, 1);
238
- } else {
239
- return matchToken(LESS_THAN_OR_EQUALS, 2);
240
- }
241
- }
242
-
243
- Token matchRegexp(char terminator) {
244
- unsigned int start = pos;
245
- bool endFound = false;
246
-
247
- // Match initial quote slash.
248
- pos++;
249
-
250
- // Match rest of regexp including terminating slash.
251
- while (pos < data.size() && !endFound) {
252
- char ch = current();
253
- if (ch == '\\') {
254
- pos++;
255
- if (pos >= data.size()) {
256
- raiseSyntaxError("unterminated regular expression");
257
- } else {
258
- pos++;
259
- }
260
- } else if (ch == terminator) {
261
- pos++;
262
- endFound = true;
263
- } else {
264
- pos++;
265
- }
266
- }
267
-
268
- if (endFound) {
269
- Token t(REGEXP, start, pos - start, data.substr(start, pos - start));
270
-
271
- // Match regexp options.
272
- endFound = false;
273
- while (pos < data.size() && !endFound) {
274
- char ch = current();
275
- if (ch == 'i') {
276
- t.options |= Tokenizer::REGEXP_OPTION_CASE_INSENSITIVE;
277
- } else if (isWhitespace(ch)) {
278
- endFound = true;
279
- }
280
- pos++;
281
- }
282
-
283
- return t;
284
- } else {
285
- raiseSyntaxError("unterminated regular expression");
286
- return Token(); // Shut up compiler warning.
287
- }
288
- }
289
-
290
- Token matchString(char terminator) {
291
- unsigned int start = pos;
292
- bool endFound = false;
293
-
294
- // Match initial quote character.
295
- pos++;
296
-
297
- // Match rest of string including terminating quote.
298
- while (pos < data.size() && !endFound) {
299
- char ch = current();
300
- if (ch == '\\') {
301
- pos++;
302
- if (pos >= data.size()) {
303
- raiseSyntaxError("unterminated string");
304
- } else {
305
- pos++;
306
- }
307
- } else if (ch == terminator) {
308
- pos++;
309
- endFound = true;
310
- } else {
311
- pos++;
312
- }
313
- }
314
-
315
- if (endFound) {
316
- return Token(STRING, start, pos - start, data.substr(start, pos - start));
317
- } else {
318
- raiseSyntaxError("unterminated string");
319
- return Token(); // Shut up compiler warning.
320
- }
321
- }
322
-
323
- Token matchInteger() {
324
- unsigned int start = pos;
325
-
326
- // Accept initial minus or digit.
327
- pos++;
328
-
329
- while (pos < data.size() && isDigit(data[pos])) {
330
- pos++;
331
- }
332
-
333
- return Token(INTEGER, start, pos - start, data.substr(start, pos - start));
334
- }
335
-
336
- Token matchIdentifier() {
337
- char ch = current();
338
- if ((ch >= 'a' && ch <= 'z') ||
339
- (ch >= 'A' && ch <= 'Z') ||
340
- ch == '_') {
341
- unsigned int start = pos;
342
- pos++;
343
- while (pos < data.size() && isIdentifierChar(current())) {
344
- pos++;
345
- }
346
-
347
- StaticString val = data.substr(start, pos - start);
348
- if (val == "true") {
349
- return Token(TRUE_LIT, start, pos - start, val);
350
- } else if (val == "false") {
351
- return Token(FALSE_LIT, start, pos - start, val);
352
- } else {
353
- return Token(IDENTIFIER, start, pos - start, val);
354
- }
355
- } else {
356
- raiseSyntaxError("Identifier expected, but got an unknown token");
357
- return Token(); // Shut up compiler warning.
358
- }
359
- }
360
-
361
- public:
362
- Tokenizer(const StaticString &data, bool debug = false) {
363
- this->data = data;
364
- this->debug = debug;
365
- pos = 0;
366
- }
367
-
368
- Token getNext() {
369
- skipWhitespaces();
370
- if (pos >= data.size()) {
371
- return logToken(Token(END_OF_DATA, data.size(), 0, ""));
372
- }
373
-
374
- switch (current()) {
375
- case '!':
376
- return logToken(matchTokensStartingWithNegation());
377
- case '&':
378
- return logToken(matchAnd());
379
- case '|':
380
- return logToken(matchOr());
381
- case '=':
382
- return logToken(matchTokensStartingWithEquals());
383
- case '>':
384
- return logToken(matchTokensStartingWithGreaterThan());
385
- case '<':
386
- return logToken(matchTokensStartingWithLessThan());
387
- case '(':
388
- return logToken(matchToken(LPARENTHESIS, 1));
389
- case ')':
390
- return logToken(matchToken(RPARENTHESIS, 1));
391
- case ',':
392
- return logToken(matchToken(COMMA, 1));
393
- case '/':
394
- return logToken(matchRegexp('/'));
395
- case '%':
396
- expectingAtLeast(3);
397
- if (memcmp(data.data() + pos, "%r{", 3) != 0) {
398
- raiseSyntaxError("expected '%r{', but found '" +
399
- data.substr(pos, 3) + "'");
400
- }
401
- pos += 2;
402
- return logToken(matchRegexp('}'));
403
- case '"':
404
- return logToken(matchString('"'));
405
- case '\'':
406
- return logToken(matchString('\''));
407
- case '-':
408
- return logToken(matchInteger());
409
- default:
410
- if (isDigit(current())) {
411
- return logToken(matchInteger());
412
- } else {
413
- return logToken(matchIdentifier());
414
- }
415
- }
416
- }
417
-
418
- static string typeToString(TokenType type) {
419
- switch (type) {
420
- case NONE:
421
- return "NONE";
422
- case NOT:
423
- return "NOT";
424
- case AND:
425
- return "AND";
426
- case OR:
427
- return "OR";
428
- case MATCHES:
429
- return "MATCHES";
430
- case NOT_MATCHES:
431
- return "NOT_MATCHES";
432
- case EQUALS:
433
- return "EQUALS";
434
- case NOT_EQUALS:
435
- return "NOT_EQUALS";
436
- case GREATER_THAN:
437
- return "GREATER_THAN";
438
- case GREATER_THAN_OR_EQUALS:
439
- return "GREATER_THAN_OR_EQUALS";
440
- case LESS_THAN:
441
- return "LESS_THAN";
442
- case LESS_THAN_OR_EQUALS:
443
- return "LESS_THAN_OR_EQUALS";
444
- case LPARENTHESIS:
445
- return "LPARENTHESIS";
446
- case RPARENTHESIS:
447
- return "RPARENTHESIS";
448
- case COMMA:
449
- return "COMMA";
450
- case REGEXP:
451
- return "REGEXP";
452
- case STRING:
453
- return "STRING";
454
- case INTEGER:
455
- return "INTEGER";
456
- case TRUE_LIT:
457
- return "TRUE";
458
- case FALSE_LIT:
459
- return "FALSE";
460
- case IDENTIFIER:
461
- return "IDENTIFIER";
462
- case END_OF_DATA:
463
- return "END_OF_DATA";
464
- default:
465
- return "(unknown)";
466
- }
467
- }
468
- };
469
-
470
-
471
- enum ValueType {
472
- REGEXP_TYPE,
473
- STRING_TYPE,
474
- INTEGER_TYPE,
475
- BOOLEAN_TYPE,
476
- UNKNOWN_TYPE
477
- };
478
-
479
-
480
- class Context {
481
- public:
482
- enum FieldIdentifier {
483
- URI,
484
- CONTROLLER,
485
- RESPONSE_TIME,
486
- RESPONSE_TIME_WITHOUT_GC,
487
- STATUS,
488
- STATUS_CODE,
489
- GC_TIME
490
- };
491
-
492
- virtual ~Context() { }
493
-
494
- virtual string getURI() const = 0;
495
- virtual string getController() const = 0;
496
- virtual int getResponseTime() const = 0;
497
- virtual string getStatus() const = 0;
498
- virtual int getStatusCode() const = 0;
499
- virtual int getGcTime() const = 0;
500
- virtual bool hasHint(const string &name) const = 0;
501
-
502
- int getResponseTimeWithoutGc() const {
503
- return getResponseTime() - getGcTime();
504
- }
505
-
506
- string queryStringField(FieldIdentifier id) const {
507
- switch (id) {
508
- case URI:
509
- return getURI();
510
- case CONTROLLER:
511
- return getController();
512
- case RESPONSE_TIME:
513
- return toString(getResponseTime());
514
- case RESPONSE_TIME_WITHOUT_GC:
515
- return toString(getResponseTimeWithoutGc());
516
- case STATUS:
517
- return getStatus();
518
- case STATUS_CODE:
519
- return toString(getStatusCode());
520
- case GC_TIME:
521
- return toString(getGcTime());
522
- default:
523
- return "";
524
- }
525
- }
526
-
527
- int queryIntField(FieldIdentifier id) const {
528
- switch (id) {
529
- case RESPONSE_TIME:
530
- return getResponseTime();
531
- case RESPONSE_TIME_WITHOUT_GC:
532
- return getResponseTimeWithoutGc();
533
- case STATUS_CODE:
534
- return getStatusCode();
535
- case GC_TIME:
536
- return getGcTime();
537
- default:
538
- return 0;
539
- }
540
- }
541
-
542
- bool queryBoolField(FieldIdentifier id) const {
543
- switch (id) {
544
- case URI:
545
- return !getURI().empty();
546
- case CONTROLLER:
547
- return !getController().empty();
548
- case RESPONSE_TIME:
549
- return getResponseTime() > 0;
550
- case RESPONSE_TIME_WITHOUT_GC:
551
- return getResponseTimeWithoutGc() > 0;
552
- case STATUS:
553
- return !getStatus().empty();
554
- case STATUS_CODE:
555
- return getStatusCode() > 0;
556
- case GC_TIME:
557
- return getGcTime() > 0;
558
- default:
559
- return false;
560
- }
561
- }
562
-
563
- static ValueType getFieldType(FieldIdentifier id) {
564
- switch (id) {
565
- case URI:
566
- case CONTROLLER:
567
- case STATUS:
568
- return STRING_TYPE;
569
- case RESPONSE_TIME:
570
- case RESPONSE_TIME_WITHOUT_GC:
571
- case STATUS_CODE:
572
- case GC_TIME:
573
- return INTEGER_TYPE;
574
- default:
575
- return UNKNOWN_TYPE;
576
- }
577
- }
578
- };
579
-
580
- class SimpleContext: public Context {
581
- public:
582
- string uri;
583
- string controller;
584
- string status;
585
- int responseTime;
586
- int statusCode;
587
- int gcTime;
588
- set<string> hints;
589
-
590
- SimpleContext() {
591
- responseTime = 0;
592
- statusCode = 0;
593
- gcTime = 0;
594
- }
595
-
596
- virtual string getURI() const {
597
- return uri;
598
- }
599
-
600
- virtual string getController() const {
601
- return controller;
602
- }
603
-
604
- virtual int getResponseTime() const {
605
- return responseTime;
606
- }
607
-
608
- virtual string getStatus() const {
609
- return status;
610
- }
611
-
612
- virtual int getStatusCode() const {
613
- return statusCode;
614
- }
615
-
616
- virtual int getGcTime() const {
617
- return gcTime;
618
- }
619
-
620
- virtual bool hasHint(const string &name) const {
621
- return hints.find(name) != hints.end();
622
- }
623
- };
624
-
625
- class ContextFromLog: public Context {
626
- private:
627
- StaticString logData;
628
- mutable SimpleContext *parsedData;
629
-
630
- struct ParseState {
631
- unsigned long long requestProcessingStart;
632
- unsigned long long requestProcessingEnd;
633
- unsigned long long smallestTimestamp;
634
- unsigned long long largestTimestamp;
635
- unsigned long long gcTimeStart;
636
- unsigned long long gcTimeEnd;
637
- };
638
-
639
- static void parseLine(const StaticString &txnId, unsigned long long timestamp,
640
- const StaticString &data, SimpleContext &ctx, ParseState &state)
641
- {
642
- if (startsWith(data, "BEGIN: request processing")) {
643
- state.requestProcessingStart = extractEventTimestamp(data);
644
- } else if (startsWith(data, "END: request processing")
645
- || startsWith(data, "FAIL: request processing")) {
646
- state.requestProcessingEnd = extractEventTimestamp(data);
647
- } else if (startsWith(data, "URI: ")) {
648
- ctx.uri = data.substr(data.find(':') + 2);
649
- } else if (startsWith(data, "Controller action: ")) {
650
- StaticString value = data.substr(data.find(':') + 2);
651
- size_t pos = value.find('#');
652
- if (pos != string::npos) {
653
- ctx.controller = value.substr(0, pos);
654
- }
655
- } else if (startsWith(data, "Status: ")) {
656
- StaticString value = data.substr(data.find(':') + 2);
657
- ctx.status = value;
658
- ctx.statusCode = stringToInt(value);
659
- } else if (startsWith(data, "Initial GC time: ")) {
660
- StaticString value = data.substr(data.find(':') + 2);
661
- state.gcTimeStart = stringToULL(value);
662
- } else if (startsWith(data, "Final GC time: ")) {
663
- StaticString value = data.substr(data.find(':') + 2);
664
- state.gcTimeEnd = stringToULL(value);
665
- }
666
-
667
- if (state.smallestTimestamp == 0 || timestamp < state.smallestTimestamp) {
668
- state.smallestTimestamp = timestamp;
669
- }
670
- if (timestamp > state.largestTimestamp) {
671
- state.largestTimestamp = timestamp;
672
- }
673
- }
674
-
675
- static void reallyParse(const StaticString &data, SimpleContext &ctx) {
676
- const char *current = data.data();
677
- const char *end = data.data() + data.size();
678
-
679
- ParseState state;
680
- memset(&state, 0, sizeof(state));
681
-
682
- while (current < end) {
683
- current = skipNewlines(current, end);
684
- if (current < end) {
685
- const char *endOfLine = findEndOfLine(current, end);
686
- StaticString line(current, endOfLine - current);
687
- if (!line.empty()) {
688
- StaticString txnId;
689
- unsigned long long timestamp;
690
- unsigned int writeCount;
691
- StaticString lineData;
692
-
693
- // If we want to do more complicated analysis we should sort
694
- // the lines but for the purposes of ContextFromLog
695
- // analyzing the data without sorting is good enough.
696
- if (splitLine(line, txnId, timestamp, writeCount, lineData)) {
697
- parseLine(txnId, timestamp, lineData, ctx,
698
- state);
699
- }
700
- }
701
- current = endOfLine;
702
- }
703
- }
704
-
705
- if (state.requestProcessingEnd != 0) {
706
- ctx.responseTime = int(state.requestProcessingEnd -
707
- state.requestProcessingStart);
708
- } else if (state.smallestTimestamp != 0) {
709
- ctx.responseTime = state.largestTimestamp - state.smallestTimestamp;
710
- }
711
-
712
- if (state.gcTimeEnd != 0) {
713
- ctx.gcTime = state.gcTimeEnd - state.gcTimeStart;
714
- }
715
- }
716
-
717
- static bool splitLine(const StaticString &line, StaticString &txnId,
718
- unsigned long long &timestamp, unsigned int &writeCount,
719
- StaticString &data)
720
- {
721
- size_t firstDelim = line.find(' ');
722
- if (firstDelim == string::npos) {
723
- return false;
724
- }
725
-
726
- size_t secondDelim = line.find(' ', firstDelim + 1);
727
- if (secondDelim == string::npos) {
728
- return false;
729
- }
730
-
731
- size_t thirdDelim = line.find(' ', secondDelim + 1);
732
- if (thirdDelim == string::npos) {
733
- return false;
734
- }
735
-
736
- txnId = line.substr(0, firstDelim);
737
- timestamp = hexatriToULL(line.substr(firstDelim + 1, secondDelim - firstDelim - 1));
738
- writeCount = (unsigned int) hexatriToULL(line.substr(secondDelim + 1,
739
- thirdDelim - secondDelim - 1));
740
- data = line.substr(thirdDelim + 1);
741
- return true;
742
- }
743
-
744
- static unsigned long long extractEventTimestamp(const StaticString &data) {
745
- size_t pos = data.find('(');
746
- if (pos == string::npos) {
747
- return 0;
748
- } else {
749
- pos++;
750
- size_t start = pos;
751
- while (pos < data.size() && isDigit(data[pos])) {
752
- pos++;
753
- }
754
- if (pos >= data.size()) {
755
- return 0;
756
- } else {
757
- return hexatriToULL(data.substr(start, pos - start));
758
- }
759
- }
760
- }
761
-
762
- static bool isNewline(char ch) {
763
- return ch == '\n' || ch == '\r';
764
- }
765
-
766
- static bool isDigit(char ch) {
767
- return ch >= '0' && ch <= '9';
768
- }
769
-
770
- static const char *skipNewlines(const char *current, const char *end) {
771
- while (current < end && isNewline(*current)) {
772
- current++;
773
- }
774
- return current;
775
- }
776
-
777
- static const char *findEndOfLine(const char *current, const char *end) {
778
- while (current < end && !isNewline(*current)) {
779
- current++;
780
- }
781
- return current;
782
- }
783
-
784
- SimpleContext *parse() const {
785
- if (parsedData == NULL) {
786
- ReleaseableScopedPointer<SimpleContext> ctx(new SimpleContext());
787
- reallyParse(logData, *ctx.get());
788
- parsedData = ctx.release();
789
- }
790
- return parsedData;
791
- }
792
-
793
- public:
794
- ContextFromLog(const StaticString &logData) {
795
- this->logData = logData;
796
- parsedData = NULL;
797
- }
798
-
799
- ~ContextFromLog() {
800
- delete parsedData;
801
- }
802
-
803
- virtual string getURI() const {
804
- return parse()->uri;
805
- }
806
-
807
- virtual string getController() const {
808
- return parse()->getController();
809
- }
810
-
811
- virtual int getResponseTime() const {
812
- return parse()->getResponseTime();
813
- }
814
-
815
- virtual string getStatus() const {
816
- return parse()->getStatus();
817
- }
818
-
819
- virtual int getStatusCode() const {
820
- return parse()->getStatusCode();
821
- }
822
-
823
- virtual int getGcTime() const {
824
- return parse()->getGcTime();
825
- }
826
-
827
- virtual bool hasHint(const string &name) const {
828
- return parse()->hasHint(name);
829
- }
830
- };
831
-
832
-
833
- class Filter {
834
- private:
835
- typedef Tokenizer::Token Token;
836
- typedef Tokenizer::TokenType TokenType;
837
-
838
- struct BooleanComponent;
839
- struct MultiExpression;
840
- struct Comparison;
841
- struct FunctionCall;
842
- typedef boost::shared_ptr<BooleanComponent> BooleanComponentPtr;
843
- typedef boost::shared_ptr<MultiExpression> MultiExpressionPtr;
844
- typedef boost::shared_ptr<Comparison> ComparisonPtr;
845
- typedef boost::shared_ptr<FunctionCall> FunctionCallPtr;
846
-
847
- struct BooleanComponent {
848
- virtual ~BooleanComponent() { }
849
- virtual bool evaluate(const Context &ctx) = 0;
850
- };
851
-
852
- enum LogicalOperator {
853
- AND,
854
- OR
855
- };
856
-
857
- enum Comparator {
858
- MATCHES,
859
- NOT_MATCHES,
860
- EQUALS,
861
- NOT_EQUALS,
862
- GREATER_THAN,
863
- GREATER_THAN_OR_EQUALS,
864
- LESS_THAN,
865
- LESS_THAN_OR_EQUALS,
866
- UNKNOWN_COMPARATOR
867
- };
868
-
869
- struct MultiExpression: public BooleanComponent {
870
- struct Part {
871
- LogicalOperator theOperator;
872
- BooleanComponentPtr expression;
873
- };
874
-
875
- BooleanComponentPtr firstExpression;
876
- vector<Part> rest;
877
-
878
- virtual bool evaluate(const Context &ctx) {
879
- bool result = firstExpression->evaluate(ctx);
880
- unsigned int i = 0;
881
- bool done = i == rest.size();
882
-
883
- while (!done) {
884
- Part &nextPart = rest[i];
885
- if (nextPart.theOperator == AND) {
886
- result = result && nextPart.expression->evaluate(ctx);
887
- done = !result;
888
- } else {
889
- result = result || nextPart.expression->evaluate(ctx);
890
- }
891
- i++;
892
- done = done || i == rest.size();
893
- }
894
-
895
- return result;
896
- }
897
- };
898
-
899
- struct Negation: public BooleanComponent {
900
- BooleanComponentPtr expr;
901
-
902
- Negation(const BooleanComponentPtr &e)
903
- : expr(e)
904
- { }
905
-
906
- virtual bool evaluate(const Context &ctx) {
907
- return !expr->evaluate(ctx);
908
- }
909
- };
910
-
911
- struct Value {
912
- enum Source {
913
- REGEXP_LITERAL,
914
- STRING_LITERAL,
915
- INTEGER_LITERAL,
916
- BOOLEAN_LITERAL,
917
- CONTEXT_FIELD_IDENTIFIER
918
- };
919
-
920
- Source source;
921
- union {
922
- struct {
923
- char stringStorage[sizeof(string)];
924
- string *stringPointer;
925
- struct {
926
- regex_t regexp;
927
- int options;
928
- } regexp;
929
- } stringOrRegexpValue;
930
- int intValue;
931
- bool boolValue;
932
- Context::FieldIdentifier contextFieldIdentifier;
933
- } u;
934
-
935
- Value() {
936
- source = INTEGER_LITERAL;
937
- u.intValue = 0;
938
- }
939
-
940
- Value(const Value &other) {
941
- initializeFrom(other);
942
- }
943
-
944
- Value(bool regexp, const StaticString &value, bool caseInsensitive = false) {
945
- if (regexp) {
946
- source = REGEXP_LITERAL;
947
- } else {
948
- source = STRING_LITERAL;
949
- }
950
- u.stringOrRegexpValue.stringPointer = new (u.stringOrRegexpValue.stringStorage)
951
- string(value.data(), value.size());
952
- if (regexp) {
953
- int options = REG_EXTENDED;
954
- u.stringOrRegexpValue.regexp.options = 0;
955
- if (caseInsensitive) {
956
- options |= REG_ICASE;
957
- u.stringOrRegexpValue.regexp.options |=
958
- Tokenizer::REGEXP_OPTION_CASE_INSENSITIVE;
959
- }
960
- regcomp(&u.stringOrRegexpValue.regexp.regexp,
961
- u.stringOrRegexpValue.stringPointer->c_str(),
962
- options);
963
- }
964
- }
965
-
966
- Value(int val) {
967
- source = INTEGER_LITERAL;
968
- u.intValue = val;
969
- }
970
-
971
- Value(bool val) {
972
- source = BOOLEAN_LITERAL;
973
- u.boolValue = val;
974
- }
975
-
976
- Value(Context::FieldIdentifier identifier) {
977
- source = CONTEXT_FIELD_IDENTIFIER;
978
- u.contextFieldIdentifier = identifier;
979
- }
980
-
981
- ~Value() {
982
- freeStorage();
983
- }
984
-
985
- Value &operator=(const Value &other) {
986
- freeStorage();
987
- initializeFrom(other);
988
- return *this;
989
- }
990
-
991
- regex_t *getRegexpValue(const Context &ctx) const {
992
- if (source == REGEXP_LITERAL) {
993
- return &storedRegexp();
994
- } else {
995
- return NULL;
996
- }
997
- }
998
-
999
- string getStringValue(const Context &ctx) const {
1000
- switch (source) {
1001
- case REGEXP_LITERAL:
1002
- case STRING_LITERAL:
1003
- return storedString();
1004
- case INTEGER_LITERAL:
1005
- return toString(u.intValue);
1006
- case BOOLEAN_LITERAL:
1007
- if (u.boolValue) {
1008
- return "true";
1009
- } else {
1010
- return "false";
1011
- }
1012
- case CONTEXT_FIELD_IDENTIFIER:
1013
- return ctx.queryStringField(u.contextFieldIdentifier);
1014
- default:
1015
- return "";
1016
- }
1017
- }
1018
-
1019
- int getIntegerValue(const Context &ctx) const {
1020
- switch (source) {
1021
- case REGEXP_LITERAL:
1022
- return 0;
1023
- case STRING_LITERAL:
1024
- return atoi(storedString());
1025
- case INTEGER_LITERAL:
1026
- return u.intValue;
1027
- case BOOLEAN_LITERAL:
1028
- return (int) u.boolValue;
1029
- case CONTEXT_FIELD_IDENTIFIER:
1030
- return ctx.queryIntField(u.contextFieldIdentifier);
1031
- default:
1032
- return 0;
1033
- }
1034
- }
1035
-
1036
- bool getBooleanValue(const Context &ctx) const {
1037
- switch (source) {
1038
- case REGEXP_LITERAL:
1039
- return true;
1040
- case STRING_LITERAL:
1041
- return !storedString().empty();
1042
- case INTEGER_LITERAL:
1043
- return (bool) u.intValue;
1044
- case BOOLEAN_LITERAL:
1045
- return u.boolValue;
1046
- case CONTEXT_FIELD_IDENTIFIER:
1047
- return ctx.queryBoolField(u.contextFieldIdentifier);
1048
- default:
1049
- return 0;
1050
- }
1051
- }
1052
-
1053
- ValueType getType() const {
1054
- switch (source) {
1055
- case REGEXP_LITERAL:
1056
- return REGEXP_TYPE;
1057
- case STRING_LITERAL:
1058
- return STRING_TYPE;
1059
- case INTEGER_LITERAL:
1060
- return INTEGER_TYPE;
1061
- case BOOLEAN_LITERAL:
1062
- return BOOLEAN_TYPE;
1063
- case CONTEXT_FIELD_IDENTIFIER:
1064
- return Context::getFieldType(u.contextFieldIdentifier);
1065
- default:
1066
- return UNKNOWN_TYPE;
1067
- }
1068
- }
1069
-
1070
- private:
1071
- const string &storedString() const {
1072
- return *u.stringOrRegexpValue.stringPointer;
1073
- }
1074
-
1075
- regex_t &storedRegexp() const {
1076
- return (regex_t &) u.stringOrRegexpValue.regexp.regexp;
1077
- }
1078
-
1079
- void freeStorage() {
1080
- if (source == REGEXP_LITERAL || source == STRING_LITERAL) {
1081
- storedString().~string();
1082
- if (source == REGEXP_LITERAL) {
1083
- regfree(&storedRegexp());
1084
- }
1085
- }
1086
- }
1087
-
1088
- void initializeFrom(const Value &other) {
1089
- int options;
1090
- source = other.source;
1091
- switch (source) {
1092
- case REGEXP_LITERAL:
1093
- u.stringOrRegexpValue.stringPointer = new (u.stringOrRegexpValue.stringStorage)
1094
- string(other.storedString());
1095
- options = REG_EXTENDED;
1096
- if (other.u.stringOrRegexpValue.regexp.options & Tokenizer::REGEXP_OPTION_CASE_INSENSITIVE) {
1097
- options |= REG_ICASE;
1098
- }
1099
- regcomp(&u.stringOrRegexpValue.regexp.regexp,
1100
- storedString().c_str(),
1101
- options);
1102
- u.stringOrRegexpValue.regexp.options = other.u.stringOrRegexpValue.regexp.options;
1103
- break;
1104
- case STRING_LITERAL:
1105
- u.stringOrRegexpValue.stringPointer = new (u.stringOrRegexpValue.stringStorage)
1106
- string(other.storedString());
1107
- break;
1108
- case INTEGER_LITERAL:
1109
- u.intValue = other.u.intValue;
1110
- break;
1111
- case BOOLEAN_LITERAL:
1112
- u.boolValue = other.u.boolValue;
1113
- break;
1114
- case CONTEXT_FIELD_IDENTIFIER:
1115
- u.contextFieldIdentifier = other.u.contextFieldIdentifier;
1116
- break;
1117
- }
1118
- }
1119
- };
1120
-
1121
- struct SingleValueComponent: public BooleanComponent {
1122
- Value val;
1123
-
1124
- SingleValueComponent(const Value &v)
1125
- : val(v)
1126
- { }
1127
-
1128
- virtual bool evaluate(const Context &ctx) {
1129
- return val.getBooleanValue(ctx);
1130
- }
1131
- };
1132
-
1133
- struct Comparison: public BooleanComponent {
1134
- Value subject;
1135
- Comparator comparator;
1136
- Value object;
1137
-
1138
- virtual bool evaluate(const Context &ctx) {
1139
- switch (subject.getType()) {
1140
- case STRING_TYPE:
1141
- return compareStringOrRegexp(subject.getStringValue(ctx), ctx);
1142
- case INTEGER_TYPE:
1143
- return compareInteger(subject.getIntegerValue(ctx), ctx);
1144
- case BOOLEAN_TYPE:
1145
- return compareBoolean(subject.getBooleanValue(ctx), ctx);
1146
- default:
1147
- // error
1148
- return false;
1149
- }
1150
- }
1151
-
1152
- private:
1153
- bool compareStringOrRegexp(const string &str, const Context &ctx) {
1154
- switch (comparator) {
1155
- case MATCHES:
1156
- return regexec(object.getRegexpValue(ctx), str.c_str(), 0, NULL, 0) == 0;
1157
- case NOT_MATCHES:
1158
- return regexec(object.getRegexpValue(ctx), str.c_str(), 0, NULL, 0) != 0;
1159
- case EQUALS:
1160
- return str == object.getStringValue(ctx);
1161
- case NOT_EQUALS:
1162
- return str != object.getStringValue(ctx);
1163
- default:
1164
- // error
1165
- return false;
1166
- }
1167
- }
1168
-
1169
- bool compareInteger(int value, const Context &ctx) {
1170
- int value2 = object.getIntegerValue(ctx);
1171
- switch (comparator) {
1172
- case EQUALS:
1173
- return value == value2;
1174
- case NOT_EQUALS:
1175
- return value != value2;
1176
- case GREATER_THAN:
1177
- return value > value2;
1178
- case GREATER_THAN_OR_EQUALS:
1179
- return value >= value2;
1180
- case LESS_THAN:
1181
- return value < value2;
1182
- case LESS_THAN_OR_EQUALS:
1183
- return value <= value2;
1184
- default:
1185
- // error
1186
- return false;
1187
- }
1188
- }
1189
-
1190
- bool compareBoolean(bool value, const Context &ctx) {
1191
- bool value2 = object.getBooleanValue(ctx);
1192
- switch (comparator) {
1193
- case EQUALS:
1194
- return value == value2;
1195
- case NOT_EQUALS:
1196
- return value != value2;
1197
- default:
1198
- // error
1199
- return false;
1200
- }
1201
- }
1202
- };
1203
-
1204
- struct FunctionCall: public BooleanComponent {
1205
- vector<Value> arguments;
1206
-
1207
- virtual void checkArguments() const = 0;
1208
- };
1209
-
1210
- struct StartsWithFunctionCall: public FunctionCall {
1211
- virtual bool evaluate(const Context &ctx) {
1212
- return startsWith(arguments[0].getStringValue(ctx),
1213
- arguments[1].getStringValue(ctx));
1214
- }
1215
-
1216
- virtual void checkArguments() const {
1217
- if (arguments.size() != 2) {
1218
- throw SyntaxError("you passed " + toString(arguments.size()) +
1219
- " argument(s) to starts_with(), but it accepts exactly 2 arguments");
1220
- }
1221
- }
1222
- };
1223
-
1224
- struct HasHintFunctionCall: public FunctionCall {
1225
- virtual bool evaluate(const Context &ctx) {
1226
- return ctx.hasHint(arguments[0].getStringValue(ctx));
1227
- }
1228
-
1229
- virtual void checkArguments() const {
1230
- if (arguments.size() != 1) {
1231
- throw SyntaxError("you passed " + toString(arguments.size()) +
1232
- " argument(s) to has_hint(), but it accepts exactly 1 argument");
1233
- }
1234
- }
1235
- };
1236
-
1237
- Tokenizer tokenizer;
1238
- BooleanComponentPtr root;
1239
- Token lookahead;
1240
- bool debug;
1241
-
1242
- static bool isLiteralToken(const Token &token) {
1243
- return token.type == Tokenizer::REGEXP
1244
- || token.type == Tokenizer::STRING
1245
- || token.type == Tokenizer::INTEGER
1246
- || token.type == Tokenizer::TRUE_LIT
1247
- || token.type == Tokenizer::FALSE_LIT;
1248
- }
1249
-
1250
- static bool isValueToken(const Token &token) {
1251
- return isLiteralToken(token) || token.type == Tokenizer::IDENTIFIER;
1252
- }
1253
-
1254
- static bool isLogicalOperatorToken(const Token &token) {
1255
- return token.type == Tokenizer::AND
1256
- || token.type == Tokenizer::OR;
1257
- }
1258
-
1259
- static Comparator determineComparator(Tokenizer::TokenType type) {
1260
- switch (type) {
1261
- case Tokenizer::MATCHES:
1262
- return MATCHES;
1263
- case Tokenizer::NOT_MATCHES:
1264
- return NOT_MATCHES;
1265
- case Tokenizer::EQUALS:
1266
- return EQUALS;
1267
- case Tokenizer::NOT_EQUALS:
1268
- return NOT_EQUALS;
1269
- case Tokenizer::GREATER_THAN:
1270
- return GREATER_THAN;
1271
- case Tokenizer::GREATER_THAN_OR_EQUALS:
1272
- return GREATER_THAN_OR_EQUALS;
1273
- case Tokenizer::LESS_THAN:
1274
- return LESS_THAN;
1275
- case Tokenizer::LESS_THAN_OR_EQUALS:
1276
- return LESS_THAN_OR_EQUALS;
1277
- default:
1278
- return UNKNOWN_COMPARATOR;
1279
- }
1280
- }
1281
-
1282
- static bool comparatorAcceptsValueTypes(Comparator cmp, ValueType subjectType, ValueType objectType) {
1283
- switch (cmp) {
1284
- case MATCHES:
1285
- case NOT_MATCHES:
1286
- return subjectType == STRING_TYPE && objectType == REGEXP_TYPE;
1287
- case EQUALS:
1288
- case NOT_EQUALS:
1289
- return (subjectType == STRING_TYPE || subjectType == INTEGER_TYPE || subjectType == BOOLEAN_TYPE)
1290
- && subjectType == objectType;
1291
- case GREATER_THAN:
1292
- case GREATER_THAN_OR_EQUALS:
1293
- case LESS_THAN:
1294
- case LESS_THAN_OR_EQUALS:
1295
- return subjectType == INTEGER_TYPE && objectType == INTEGER_TYPE;
1296
- default:
1297
- abort();
1298
- return false; // Shut up compiler warning.
1299
- }
1300
- }
1301
-
1302
- static string unescapeCString(const StaticString &data) {
1303
- string result;
1304
- result.reserve(data.size());
1305
-
1306
- const char *current = data.data();
1307
- const char *end = data.data() + data.size();
1308
- while (current < end) {
1309
- char ch = *current;
1310
- if (ch == '\\') {
1311
- current++;
1312
- if (current < end) {
1313
- ch = *current;
1314
- switch (ch) {
1315
- case 'r':
1316
- result.append(1, '\r');
1317
- break;
1318
- case 'n':
1319
- result.append(1, '\n');
1320
- break;
1321
- case 't':
1322
- result.append(1, '\t');
1323
- break;
1324
- default:
1325
- result.append(1, ch);
1326
- break;
1327
- }
1328
- current++;
1329
- }
1330
- } else {
1331
- result.append(1, ch);
1332
- current++;
1333
- }
1334
- }
1335
-
1336
- return result;
1337
- }
1338
-
1339
- void logMatch(int level, const char *name) const {
1340
- if (level > 100) {
1341
- // If level is too deep then it's probably a bug.
1342
- abort();
1343
- }
1344
- if (debug) {
1345
- for (int i = 0; i < level; i++) {
1346
- printf(" ");
1347
- }
1348
- printf("Matching: %s\n", name);
1349
- }
1350
- }
1351
-
1352
- Token peek() const {
1353
- return lookahead;
1354
- }
1355
-
1356
- bool peek(Tokenizer::TokenType type) const {
1357
- return lookahead.type == type;
1358
- }
1359
-
1360
- Token match(TokenType type) {
1361
- if (lookahead.type == type) {
1362
- return match();
1363
- } else {
1364
- raiseSyntaxError("Expected a " + Tokenizer::typeToString(type) +
1365
- " token, but got " + lookahead.toString(),
1366
- lookahead);
1367
- return Token(); // Shut up compiler warning.
1368
- }
1369
- }
1370
-
1371
- Token match() {
1372
- Token old = lookahead;
1373
- lookahead = tokenizer.getNext();
1374
- return old;
1375
- }
1376
-
1377
- void raiseSyntaxError(const string &msg = "", const Token &token = Token()) {
1378
- if (token.type != Tokenizer::NONE) {
1379
- string message = "at character " + toString(token.pos + 1);
1380
- if (!msg.empty()) {
1381
- message.append(": ");
1382
- message.append(msg);
1383
- }
1384
- throw SyntaxError(message);
1385
- } else {
1386
- throw SyntaxError(msg);
1387
- }
1388
- }
1389
-
1390
- BooleanComponentPtr matchMultiExpression(int level) {
1391
- logMatch(level, "matchMultiExpression()");
1392
- MultiExpressionPtr result = boost::make_shared<MultiExpression>();
1393
-
1394
- result->firstExpression = matchExpression(level + 1);
1395
- while (isLogicalOperatorToken(peek())) {
1396
- MultiExpression::Part part;
1397
- part.theOperator = matchOperator(level + 1);
1398
- part.expression = matchExpression(level + 1);
1399
- result->rest.push_back(part);
1400
- }
1401
-
1402
- return result;
1403
- }
1404
-
1405
- BooleanComponentPtr matchExpression(int level) {
1406
- logMatch(level, "matchExpression()");
1407
- bool negate = false;
1408
-
1409
- if (peek(Tokenizer::NOT)) {
1410
- match();
1411
- negate = true;
1412
- }
1413
-
1414
- Token next = peek();
1415
- if (next.type == Tokenizer::LPARENTHESIS) {
1416
- match();
1417
- BooleanComponentPtr expression = matchMultiExpression(level + 1);
1418
- match(Tokenizer::RPARENTHESIS);
1419
- if (negate) {
1420
- return boost::make_shared<Negation>(expression);
1421
- } else {
1422
- return expression;
1423
- }
1424
- } else if (isValueToken(next)) {
1425
- BooleanComponentPtr component;
1426
- Token &current = next;
1427
- match();
1428
-
1429
- if (peek(Tokenizer::LPARENTHESIS)) {
1430
- component = matchFunctionCall(level + 1, current);
1431
- } else if (determineComparator(peek().type) != UNKNOWN_COMPARATOR) {
1432
- component = matchComparison(level + 1, current);
1433
- } else if (current.type == Tokenizer::TRUE_LIT || current.type == Tokenizer::FALSE_LIT) {
1434
- component = matchSingleValueComponent(level + 1, current);
1435
- } else {
1436
- raiseSyntaxError("expected a function call, comparison or boolean literal", current);
1437
- }
1438
-
1439
- if (negate) {
1440
- return boost::make_shared<Negation>(component);
1441
- } else {
1442
- return component;
1443
- }
1444
- } else {
1445
- raiseSyntaxError("expected a left parenthesis or an identifier", next);
1446
- return BooleanComponentPtr(); // Shut up compiler warning.
1447
- }
1448
- }
1449
-
1450
- BooleanComponentPtr matchSingleValueComponent(int level, const Token &token) {
1451
- logMatch(level, "matchSingleValueComponent()");
1452
- return boost::make_shared<SingleValueComponent>(matchLiteral(level + 1, token));
1453
- }
1454
-
1455
- ComparisonPtr matchComparison(int level, const Token &subjectToken) {
1456
- logMatch(level, "matchComparison()");
1457
- ComparisonPtr comparison = boost::make_shared<Comparison>();
1458
- comparison->subject = matchValue(level + 1, subjectToken);
1459
- comparison->comparator = matchComparator(level + 1);
1460
- comparison->object = matchValue(level + 1, match());
1461
- if (!comparatorAcceptsValueTypes(comparison->comparator, comparison->subject.getType(), comparison->object.getType())) {
1462
- raiseSyntaxError("the comparator cannot operate on the given combination of types", subjectToken);
1463
- }
1464
- return comparison;
1465
- }
1466
-
1467
- FunctionCallPtr matchFunctionCall(int level, const Token &id) {
1468
- logMatch(level, "matchFunctionCall()");
1469
- FunctionCallPtr function;
1470
-
1471
- if (id.rawValue == "starts_with") {
1472
- function = boost::make_shared<StartsWithFunctionCall>();
1473
- } else if (id.rawValue == "has_hint") {
1474
- function = boost::make_shared<HasHintFunctionCall>();
1475
- } else {
1476
- raiseSyntaxError("unknown function '" + id.rawValue + "'", id);
1477
- }
1478
-
1479
- match(Tokenizer::LPARENTHESIS);
1480
- if (isValueToken(peek())) {
1481
- function->arguments.push_back(matchValue(level + 1, match()));
1482
- while (peek(Tokenizer::COMMA)) {
1483
- match();
1484
- function->arguments.push_back(matchValue(level + 1, match()));
1485
- }
1486
- }
1487
- match(Tokenizer::RPARENTHESIS);
1488
- function->checkArguments();
1489
- return function;
1490
- }
1491
-
1492
- Value matchValue(int level, const Token &token) {
1493
- logMatch(level, "matchValue()");
1494
- if (isLiteralToken(token)) {
1495
- return matchLiteral(level + 1, token);
1496
- } else if (token.type == Tokenizer::IDENTIFIER) {
1497
- return matchContextFieldIdentifier(level + 1, token);
1498
- } else {
1499
- raiseSyntaxError("Unrecognized value token " +
1500
- Tokenizer::typeToString(token.type), token);
1501
- return Value(); // Shut up compiler warning.
1502
- }
1503
- }
1504
-
1505
- LogicalOperator matchOperator(int level) {
1506
- logMatch(level, "matchOperator()");
1507
- if (peek(Tokenizer::AND)) {
1508
- logMatch(level + 1, "AND");
1509
- match();
1510
- return AND;
1511
- } else if (peek(Tokenizer::OR)) {
1512
- logMatch(level + 1, "OR");
1513
- match();
1514
- return OR;
1515
- } else {
1516
- raiseSyntaxError("", peek());
1517
- return AND; // Shut up compiler warning.
1518
- }
1519
- }
1520
-
1521
- Comparator matchComparator(int level) {
1522
- logMatch(level, "matchComparator()");
1523
- Comparator comparator = determineComparator(peek().type);
1524
- if (comparator == UNKNOWN_COMPARATOR) {
1525
- raiseSyntaxError("", peek());
1526
- return MATCHES; // Shut up compiler warning.
1527
- } else {
1528
- logMatch(level + 1, Tokenizer::typeToString(peek().type).c_str());
1529
- match();
1530
- return comparator;
1531
- }
1532
- }
1533
-
1534
- Value matchLiteral(int level, const Token &token) {
1535
- logMatch(level, "matchLiteral()");
1536
- if (token.type == Tokenizer::REGEXP) {
1537
- logMatch(level + 1, "regexp");
1538
- return Value(true, unescapeCString(token.rawValue.substr(1, token.rawValue.size() - 2)),
1539
- token.options & Tokenizer::REGEXP_OPTION_CASE_INSENSITIVE);
1540
- } else if (token.type == Tokenizer::STRING) {
1541
- logMatch(level + 1, "string");
1542
- return Value(false, unescapeCString(token.rawValue.substr(1, token.rawValue.size() - 2)));
1543
- } else if (token.type == Tokenizer::INTEGER) {
1544
- logMatch(level + 1, "integer");
1545
- return Value(atoi(token.rawValue.toString()));
1546
- } else if (token.type == Tokenizer::TRUE_LIT) {
1547
- logMatch(level + 1, "true");
1548
- return Value(true);
1549
- } else if (token.type == Tokenizer::FALSE_LIT) {
1550
- logMatch(level + 1, "false");
1551
- return Value(false);
1552
- } else {
1553
- raiseSyntaxError("regular expression, string, integer or boolean expected", token);
1554
- return Value(); // Shut up compiler warning.
1555
- }
1556
- }
1557
-
1558
- Value matchContextFieldIdentifier(int level, const Token &token) {
1559
- logMatch(level, "matchContextFieldIdentifier()");
1560
- if (token.rawValue == "uri") {
1561
- return Value(Context::URI);
1562
- } else if (token.rawValue == "controller") {
1563
- return Value(Context::CONTROLLER);
1564
- } else if (token.rawValue == "response_time") {
1565
- return Value(Context::RESPONSE_TIME);
1566
- } else if (token.rawValue == "response_time_without_gc") {
1567
- return Value(Context::RESPONSE_TIME_WITHOUT_GC);
1568
- } else if (token.rawValue == "status") {
1569
- return Value(Context::STATUS);
1570
- } else if (token.rawValue == "status_code") {
1571
- return Value(Context::STATUS_CODE);
1572
- } else if (token.rawValue == "gc_time") {
1573
- return Value(Context::GC_TIME);
1574
- } else {
1575
- raiseSyntaxError("unknown field '" + token.rawValue + "'", token);
1576
- return Value(); // Shut up compiler warning.
1577
- }
1578
- }
1579
-
1580
- public:
1581
- Filter(const StaticString &source, bool debug = false)
1582
- : tokenizer(source, debug)
1583
- {
1584
- this->debug = debug;
1585
- lookahead = tokenizer.getNext();
1586
- root = matchMultiExpression(0);
1587
- logMatch(0, "end of data");
1588
- match(Tokenizer::END_OF_DATA);
1589
- }
1590
-
1591
- bool run(const Context &ctx) {
1592
- return root->evaluate(ctx);
1593
- }
1594
- };
1595
-
1596
- typedef boost::shared_ptr<Filter> FilterPtr;
1597
-
1598
-
1599
- } // namespace FilterSupport
1600
- } // namespace Passenger
1601
-
1602
- #endif /* __cplusplus */
1603
-
1604
-
1605
- /********* C bindings *********/
1606
-
1607
- #ifdef __cplusplus
1608
- extern "C" {
1609
- #endif
1610
-
1611
- typedef void *PassengerFilter;
1612
-
1613
- PassengerFilter *passenger_filter_create(const char *source, int size, char **error);
1614
- void passenger_filter_free(PassengerFilter *filter);
1615
- char *passenger_filter_validate(const char *source, int size);
1616
-
1617
- #ifdef __cplusplus
1618
- }
1619
- #endif
1620
-
1621
-
1622
- #endif /* _PASSENGER_FILTER_SUPPORT_H_ */