puma 2.3.2 → 2.4.0

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

Potentially problematic release.


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

@@ -1,3 +1,26 @@
1
+ === 2.4.0 / 2013-07-22
2
+
3
+ * 5 minor features:
4
+ * Add PUMA_JRUBY_DAEMON_OPTS to get around agent starting twice
5
+ * Add ability to drain accept socket on shutdown
6
+ * Add port to DSL
7
+ * Adds support for using puma config file in capistrano deploys.
8
+ * Make phased_restart fallback to restart if not available
9
+
10
+ * 10 bug fixes:
11
+
12
+ * Be sure to only delete the pid in the master. Fixes #334
13
+ * Call out -C/--config flags
14
+ * Change parser symbol names to avoid clash. Fixes #179
15
+ * Convert thread pool sizes to integers
16
+ * Detect when the jruby daemon child doesn't start properly
17
+ * Fix typo in CLI help
18
+ * Improve the logging output when hijack is used. Fixes #332
19
+ * Remove unnecessary thread pool size conversions
20
+ * Setup :worker_boot as an Array. Fixes #317
21
+ * Use 127.0.0.1 as REMOTE_ADDR of unix client. Fixes #309
22
+
23
+
1
24
  === 2.3.2 / 2013-07-08
2
25
 
3
26
  * 1 bug fix:
data/README.md CHANGED
@@ -78,38 +78,37 @@ Puma will automatically scale the number of threads based on how much traffic is
78
78
  Puma 2 offers clustered mode, allowing you to use forked processes to handle multiple incoming requests concurrently, in addition to threads already provided. You can tune the number of workers with the `-w` (or `--workers`) flag:
79
79
 
80
80
  $ puma -t 8:32 -w 3
81
-
82
- On a ruby implementation that offers native threads, you should tune this number to match the number of cores available.
83
- Note that threads are still used in clustered mode, and the `-t` thread flag setting is per worker, so `-w 2 -t 16:16` will be 32 threads.
84
81
 
85
- This code can be used to setup the process before booting the application, allowing
86
- you to do some puma-specific things that you don't want to embed in your application.
87
- For instance, you could fire a log notification that a worker booted or send something to statsd.
88
- This can be called multiple times to add hooks.
82
+ On a ruby implementation that offers native threads, you should tune this number to match the number of cores available.
83
+ Note that threads are still used in clustered mode, and the `-t` thread flag setting is per worker, so `-w 2 -t 16:16` will be 32 threads.
89
84
 
90
85
  If you're running in Clustered Mode you can optionally choose to preload your application before starting up the workers. To do this simply specify the `--preload` flag in invocation:
91
86
 
92
87
  # CLI invocation
93
88
  $ puma -t 8:32 -w 3 --preload
94
-
89
+
95
90
  If you're using a configuration file, use the `preload_app!` method, and be sure to specify your config file's location with the `-C` flag:
96
91
 
97
92
  $ puma -C config/puma.rb
98
-
93
+
99
94
  # config/puma.rb
100
95
  threads 8,32
101
96
  workers 3
102
- preload_app!
103
-
97
+ preload_app!
104
98
 
105
- Additionally, you can specify a block in your configuration that will be run on boot of each worker:
99
+ Additionally, you can specify a block in your configuration file that will be run on boot of each worker:
106
100
 
107
101
  # config/puma.rb
108
102
  on_worker_boot do
109
103
  # configuration here
110
104
  end
111
-
112
- If you're preloading your application and using ActiveRecord, it's recommend you setup your connection pool here:
105
+
106
+ This code can be used to setup the process before booting the application, allowing
107
+ you to do some puma-specific things that you don't want to embed in your application.
108
+ For instance, you could fire a log notification that a worker booted or send something to statsd.
109
+ This can be called multiple times to add hooks.
110
+
111
+ If you're preloading your application and using ActiveRecord, it's recommend you setup your connection pool here:
113
112
 
114
113
  # config/puma.rb
115
114
  on_worker_boot do
@@ -142,15 +141,11 @@ Puma comes with a builtin status/control app that can be used query and control
142
141
 
143
142
  $ puma --control tcp://127.0.0.1:9293 --control-token foo
144
143
 
145
- This directs puma to start the control server on localhost port 9293. Additionally, all requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out https://github.com/puma/puma/blob/master/lib/puma/app/status.rb to see what the app has available.
144
+ This directs puma to start the control server on localhost port 9293. Additionally, all requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the app has available.
146
145
 
147
146
  ### Configuration file
148
147
 
149
- You can also provide a configuration file which puma will use:
150
-
151
- $ puma --config /path/to/config
152
-
153
- or
148
+ You can also provide a configuration file which puma will use with the `-C` (or `--config`) flag:
154
149
 
155
150
  $ puma -C /path/to/config
156
151
 
