passenger 4.0.48 → 4.0.49

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +36 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG +16 -0
  7. data/Rakefile +0 -1
  8. data/build/apache2.rb +4 -4
  9. data/build/common_library.rb +18 -18
  10. data/build/cplusplus_support.rb +2 -2
  11. data/build/documentation.rb +1 -1
  12. data/build/integration_tests.rb +12 -4
  13. data/build/misc.rb +12 -7
  14. data/build/packaging.rb +14 -14
  15. data/build/preprocessor.rb +10 -10
  16. data/build/rake_extensions.rb +11 -11
  17. data/build/ruby_extension.rb +2 -2
  18. data/dev/ci/inituidgid +24 -0
  19. data/dev/ci/run_jenkins.sh +57 -0
  20. data/dev/ci/run_rpm_tests.sh +77 -0
  21. data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
  22. data/doc/Users guide Nginx.txt +2 -2
  23. data/doc/users_guide_snippets/environment_variables.txt +0 -2
  24. data/doc/users_guide_snippets/tips.txt +20 -1
  25. data/ext/apache2/Bucket.cpp +18 -18
  26. data/ext/apache2/Bucket.h +4 -4
  27. data/ext/apache2/Configuration.cpp +7 -7
  28. data/ext/apache2/Configuration.hpp +43 -43
  29. data/ext/apache2/DirectoryMapper.h +5 -5
  30. data/ext/apache2/Hooks.cpp +142 -142
  31. data/ext/apache2/MergeDirConfig.cpp +40 -40
  32. data/ext/common/Account.h +17 -17
  33. data/ext/common/AccountsDatabase.h +9 -9
  34. data/ext/common/AgentsStarter.cpp +2 -2
  35. data/ext/common/AgentsStarter.h +40 -40
  36. data/ext/common/ApplicationPool2/Common.h +10 -6
  37. data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
  38. data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
  39. data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
  40. data/ext/common/ApplicationPool2/Group.h +54 -38
  41. data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
  42. data/ext/common/ApplicationPool2/Options.h +98 -91
  43. data/ext/common/ApplicationPool2/Pool.h +70 -69
  44. data/ext/common/ApplicationPool2/Process.h +21 -21
  45. data/ext/common/ApplicationPool2/Session.h +11 -11
  46. data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
  47. data/ext/common/ApplicationPool2/Socket.h +19 -19
  48. data/ext/common/ApplicationPool2/Spawner.h +64 -72
  49. data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
  50. data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
  51. data/ext/common/BackgroundEventLoop.cpp +1 -1
  52. data/ext/common/BackgroundEventLoop.h +2 -2
  53. data/ext/common/Constants.h +1 -1
  54. data/ext/common/EventedBufferedInput.h +5 -5
  55. data/ext/common/EventedClient.h +51 -51
  56. data/ext/common/EventedMessageServer.h +39 -39
  57. data/ext/common/EventedServer.h +32 -32
  58. data/ext/common/Exceptions.h +23 -23
  59. data/ext/common/FileDescriptor.h +18 -18
  60. data/ext/common/Logging.cpp +1 -1
  61. data/ext/common/MessageClient.h +27 -27
  62. data/ext/common/MessageReadersWriters.h +79 -79
  63. data/ext/common/MessageServer.h +59 -59
  64. data/ext/common/RandomGenerator.h +12 -12
  65. data/ext/common/ResourceLocator.h +8 -8
  66. data/ext/common/SafeLibev.h +54 -25
  67. data/ext/common/ServerInstanceDir.h +31 -31
  68. data/ext/common/StaticString.h +50 -48
  69. data/ext/common/Utils.cpp +73 -78
  70. data/ext/common/Utils.h +6 -6
  71. data/ext/common/Utils/Base64.cpp +3 -3
  72. data/ext/common/Utils/Base64.h +7 -7
  73. data/ext/common/Utils/BlockingQueue.h +9 -9
  74. data/ext/common/Utils/BufferedIO.h +17 -17
  75. data/ext/common/Utils/CachedFileStat.hpp +16 -16
  76. data/ext/common/Utils/Dechunker.h +25 -25
  77. data/ext/common/Utils/FileChangeChecker.h +10 -10
  78. data/ext/common/Utils/MemZeroGuard.h +5 -5
  79. data/ext/common/Utils/MemoryBarrier.h +1 -1
  80. data/ext/common/Utils/MessageIO.h +61 -61
  81. data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
  82. data/ext/common/Utils/ScopeGuard.h +7 -7
  83. data/ext/common/Utils/SpeedMeter.h +1 -1
  84. data/ext/common/Utils/StrIntUtils.cpp +13 -13
  85. data/ext/common/Utils/StrIntUtils.h +3 -3
  86. data/ext/common/Utils/StringScanning.h +5 -5
  87. data/ext/common/Utils/SystemMetricsCollector.h +2 -2
  88. data/ext/common/Utils/SystemTime.h +10 -10
  89. data/ext/common/Utils/Template.h +2 -2
  90. data/ext/common/Utils/Timer.h +6 -6
  91. data/ext/common/Utils/VariantMap.h +29 -29
  92. data/ext/common/agents/Base.cpp +19 -19
  93. data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
  94. data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
  95. data/ext/common/agents/HelperAgent/Main.cpp +44 -43
  96. data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
  97. data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
  98. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
  99. data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
  100. data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
  101. data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
  102. data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
  103. data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
  104. data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
  105. data/ext/common/agents/SpawnPreparer.cpp +4 -4
  106. data/ext/common/agents/TempDirToucher.c +2 -2
  107. data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
  108. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
  109. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
  110. data/ext/common/agents/Watchdog/Main.cpp +22 -22
  111. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
  112. data/ext/libeio/eio.c +1 -1
  113. data/ext/nginx/Configuration.c +30 -30
  114. data/ext/nginx/Configuration.h +1 -1
  115. data/ext/nginx/ContentHandler.c +54 -54
  116. data/ext/nginx/ContentHandler.h +3 -3
  117. data/ext/nginx/StaticContentHandler.c +2 -2
  118. data/ext/nginx/ngx_http_passenger_module.c +21 -21
  119. data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
  120. data/ext/oxt/detail/context.hpp +1 -1
  121. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
  122. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
  123. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  124. data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
  125. data/ext/oxt/dynamic_thread_group.hpp +18 -18
  126. data/ext/oxt/implementation.cpp +9 -8
  127. data/ext/oxt/macros.hpp +2 -2
  128. data/ext/oxt/system_calls.cpp +11 -11
  129. data/ext/oxt/system_calls.hpp +13 -13
  130. data/ext/oxt/thread.hpp +22 -14
  131. data/ext/ruby/passenger_native_support.c +55 -55
  132. data/lib/phusion_passenger.rb +24 -24
  133. data/lib/phusion_passenger/common_library.rb +2 -0
  134. data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
  135. data/lib/phusion_passenger/packaging.rb +9 -4
  136. data/lib/phusion_passenger/platform_info/apache.rb +45 -31
  137. data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
  138. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
  139. data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
  140. data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
  141. data/lib/phusion_passenger/standalone/command.rb +22 -22
  142. data/packaging/rpm/LICENSE.txt +19 -0
  143. data/packaging/rpm/Makefile +13 -0
  144. data/packaging/rpm/README.md +41 -0
  145. data/packaging/rpm/Vagrantfile +38 -0
  146. data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
  147. data/packaging/rpm/build +170 -0
  148. data/packaging/rpm/create_project +41 -0
  149. data/packaging/rpm/git_update +88 -0
  150. data/packaging/rpm/image/Dockerfile +37 -0
  151. data/packaging/rpm/image/Gemfile +3 -0
  152. data/packaging/rpm/image/Gemfile.lock +12 -0
  153. data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
  154. data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
  155. data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
  156. data/packaging/rpm/image/site-defaults.cfg +168 -0
  157. data/packaging/rpm/internal/build_tasks.rb +238 -0
  158. data/packaging/rpm/internal/dummygpg +11 -0
  159. data/packaging/rpm/internal/exec_build +42 -0
  160. data/packaging/rpm/internal/get_distro_arch +14 -0
  161. data/packaging/rpm/internal/get_distro_id +10 -0
  162. data/packaging/rpm/internal/git_update +27 -0
  163. data/packaging/rpm/internal/inituidgid +17 -0
  164. data/packaging/rpm/internal/my_init +344 -0
  165. data/packaging/rpm/internal/python27 +3 -0
  166. data/packaging/rpm/internal/repo_update +46 -0
  167. data/packaging/rpm/internal/setuser +26 -0
  168. data/packaging/rpm/internal/tracking_helper +40 -0
  169. data/packaging/rpm/jenkins_release +99 -0
  170. data/packaging/rpm/lib/build_tasks_support.rb +402 -0
  171. data/packaging/rpm/lib/preprocessor.rb +341 -0
  172. data/packaging/rpm/nginx_spec/404.html +119 -0
  173. data/packaging/rpm/nginx_spec/50x.html +119 -0
  174. data/packaging/rpm/nginx_spec/index.html +116 -0
  175. data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
  176. data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
  177. data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
  178. data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
  179. data/packaging/rpm/nginx_spec/nginx.conf +131 -0
  180. data/packaging/rpm/nginx_spec/nginx.init +144 -0
  181. data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
  182. data/packaging/rpm/nginx_spec/nginx.service +15 -0
  183. data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
  184. data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
  185. data/packaging/rpm/nginx_spec/passenger.conf +9 -0
  186. data/packaging/rpm/nginx_spec/poweredby.png +0 -0
  187. data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
  188. data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
  189. data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
  190. data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
  191. data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
  192. data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
  193. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
  194. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
  195. data/packaging/rpm/repo_update +114 -0
  196. data/packaging/rpm/setup-system +60 -0
  197. data/packaging/rpm/shell +10 -0
  198. data/resources/templates/standalone/config.erb +3 -1
  199. data/test/config.json.rpm-automation +1 -1
  200. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
  201. data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
  202. data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
  203. data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
  204. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
  205. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
  206. data/test/cxx/ScgiRequestParserTest.cpp +75 -61
  207. data/test/cxx/UtilsTest.cpp +86 -85
  208. data/test/gdbinit.example +3 -0
  209. data/test/integration_tests/nginx_tests.rb +3 -3
  210. data/test/integration_tests/source_packaging_test.rb +3 -1
  211. data/test/stub/nginx/nginx.conf.erb +8 -1
  212. data/test/support/nginx_controller.rb +7 -7
  213. metadata +62 -17
  214. metadata.gz.asc +7 -7
  215. data/build/rpm.rb +0 -128
  216. data/dev/rpmtool +0 -21
  217. data/dev/test_rpm_packaging.sh +0 -28
  218. data/rpm/get_distro_id.py +0 -4
@@ -41,16 +41,16 @@ class AdminController: public MessageServer::Handler {
41
41
  private:
42
42
  struct SpecificContext: public MessageServer::ClientContext {
43
43
  };
44
-
44
+
45
45
  typedef MessageServer::CommonClientContext CommonClientContext;
46
-
46
+
47
47
  LoggingServerPtr server;
48
-
49
-
48
+
49
+
50
50
  /*********************************************
51
51
  * Message handler methods
52
52
  *********************************************/
53
-
53
+
54
54
  void processStatus(CommonClientContext &commonContext, SpecificContext *specificContext,
55
55
  const vector<string> &args)
56
56
  {
@@ -60,16 +60,16 @@ private:
60
60
  server->dump(stream);
61
61
  writeScalarMessage(commonContext.fd, stream.str());
62
62
  }
63
-
63
+
64
64
  public:
65
65
  AdminController(const LoggingServerPtr &server) {
66
66
  this->server = server;
67
67
  }
68
-
68
+
69
69
  virtual MessageServer::ClientContextPtr newClient(CommonClientContext &commonContext) {
70
70
  return boost::make_shared<SpecificContext>();
71
71
  }
72
-
72
+
73
73
  virtual bool processMessage(CommonClientContext &commonContext,
74
74
  MessageServer::ClientContextPtr &_specificContext,
75
75
  const vector<string> &args)
@@ -42,11 +42,11 @@ private:
42
42
  unsigned short groupNameSize;
43
43
  unsigned short nodeNameSize;
44
44
  unsigned short categorySize;
45
-
45
+
46
46
  size_t totalSize() const {
47
47
  return groupNameSize + nodeNameSize + categorySize + 3;
48
48
  }
49
-
49
+
50
50
  StaticString toStaticString() const {
51
51
  if (id == NULL) {
52
52
  return StaticString();
@@ -54,7 +54,7 @@ private:
54
54
  return StaticString(id, totalSize());
55
55
  }
56
56
  }
57
-
57
+
58
58
  public:
59
59
  DataStoreId(const StaticString &groupName, const StaticString &nodeName,
60
60
  const StaticString &category)
@@ -62,35 +62,35 @@ public:
62
62
  assert(groupName.size() <= USHRT_MAX);
63
63
  assert(nodeName.size() <= USHRT_MAX);
64
64
  assert(category.size() <= USHRT_MAX);
65
-
65
+
66
66
  char *end;
67
-
67
+
68
68
  id = new char[groupName.size() + nodeName.size() +
69
69
  category.size() + 3];
70
70
  end = id;
71
-
71
+
72
72
  memcpy(end, groupName.c_str(), groupName.size());
73
73
  groupNameSize = groupName.size();
74
74
  end += groupName.size();
75
75
  *end = '\0';
76
76
  end++;
77
-
77
+
78
78
  memcpy(end, nodeName.c_str(), nodeName.size());
79
79
  nodeNameSize = nodeName.size();
80
80
  end += nodeName.size();
81
81
  *end = '\0';
82
82
  end++;
83
-
83
+
84
84
  memcpy(end, category.c_str(), category.size());
85
85
  categorySize = category.size();
86
86
  end += category.size();
87
87
  *end = '\0';
88
88
  }
