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
@@ -36,6 +36,8 @@ namespace Passenger {
36
36
 
37
37
  using namespace std;
38
38
 
39
+ #define P_STATIC_STRING(x) Passenger::StaticString(x, sizeof(x) - 1)
40
+
39
41
  /**
40
42
  * An immutable, static byte buffer. This class will never copy data:
41
43
  * it just holds a pointer to the data. So a StaticString will become unusable
@@ -47,7 +49,7 @@ class StaticString {
47
49
  private:
48
50
  const char *content;
49
51
  string::size_type len;
50
-
52
+
51
53
  static const char *memmem(const char *haystack, string::size_type haystack_len,
52
54
  const char *needle, string::size_type needle_len)
53
55
  {
@@ -77,7 +79,7 @@ private:
77
79
  }
78
80
  } while (true);
79
81
  }
80
-
82
+
81
83
  public:
82
84
  /** A hash function object for StaticString. */
83
85
  struct Hash {
@@ -85,7 +87,7 @@ public:
85
87
  const char *data = str.content;
86
88
  const char *end = str.content + str.len;
87
89
  size_t result = 0;
88
-
90
+
89
91
  #if defined(__i386__) || defined(__x86_64__)
90
92
  /* When on x86 or x86_64, process 4 or 8 bytes
91
93
  * per iteration by treating the data as an
@@ -96,15 +98,15 @@ public:
96
98
  const char *last_long = str.content +
97
99
  str.len / sizeof(unsigned long) *
98
100
  sizeof(unsigned long);
99
-
101
+
100
102
  while (data < last_long) {
101
103
  result = result * 33 + *((unsigned long *) data);
102
104
  data += sizeof(unsigned long);
103
105
  }
104
-
106
+
105
107
  /* Process leftover data byte-by-byte. */
106
108
  #endif
107
-
109
+
108
110
  while (data < end) {
109
111
  result = result * 33 + *data;
110
112
  data++;
@@ -112,68 +114,68 @@ public:
112
114
  return result;
113
115
  }
114
116
  };
115
-
116
- StaticString() {
117
- content = "";
118
- len = 0;
119
- }
120
-
121
- StaticString(const StaticString &b) {
122
- content = b.content;
123
- len = b.len;
124
- }
125
-
117
+
118
+ StaticString()
119
+ : content(""),
120
+ len(0)
121
+ { }
122
+
123
+ StaticString(const StaticString &b)
124
+ : content(b.content),
125
+ len(b.len)
126
+ { }
127
+
126
128
  StaticString(const string &s) {
127
129
  content = s.data();
128
130
  len = s.size();
129
131
  }
130
-
132
+
131
133
  StaticString(const char *data) {
132
134
  content = data;
133
135
  len = strlen(data);
134
136
  }
135
-
136
- StaticString(const char *data, string::size_type len) {
137
- content = data;
138
- this->len = len;
139
- }
140
-
137
+
138
+ StaticString(const char *data, string::size_type _len)
139
+ : content(data),
140
+ len(_len)
141
+ { }
142
+
141
143
  bool empty() const {
142
144
  return len == 0;
143
145
  }
144
-
146
+
145
147
  string::size_type size() const {
146
148
  return len;
147
149
  }
148
-
150
+
149
151
  char operator[](string::size_type i) const {
150
152
  return content[i];
151
153
  }
152
-
154
+
153
155
  char at(string::size_type i) const {
154
156
  return content[i];
155
157
  }
156
-
158
+
157
159
  const char *c_str() const {
158
160
  return content;
159
161
  }
160
-
162
+
161
163
  const char *data() const {
162
164
  return content;
163
165
  }
164
-
166
+
165
167
  string toString() const {
166
168
  return string(content, len);
167
169
  }
168
-
170
+
169
171
  bool equals(const StaticString &other) const {
170
172
  return len == other.len && memcmp(content, other.content, len) == 0;
171
173
  }
172
-
174
+
173
175
  bool equals(const string &other) const {
174
176
  return len == other.size() && memcmp(content, other.data(), len) == 0;
175
177
  }
176
-
178
+
177
179
  string::size_type find(char c, string::size_type pos = 0) const {
178
180
  if (pos < len) {
179
181
  const char *result = (const char *) memchr(content + pos, c, len - pos);
@@ -186,7 +188,7 @@ public:
186
188
  return string::npos;
187
189
  }
188
190
  }
189
-
191
+
190
192
  string::size_type find(const StaticString &s, string::size_type pos = 0) const {
191
193
  if (s.empty()) {
192
194
  return 0;
@@ -201,11 +203,11 @@ public:
201
203
  return string::npos;
202
204
  }
203
205
  }
204
-
206
+
205
207
  string::size_type find(const char *s, string::size_type pos, string::size_type n) const {
206
208
  return find(StaticString(s, n), pos);
207
209
  }
208
-
210
+
209
211
  StaticString substr(string::size_type pos = 0, string::size_type n = string::npos) const {
210
212
  if (pos > len) {
211
213
  throw out_of_range("Argument 'pos' out of range");
@@ -216,33 +218,33 @@ public:
216
218
  return StaticString(content + pos, n);
217
219
  }
218
220
  }
219
-
221
+
220
222
  bool operator==(const StaticString &other) const {
221
223
  return len == other.len && memcmp(content, other.content, len) == 0;
222
224
  }
223
-
225
+
224
226
  bool operator==(const string &other) const {
225
227
  return len == other.size() && memcmp(content, other.data(), len) == 0;
226
228
  }
227
-
229
+
228
230
  bool operator==(const char *other) const {
229
231
  size_t other_len = strlen(other);
230
232
  return len == other_len && memcmp(content, other, other_len) == 0;
231
233
  }
232
-
234
+
233
235
  bool operator!=(const StaticString &other) const {
234
236
  return len != other.len || memcmp(content, other.content, len) != 0;
235
237
  }
236
-
238
+
237
239
  bool operator!=(const string &other) const {
238
240
  return len != other.size() || memcmp(content, other.data(), len) != 0;
239
241
  }
240
-
242
+
241
243
  bool operator!=(const char *other) const {
242
244
  size_t other_len = strlen(other);
243
245
  return len != other_len || memcmp(content, other, other_len) != 0;
244
246
  }
245
-
247
+
246
248
  bool operator<(const StaticString &other) const {
247
249
  size_t size = (len < other.size()) ? len : other.size();
248
250
  int result = memcmp(content, other.data(), size);
@@ -252,25 +254,25 @@ public:
252
254
  return result < 0;
253
255
  }
254
256
  }
255
-
257
+
256
258
  bool operator<(const char *other) const {
257
259
  return *this < StaticString(other);
258
260
  }
259
-
261
+
260
262
  string operator+(const char *other) const {
261
263
  return string(content, len) + other;
262
264
  }
263
-
265
+
264
266
  string operator+(const string &other) const {
265
267
  return string(content, len) + other;
266
268
  }
267
-
269
+
268
270
  string operator+(const StaticString &other) const {
269
271
  string result(content, len);
270
272
  result.append(other.data(), other.size());
271
273
  return result;
272
274
  }
273
-
275
+
274
276
  operator string() const {
275
277
  return string(content, len);
276
278
  }
@@ -27,6 +27,7 @@
27
27
  #include <boost/thread.hpp>
28
28
  #include <boost/shared_array.hpp>
29
29
 
30
+ #include <algorithm>
30
31
  #include <cassert>
31
32
  #include <cstdlib>
32
33
  #include <cstring>
@@ -90,12 +91,12 @@ namespace {
90
91
  struct FileGuard {
91
92
  string filename;
92
93
  bool committed;
93
-
94
+
94
95
  FileGuard(const string &filename) {
95
96
  this->filename = filename;
96
97
  committed = false;
97
98
  }
98
-
99
+
99
100
  ~FileGuard() {
100
101
  if (!committed) {
101
102
  int ret;
@@ -104,7 +105,7 @@ namespace {
104
105
  } while (ret == -1 && errno == EINTR);
105
106
  }
106
107
  }
107
-
108
+
108
109
  void commit() {
109
110
  committed = true;
110
111
  }
@@ -120,7 +121,7 @@ FileType
120
121
  getFileType(const StaticString &filename, CachedFileStat *cstat, unsigned int throttleRate) {
121
122
  struct stat buf;
122
123
  int ret;
123
-
124
+
124
125
  if (cstat != NULL) {
125
126
  ret = cstat->stat(filename, &buf, throttleRate);
126
127
  } else {
@@ -153,7 +154,7 @@ createFile(const string &filename, const StaticString &contents, mode_t permissi
153
154
  {
154
155
  FileDescriptor fd;
155
156
  int ret, e, options;
156
-
157
+
157
158
  options = O_WRONLY | O_CREAT | O_TRUNC;
158
159
  if (!overwrite) {
159
160
  options |= O_EXCL;
@@ -163,7 +164,7 @@ createFile(const string &filename, const StaticString &contents, mode_t permissi
163
164
  } while (fd == -1 && errno == EINTR);
164
165
  if (fd != -1) {
165
166
  FileGuard guard(filename);
166
-
167
+
167
168
  // The file permission may not be as expected because of the active
168
169
  // umask, so fchmod() it here to ensure correct permissions.
169
170
  do {
@@ -174,7 +175,7 @@ createFile(const string &filename, const StaticString &contents, mode_t permissi
174
175
  throw FileSystemException("Cannot set permissions on " + filename,
175
176
  e, filename);
176
177
  }
177
-
178
+
178
179
  if (owner != USER_NOT_GIVEN && group != GROUP_NOT_GIVEN) {
179
180
  if (owner == USER_NOT_GIVEN) {
180
181
  owner = (uid_t) -1; // Don't let fchown change file owner.
@@ -191,7 +192,7 @@ createFile(const string &filename, const StaticString &contents, mode_t permissi
191
192
  e, filename);
192
193
  }
193
194
  }
194
-
195
+
195
196
  try {
196
197
  writeExact(fd, contents);
197
198
  fd.close();
@@ -219,7 +220,7 @@ canonicalizePath(const string &path) {
219
220
  if (tmp == NULL) {
220
221
  int e = errno;
221
222
  string message;
222
-
223
+
223
224
  message = "Cannot resolve the path '";
224
225
  message.append(path);
225
226
  message.append("'");
@@ -234,7 +235,7 @@ canonicalizePath(const string &path) {
234
235
  if (realpath(path.c_str(), tmp) == NULL) {
235
236
  int e = errno;
236
237
  string message;
237
-
238
+
238
239
  message = "Cannot resolve the path '";
239
240
  message.append(path);
240
241
  message.append("'");
@@ -249,7 +250,7 @@ string
249
250
  resolveSymlink(const StaticString &path) {
250
251
  char buf[PATH_MAX];
251
252
  ssize_t size;
252
-
253
+
253
254
  size = readlink(path.c_str(), buf, sizeof(buf) - 1);
254
255
  if (size == -1) {
255
256
  if (errno == EINVAL) {
@@ -347,10 +348,10 @@ escapeForXml(const StaticString &input) {
347
348
  string::size_type input_pos = 0;
348
349
  string::size_type input_end_pos = input.size();
349
350
  string::size_type result_pos = 0;
350
-
351
+
351
352
  while (input_pos < input_end_pos) {
352
353
  const unsigned char ch = input[input_pos];
353
-
354
+
354
355
  if ((ch >= 'A' && ch <= 'z')
355
356
  || (ch >= '0' && ch <= '9')
356
357
  || ch == '/' || ch == ' ' || ch == '_' || ch == '.'
@@ -362,7 +363,7 @@ escapeForXml(const StaticString &input) {
362
363
  // Not an ASCII character; escape it.
363
364
  char escapedCharacter[sizeof("&#255;") + 1];
364
365
  int size;
365
-
366
+
366
367
  size = snprintf(escapedCharacter,
367
368
  sizeof(escapedCharacter) - 1,
368
369
  "&#%d;",
@@ -371,13 +372,13 @@ escapeForXml(const StaticString &input) {
371
372
  throw std::bad_alloc();
372
373
  }
373
374
  escapedCharacter[sizeof(escapedCharacter) - 1] = '\0';
374
-
375
+
375
376
  result.replace(result_pos, 1, escapedCharacter, size);
376
377
  result_pos += size;
377
378
  }
378
379
  input_pos++;
379
380
  }
380
-
381
+
381
382
  return result;
382
383
  }
383
384
 
@@ -387,11 +388,9 @@ getProcessUsername() {
387
388
  long bufSize;
388
389
  shared_array<char> strings;
389
390
 
390
- bufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
391
- if (bufSize == -1) {
392
- // Let's hope this is enough.
393
- bufSize = 1024 * 64;
394
- }
391
+ // _SC_GETPW_R_SIZE_MAX is not a maximum:
392
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
393
+ bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
395
394
  strings.reset(new char[bufSize]);
396
395
 
397
396
  result = (struct passwd *) NULL;
@@ -414,11 +413,9 @@ getGroupName(gid_t gid) {
414
413
  long bufSize;
415
414
  shared_array<char> strings;
416
415
 
417
- bufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
418
- if (bufSize == -1) {
419
- // Let's hope this is enough.
420
- bufSize = 1024 * 64;
421
- }
416
+ // _SC_GETGR_R_SIZE_MAX is not a maximum:
417
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
418
+ bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETGR_R_SIZE_MAX));
422
419
  strings.reset(new char[bufSize]);
423
420
 
424
421
  groupEntry = (struct group *) NULL;
@@ -439,11 +436,9 @@ lookupGid(const string &groupName) {
439
436
  long bufSize;
440
437
  shared_array<char> strings;
441
438
 
442
- bufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
443
- if (bufSize == -1) {
444
- // Let's hope this is enough.
445
- bufSize = 1024 * 64;
446
- }
439
+ // _SC_GETGR_R_SIZE_MAX is not a maximum:
440
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
441
+ bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETGR_R_SIZE_MAX));
447
442
  strings.reset(new char[bufSize]);
448
443
 
449
444
  groupEntry = (struct group *) NULL;
@@ -467,17 +462,17 @@ parseModeString(const StaticString &mode) {
467
462
  mode_t modeBits = 0;
468
463
  vector<string> clauses;
469
464
  vector<string>::iterator it;
470
-
465
+
471
466
  split(mode, ',', clauses);
472
467
  for (it = clauses.begin(); it != clauses.end(); it++) {
473
468
  const string &clause = *it;
474
-
469
+
475
470
  if (clause.empty()) {
476
471
  continue;
477
472
  } else if (clause.size() < 2 || (clause[0] != '+' && clause[1] != '=')) {
478
473
  throw InvalidModeStringException("Invalid mode clause specification '" + clause + "'");
479
474
  }
480
-
475
+
481
476
  switch (clause[0]) {
482
477
  case 'u':
483
478
  for (string::size_type i = 2; i < clause.size(); i++) {
@@ -564,7 +559,7 @@ parseModeString(const StaticString &mode) {
564
559
  "' in mode clause specification '" + clause + "'");
565
560
  }
566
561
  }
567
-
562
+
568
563
  return modeBits;
569
564
  }
570
565
 
@@ -648,13 +643,13 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
648
643
  string current = path;
649
644
  mode_t modeBits;
650
645
  int ret;
651
-
646
+
652
647
  if (stat(path.c_str(), &buf) == 0) {
653
648
  return;
654
649
  }
655
-
650
+
656
651
  modeBits = parseModeString(mode);
657
-
652
+
658
653
  /* Create a list of parent paths that don't exist. For example, given
659
654
  * path == "/a/b/c/d/e" and that only /a exists, the list will become
660
655
  * as follows:
@@ -667,11 +662,11 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
667
662
  paths.push_back(current);
668
663
  current = extractDirName(current);
669
664
  }
670
-
665
+
671
666
  /* Now traverse the list in reverse order and create directories that don't exist. */
672
667
  for (rit = paths.rbegin(); rit != paths.rend(); rit++) {
673
668
  current = *rit;
674
-
669
+
675
670
  do {
676
671
  ret = mkdir(current.c_str(), modeBits);
677
672
  } while (ret == -1 && errno == EINTR);
@@ -685,12 +680,12 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
685
680
  e, current);
686
681
  }
687
682
  }
688
-
683
+
689
684
  /* Chmod in order to override the umask. */
690
685
  do {
691
686
  ret = chmod(current.c_str(), modeBits);
692
687
  } while (ret == -1 && errno == EINTR);
693
-
688
+
694
689
  if (owner != USER_NOT_GIVEN && group != GROUP_NOT_GIVEN) {
695
690
  if (owner == USER_NOT_GIVEN) {
696
691
  owner = (uid_t) -1; // Don't let chown change file owner.
@@ -704,7 +699,7 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
704
699
  if (ret == -1) {
705
700
  char message[1024];
706
701
  int e = errno;
707
-
702
+
708
703
  snprintf(message, sizeof(message) - 1,
709
704
  "Cannot change the directory '%s' its UID to %lld and GID to %lld",
710
705
  current.c_str(), (long long) owner, (long long) group);
@@ -779,32 +774,32 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
779
774
  * executing the prespawning scripts.
780
775
  */
781
776
  syscalls::sleep(2);
782
-
777
+
783
778
  this_thread::disable_interruption di;
784
779
  this_thread::disable_syscall_interruption dsi;
785
780
  vector<string>::const_iterator it;
786
781
  string prespawnScript = locator.getHelperScriptsDir() + "/prespawn";
787
-
782
+
788
783
  it = prestartURLs.begin();
789
784
  while (it != prestartURLs.end() && !this_thread::interruption_requested()) {
790
785
  if (it->empty()) {
791
786
  it++;
792
787
  continue;
793
788
  }
794
-
789
+
795
790
  pid_t pid;
796
-
791
+
797
792
  pid = fork();
798
793
  if (pid == 0) {
799
794
  long max_fds, i;
800
795
  int e;
801
-
796
+
802
797
  // Close all unnecessary file descriptors.
803
798
  max_fds = sysconf(_SC_OPEN_MAX);
804
799
  for (i = 3; i < max_fds; i++) {
805
800
  syscalls::close(i);
806
801
  }
807
-
802
+
808
803
  execlp(ruby.c_str(),
809
804
  ruby.c_str(),
810
805
  prespawnScript.c_str(),
@@ -829,7 +824,7 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
829
824
  throw;
830
825
  }
831
826
  }
832
-
827
+
833
828
  this_thread::restore_interruption si(di);
834
829
  this_thread::restore_syscall_interruption ssi(dsi);
835
830
  syscalls::sleep(1);
@@ -962,7 +957,7 @@ resetSignalHandlersAndMask() {
962
957
 
963
958
  sigset_t signal_set;
964
959
  int ret;
965
-
960
+
966
961
  sigemptyset(&signal_set);
967
962
  do {
968
963
  ret = sigprocmask(SIG_SETMASK, &signal_set, NULL);
@@ -1033,9 +1028,9 @@ runCommandAndCaptureOutput(const char **command) {
1033
1028
  pid_t pid;
1034
1029
  int e;
1035
1030
  Pipe p;
1036
-
1031
+
1037
1032
  p = createPipe();
1038
-
1033
+
1039
1034
  this_thread::disable_syscall_interruption dsi;
1040
1035
  pid = syscalls::fork();
1041
1036
  if (pid == 0) {
@@ -1060,12 +1055,12 @@ runCommandAndCaptureOutput(const char **command) {
1060
1055
  } else {
1061
1056
  bool done = false;
1062
1057
  string result;
1063
-
1058
+
1064
1059
  p[1].close();
1065
1060
  while (!done) {
1066
1061
  char buf[1024 * 4];
1067
1062
  ssize_t ret;
1068
-
1063
+
1069
1064
  try {
1070
1065
  this_thread::restore_syscall_interruption rsi(dsi);
1071
1066
  ret = syscalls::read(p[0], buf, sizeof(buf));
@@ -1086,7 +1081,7 @@ runCommandAndCaptureOutput(const char **command) {
1086
1081
  }
1087
1082
  p[0].close();
1088
1083
  syscalls::waitpid(pid, NULL, 0);
1089
-
1084
+
1090
1085
  if (result.empty()) {
1091
1086
  throw RuntimeException(string("The '") + command[1] +
1092
1087
  "' command failed");
@@ -1123,7 +1118,7 @@ asyncFork() {
1123
1118
  static int
1124
1119
  getFileDescriptorLimit() {
1125
1120
  long long sysconfResult = sysconf(_SC_OPEN_MAX);
1126
-
1121
+
1127
1122
  struct rlimit rl;
1128
1123
  long long rlimitResult;
1129
1124
  if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
@@ -1131,7 +1126,7 @@ getFileDescriptorLimit() {
1131
1126
  } else {
1132
1127
  rlimitResult = (long long) rl.rlim_max;
1133
1128
  }
1134
-
1129
+
1135
1130
  long result;
1136
1131
  // OS X 10.9 returns LLONG_MAX. It doesn't make sense
1137
1132
  // to use that result so we limit ourselves to the
@@ -1159,7 +1154,7 @@ static int
1159
1154
  getHighestFileDescriptor(bool asyncSignalSafe) {
1160
1155
  #if defined(F_MAXFD)
1161
1156
  int ret;
1162
-
1157
+
1163
1158
  do {
1164
1159
  ret = fcntl(0, F_MAXFD);
1165
1160
  } while (ret == -1 && errno == EINTR);
@@ -1167,17 +1162,17 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1167
1162
  ret = getFileDescriptorLimit();
1168
1163
  }
1169
1164
  return ret;
1170
-
1165
+
1171
1166
  #else
1172
1167
  int p[2], ret, flags;
1173
1168
  pid_t pid = -1;
1174
1169
  int result = -1;
1175
-
1170
+
1176
1171
  /* Since opendir() may not be async signal safe and thus may lock up
1177
1172
  * or crash, we use it in a child process which we kill if we notice
1178
1173
  * that things are going wrong.
1179
1174
  */
1180
-
1175
+
1181
1176
  // Make a pipe.
1182
1177
  p[0] = p[1] = -1;
1183
1178
  do {
@@ -1186,7 +1181,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1186
1181
  if (ret == -1) {
1187
1182
  goto done;
1188
1183
  }
1189
-
1184
+
1190
1185
  // Make the read side non-blocking.
1191
1186
  do {
1192
1187
  flags = fcntl(p[0], F_GETFL);
@@ -1200,7 +1195,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1200
1195
  if (ret == -1) {
1201
1196
  goto done;
1202
1197
  }
1203
-
1198
+
1204
1199
  if (asyncSignalSafe) {
1205
1200
  do {
1206
1201
  pid = asyncFork();
@@ -1210,12 +1205,12 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1210
1205
  pid = fork();
1211
1206
  } while (pid == -1 && errno == EINTR);
1212
1207
  }
1213
-
1208
+
1214
1209
  if (pid == 0) {
1215
1210
  // Don't close p[0] here or it might affect the result.
1216
-
1211
+
1217
1212
  resetSignalHandlersAndMask();
1218
-
1213
+
1219
1214
  struct sigaction action;
1220
1215
  action.sa_handler = _exit;
1221
1216
  action.sa_flags = SA_RESTART;
@@ -1226,7 +1221,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1226
1221
  sigaction(SIGILL, &action, NULL);
1227
1222
  sigaction(SIGFPE, &action, NULL);
1228
1223
  sigaction(SIGABRT, &action, NULL);
1229
-
1224
+
1230
1225
  DIR *dir = NULL;
1231
1226
  #ifdef __APPLE__
1232
1227
  /* /dev/fd can always be trusted on OS X. */
@@ -1253,14 +1248,14 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1253
1248
  _exit(1);
1254
1249
  }
1255
1250
  }
1256
-
1251
+
1257
1252
  struct dirent *ent;
1258
1253
  union {
1259
1254
  int highest;
1260
1255
  char data[sizeof(int)];
1261
1256
  } u;
1262
1257
  u.highest = -1;
1263
-
1258
+
1264
1259
  while ((ent = readdir(dir)) != NULL) {
1265
1260
  if (ent->d_name[0] != '.') {
1266
1261
  int number = atoi(ent->d_name);
@@ -1281,14 +1276,14 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1281
1276
  }
1282
1277
  closedir(dir);
1283
1278
  _exit(0);
1284
-
1279
+
1285
1280
  } else if (pid == -1) {
1286
1281
  goto done;
1287
-
1282
+
1288
1283
  } else {
1289
1284
  close(p[1]); // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
1290
1285
  p[1] = -1;
1291
-
1286
+
1292
1287
  union {
1293
1288
  int highest;
1294
1289
  char data[sizeof(int)];
@@ -1297,7 +1292,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1297
1292
  struct pollfd pfd;
1298
1293
  pfd.fd = p[0];
1299
1294
  pfd.events = POLLIN;
1300
-
1295
+
1301
1296
  do {
1302
1297
  do {
1303
1298
  // The child process must finish within 30 ms, otherwise
@@ -1307,7 +1302,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1307
1302
  if (ret <= 0) {
1308
1303
  goto done;
1309
1304
  }
1310
-
1305
+
1311
1306
  do {
1312
1307
  ret = read(p[0], u.data + bytesRead, sizeof(int) - bytesRead);
1313
1308
  } while (ret == -1 && ret == EINTR);
@@ -1321,7 +1316,7 @@ getHighestFileDescriptor(bool asyncSignalSafe) {
1321
1316
  bytesRead += ret;
1322
1317
  }
1323
1318
  } while (bytesRead < (ssize_t) sizeof(int));
1324
-
1319
+
1325
1320
  result = u.highest;
1326
1321
  goto done;
1327
1322
  }
@@ -1342,7 +1337,7 @@ done:
1342
1337
  ret = waitpid(pid, NULL, 0);
1343
1338
  } while (ret == -1 && errno == EINTR);
1344
1339
  }
1345
-
1340
+
1346
1341
  if (result == -1) {
1347
1342
  result = getFileDescriptorLimit();
1348
1343
  }
@@ -1364,7 +1359,7 @@ closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe) {
1364
1359
  closefrom(lastToKeepOpen + 1);
1365
1360
  return;
1366
1361
  #endif
1367
-
1362
+
1368
1363
  for (int i = getHighestFileDescriptor(asyncSignalSafe); i > lastToKeepOpen; i--) {
1369
1364
  /* Even though we normally shouldn't retry on EINTR
1370
1365
  * (http://news.ycombinator.com/item?id=3363819)