puma 5.0.2-java → 5.0.3-java

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.

data/README.md CHANGED
@@ -4,7 +4,8 @@
4
4
 
5
5
  # Puma: A Ruby Web Server Built For Concurrency
6
6
 
7
- [![Actions Build Status](https://github.com/puma/puma/workflows/CI/badge.svg?branch=master)](https://github.com/puma/puma/actions)
7
+ [![Actions MRI](https://github.com/puma/puma/workflows/MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3AMRI)
8
+ [![Actions non MRI](https://github.com/puma/puma/workflows/non_MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3Anon_MRI)
8
9
  [![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
9
10
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=puma&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=puma&package-manager=bundler&version-scheme=semver)
10
11
  [![StackOverflow](https://img.shields.io/badge/stackoverflow-Puma-blue.svg)]( https://stackoverflow.com/questions/tagged/puma )
@@ -273,18 +274,17 @@ end
273
274
 
274
275
  Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma).
275
276
 
276
- It is common to use process monitors with Puma. Modern process monitors like systemd or upstart
277
+ It is common to use process monitors with Puma. Modern process monitors like systemd or rc.d
277
278
  provide continuous monitoring and restarts for increased
278
279
  reliability in production environments:
279
280
 
280
- * [docs/jungle](https://github.com/puma/puma/tree/master/docs/jungle) for rc.d and upstart
281
+ * [docs/jungle](https://github.com/puma/puma/tree/master/docs/jungle) for rc.d
281
282
  * [docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md)
282
283
 
283
284
  ## Community Extensions
284
285
 
285
286
  ### Plugins
286
287
 
287
- * [puma-heroku](https://github.com/puma/puma-heroku) — default Puma configuration for running on Heroku
288
288
  * [puma-metrics](https://github.com/harmjanblok/puma-metrics) — export Puma metrics to Prometheus
289
289
  * [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma metrics to statsd
290
290
  * [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper integration with systemd for notify, status and watchdog
@@ -5,24 +5,18 @@
5
5
 
6
6
  require 'rubygems'
7
7
 
8
- gems = ARGV.shift
8
+ cli_arg = ARGV.shift
9
9
 
10
10
  inc = ""
11
11
 
12
- if gems == "-I"
12
+ if cli_arg == "-I"
13
13
  inc = ARGV.shift
14
14
  $LOAD_PATH.concat inc.split(":")
15
- gems = ARGV.shift
16
- end
17
-
18
- gems.split(",").each do |s|
19
- name, ver = s.split(":",2)
20
- gem name, ver
21
15
  end
22
16
 
23
17
  module Puma; end
24
18
 
25
- Puma.const_set("WILD_ARGS", ["-I", inc, gems])
19
+ Puma.const_set("WILD_ARGS", ["-I", inc])
26
20
 
27
21
  require 'puma/cli'
28
22
 
@@ -1,4 +1,4 @@
1
- # Deployment engineering for puma
1
+ # Deployment engineering for Puma
2
2
 
3
3
  Puma is software that is expected to be run in a deployed environment eventually.
4
4
  You can certainly use it as your dev server only, but most people look to use
@@ -7,12 +7,11 @@ it in their production deployments as well.
7
7
  To that end, this is meant to serve as a foundation of wisdom how to do that
8
8
  in a way that increases happiness and decreases downtime.
9
9
 
10
- ## Specifying puma
10
+ ## Specifying Puma
11
11
 
12
12
  Most people want to do this by putting `gem "puma"` into their Gemfile, so we'll
13
13
  go ahead and assume that. Go add it now... we'll wait.
14
14
 
15
-
16
15
  Welcome back!
17
16
 
18
17
  ## Single vs Cluster mode
@@ -20,7 +19,7 @@ Welcome back!
20
19
  Puma was originally conceived as a thread-only webserver, but grew the ability to
21
20
  also use processes in version 2.
22
21
 
23
- To run puma in single mode (e.g. for a development environment) you will need to
22
+ To run `puma` in single mode (e.g. for a development environment) you will need to
24
23
  set the number of workers to 0, anything above will run in cluster mode.
25
24
 
26
25
  Here are some rules of thumb for cluster mode:
@@ -82,7 +81,7 @@ thread to become available.
82
81
 
83
82
  Daemonization was removed in Puma 5.0. For alternatives, continue reading.
84
83
 
85
- I prefer to not daemonize my servers and use something like `runit` or `upstart` to
84
+ I prefer to not daemonize my servers and use something like `runit` or `systemd` to
86
85
  monitor them as child processes. This gives them fast response to crashes and
87
86
  makes it easy to figure out what is going on. Additionally, unlike `unicorn`,
88
87
  puma does not require daemonization to do zero-downtime restarts.
@@ -92,7 +91,7 @@ task and thus want it to live on past the `cap deploy`. To these people I say:
92
91
  You need to be using a process monitor. Nothing is making sure puma stays up in
93
92
  this scenario! You're just waiting for something weird to happen, puma to die,
94
93
  and to get paged at 3am. Do yourself a favor, at least the process monitoring
95
- your OS comes with, be it `sysvinit`, `upstart`, or `systemd`. Or branch out
94
+ your OS comes with, be it `sysvinit` or `systemd`. Or branch out
96
95
  and use `runit` or hell, even `monit`.
97
96
 
98
97
  ## Restarting
@@ -1,9 +1,5 @@
1
1
  # Puma as a service
2
2
 
3
- ## Upstart
4
-
5
- See `/docs/jungle/upstart` for Ubuntu's upstart scripts.
6
-
7
3
  ## Systemd
8
4
 
9
5
  See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
@@ -23,7 +23,7 @@ puma_start()
23
23
  rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
24
24
  case $rb_env in
25
25
  "rbenv")
26
- su - $user -c "cd $dir && rbenv shell $rb_ver && bundle exec puma -C $dir/config/puma.rb -d"
26
+ cd $dir && rbenv shell $rb_ver && /usr/sbin/daemon -u $user bundle exec puma -C $dir/config/puma.rb
27
27
  ;;
28
28
  *)
29
29
  ;;
@@ -48,7 +48,7 @@ puma_restart()
48
48
  rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
49
49
  case $rb_env in
50
50
  "rbenv")
51
- su - $user -c "cd $dir && pkill ruby && rbenv shell $ruby_version && bundle exec puma -C $dir/config/puma.rb -d"
51
+ cd $dir && rbenv shell $rb_ver && /usr/sbin/daemon -u $user bundle exec puma -C $dir/config/puma.rb
52
52
  ;;
53
53
  *)
54
54
  ;;
@@ -31,7 +31,7 @@ server {
31
31
 
32
32
  location / {
33
33
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
34
- proxy_set_header Host $http_host;
34
+ proxy_set_header Host $host;
35
35
 
36
36
  # If the file exists as a static file serve it directly without
37
37
  # running all the other rewrite tests on it
@@ -1,41 +1,64 @@
1
- # Restarts
1
+ Puma provides three distinct kinds of restart operations, each for different use cases. Hot restarts and phased restarts are described here. The third kind of restart operation is called "refork" and is described in the documentation for [`fork_worker`](fork_worker.md).
2
2
 
3
- To perform a restart, there are 3 builtin mechanisms:
3
+ ## Hot restart
4
4
 
5
- * Send the `puma` process the `SIGUSR2` signal (normal restart)
6
- * Send the `puma` process the `SIGUSR1` signal (restart in phases (a "rolling restart"), cluster mode only)
7
- * Use the status server and issue `/restart`
5
+ To perform a "hot" restart, Puma performs an `exec` operation to start the process up again, so no memory is shared between the old process and the new process. As a result, it is safe to issue a restart any place where you would manually stop Puma and start it again. In particular, it is safe to upgrade Puma itself using a hot restart.
8
6
 
9
- No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop Puma and start it again.
7
+ If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor when using it in production.
10
8
 
11
- If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor (see below) when using it in production.
9
+ ### How-to
12
10
 
13
- ### Normal vs Hot vs Phased Restart
11
+ Any of the following will cause a Puma server to perform a hot restart:
14
12
 
15
- A hot restart means that no requests will be lost while deploying your new code, since the server socket is kept open between restarts.
13
+ * Send the `puma` process the `SIGUSR2` signal
14
+ * Issue a `GET` request to the Puma status/control server with the path `/restart`
15
+ * Issue `pumactl restart` (this uses the control server method if available, otherwise sends the `SIGUSR2` signal to the process)
16
16
 
17
- But beware, hot restart does not mean that the incoming requests won’t hang for multiple seconds while your new code has not fully deployed. If you need a zero downtime and zero hanging requests deploy, you must use phased restart.
17
+ ### Supported configurations
18
18
 
19
- When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that at least another worker is still available to serve requests, which lead to zero hanging requests (yay!).
19
+ * Works in cluster mode and in single mode
20
+ * Supported on all platforms
20
21
 
21
- But again beware, upgrading an application sometimes involves upgrading the database schema. With phased restart, there may be a moment during the deployment where processes belonging to the previous version and processes belonging to the new version both exist at the same time. Any database schema upgrades you perform must therefore be backwards-compatible with the old application version.
22
+ ### Client experience
22
23
 
23
- If you perform a lot of database migrations, you probably should not use phased restart and use a normal/hot restart instead (`pumactl restart`). That way, no code is shared while deploying (in that case, `preload_app!` might help for quicker deployment, see ["Clustered Mode" in the README](../README.md#clustered-mode)).
24
+ * All platforms: for clients with an in-flight request, those clients will be served responses before the connection is closed gracefully. Puma gracefully disconnects any idle HTTP persistent connections before restarting.
25
+ * On MRI or TruffleRuby on Linux and BSD: Clients who connect just before the server restarts may experience increased latency while the server stops and starts again, but their connections will not be closed prematurely.
26
+ * On Windows and on JRuby: Clients who connect just before a restart may experience "connection reset" errors.
24
27
 
25
- **Note**: Hot and phased restarts are only available on MRI, not on JRuby. They are also unavailable on Windows servers.
28
+ ### Additional notes
26
29
 
27
- ### Release Directory
30
+ * Only one version of the application is running at a time.
31
+ * `on_restart` is invoked just before the server shuts down. This can be used to clean up resources (like long-lived database connections) gracefully. Since Ruby 2.0, it is not typically necessary to explicitly close file descriptors on restart. This is because any file descriptor opened by Ruby will have the `FD_CLOEXEC` flag set, meaning that file descriptors are closed on `exec`. `on_restart` is useful, though, if your application needs to perform any more graceful protocol-specific shutdown procedures before closing connections.
28
32
 
29
- If your symlink releases into a common working directory (i.e., `/current` from Capistrano), Puma won't pick up your new changes when running phased restarts without additional configuration. You should set your working directory within Puma's config to specify the directory it should use. This is a change from earlier versions of Puma (< 2.15) that would infer the directory for you.
33
+ ## Phased restart
30
34
 
31
- ```ruby
32
- # config/puma.rb
35
+ Phased restarts replace all running workers in a Puma cluster. This is a useful way to gracefully upgrade the application that Puma is serving. A phased restart works by first killing an old worker, then starting a new worker, waiting until the new worker has successfully started before proceeding to the next worker. This process continues until all workers have been replaced. The master process is not restarted.
33
36
 
34
- directory '/var/www/current'
35
- ```
37
+ ### How-to
36
38
 
37
- ### Cleanup Code
39
+ Any of the following will cause a Puma server to perform a phased restart:
38
40
 
39
- 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.
41
+ * Send the `puma` process the `SIGUSR1` signal
42
+ * Issue a `GET` request to the Puma status/control server with the path `/phased-restart`
43
+ * Issue `pumactl phased-restart` (this uses the control server method if available, otherwise sends the `SIGUSR1` signal to the process)
40
44
 
41
- 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 restarted many times.
45
+ ### Supported configurations
46
+
47
+ * Works in cluster mode only
48
+ * To support upgrading the application that Puma is serving, ensure `prune_bundler` is enabled and that `preload_app` is disabled (it is disabled by default).
49
+ * Supported on all platforms where cluster mode is supported
50
+
51
+ ### Client experience
52
+
53
+ * In-flight requests are always served responses before the connection is closed gracefully
54
+ * Idle persistent connections are gracefully disconnected
55
+ * New connections are not lost, and clients will not experience any increase in latency (as long as the number of configured workers is greater than one)
56
+
57
+ ### Additional notes
58
+
59
+ * When a phased restart begins, the Puma master process changes its current working directory to the directory specified by the `directory` option. If `directory` is set to symlink, this is automatically re-evaluated, so this mechanism can be used to upgrade the application.
60
+ * On a single server, it's possible that two versions of the application are running concurrently during a phased restart.
61
+ * `on_restart` is not invoked
62
+ * Phased restarts can be slow for Puma clusters with many workers. Hot restarts often complete more quickly, but at the cost of increased latency during the restart.
63
+ * Phased restarts cannot be used to upgrade any gems loaded by the Puma master process, including `puma` itself, anything in `extra_runtime_dependencies`, or dependencies thereof. Upgrading other gems is safe.
64
+ * If you remove the gems from old releases as part of your deployment strategy, there are additional considerations. Do not put any gems into `extra_runtime_dependencies` that have native extensions or have dependencies that have native extensions (one common example is `puma_worker_killer` and its dependency on `ffi`). Workers will fail on boot during a phased restart. The underlying issue is recorded in [an issue on the rubygems project](https://github.com/rubygems/rubygems/issues/4004). Hot restarts are your only option here if you need these dependencies.
@@ -76,7 +76,7 @@ pass the `--keep-file-descriptors` flag. `bundle exec` can be avoided by using a
76
76
  `puma` executable generated by `bundle binstubs puma`. This is tracked in
77
77
  [#1499].
78
78
 
79
- **Note:** Socket activation doesn't currently work on jruby. This is
79
+ **Note:** Socket activation doesn't currently work on JRuby. This is
80
80
  tracked in [#1367].
81
81
 
82
82
  To use socket activation, configure one or more `ListenStream` sockets
@@ -2,7 +2,7 @@
2
2
  #define ext_help_h
3
3
 
4
4
  #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "%s", "NULL found for " # T " when shouldn't be.");
5
- #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
5
+ #define DATA_GET(from,type,data_type,name) TypedData_Get_Struct(from,type,data_type,name); RAISE_NOT_NULL(name);
6
6
  #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "%s", "Wrong argument type for " # V " required " # T);
7
7
  #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
8
8
 
@@ -2,12 +2,7 @@
2
2
 
3
3
  #include <ruby.h>
4
4
  #include <ruby/version.h>
5
-
6
- #if RUBY_API_VERSION_MAJOR == 1
7
- #include <rubyio.h>
8
- #else
9
5
  #include <ruby/io.h>
10
- #endif
11
6
 
12
7
  #ifdef HAVE_OPENSSL_BIO_H
13
8
 
@@ -33,7 +28,8 @@ typedef struct {
33
28
  int bytes;
34
29
  } ms_cert_buf;
35
30
 
36
- void engine_free(ms_conn* conn) {
31
+ void engine_free(void *ptr) {
32
+ ms_conn *conn = ptr;
37
33
  ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
38
34
  if(cert_buf) {
39
35
  OPENSSL_free(cert_buf->buf);
@@ -45,10 +41,16 @@ void engine_free(ms_conn* conn) {
45
41
  free(conn);
46
42
  }
47
43
 
44
+ const rb_data_type_t engine_data_type = {
45
+ "MiniSSL/ENGINE",
46
+ { 0, engine_free, 0 },
47
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
48
+ };
49
+
48
50
  ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
49
51
  ms_conn* conn;
50
52
 
51
- *obj = Data_Make_Struct(klass, ms_conn, 0, engine_free, conn);
53
+ *obj = TypedData_Make_Struct(klass, ms_conn, &engine_data_type, conn);
52
54
 
53
55
  conn->read = BIO_new(BIO_s_mem());
54
56
  BIO_set_nbio(conn->read, 1);
@@ -198,7 +200,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
198
200
  else {
199
201
  min = TLS1_VERSION;
200
202
  }
201
-
203
+
202
204
  SSL_CTX_set_min_proto_version(ctx, min);
203
205
 
204
206
  SSL_CTX_set_options(ctx, ssl_options);
@@ -281,7 +283,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
281
283
  ms_conn* conn;
282
284
  long used;
283
285
 
284
- Data_Get_Struct(self, ms_conn, conn);
286
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
285
287
 
286
288
  StringValue(str);
287
289
 
@@ -334,7 +336,7 @@ VALUE engine_read(VALUE self) {
334
336
  char buf[512];
335
337
  int bytes, error;
336
338
 
337
- Data_Get_Struct(self, ms_conn, conn);
339
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
338
340
 
339
341
  ERR_clear_error();
340
342
 
@@ -361,7 +363,7 @@ VALUE engine_write(VALUE self, VALUE str) {
361
363
  ms_conn* conn;
362
364
  int bytes;
363
365
 
364
- Data_Get_Struct(self, ms_conn, conn);
366
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
365
367
 
366
368
  StringValue(str);
367
369
 
@@ -385,7 +387,7 @@ VALUE engine_extract(VALUE self) {
385
387
  size_t pending;
386
388
  char buf[512];
387
389
 
388
- Data_Get_Struct(self, ms_conn, conn);
390
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
389
391
 
390
392
  pending = BIO_pending(conn->write);
391
393
  if(pending > 0) {
@@ -404,7 +406,7 @@ VALUE engine_shutdown(VALUE self) {
404
406
  ms_conn* conn;
405
407
  int ok;
406
408
 
407
- Data_Get_Struct(self, ms_conn, conn);
409
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
408
410
 
409
411
  ERR_clear_error();
410
412
 
@@ -419,7 +421,7 @@ VALUE engine_shutdown(VALUE self) {
419
421
  VALUE engine_init(VALUE self) {
420
422
  ms_conn* conn;
421
423
 
422
- Data_Get_Struct(self, ms_conn, conn);
424
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
423
425
 
424
426
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
425
427
  }
@@ -432,7 +434,7 @@ VALUE engine_peercert(VALUE self) {
432
434
  ms_cert_buf* cert_buf = NULL;
433
435
  VALUE rb_cert_buf;
434
436
 
435
- Data_Get_Struct(self, ms_conn, conn);
437
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
436
438
 
437
439
  cert = SSL_get_peer_certificate(conn->ssl);
438
440
  if(!cert) {
@@ -469,7 +471,7 @@ VALUE engine_peercert(VALUE self) {
469
471
  static VALUE
470
472
  engine_ssl_vers_st(VALUE self) {
471
473
  ms_conn* conn;
472
- Data_Get_Struct(self, ms_conn, conn);
474
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
473
475
  return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
474
476
  }
475
477
 
@@ -504,27 +506,27 @@ void Init_mini_ssl(VALUE puma) {
504
506
  #else
505
507
  rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
506
508
  #endif
507
-
508
- #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
509
- /* True if SSL3 is not available */
510
- rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
511
- #else
512
- rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
513
- #endif
514
-
515
- #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
516
- /* True if TLS1 is not available */
517
- rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
518
- #else
519
- rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
520
- #endif
521
-
522
- #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
523
- /* True if TLS1_1 is not available */
524
- rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
525
- #else
526
- rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
527
- #endif
509
+
510
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
511
+ /* True if SSL3 is not available */
512
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
513
+ #else
514
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
515
+ #endif
516
+
517
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
518
+ /* True if TLS1 is not available */
519
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
520
+ #else
521
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
522
+ #endif
523
+
524
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
525
+ /* True if TLS1_1 is not available */
526
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
527
+ #else
528
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
529
+ #endif
528
530
 
529
531
  rb_define_singleton_method(mod, "check", noop, 0);
530
532
 
@@ -253,11 +253,18 @@ void HttpParser_free(void *data) {
253
253
  }
254
254
  }
255
255
 
256
- void HttpParser_mark(puma_parser* hp) {
256
+ void HttpParser_mark(void *ptr) {
257
+ puma_parser *hp = ptr;
257
258
  if(hp->request) rb_gc_mark(hp->request);
258
259
  if(hp->body) rb_gc_mark(hp->body);
259
260
  }
260
261
 
262
+ const rb_data_type_t HttpParser_data_type = {
263
+ "HttpParser",
264
+ { HttpParser_mark, HttpParser_free, 0 },
265
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
266
+ };
267
+
261
268
  VALUE HttpParser_alloc(VALUE klass)
262
269
  {
263
270
  puma_parser *hp = ALLOC_N(puma_parser, 1);
@@ -274,7 +281,7 @@ VALUE HttpParser_alloc(VALUE klass)
274
281
 
275
282
  puma_parser_init(hp);
276
283
 
277
- return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp);
284
+ return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
278
285
  }
279
286
 
280
287
  /**
@@ -286,7 +293,7 @@ VALUE HttpParser_alloc(VALUE klass)
286
293
  VALUE HttpParser_init(VALUE self)
287
294
  {
288
295
  puma_parser *http = NULL;
289
- DATA_GET(self, puma_parser, http);
296
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
290
297
  puma_parser_init(http);
291
298
 
292
299
  return self;
@@ -303,7 +310,7 @@ VALUE HttpParser_init(VALUE self)
303
310
  VALUE HttpParser_reset(VALUE self)
304
311
  {
305
312
  puma_parser *http = NULL;
306
- DATA_GET(self, puma_parser, http);
313
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
307
314
  puma_parser_init(http);
308
315
 
309
316
  return Qnil;
@@ -320,7 +327,7 @@ VALUE HttpParser_reset(VALUE self)
320
327
  VALUE HttpParser_finish(VALUE self)
321
328
  {
322
329
  puma_parser *http = NULL;
323
- DATA_GET(self, puma_parser, http);
330
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
324
331
  puma_parser_finish(http);
325
332
 
326
333
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
@@ -351,7 +358,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
351
358
  char *dptr = NULL;
352
359
  long dlen = 0;
353
360
 
354
- DATA_GET(self, puma_parser, http);
361
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
355
362
 
356
363
  from = FIX2INT(start);
357
364
  dptr = rb_extract_chars(data, &dlen);
@@ -385,7 +392,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
385
392
  VALUE HttpParser_has_error(VALUE self)
386
393
  {
387
394
  puma_parser *http = NULL;
388
- DATA_GET(self, puma_parser, http);
395
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
389
396
 
390
397
  return puma_parser_has_error(http) ? Qtrue : Qfalse;
391
398
  }
@@ -400,7 +407,7 @@ VALUE HttpParser_has_error(VALUE self)
400
407
  VALUE HttpParser_is_finished(VALUE self)
401
408
  {
402
409
  puma_parser *http = NULL;
403
- DATA_GET(self, puma_parser, http);
410
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
404
411
 
405
412
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
406
413
  }
@@ -416,7 +423,7 @@ VALUE HttpParser_is_finished(VALUE self)
416
423
  VALUE HttpParser_nread(VALUE self)
417
424
  {
418
425
  puma_parser *http = NULL;
419
- DATA_GET(self, puma_parser, http);
426
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
420
427
 
421
428
  return INT2FIX(http->nread);
422
429
  }
@@ -429,7 +436,7 @@ VALUE HttpParser_nread(VALUE self)
429
436
  */
430
437
  VALUE HttpParser_body(VALUE self) {
431
438
  puma_parser *http = NULL;
432
- DATA_GET(self, puma_parser, http);
439
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
433
440
 
434
441
  return http->body;
435
442
  }