89
-
89
+
90
90
  DataStoreId() {
91
91
  id = NULL;
92
92
  }
93
-
93
+
94
94
  DataStoreId(const DataStoreId &other) {
95
95
  if (other.id == NULL) {
96
96
  id = NULL;
@@ -102,11 +102,11 @@ public:
102
102
  categorySize = other.categorySize;
103
103
  }
104
104
  }
105
-
105
+
106
106
  ~DataStoreId() {
107
107
  delete id;
108
108
  }
109
-
109
+
110
110
  DataStoreId &operator=(const DataStoreId &other) {
111
111
  if (other.id == NULL) {
112
112
  delete id;
@@ -127,11 +127,11 @@ public:
127
127
  return *this;
128
128
  }
129
129
  }
130
-
130
+
131
131
  bool operator<(const DataStoreId &other) const {
132
132
  return toStaticString() < other.toStaticString();
133
133
  }
134
-
134
+
135
135
  bool operator==(const DataStoreId &other) const {
136
136
  if (id == NULL) {
137
137
  return other.id == NULL;
@@ -143,7 +143,7 @@ public:
143
143
  }
144
144
  }
145
145
  }
146
-
146
+
147
147
  StaticString getGroupName() const {
148
148
  if (id != NULL) {
149
149
  return StaticString(id, groupNameSize);
@@ -151,7 +151,7 @@ public:
151
151
  return StaticString();
152
152
  }
153
153
  }
154
-
154
+
155
155
  StaticString getNodeName() const {
156
156
  if (id != NULL) {
157
157
  return StaticString(id + groupNameSize + 1,
@@ -160,7 +160,7 @@ public:
160
160
  return StaticString();
161
161
  }
162
162
  }
163
-
163
+
164
164
  StaticString getCategory() const {
165
165
  if (id != NULL) {
166
166
  return StaticString(id + groupNameSize + 1 + nodeNameSize + 1,
@@ -81,23 +81,23 @@ public:
81
81
  IDENTIFIER,
82
82
  END_OF_DATA
83
83
  };
84
-
84
+
85
85
  enum TokenOptions {
86
86
  NO_OPTIONS = 0,
87
87
  REGEXP_OPTION_CASE_INSENSITIVE = 1
88
88
  };
89
-
89
+
90
90
  struct Token {
91
91
  TokenType type;
92
92
  int options;
93
93
  unsigned int pos;
94
94
  unsigned int size;
95
95
  StaticString rawValue;
96
-
96
+
97
97
  Token() {
98
98
  type = NONE;
99
99
  }
100
-
100
+
101
101
  Token(TokenType _type, unsigned int _pos, unsigned int _size, const StaticString &_rawValue)
102
102
  : type(_type),
103
103
  options(NO_OPTIONS),
@@ -105,7 +105,7 @@ public:
105
105
  size(_size),
106
106
  rawValue(_rawValue)
107
107
  { }
108
-
108
+
109
109
  string toString() const {
110
110
  return Tokenizer::typeToString(type);
111
111
  }
@@ -115,47 +115,47 @@ private:
115
115
  StaticString data;
116
116
  bool debug;
117
117
  unsigned int pos;
118
-
118
+
119
119
  static bool isWhitespace(char ch) {
120
120
  return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
121
121
  }
122
-
122
+
123
123
  void skipWhitespaces() {
124
124
  while (pos < data.size() && isWhitespace(data[pos])) {
125
125
  pos++;
126
126
  }
127
127
  }
128
-
128
+
129
129
  unsigned int available() const {
130
130
  return data.size() - pos;
131
131
  }
132
-
132
+
133
133
  char current() const {
134
134
  return data[pos];
135
135
  }
136
-
136
+
137
137
  char next() const {
138
138
  return data[pos + 1];
139
139
  }
140
-
140
+
141
141
  static bool isIdentifierChar(char ch) {
142
142
  return (ch >= 'a' && ch <= 'z')
143
143
  || (ch >= 'A' && ch <= 'Z')
144
144
  || (ch >= '0' && ch <= '9')
145
145
  || ch == '_';
146
146
  }
147
-
147
+
148
148
  static bool isDigit(char ch) {
149
149
  return ch >= '0' && ch <= '9';
150
150
  }
151
-
151
+
152
152
  Token logToken(const Token &token) const {
153
153
  if (debug) {
154
154
  printf("# Token: %s\n", token.toString().c_str());
155
155
  }
156
156
  return token;
157
157
  }
158
-
158
+
159
159
  void raiseSyntaxError(const string &message = "") {
160
160
  string msg = "Syntax error at character " + toString(pos + 1);
161
161
  if (!message.empty()) {
@@ -164,14 +164,14 @@ private:
164
164
  }
165
165
  throw SyntaxError(msg);
166
166
  }
167
-
167
+
168
168
  void expectingAtLeast(unsigned int size) {
169
169
  if (available() < size) {
170
170
  raiseSyntaxError("at least " + toString(size) +
171
171
  " more characters expected");
172
172
  }
173
173
  }
174
-
174
+
175
175
  void expectingNextChar(char ch) {
176
176
  expectingAtLeast(2);
177
177
  if (next() != ch) {
@@ -180,13 +180,13 @@ private:
180
180
  "'");
181
181
  }
182
182
  }
183
-
183
+
184
184
  Token matchToken(TokenType type, unsigned int size = 0) {
185
185
  unsigned int oldPos = pos;
186
186
  pos += size;
187
187
  return Token(type, oldPos, size, data.substr(oldPos, size));
188
188
  }
189
-
189
+
190
190
  Token matchTokensStartingWithNegation() {
191
191
  expectingAtLeast(2);
192
192
  switch (next()) {
@@ -199,17 +199,17 @@ private:
199
199
  return Token(); // Shut up compiler warning.
200
200
  };
201
201
  }
202
-
202
+
203
203
  Token matchAnd() {
204
204
  expectingNextChar('&');
205
205
  return matchToken(AND, 2);
206
206
  }
207
-
207
+
208
208
  Token matchOr() {
209
209
  expectingNextChar('|');
210
210
  return matchToken(OR, 2);
211
211
  }
212
-
212
+
213
213
  Token matchTokensStartingWithEquals() {
214
214
  expectingAtLeast(2);
215
215
  switch (next()) {
@@ -222,7 +222,7 @@ private:
222
222
  return Token(); // Shut up compiler warning.
223
223
  }
224
224
  }
225
-
225
+
226
226
  Token matchTokensStartingWithGreaterThan() {
227
227
  if (available() == 0 || next() != '=') {
228
228
  return matchToken(GREATER_THAN, 1);
@@ -230,7 +230,7 @@ private:
230
230
  return matchToken(GREATER_THAN_OR_EQUALS, 2);
231
231
  }
232
232
  }
233
-
233
+
234
234
  Token matchTokensStartingWithLessThan() {
235
235
  if (available() == 0 || next() != '=') {
236
236
  return matchToken(LESS_THAN, 1);
@@ -238,14 +238,14 @@ private:
238
238
  return matchToken(LESS_THAN_OR_EQUALS, 2);
239
239
  }
240
240
  }
241
-
241
+
242
242
  Token matchRegexp(char terminator) {
243
243
  unsigned int start = pos;
244
244
  bool endFound = false;
245
-
245
+
246
246
  // Match initial quote slash.
247
247
  pos++;
248
-
248
+
249
249
  // Match rest of regexp including terminating slash.
250
250
  while (pos < data.size() && !endFound) {
251
251
  char ch = current();
@@ -263,10 +263,10 @@ private:
263
263
  pos++;
264
264
  }
265
265
  }
266
-
266
+
267
267
  if (endFound) {
268
268
  Token t(REGEXP, start, pos - start, data.substr(start, pos - start));
269
-
269
+
270
270
  // Match regexp options.
271
271
  endFound = false;
272
272
  while (pos < data.size() && !endFound) {
@@ -278,21 +278,21 @@ private:
278
278
  }
279
279
  pos++;
280
280
  }
281
-
281
+
282
282
  return t;
283
283
  } else {
284
284
  raiseSyntaxError("unterminated regular expression");
285
285
  return Token(); // Shut up compiler warning.
286
286
  }
287
287
  }
288
-
288
+
289
289
  Token matchString(char terminator) {
290
290
  unsigned int start = pos;
291
291
  bool endFound = false;
292
-
292
+
293
293
  // Match initial quote character.
294
294
  pos++;
295
-
295
+
296
296
  // Match rest of string including terminating quote.
297
297
  while (pos < data.size() && !endFound) {
298
298
  char ch = current();
@@ -310,7 +310,7 @@ private:
310
310
  pos++;
311
311
  }
312
312
  }
313
-
313
+
314
314
  if (endFound) {
315
315
  return Token(STRING, start, pos - start, data.substr(start, pos - start));
316
316
  } else {
@@ -318,20 +318,20 @@ private:
318
318
  return Token(); // Shut up compiler warning.
319
319
  }
320
320
  }
321
-
321
+
322
322
  Token matchInteger() {
323
323
  unsigned int start = pos;
324
-
324
+
325
325
  // Accept initial minus or digit.
326
326
  pos++;
327
-
327
+
328
328
  while (pos < data.size() && isDigit(data[pos])) {
329
329
  pos++;
330
330
  }
331
-
331
+
332
332
  return Token(INTEGER, start, pos - start, data.substr(start, pos - start));
333
333
  }
334
-
334
+
335
335
  Token matchIdentifier() {
336
336
  char ch = current();
337
337
  if ((ch >= 'a' && ch <= 'z') ||
@@ -342,7 +342,7 @@ private:
342
342
  while (pos < data.size() && isIdentifierChar(current())) {
343
343
  pos++;
344
344
  }
345
-
345
+
346
346
  StaticString val = data.substr(start, pos - start);
347
347
  if (val == "true") {
348
348
  return Token(TRUE_LIT, start, pos - start, val);
@@ -363,13 +363,13 @@ public:
363
363
  this->debug = debug;
364
364
  pos = 0;
365
365
  }
366
-
366
+
367
367
  Token getNext() {
368
368
  skipWhitespaces();
369
369
  if (pos >= data.size()) {
370
370
  return logToken(Token(END_OF_DATA, data.size(), 0, ""));
371
371
  }
372
-
372
+
373
373
  switch (current()) {
374
374
  case '!':
375
375
  return logToken(matchTokensStartingWithNegation());
@@ -413,7 +413,7 @@ public:
413
413
  }
414
414
  }
415
415
  }
416
-
416
+
417
417
  static string typeToString(TokenType type) {
418
418
  switch (type) {
419
419
  case NONE:
@@ -487,9 +487,9 @@ public:
487
487
  STATUS_CODE,
488
488
  GC_TIME
489
489
  };
490
-
490
+
491
491
  virtual ~Context() { }
492
-
492
+
493
493
  virtual string getURI() const = 0;
494
494
  virtual string getController() const = 0;
495
495
  virtual int getResponseTime() const = 0;
@@ -497,11 +497,11 @@ public:
497
497
  virtual int getStatusCode() const = 0;
498
498
  virtual int getGcTime() const = 0;
499
499
  virtual bool hasHint(const string &name) const = 0;
500
-
500
+
501
501
  int getResponseTimeWithoutGc() const {
502
502
  return getResponseTime() - getGcTime();
503
503
  }
504
-
504
+
505
505
  string queryStringField(FieldIdentifier id) const {
506
506
  switch (id) {
507
507
  case URI:
@@ -522,7 +522,7 @@ public:
522
522
  return "";
523
523
  }
524
524
  }
525
-
525
+
526
526
  int queryIntField(FieldIdentifier id) const {
527
527
  switch (id) {
528
528
  case RESPONSE_TIME:
@@ -537,7 +537,7 @@ public:
537
537
  return 0;
538
538
  }
539
539
  }
540
-
540
+
541
541
  bool queryBoolField(FieldIdentifier id) const {
542
542
  switch (id) {
543
543
  case URI:
@@ -558,7 +558,7 @@ public:
558
558
  return false;
559
559
  }
560
560
  }
561
-
561
+
562
562
  static ValueType getFieldType(FieldIdentifier id) {
563
563
  switch (id) {
564
564
  case URI:
@@ -585,37 +585,37 @@ public:
585
585
  int statusCode;
586
586
  int gcTime;
587
587
  set<string> hints;
588
-
588
+
589
589
  SimpleContext() {
590
590
  responseTime = 0;
591
591
  statusCode = 0;
592
592
  gcTime = 0;
593
593
  }
594
-
594
+
595
595
  virtual string getURI() const {
596
596
  return uri;
597
597
  }
598
-
598
+
599
599
  virtual string getController() const {
600
600
  return controller;
601
601
  }
602
-
602
+
603
603
  virtual int getResponseTime() const {
604
604
  return responseTime;
605
605
  }
606
-
606
+
607
607
  virtual string getStatus() const {
608
608
  return status;
609
609
  }
610
-
610
+
611
611
  virtual int getStatusCode() const {
612
612
  return statusCode;
613
613
  }
614
-
614
+
615
615
  virtual int getGcTime() const {
616
616
  return gcTime;
617
617
  }
618
-
618
+
619
619
  virtual bool hasHint(const string &name) const {
620
620
  return hints.find(name) != hints.end();
621
621
  }
@@ -625,7 +625,7 @@ class ContextFromLog: public Context {
625
625
  private:
626
626
  StaticString logData;
627
627
  mutable SimpleContext *parsedData;
628
-
628
+
629
629
  struct ParseState {
630
630
  unsigned long long requestProcessingStart;
631
631
  unsigned long long requestProcessingEnd;
@@ -634,7 +634,7 @@ private:
634
634
  unsigned long long gcTimeStart;
635
635
  unsigned long long gcTimeEnd;
636
636
  };
637
-
637
+
638
638
  static void parseLine(const StaticString &txnId, unsigned long long timestamp,
639
639
  const StaticString &data, SimpleContext &ctx, ParseState &state)
640
640
  {
@@ -662,7 +662,7 @@ private:
662
662
  StaticString value = data.substr(data.find(':') + 2);
663
663
  state.gcTimeEnd = stringToULL(value);
664
664
  }
665
-
665
+
666
666
  if (state.smallestTimestamp == 0 || timestamp < state.smallestTimestamp) {
667
667
  state.smallestTimestamp = timestamp;
668
668
  }
@@ -670,14 +670,14 @@ private:
670
670
  state.largestTimestamp = timestamp;
671
671
  }
672
672
  }
673
-
673
+
674
674
  static void reallyParse(const StaticString &data, SimpleContext &ctx) {
675
675
  const char *current = data.data();
676
676
  const char *end = data.data() + data.size();
677
-
677
+
678
678
  ParseState state;
679
679
  memset(&state, 0, sizeof(state));
680
-
680
+
681
681
  while (current < end) {
682
682
  current = skipNewlines(current, end);
683
683
  if (current < end) {
@@ -688,7 +688,7 @@ private:
688
688
  unsigned long long timestamp;
689
689
  unsigned int writeCount;
690
690
  StaticString lineData;
691
-
691
+
692
692
  // If we want to do more complicated analysis we should sort
693
693
  // the lines but for the purposes of ContextFromLog
694
694
  // analyzing the data without sorting is good enough.
@@ -700,19 +700,19 @@ private:
700
700
  current = endOfLine;
701
701
  }
702
702
  }
703
-
703
+
704
704
  if (state.requestProcessingEnd != 0) {
705
705
  ctx.responseTime = int(state.requestProcessingEnd -
706
706
  state.requestProcessingStart);
707
707
  } else if (state.smallestTimestamp != 0) {
708
708
  ctx.responseTime = state.largestTimestamp - state.smallestTimestamp;
709
709
  }
710
-
710
+
711
711
  if (state.gcTimeEnd != 0) {
712
712
  ctx.gcTime = state.gcTimeEnd - state.gcTimeStart;
713
713
  }
714
714
  }
715
-
715
+
716
716
  static bool splitLine(const StaticString &line, StaticString &txnId,
717
717
  unsigned long long &timestamp, unsigned int &writeCount,
718
718
  StaticString &data)
@@ -721,17 +721,17 @@ private:
721
721
  if (firstDelim == string::npos) {
722
722
  return false;
723
723
  }
724
-
724
+
725
725
  size_t secondDelim = line.find(' ', firstDelim + 1);
726
726
  if (secondDelim == string::npos) {
727
727
  return false;
728
728
  }
729
-
729
+
730
730
  size_t thirdDelim = line.find(' ', secondDelim + 1);
731
731
  if (thirdDelim == string::npos) {
732
732
  return false;
733
733
  }
734
-
734
+
735
735
  txnId = line.substr(0, firstDelim);
736
736
  timestamp = hexatriToULL(line.substr(firstDelim + 1, secondDelim - firstDelim - 1));
737
737
  writeCount = (unsigned int) hexatriToULL(line.substr(secondDelim + 1,
@@ -739,7 +739,7 @@ private:
739
739
  data = line.substr(thirdDelim + 1);
740
740
  return true;
741
741
  }
742
-
742
+
743
743
  static unsigned long long extractEventTimestamp(const StaticString &data) {
744
744
  size_t pos = data.find('(');
745
745
  if (pos == string::npos) {
@@ -757,29 +757,29 @@ private:
757
757
  }
758
758
  }
759
759
  }
760
-
760
+
761
761
  static bool isNewline(char ch) {
762
762
  return ch == '\n' || ch == '\r';
763
763
  }
764
-
764
+
765
765
  static bool isDigit(char ch) {
766
766
  return ch >= '0' && ch <= '9';
767
767
  }
768
-
768
+
769
769
  static const char *skipNewlines(const char *current, const char *end) {
770
770
  while (current < end && isNewline(*current)) {
771
771
  current++;
772
772
  }
773
773
  return current;
774
774
  }
775
-
775
+
776
776
  static const char *findEndOfLine(const char *current, const char *end) {
777
777
  while (current < end && !isNewline(*current)) {
778
778
  current++;
779
779
  }
780
780
  return current;
781
781
  }
782
-
782
+
783
783
  SimpleContext *parse() const {
784
784
  if (parsedData == NULL) {
785
785
  auto_ptr<SimpleContext> ctx(new SimpleContext());
@@ -788,41 +788,41 @@ private:
788
788
  }
789
789
  return parsedData;
790
790
  }
791
-
791
+
792
792
  public:
793
793
  ContextFromLog(const StaticString &logData) {
794
794
  this->logData = logData;
795
795
  parsedData = NULL;
796
796
  }
797
-
797
+
798
798
  ~ContextFromLog() {
799
799
  delete parsedData;
800
800
  }
801
-
801
+
802
802
  virtual string getURI() const {
803
803
  return parse()->uri;
804
804
  }
805
-
805
+
806
806
  virtual string getController() const {
807
807
  return parse()->getController();
808
808
  }
809
-
809
+
810
810
  virtual int getResponseTime() const {
811
811
  return parse()->getResponseTime();
812
812
  }
813
-
813
+
814
814
  virtual string getStatus() const {
815
815
  return parse()->getStatus();
816
816
  }
817
-
817
+
818
818
  virtual int getStatusCode() const {
819
819
  return parse()->getStatusCode();
820
820
  }
821
-
821
+
822
822
  virtual int getGcTime() const {
823
823
  return parse()->getGcTime();
824
824
  }
825
-
825
+
826
826
  virtual bool hasHint(const string &name) const {
827
827
  return parse()->hasHint(name);
828
828
  }
@@ -833,7 +833,7 @@ class Filter {
833
833
  private:
834
834
  typedef Tokenizer::Token Token;
835
835
  typedef Tokenizer::TokenType TokenType;
836
-
836
+
837
837
  struct BooleanComponent;
838
838
  struct MultiExpression;
839
839
  struct Comparison;
@@ -842,17 +842,17 @@ private:
842
842
  typedef boost::shared_ptr<MultiExpression> MultiExpressionPtr;
843
843
  typedef boost::shared_ptr<Comparison> ComparisonPtr;
844
844
  typedef boost::shared_ptr<FunctionCall> FunctionCallPtr;
845
-
845
+
846
846
  struct BooleanComponent {
847
847
  virtual ~BooleanComponent() { }
848
848
  virtual bool evaluate(const Context &ctx) = 0;
849
849
  };
850
-
850
+
851
851
  enum LogicalOperator {
852
852
  AND,
853
853
  OR
854
854
  };
855
-
855
+
856
856
  enum Comparator {
857
857
  MATCHES,
858
858
  NOT_MATCHES,
@@ -864,21 +864,21 @@ private:
864
864
  LESS_THAN_OR_EQUALS,
865
865
  UNKNOWN_COMPARATOR
866
866
  };
867
-
867
+
868
868
  struct MultiExpression: public BooleanComponent {
869
869
  struct Part {
870
870
  LogicalOperator theOperator;
871
871
  BooleanComponentPtr expression;
872
872
  };
873
-
873
+
874
874
  BooleanComponentPtr firstExpression;
875
875
  vector<Part> rest;
876
-
876
+
877
877
  virtual bool evaluate(const Context &ctx) {
878
878
  bool result = firstExpression->evaluate(ctx);
879
879
  unsigned int i = 0;
880
880
  bool done = i == rest.size();
881
-
881
+
882
882
  while (!done) {
883
883
  Part &nextPart = rest[i];
884
884
  if (nextPart.theOperator == AND) {
@@ -890,23 +890,23 @@ private:
890
890
  i++;
891
891
  done = done || i == rest.size();
892
892
  }
893
-
893
+
894
894
  return result;
895
895
  }
896
896
  };
897
-
897
+
898
898
  struct Negation: public BooleanComponent {
899
899
  BooleanComponentPtr expr;
900
-
900
+
901
901
  Negation(const BooleanComponentPtr &e)
902
902
  : expr(e)
903
903
  { }
904
-
904
+
905
905
  virtual bool evaluate(const Context &ctx) {
906
906
  return !expr->evaluate(ctx);
907
907
  }
908
908
  };
909
-
909
+
910
910
  struct Value {
911
911
  enum Source {
912
912
  REGEXP_LITERAL,
@@ -915,7 +915,7 @@ private:
915
915
  BOOLEAN_LITERAL,
916
916
  CONTEXT_FIELD_IDENTIFIER
917
917
  };
918
-
918
+
919
919
  Source source;
920
920
  union {
921
921
  struct {
@@ -930,16 +930,16 @@ private:
930
930
  bool boolValue;
931
931
  Context::FieldIdentifier contextFieldIdentifier;
932
932
  } u;
933
-
933
+
934
934
  Value() {
935
935
  source = INTEGER_LITERAL;
936
936
  u.intValue = 0;
937
937
  }
938
-
938
+
939
939
  Value(const Value &other) {
940
940
  initializeFrom(other);
941
941
  }
942
-
942
+
943
943
  Value(bool regexp, const StaticString &value, bool caseInsensitive = false) {
944
944
  if (regexp) {
945
945
  source = REGEXP_LITERAL;
@@ -961,32 +961,32 @@ private:
961
961
  options);
962
962
  }
963
963
  }
964
-
964
+
965
965
  Value(int val) {
966
966
  source = INTEGER_LITERAL;
967
967
  u.intValue = val;
968
968
  }
969
-
969
+
970
970
  Value(bool val) {
971
971
  source = BOOLEAN_LITERAL;
972
972
  u.boolValue = val;
973
973
  }
974
-
974
+
975
975
  Value(Context::FieldIdentifier identifier) {
976
976
  source = CONTEXT_FIELD_IDENTIFIER;
977
977
  u.contextFieldIdentifier = identifier;
978
978
  }
979
-
979
+
980
980
  ~Value() {
981
981
  freeStorage();
982
982
  }
983
-
983
+
984
984
  Value &operator=(const Value &other) {
985
985
  freeStorage();
986
986
  initializeFrom(other);
987
987
  return *this;
988
988
  }
989
-
989
+
990
990
  regex_t *getRegexpValue(const Context &ctx) const {
991
991
  if (source == REGEXP_LITERAL) {
992
992
  return &storedRegexp();
@@ -994,7 +994,7 @@ private:
994
994
  return NULL;
995
995
  }
996
996
  }
997
-
997
+
998
998
  string getStringValue(const Context &ctx) const {
999
999
  switch (source) {
1000
1000
  case REGEXP_LITERAL:
@@ -1014,7 +1014,7 @@ private:
1014
1014
  return "";
1015
1015
  }
1016
1016
  }
1017
-
1017
+
1018
1018
  int getIntegerValue(const Context &ctx) const {
1019
1019
  switch (source) {
1020
1020
  case REGEXP_LITERAL:
@@ -1031,7 +1031,7 @@ private:
1031
1031
  return 0;
1032
1032
  }
1033
1033
  }
1034
-
1034
+
1035
1035
  bool getBooleanValue(const Context &ctx) const {
1036
1036
  switch (source) {
1037
1037
  case REGEXP_LITERAL:
@@ -1048,7 +1048,7 @@ private:
1048
1048
  return 0;
1049
1049
  }
1050
1050
  }
1051
-
1051
+
1052
1052
  ValueType getType() const {
1053
1053
  switch (source) {
1054
1054
  case REGEXP_LITERAL:
@@ -1065,16 +1065,16 @@ private:
1065
1065
  return UNKNOWN_TYPE;
1066
1066
  }
1067
1067
  }
1068
-
1068
+
1069
1069
  private:
1070
1070
  const string &storedString() const {
1071
1071
  return *u.stringOrRegexpValue.stringPointer;
1072
1072
  }
1073
-
1073
+
1074
1074
  regex_t &storedRegexp() const {
1075
1075
  return (regex_t &) u.stringOrRegexpValue.regexp.regexp;
1076
1076
  }
1077
-
1077
+
1078
1078
  void freeStorage() {
1079
1079
  if (source == REGEXP_LITERAL || source == STRING_LITERAL) {
1080
1080
  storedString().~string();
@@ -1083,7 +1083,7 @@ private:
1083
1083
  }
1084
1084
  }
1085
1085
  }
1086
-
1086
+
1087
1087
  void initializeFrom(const Value &other) {
1088
1088
  int options;
1089
1089
  source = other.source;
@@ -1116,24 +1116,24 @@ private:
1116
1116
  }
1117
1117
  }
1118
1118
  };
1119
-
1119
+
1120
1120
  struct SingleValueComponent: public BooleanComponent {
1121
1121
  Value val;
1122
-
1122
+
1123
1123
  SingleValueComponent(const Value &v)
1124
1124
  : val(v)
1125
1125
  { }
1126
-
1126
+
1127
1127
  virtual bool evaluate(const Context &ctx) {
1128
1128
  return val.getBooleanValue(ctx);
1129
1129
  }
1130
1130
  };
1131
-
1131
+
1132
1132
  struct Comparison: public BooleanComponent {
1133
1133
  Value subject;
1134
1134
  Comparator comparator;
1135
1135
  Value object;
1136
-
1136
+
1137
1137
  virtual bool evaluate(const Context &ctx) {
1138
1138
  switch (subject.getType()) {
1139
1139
  case STRING_TYPE:
@@ -1147,7 +1147,7 @@ private:
1147
1147
  return false;
1148
1148
  }
1149
1149
  }
1150
-
1150
+
1151
1151
  private:
1152
1152
  bool compareStringOrRegexp(const string &str, const Context &ctx) {
1153
1153
  switch (comparator) {
@@ -1164,7 +1164,7 @@ private:
1164
1164
  return false;
1165
1165
  }
1166
1166
  }
1167
-
1167
+
1168
1168
  bool compareInteger(int value, const Context &ctx) {
1169
1169
  int value2 = object.getIntegerValue(ctx);
1170
1170
  switch (comparator) {
@@ -1185,7 +1185,7 @@ private:
1185
1185
  return false;
1186
1186
  }
1187
1187
  }
1188
-
1188
+
1189
1189
  bool compareBoolean(bool value, const Context &ctx) {
1190
1190
  bool value2 = object.getBooleanValue(ctx);
1191
1191
  switch (comparator) {
@@ -1199,45 +1199,45 @@ private:
1199
1199
  }
1200
1200
  }
1201
1201
  };
1202
-
1202
+
1203
1203
  struct FunctionCall: public BooleanComponent {
1204
1204
  vector<Value> arguments;
1205
-
1205
+
1206
1206
  virtual void checkArguments() const = 0;
1207
1207
  };
1208
-
1208
+
1209
1209
  struct StartsWithFunctionCall: public FunctionCall {
1210
1210
  virtual bool evaluate(const Context &ctx) {
1211
1211
  return startsWith(arguments[0].getStringValue(ctx),
1212
1212
  arguments[1].getStringValue(ctx));
1213
1213
  }
1214
-
1214
+
1215
1215
  virtual void checkArguments() const {
1216
1216
  if (arguments.size() != 2) {
1217
- throw SyntaxError("you passed " + toString(arguments.size()) +
1217
+ throw SyntaxError("you passed " + toString(arguments.size()) +
1218
1218
  " argument(s) to starts_with(), but it accepts exactly 2 arguments");
1219
1219
  }
1220
1220
  }
1221
1221
  };
1222
-
1222
+
1223
1223
  struct HasHintFunctionCall: public FunctionCall {
1224
1224
  virtual bool evaluate(const Context &ctx) {
1225
1225
  return ctx.hasHint(arguments[0].getStringValue(ctx));
1226
1226
  }
1227
-
1227
+
1228
1228
  virtual void checkArguments() const {
1229
1229
  if (arguments.size() != 1) {
1230
- throw SyntaxError("you passed " + toString(arguments.size()) +
1230
+ throw SyntaxError("you passed " + toString(arguments.size()) +
1231
1231
  " argument(s) to has_hint(), but it accepts exactly 1 argument");
1232
1232
  }
1233
1233
  }
1234
1234
  };
1235
-
1235
+
1236
1236
  Tokenizer tokenizer;
1237
1237
  BooleanComponentPtr root;
1238
1238
  Token lookahead;
1239
1239
  bool debug;
1240
-
1240
+
1241
1241
  static bool isLiteralToken(const Token &token) {
1242
1242
  return token.type == Tokenizer::REGEXP
1243
1243
  || token.type == Tokenizer::STRING
@@ -1245,16 +1245,16 @@ private:
1245
1245
  || token.type == Tokenizer::TRUE_LIT
1246
1246
  || token.type == Tokenizer::FALSE_LIT;
1247
1247
  }
1248
-
1248
+
1249
1249
  static bool isValueToken(const Token &token) {
1250
1250
  return isLiteralToken(token) || token.type == Tokenizer::IDENTIFIER;
1251
1251
  }
1252
-
1252
+
1253
1253
  static bool isLogicalOperatorToken(const Token &token) {
1254
1254
  return token.type == Tokenizer::AND
1255
1255
  || token.type == Tokenizer::OR;
1256
1256
  }
1257
-
1257
+
1258
1258
  static Comparator determineComparator(Tokenizer::TokenType type) {
1259
1259
  switch (type) {
1260
1260
  case Tokenizer::MATCHES:
@@ -1277,7 +1277,7 @@ private:
1277
1277
  return UNKNOWN_COMPARATOR;
1278
1278
  }
1279
1279
  }
1280
-
1280
+
1281
1281
  static bool comparatorAcceptsValueTypes(Comparator cmp, ValueType subjectType, ValueType objectType) {
1282
1282
  switch (cmp) {
1283
1283
  case MATCHES:
@@ -1297,11 +1297,11 @@ private:
1297
1297
  return false; // Shut up compiler warning.
1298
1298
  }
1299
1299
  }
1300
-
1300
+
1301
1301
  static string unescapeCString(const StaticString &data) {
1302
1302
  string result;
1303
1303
  result.reserve(data.size());
1304
-
1304
+
1305
1305
  const char *current = data.data();
1306
1306
  const char *end = data.data() + data.size();
1307
1307
  while (current < end) {
@@ -1331,10 +1331,10 @@ private:
1331
1331
  current++;
1332
1332
  }
1333
1333
  }
1334
-
1334
+
1335
1335
  return result;
1336
1336
  }
1337
-
1337
+
1338
1338
  void logMatch(int level, const char *name) const {
1339
1339
  if (level > 100) {
1340
1340
  // If level is too deep then it's probably a bug.
@@ -1347,15 +1347,15 @@ private:
1347
1347
  printf("Matching: %s\n", name);
1348
1348
  }
1349
1349
  }
1350
-
1350
+
1351
1351
  Token peek() const {
1352
1352
  return lookahead;
1353
1353
  }
1354
-
1354
+
1355
1355
  bool peek(Tokenizer::TokenType type) const {
1356
1356
  return lookahead.type == type;
1357
1357
  }
1358
-
1358
+
1359
1359
  Token match(TokenType type) {
1360
1360
  if (lookahead.type == type) {
1361
1361
  return match();
@@ -1366,13 +1366,13 @@ private:
1366
1366
  return Token(); // Shut up compiler warning.
1367
1367
  }
1368
1368
  }
1369
-
1369
+
1370
1370
  Token match() {
1371
1371
  Token old = lookahead;
1372
1372
  lookahead = tokenizer.getNext();
1373
1373
  return old;
1374
1374
  }
1375
-
1375
+
1376
1376
  void raiseSyntaxError(const string &msg = "", const Token &token = Token()) {
1377
1377
  if (token.type != Tokenizer::NONE) {
1378
1378
  string message = "at character " + toString(token.pos + 1);
@@ -1385,11 +1385,11 @@ private:
1385
1385
  throw SyntaxError(msg);
1386
1386
  }
1387
1387
  }
1388
-
1388
+
1389
1389
  BooleanComponentPtr matchMultiExpression(int level) {
1390
1390
  logMatch(level, "matchMultiExpression()");
1391
1391
  MultiExpressionPtr result = boost::make_shared<MultiExpression>();
1392
-
1392
+
1393
1393
  result->firstExpression = matchExpression(level + 1);
1394
1394
  while (isLogicalOperatorToken(peek())) {
1395
1395
  MultiExpression::Part part;
@@ -1397,19 +1397,19 @@ private:
1397
1397
  part.expression = matchExpression(level + 1);
1398
1398
  result->rest.push_back(part);
1399
1399
  }
1400
-
1400
+
1401
1401
  return result;
1402
1402
  }
1403
-
1403
+
1404
1404
  BooleanComponentPtr matchExpression(int level) {
1405
1405
  logMatch(level, "matchExpression()");
1406
1406
  bool negate = false;
1407
-
1407
+
1408
1408
  if (peek(Tokenizer::NOT)) {
1409
1409
  match();
1410
1410
  negate = true;
1411
1411
  }
1412
-
1412
+
1413
1413
  Token next = peek();
1414
1414
  if (next.type == Tokenizer::LPARENTHESIS) {
1415
1415
  match();
@@ -1424,7 +1424,7 @@ private:
1424
1424
  BooleanComponentPtr component;
1425
1425
  Token &current = next;
1426
1426
  match();
1427
-
1427
+
1428
1428
  if (peek(Tokenizer::LPARENTHESIS)) {
1429
1429
  component = matchFunctionCall(level + 1, current);
1430
1430
  } else if (determineComparator(peek().type) != UNKNOWN_COMPARATOR) {
@@ -1434,7 +1434,7 @@ private:
1434
1434
  } else {
1435
1435
  raiseSyntaxError("expected a function call, comparison or boolean literal", current);
1436
1436
  }
1437
-
1437
+
1438
1438
  if (negate) {
1439
1439
  return boost::make_shared<Negation>(component);
1440
1440
  } else {
@@ -1445,12 +1445,12 @@ private:
1445
1445
  return BooleanComponentPtr(); // Shut up compiler warning.
1446
1446
  }
1447
1447
  }
1448
-
1448
+
1449
1449
  BooleanComponentPtr matchSingleValueComponent(int level, const Token &token) {
1450
1450
  logMatch(level, "matchSingleValueComponent()");
1451
1451
  return boost::make_shared<SingleValueComponent>(matchLiteral(level + 1, token));
1452
1452
  }
1453
-
1453
+
1454
1454
  ComparisonPtr matchComparison(int level, const Token &subjectToken) {
1455
1455
  logMatch(level, "matchComparison()");
1456
1456
  ComparisonPtr comparison = boost::make_shared<Comparison>();
@@ -1462,11 +1462,11 @@ private:
1462
1462
  }
1463
1463
  return comparison;
1464
1464
  }
1465
-
1465
+
1466
1466
  FunctionCallPtr matchFunctionCall(int level, const Token &id) {
1467
1467
  logMatch(level, "matchFunctionCall()");
1468
1468
  FunctionCallPtr function;
1469
-
1469
+
1470
1470
  if (id.rawValue == "starts_with") {
1471
1471
  function = boost::make_shared<StartsWithFunctionCall>();
1472
1472
  } else if (id.rawValue == "has_hint") {
@@ -1474,7 +1474,7 @@ private:
1474
1474
  } else {
1475
1475
  raiseSyntaxError("unknown function '" + id.rawValue + "'", id);
1476
1476
  }
1477
-
1477
+
1478
1478
  match(Tokenizer::LPARENTHESIS);
1479
1479
  if (isValueToken(peek())) {
1480
1480
  function->arguments.push_back(matchValue(level + 1, match()));
@@ -1487,7 +1487,7 @@ private:
1487
1487
  function->checkArguments();
1488
1488
  return function;
1489
1489
  }
1490
-
1490
+
1491
1491
  Value matchValue(int level, const Token &token) {
1492
1492
  logMatch(level, "matchValue()");
1493
1493
  if (isLiteralToken(token)) {
@@ -1500,7 +1500,7 @@ private:
1500
1500
  return Value(); // Shut up compiler warning.
1501
1501
  }
1502
1502
  }
1503
-
1503
+
1504
1504
  LogicalOperator matchOperator(int level) {
1505
1505
  logMatch(level, "matchOperator()");
1506
1506
  if (peek(Tokenizer::AND)) {
@@ -1516,7 +1516,7 @@ private:
1516
1516
  return AND; // Shut up compiler warning.
1517
1517
  }
1518
1518
  }
1519
-
1519
+
1520
1520
  Comparator matchComparator(int level) {
1521
1521
  logMatch(level, "matchComparator()");
1522
1522
  Comparator comparator = determineComparator(peek().type);
@@ -1529,7 +1529,7 @@ private:
1529
1529
  return comparator;
1530
1530
  }
1531
1531
  }
1532
-
1532
+
1533
1533
  Value matchLiteral(int level, const Token &token) {
1534
1534
  logMatch(level, "matchLiteral()");
1535
1535
  if (token.type == Tokenizer::REGEXP) {
@@ -1553,7 +1553,7 @@ private:
1553
1553
  return Value(); // Shut up compiler warning.
1554
1554
  }
1555
1555
  }
1556
-
1556
+
1557
1557
  Value matchContextFieldIdentifier(int level, const Token &token) {
1558
1558
  logMatch(level, "matchContextFieldIdentifier()");
1559
1559
  if (token.rawValue == "uri") {
@@ -1575,7 +1575,7 @@ private:
1575
1575
  return Value(); // Shut up compiler warning.
1576
1576
  }
1577
1577
  }
1578
-
1578
+
1579
1579
  public:
1580
1580
  Filter(const StaticString &source, bool debug = false)
1581
1581
  : tokenizer(source, debug)
@@ -1586,7 +1586,7 @@ public:
1586
1586
  logMatch(0, "end of data");
1587
1587
  match(Tokenizer::END_OF_DATA);
1588
1588
  }
1589
-
1589
+
1590
1590
  bool run(const Context &ctx) {
1591
1591
  return root->evaluate(ctx);
1592
1592
  }