@@ -158,7 +153,7 @@ Take the following [sample configuration](https://github.com/puma/puma/blob/mast
158
153
 
159
154
  ## Restart
160
155
 
161
- Puma includes the ability to restart itself, allowing for new versions to be easily upgraded to. When available (MRI, Rubinius, JRuby), puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
156
+ Puma includes the ability to restart itself allowing easy upgrades to new versions. When available (MRI, Rubinius, JRuby), puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
162
157
 
163
158
  To perform a restart, there are 2 builtin mechanisms:
164
159
 
@@ -171,11 +166,11 @@ If the new process is unable to load, it will simply exit. You should therefore
171
166
 
172
167
  ### Cleanup Code
173
168
 
174
- Puma isn't able to understand all the resources that your app may use, so it provides a hook in the configuration file you pass to `-C` call `on_restart`. The block passed to `on_restart` will be called, unsurprisingly, just before puma restarts itself.
169
+ Puma isn't able to understand all the resources that your app may use, so it provides a hook in the configuration file you pass to `-C` called `on_restart`. The block passed to `on_restart` will be called, unsurprisingly, just before puma restarts itself.
175
170
 
176
171
  You should place code to close global log files, redis connections, etc in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restart many times.
177
172
 
178
- ### Platform Constaints
173
+ ### Platform Constraints
179
174
 
180
175
  Because of various platforms not being implement certain things, the following differences occur when puma is used on different platforms:
181
176
 
@@ -195,7 +190,7 @@ or
195
190
 
196
191
  will cause the server to perform a restart. `pumactl` is a simple CLI frontend to the control/status app described above.
197
192
 
198
- Allowed commands: status, restart, halt, stop
193
+ Allowed commands: `status`, `restart`, `halt`, `stop`
199
194
 
200
195
  ## Managing multiple Pumas / init.d / upstart scripts
201
196
 
@@ -215,7 +210,7 @@ and then
215
210
 
216
211
  ```bash
217
212
  $ bundle exec cap puma:start
218
- $ bundle exec cap puma:restart
213
+ $ bundle exec cap puma:restart
219
214
  $ bundle exec cap puma:stop
220
215
  ```
221
216
 
@@ -36,21 +36,21 @@ static void snake_upcase_char(char *c)
36
36
  /** Data **/
37
37
 
38
38
  #line 39 "ext/http11/http11_parser.c"
39
- static const int http_parser_start = 1;
40
- static const int http_parser_first_final = 57;
41
- static const int http_parser_error = 0;
39
+ static const int puma_parser_start = 1;
40
+ static const int puma_parser_first_final = 57;
41
+ static const int puma_parser_error = 0;
42
42
 
43
- static const int http_parser_en_main = 1;
43
+ static const int puma_parser_en_main = 1;
44
44
 
45
45
 
46
46
  #line 82 "ext/http11/http11_parser.rl"
47
47
 
48
- int http_parser_init(http_parser *parser) {
48
+ int puma_parser_init(puma_parser *parser) {
49
49
  int cs = 0;
50
50
 
51
51
  #line 52 "ext/http11/http11_parser.c"
52
52
  {
53
- cs = http_parser_start;
53
+ cs = puma_parser_start;
54
54
  }
55
55
 
56
56
  #line 86 "ext/http11/http11_parser.rl"
@@ -69,7 +69,7 @@ int http_parser_init(http_parser *parser) {
69
69
 
70
70
 
71
71
  /** exec **/
72
- size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
72
+ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len, size_t off) {
73
73
  const char *p, *pe;
74
74
  int cs = parser->cs;
75
75
 
@@ -1191,7 +1191,7 @@ case 56:
1191
1191
 
1192
1192
  #line 114 "ext/http11/http11_parser.rl"
1193
1193
 
1194
- if (!http_parser_has_error(parser))
1194
+ if (!puma_parser_has_error(parser))
1195
1195
  parser->cs = cs;
1196
1196
  parser->nread += p - (buffer + off);
1197
1197
 
@@ -1205,21 +1205,21 @@ case 56:
1205
1205
  return(parser->nread);
1206
1206
  }
1207
1207
 
1208
- int http_parser_finish(http_parser *parser)
1208
+ int puma_parser_finish(puma_parser *parser)
1209
1209
  {
1210
- if (http_parser_has_error(parser) ) {
1210
+ if (puma_parser_has_error(parser) ) {
1211
1211
  return -1;
1212
- } else if (http_parser_is_finished(parser) ) {
1212
+ } else if (puma_parser_is_finished(parser) ) {
1213
1213
  return 1;
1214
1214
  } else {
1215
1215
  return 0;
1216
1216
  }
1217
1217
  }
1218
1218
 
1219
- int http_parser_has_error(http_parser *parser) {
1220
- return parser->cs == http_parser_error;
1219
+ int puma_parser_has_error(puma_parser *parser) {
1220
+ return parser->cs == puma_parser_error;
1221
1221
  }
1222
1222
 
1223
- int http_parser_is_finished(http_parser *parser) {
1224
- return parser->cs >= http_parser_first_final;
1223
+ int puma_parser_is_finished(puma_parser *parser) {
1224
+ return parser->cs >= puma_parser_first_final;
1225
1225
  }
@@ -16,16 +16,16 @@
16
16
 
17
17
  #define BUFFER_LEN 1024
18
18
 
19
- struct http_parser;
19
+ struct puma_parser;
20
20
 
21
- typedef void (*element_cb)(struct http_parser* hp,
21
+ typedef void (*element_cb)(struct puma_parser* hp,
22
22
  const char *at, size_t length);
23
23
 
24
- typedef void (*field_cb)(struct http_parser* hp,
24
+ typedef void (*field_cb)(struct puma_parser* hp,
25
25
  const char *field, size_t flen,
26
26
  const char *value, size_t vlen);
27
27
 
28
- typedef struct http_parser {
28
+ typedef struct puma_parser {
29
29
  int cs;
30
30
  size_t body_start;
31
31
  int content_len;
@@ -49,15 +49,15 @@ typedef struct http_parser {
49
49
 
50
50
  char buf[BUFFER_LEN];
51
51
 
52
- } http_parser;
52
+ } puma_parser;
53
53
 
54
- int http_parser_init(http_parser *parser);
55
- int http_parser_finish(http_parser *parser);
56
- size_t http_parser_execute(http_parser *parser, const char *data,
54
+ int puma_parser_init(puma_parser *parser);
55
+ int puma_parser_finish(puma_parser *parser);
56
+ size_t puma_parser_execute(puma_parser *parser, const char *data,
57
57
  size_t len, size_t off);
58
- int http_parser_has_error(http_parser *parser);
59
- int http_parser_is_finished(http_parser *parser);
58
+ int puma_parser_has_error(puma_parser *parser);
59
+ int puma_parser_is_finished(puma_parser *parser);
60
60
 
61
- #define http_parser_nread(parser) (parser)->nread
61
+ #define puma_parser_nread(parser) (parser)->nread
62
62
 
63
63
  #endif
@@ -29,7 +29,7 @@ static void snake_upcase_char(char *c)
29
29
 
30
30
  %%{
31
31
 
32
- machine http_parser;
32
+ machine puma_parser;
33
33
 
34
34
  action mark { MARK(mark, fpc); }
35
35
 
@@ -73,14 +73,14 @@ static void snake_upcase_char(char *c)
73
73
  fbreak;
74
74
  }
75
75
 
76
- include http_parser_common "http11_parser_common.rl";
76
+ include puma_parser_common "http11_parser_common.rl";
77
77
 
78
78
  }%%
79
79
 
80
80
  /** Data **/
81
81
  %% write data;
82
82
 
83
- int http_parser_init(http_parser *parser) {
83
+ int puma_parser_init(puma_parser *parser) {
84
84
  int cs = 0;
85
85
  %% write init;
86
86
  parser->cs = cs;
@@ -98,7 +98,7 @@ int http_parser_init(http_parser *parser) {
98
98
 
99
99
 
100
100
  /** exec **/
101
- size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
101
+ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len, size_t off) {
102
102
  const char *p, *pe;
103
103
  int cs = parser->cs;
104
104
 
@@ -112,7 +112,7 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len,
112
112
 
113
113
  %% write exec;
114
114
 
115
- if (!http_parser_has_error(parser))
115
+ if (!puma_parser_has_error(parser))
116
116
  parser->cs = cs;
117
117
  parser->nread += p - (buffer + off);
118
118
 
@@ -126,21 +126,21 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len,
126
126
  return(parser->nread);
127
127
  }
128
128
 
129
- int http_parser_finish(http_parser *parser)
129
+ int puma_parser_finish(puma_parser *parser)
130
130
  {
131
- if (http_parser_has_error(parser) ) {
131
+ if (puma_parser_has_error(parser) ) {
132
132
  return -1;
133
- } else if (http_parser_is_finished(parser) ) {
133
+ } else if (puma_parser_is_finished(parser) ) {
134
134
  return 1;
135
135
  } else {
136
136
  return 0;
137
137
  }
138
138
  }
139
139
 
140
- int http_parser_has_error(http_parser *parser) {
141
- return parser->cs == http_parser_error;
140
+ int puma_parser_has_error(puma_parser *parser) {
141
+ return parser->cs == puma_parser_error;
142
142
  }
143
143
 
144
- int http_parser_is_finished(http_parser *parser) {
145
- return parser->cs >= http_parser_first_final;
144
+ int puma_parser_is_finished(puma_parser *parser) {
145
+ return parser->cs >= puma_parser_first_final;
146
146
  }
@@ -1,6 +1,6 @@
1
1
  %%{
2
2
 
3
- machine http_parser_common;
3
+ machine puma_parser_common;
4
4
 
5
5
  #### HTTP PROTOCOL GRAMMAR
6
6
  # line endings
@@ -38,10 +38,10 @@ static VALUE global_http_version;
38
38
  static VALUE global_request_path;
39
39
 
40
40
  /** Defines common length and error messages for input length validation. */
41
- #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length."
41
+ #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length (was %d)"
42
42
 
43
43
  /** Validates the max length of given input and throws an HttpParserError exception if over. */
44
- #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, "%s", MAX_##N##_LENGTH_ERR); }
44
+ #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
45
45
 
46
46
  /** Defines global strings in the init method. */
47
47
  #define DEF_GLOBAL(N, val) global_##N = rb_str_new2(val); rb_global_variable(&global_##N)
@@ -173,7 +173,7 @@ static VALUE find_common_field_value(const char *field, size_t flen)
173
173
  #endif /* !HAVE_QSORT_BSEARCH */
174
174
  }
175
175
 
176
- void http_field(http_parser* hp, const char *field, size_t flen,
176
+ void http_field(puma_parser* hp, const char *field, size_t flen,
177
177
  const char *value, size_t vlen)
178
178
  {
179
179
  VALUE v = Qnil;
@@ -204,7 +204,7 @@ void http_field(http_parser* hp, const char *field, size_t flen,
204
204
  rb_hash_aset(hp->request, f, v);
205
205
  }
206
206
 
207
- void request_method(http_parser* hp, const char *at, size_t length)
207
+ void request_method(puma_parser* hp, const char *at, size_t length)
208
208
  {
209
209
  VALUE val = Qnil;
210
210
 
@@ -212,7 +212,7 @@ void request_method(http_parser* hp, const char *at, size_t length)
212
212
  rb_hash_aset(hp->request, global_request_method, val);
213
213
  }
214
214
 
215
- void request_uri(http_parser* hp, const char *at, size_t length)
215
+ void request_uri(puma_parser* hp, const char *at, size_t length)
216
216
  {
217
217
  VALUE val = Qnil;
218
218
 
@@ -222,7 +222,7 @@ void request_uri(http_parser* hp, const char *at, size_t length)
222
222
  rb_hash_aset(hp->request, global_request_uri, val);
223
223
  }
224
224
 
225
- void fragment(http_parser* hp, const char *at, size_t length)
225
+ void fragment(puma_parser* hp, const char *at, size_t length)
226
226
  {
227
227
  VALUE val = Qnil;
228
228
 
@@ -232,7 +232,7 @@ void fragment(http_parser* hp, const char *at, size_t length)
232
232
  rb_hash_aset(hp->request, global_fragment, val);
233
233
  }
234
234
 
235
- void request_path(http_parser* hp, const char *at, size_t length)
235
+ void request_path(puma_parser* hp, const char *at, size_t length)
236
236
  {
237
237
  VALUE val = Qnil;
238
238
 
@@ -242,7 +242,7 @@ void request_path(http_parser* hp, const char *at, size_t length)
242
242
  rb_hash_aset(hp->request, global_request_path, val);
243
243
  }
244
244
 
245
- void query_string(http_parser* hp, const char *at, size_t length)
245
+ void query_string(puma_parser* hp, const char *at, size_t length)
246
246
  {
247
247
  VALUE val = Qnil;
248
248
 
@@ -252,7 +252,7 @@ void query_string(http_parser* hp, const char *at, size_t length)
252
252
  rb_hash_aset(hp->request, global_query_string, val);
253
253
  }
254
254
 
255
- void http_version(http_parser* hp, const char *at, size_t length)
255
+ void http_version(puma_parser* hp, const char *at, size_t length)
256
256
  {
257
257
  VALUE val = rb_str_new(at, length);
258
258
  rb_hash_aset(hp->request, global_http_version, val);
@@ -261,7 +261,7 @@ void http_version(http_parser* hp, const char *at, size_t length)
261
261
  /** Finalizes the request header to have a bunch of stuff that's
262
262
  needed. */
263
263
 
264
- void header_done(http_parser* hp, const char *at, size_t length)
264
+ void header_done(puma_parser* hp, const char *at, size_t length)
265
265
  {
266
266
  hp->body = rb_str_new(at, length);
267
267
  }
@@ -275,14 +275,14 @@ void HttpParser_free(void *data) {
275
275
  }
276
276
  }
277
277
 
278
- void HttpParser_mark(http_parser* hp) {
278
+ void HttpParser_mark(puma_parser* hp) {
279
279
  if(hp->request) rb_gc_mark(hp->request);
280
280
  if(hp->body) rb_gc_mark(hp->body);
281
281
  }
282
282
 
283
283
  VALUE HttpParser_alloc(VALUE klass)
284
284
  {
285
- http_parser *hp = ALLOC_N(http_parser, 1);
285
+ puma_parser *hp = ALLOC_N(puma_parser, 1);
286
286
  TRACE();
287
287
  hp->http_field = http_field;
288
288
  hp->request_method = request_method;
@@ -294,7 +294,7 @@ VALUE HttpParser_alloc(VALUE klass)
294
294
  hp->header_done = header_done;
295
295
  hp->request = Qnil;
296
296
 
297
- http_parser_init(hp);
297
+ puma_parser_init(hp);
298
298
 
299
299
  return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp);
300
300
  }
@@ -307,9 +307,9 @@ VALUE HttpParser_alloc(VALUE klass)
307
307
  */
308
308
  VALUE HttpParser_init(VALUE self)
309
309
  {
310
- http_parser *http = NULL;
311
- DATA_GET(self, http_parser, http);
312
- http_parser_init(http);
310
+ puma_parser *http = NULL;
311
+ DATA_GET(self, puma_parser, http);
312
+ puma_parser_init(http);
313
313
 
314
314
  return self;
315
315
  }
@@ -324,9 +324,9 @@ VALUE HttpParser_init(VALUE self)
324
324
  */
325
325
  VALUE HttpParser_reset(VALUE self)
326
326
  {
327
- http_parser *http = NULL;
328
- DATA_GET(self, http_parser, http);
329
- http_parser_init(http);
327
+ puma_parser *http = NULL;
328
+ DATA_GET(self, puma_parser, http);
329
+ puma_parser_init(http);
330
330
 
331
331
  return Qnil;
332
332
  }
@@ -341,11 +341,11 @@ VALUE HttpParser_reset(VALUE self)
341
341
  */
342
342
  VALUE HttpParser_finish(VALUE self)
343
343
  {
344
- http_parser *http = NULL;
345
- DATA_GET(self, http_parser, http);
346
- http_parser_finish(http);
344
+ puma_parser *http = NULL;
345
+ DATA_GET(self, puma_parser, http);
346
+ puma_parser_finish(http);
347
347
 
348
- return http_parser_is_finished(http) ? Qtrue : Qfalse;
348
+ return puma_parser_is_finished(http) ? Qtrue : Qfalse;
349
349
  }
350
350
 
351
351
 
@@ -368,12 +368,12 @@ VALUE HttpParser_finish(VALUE self)
368
368
  */
369
369
  VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
370
370
  {
371
- http_parser *http = NULL;
371
+ puma_parser *http = NULL;
372
372
  int from = 0;
373
373
  char *dptr = NULL;
374
374
  long dlen = 0;
375
375
 
376
- DATA_GET(self, http_parser, http);
376
+ DATA_GET(self, puma_parser, http);
377
377
 
378
378
  from = FIX2INT(start);
379
379
  dptr = rb_extract_chars(data, &dlen);
@@ -383,15 +383,15 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
383
383
  rb_raise(eHttpParserError, "%s", "Requested start is after data buffer end.");
384
384
  } else {
385
385
  http->request = req_hash;
386
- http_parser_execute(http, dptr, dlen, from);
386
+ puma_parser_execute(http, dptr, dlen, from);
387
387
 
388
388
  rb_free_chars(dptr);
389
- VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER);
389
+ VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
390
390
 
391
- if(http_parser_has_error(http)) {
391
+ if(puma_parser_has_error(http)) {
392
392
  rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
393
393
  } else {
394
- return INT2FIX(http_parser_nread(http));
394
+ return INT2FIX(puma_parser_nread(http));
395
395
  }
396
396
  }
397
397
  }
@@ -406,10 +406,10 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
406
406
  */
407
407
  VALUE HttpParser_has_error(VALUE self)
408
408
  {
409
- http_parser *http = NULL;
410
- DATA_GET(self, http_parser, http);
409
+ puma_parser *http = NULL;
410
+ DATA_GET(self, puma_parser, http);
411
411
 
412
- return http_parser_has_error(http) ? Qtrue : Qfalse;
412
+ return puma_parser_has_error(http) ? Qtrue : Qfalse;
413
413
  }
414
414
 
415
415
 
@@ -421,10 +421,10 @@ VALUE HttpParser_has_error(VALUE self)
421
421
  */
422
422
  VALUE HttpParser_is_finished(VALUE self)
423
423
  {
424
- http_parser *http = NULL;
425
- DATA_GET(self, http_parser, http);
424
+ puma_parser *http = NULL;
425
+ DATA_GET(self, puma_parser, http);
426
426
 
427
- return http_parser_is_finished(http) ? Qtrue : Qfalse;
427
+ return puma_parser_is_finished(http) ? Qtrue : Qfalse;
428
428
  }
429
429
 
430
430
 
@@ -437,8 +437,8 @@ VALUE HttpParser_is_finished(VALUE self)
437
437
  */
438
438
  VALUE HttpParser_nread(VALUE self)
439
439
  {
440
- http_parser *http = NULL;
441
- DATA_GET(self, http_parser, http);
440
+ puma_parser *http = NULL;
441
+ DATA_GET(self, puma_parser, http);
442
442
 
443
443
  return INT2FIX(http->nread);
444
444
  }
@@ -450,8 +450,8 @@ VALUE HttpParser_nread(VALUE self)
450
450
  * If the request included a body, returns it.
451
451
  */
452
452
  VALUE HttpParser_body(VALUE self) {
453
- http_parser *http = NULL;
454
- DATA_GET(self, http_parser, http);
453
+ puma_parser *http = NULL;
454
+ DATA_GET(self, puma_parser, http);
455
455
 
456
456
  return http->body;
457
457
  }
@@ -17,18 +17,49 @@ Capistrano::Configuration.instance.load do
17
17
  namespace :puma do
18
18
  desc 'Start puma'
19
19
  task :start, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
20
- puma_env = fetch(:rack_env, fetch(:rails_env, 'production'))
21
- run "cd #{current_path} && #{fetch(:puma_cmd)} -q -d -e #{puma_env} -b '#{fetch(:puma_socket)}' -S #{fetch(:puma_state)} --control 'unix://#{shared_path}/sockets/pumactl.sock'", :pty => false
20
+ run "cd #{current_path} && #{fetch(:puma_cmd)} #{start_options}", :pty => false
22
21
  end
23
22
 
24
23
  desc 'Stop puma'
25
24
  task :stop, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
26
- run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S #{fetch(:puma_state)} stop"
25
+ run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S #{state_path} stop"
27
26
  end
28
27
 
29
28
  desc 'Restart puma'
30
29
  task :restart, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
31
- run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S #{fetch(:puma_state)} restart"
30
+ run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S #{state_path} restart"
32
31
  end
33
32
  end
33
+
34
+ def start_options
35
+ if config_file
36
+ "-q -d -e #{puma_env} -C #{config_file}"
37
+ else
38
+ "-q -d -e #{puma_env} -b '#{fetch(:puma_socket)}' -S #{state_path} --control 'unix://#{shared_path}/sockets/pumactl.sock'"
39
+ end
40
+ end
41
+
42
+ def config_file
43
+ @_config_file ||= begin
44
+ file = fetch(:puma_config_file, nil)
45
+ file = "./config/puma/#{puma_env}.rb" if !file && File.exists?("./config/puma/#{puma_env}.rb")
46
+ file
47
+ end
48
+ end
49
+
50
+ def puma_env
51
+ fetch(:rack_env, fetch(:rails_env, 'production'))
52
+ end
53
+
54
+ def state_path
55
+ (config_file ? configuration.options[:state] : nil) || fetch(:puma_state)
56
+ end
57
+
58
+ def configuration
59
+ require 'puma/configuration'
60
+
61
+ config = Puma::Configuration.new(:config_file => config_file)
62
+ config.load
63
+ config
64
+ end
34
65
  end
@@ -148,7 +148,7 @@ module Puma
148
148
  $LOAD_PATH.unshift(*arg.split(':'))
149
149
  end
150
150
 
151
- o.on "-p", "--port PORT", "Define what port TCP port to bind to",
151
+ o.on "-p", "--port PORT", "Define the TCP port to bind to",
152
152
  "Use -b for more advanced options" do |arg|
153
153
  @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{arg}"
154
154
  end
@@ -178,11 +178,11 @@ module Puma
178
178
  o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
179
179
  min, max = arg.split(":")
180
180
  if max
181
- @options[:min_threads] = min.to_i
182
- @options[:max_threads] = max.to_i
181
+ @options[:min_threads] = min
182
+ @options[:max_threads] = max
183
183
  else
184
184
  @options[:min_threads] = 0
185
- @options[:max_threads] = arg.to_i
185
+ @options[:max_threads] = arg
186
186
  end
187
187
  end
188
188
 
@@ -235,7 +235,13 @@ module Puma
235
235
  f.puts Process.pid
236
236
  end
237
237
 
238
- at_exit { delete_pidfile }
238
+ cur = Process.pid
239
+
240
+ at_exit do
241
+ if cur == Process.pid
242
+ delete_pidfile
243
+ end
244
+ end
239
245
  end
240
246
  end
241
247
 
@@ -443,6 +449,9 @@ module Puma
443
449
  when :exit
444
450
  # nothing
445
451
  end
452
+
453
+ ensure
454
+ delete_pidfile
446
455
  end
447
456
 
448
457
  def setup_signals
@@ -454,6 +463,14 @@ module Puma
454
463
  log "*** SIGUSR2 not implemented, signal based restart unavailable!"
455
464
  end
456
465
 
466
+ begin
467
+ Signal.trap "SIGUSR1" do
468
+ phased_restart
469
+ end
470
+ rescue Exception
471
+ log "*** SIGUSR1 not implemented, signal based restart unavailable!"
472
+ end
473
+
457
474
  begin
458
475
  Signal.trap "SIGTERM" do
459
476
  stop
@@ -482,8 +499,8 @@ module Puma
482
499
  end
483
500
 
484
501
  def phased_restart
485
- return false unless @runner.respond_to? :phased_restart
486
- @runner.phased_restart
502
+ return restart unless @runner.respond_to? :phased_restart
503
+ return restart unless @runner.phased_restart
487
504
  end
488
505
 
489
506
  def stats
@@ -233,16 +233,6 @@ module Puma
233
233
  end
234
234
  end
235
235
 
236
- if preload?
237
- Signal.trap "SIGUSR1" do
238
- log "App preloaded, phased restart unavailable"
239
- end
240
- else
241
- Signal.trap "SIGUSR1" do
242
- phased_restart
243
- end
244
- end
245
-
246
236
  # Used by the workers to detect if the master process dies.
247
237
  # If select says that @check_pipe is ready, it's because the
248
238
  # master has exited and @suicide_pipe has been automatically
@@ -19,6 +19,7 @@ module Puma
19
19
  @options = options
20
20
  @options[:binds] ||= []
21
21
  @options[:on_restart] ||= []
22
+ @options[:worker_boot] ||= []
22
23
  end
23
24
 
24
25
  attr_reader :options
@@ -187,12 +188,26 @@ module Puma
187
188
  @options[:binds] << url
188
189
  end
189
190
 
191
+ # Define the TCP port to bind to. Use +bind+ for more advanced options.
192
+ #
193
+ def port(port)
194
+ @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
195
+ end
196
+
190
197
  # Daemonize the server into the background. Highly suggest that
191
198
  # this be combined with +pidfile+ and +stdout_redirect+.
192
199
  def daemonize(which=true)
193
200
  @options[:daemon] = which
194
201
  end
195
202
 
203
+ # When shutting down, drain the accept socket of pending
204
+ # connections and proces them. This loops over the accept
205
+ # socket until there are no more read events and then stops
206
+ # looking and waits for the requests to finish.
207
+ def drain_on_shutdown(which=true)
208
+ @options[:drain_on_shutdown] = which
209
+ end
210
+
196
211
  # Set the environment in which the Rack's app will run.
197
212
  def environment(environment)
198
213
  @options[:environment] = environment
@@ -28,8 +28,8 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.3.2".freeze
32
- CODE_NAME = "Delicious Thin Mints"
31
+ PUMA_VERSION = VERSION = "2.4.0".freeze
32
+ CODE_NAME = "Crunchy Munchy Lunchy"
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
35
35
 
@@ -20,6 +20,8 @@ module Puma
20
20
  @stdout.sync = true
21
21
  @stderr.sync = true
22
22
 
23
+ @debug = ENV.key? 'PUMA_DEBUG'
24
+
23
25
  @on_booted = []
24
26
  end
25
27
 
@@ -35,6 +37,10 @@ module Puma
35
37
  @stdout.write str
36
38
  end
37
39
 
40
+ def debug(str)
41
+ log("% #{str}") if @debug
42
+ end
43
+
38
44
  # Write +str+ to +@stderr+
39
45
  #
40
46
  def error(str)
@@ -44,6 +44,10 @@ module Puma
44
44
  def self.daemon_start(dir, argv)
45
45
  ENV['PUMA_DAEMON_RESTART'] = Process.pid.to_s
46
46
 
47
+ if k = ENV['PUMA_JRUBY_DAEMON_OPTS']
48
+ ENV['JRUBY_OPTS'] = k
49
+ end
50
+
47
51
  cmd = argv.first
48
52
  argv = ([:string] * argv.size).zip(argv).flatten
49
53
  argv << :string
@@ -13,7 +13,10 @@ module Rack
13
13
  status, header, body = @app.call(env)
14
14
  header = Utils::HeaderHash.new(header)
15
15
 
16
- if ary = env['rack.after_reply']
16
+ # If we've been hijacked, then output a special line
17
+ if env['rack.hijack_io']
18
+ log_hijacking(env, 'HIJACK', header, began_at)
19
+ elsif ary = env['rack.after_reply']
17
20
  ary << lambda { log(env, status, header, began_at) }
18
21
  else
19
22
  body = BodyProxy.new(body) { log(env, status, header, began_at) }
@@ -21,5 +24,22 @@ module Rack
21
24
 
22
25
  [status, header, body]
23
26
  end
27
+
28
+ HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
29
+
30
+ def log_hijacking(env, status, header, began_at)
31
+ now = Time.now
32
+
33
+ logger = @logger || env['rack.errors']
34
+ logger.write HIJACK_FORMAT % [
35
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
36
+ env["REMOTE_USER"] || "-",
37
+ now.strftime("%d/%b/%Y %H:%M:%S"),
38
+ env["REQUEST_METHOD"],
39
+ env["PATH_INFO"],
40
+ env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
41
+ env["HTTP_VERSION"],
42
+ now - began_at ]
43
+ end
24
44
  end
25
45
  end
@@ -115,7 +115,7 @@ module Puma
115
115
  min_t = @options[:min_threads]
116
116
  max_t = @options[:max_threads]
117
117
 
118
- server = Puma::Server.new app, @cli.events
118
+ server = Puma::Server.new app, @cli.events, @options
119
119
  server.min_threads = min_t
120
120
  server.max_threads = max_t
121
121
  server.inherit_binder @cli.binder
@@ -13,6 +13,8 @@ require 'puma/delegation'
13
13
  require 'puma/accept_nonblock'
14
14
  require 'puma/util'
15
15
 
16
+ require 'puma/rack_patch'
17
+
16
18
  require 'puma/puma_http11'
17
19
 
18
20
  unless Puma.const_defined? "IOBuffer"
@@ -46,7 +48,7 @@ module Puma
46
48
  # Server#run returns a thread that you can join on to wait for the server
47
49
  # to do it's work.
48
50
  #
49
- def initialize(app, events=Events.stdio)
51
+ def initialize(app, events=Events.stdio, options={})
50
52
  @app = app
51
53
  @events = events
52
54
 
@@ -70,6 +72,8 @@ module Puma
70
72
 
71
73
  @leak_stack_on_error = true
72
74
 
75
+ @options = options
76
+
73
77
  ENV['RACK_ENV'] ||= "development"
74
78
  end
75
79
 
@@ -327,7 +331,13 @@ module Puma
327
331
  # server; that client may be a proxy, gateway, or other
328
332
  # intermediary acting on behalf of the actual source client."
329
333
  #
330
- env[REMOTE_ADDR] = client.peeraddr.last
334
+
335
+ addr = client.peeraddr.last
336
+
337
+ # Set unix socket addrs to localhost
338
+ addr = "127.0.0.1" if addr.empty?
339
+
340
+ env[REMOTE_ADDR] = addr
331
341
  end
332
342
 
333
343
  def default_server_port(env)
@@ -594,6 +604,28 @@ module Puma
594
604
  # Wait for all outstanding requests to finish.
595
605
  #
596
606
  def graceful_shutdown
607
+ if @options[:drain_on_shutdown]
608
+ count = 0
609
+
610
+ while true
611
+ ios = IO.select @binder.ios, nil, nil, 0
612
+ break unless ios
613
+
614
+ ios.first.each do |sock|
615
+ begin
616
+ if io = sock.accept_nonblock
617
+ count += 1
618
+ c = Client.new io, @binder.env(sock)
619
+ @thread_pool << c
620
+ end
621
+ rescue SystemCallError
622
+ end
623
+ end
624
+ end
625
+
626
+ @events.debug "Drained #{count} additional connections."
627
+ end
628
+
597
629
  @thread_pool.shutdown if @thread_pool
598
630
  end
599
631
 
@@ -55,6 +55,11 @@ module Puma
55
55
  exit
56
56
  end
57
57
 
58
+ Signal.trap "SIGCHLD" do
59
+ log "! Error starting new process as daemon, exitting"
60
+ exit 1
61
+ end
62
+
58
63
  pid = @cli.jruby_daemon_start
59
64
  sleep
60
65
  end
@@ -20,8 +20,8 @@ module Puma
20
20
  @spawned = 0
21
21
  @waiting = 0
22
22
 
23
- @min = min
24
- @max = max
23
+ @min = Integer(min)
24
+ @max = Integer(max)
25
25
  @block = block
26
26
  @extra = extra
27
27
 
@@ -34,7 +34,7 @@ module Puma
34
34
  @auto_trim = nil
35
35
 
36
36
  @mutex.synchronize do
37
- min.times { spawn_thread }
37
+ @min.times { spawn_thread }
38
38
  end
39
39
  end
40
40
 
@@ -31,8 +31,8 @@ module Rack
31
31
  puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
32
32
 
33
33
  server.add_tcp_listener options[:Host], options[:Port]
34
- server.min_threads = Integer(min)
35
- server.max_threads = Integer(max)
34
+ server.min_threads = min
35
+ server.max_threads = max
36
36
  yield server if block_given?
37
37
 
38
38
  begin
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "2.3.2"
5
+ s.version = "2.4.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Phoenix"]
9
- s.date = "2013-07-09"
9
+ s.date = "2013-07-22"
10
10
  s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like Rubinius or JRuby."
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma", "pumactl"]
@@ -32,6 +32,16 @@ class TestThreadPool < Test::Unit::TestCase
32
32
  assert_equal 1, pool.spawned
33
33
  end
34
34
 
35
+ def test_converts_pool_sizes
36
+ pool = new_pool('0', '1')
37
+
38
+ assert_equal 0, pool.spawned
39
+
40
+ pool << 1
41
+
42
+ assert_equal 1, pool.spawned
43
+ end
44
+
35
45
  def test_append_queues_on_max
36
46
  finish = false
37
47
  pool = new_pool(0, 1) { Thread.pass until finish }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.2
4
+ version: 2.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-09 00:00:00.000000000 Z
12
+ date: 2013-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack