puma 3.5.0 → 3.12.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.

Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +318 -75
  3. data/README.md +143 -227
  4. data/docs/architecture.md +36 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +0 -0
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/plugins.md +28 -0
  10. data/docs/restart.md +39 -0
  11. data/docs/signals.md +56 -3
  12. data/docs/systemd.md +124 -22
  13. data/ext/puma_http11/extconf.rb +2 -0
  14. data/ext/puma_http11/http11_parser.c +85 -84
  15. data/ext/puma_http11/http11_parser.h +1 -0
  16. data/ext/puma_http11/http11_parser.rl +10 -9
  17. data/ext/puma_http11/io_buffer.c +7 -7
  18. data/ext/puma_http11/mini_ssl.c +67 -6
  19. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +13 -16
  20. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +15 -2
  21. data/ext/puma_http11/puma_http11.c +1 -0
  22. data/lib/puma.rb +13 -5
  23. data/lib/puma/app/status.rb +8 -0
  24. data/lib/puma/binder.rb +22 -17
  25. data/lib/puma/cli.rb +49 -33
  26. data/lib/puma/client.rb +149 -4
  27. data/lib/puma/cluster.rb +54 -12
  28. data/lib/puma/commonlogger.rb +19 -20
  29. data/lib/puma/compat.rb +3 -7
  30. data/lib/puma/configuration.rb +133 -130
  31. data/lib/puma/const.rb +19 -37
  32. data/lib/puma/control_cli.rb +38 -35
  33. data/lib/puma/convenient.rb +3 -3
  34. data/lib/puma/detect.rb +3 -1
  35. data/lib/puma/dsl.rb +80 -58
  36. data/lib/puma/events.rb +6 -8
  37. data/lib/puma/io_buffer.rb +1 -1
  38. data/lib/puma/jruby_restart.rb +0 -1
  39. data/lib/puma/launcher.rb +61 -30
  40. data/lib/puma/minissl.rb +85 -4
  41. data/lib/puma/null_io.rb +6 -13
  42. data/lib/puma/plugin.rb +12 -1
  43. data/lib/puma/plugin/tmp_restart.rb +1 -2
  44. data/lib/puma/rack/builder.rb +3 -0
  45. data/lib/puma/rack/urlmap.rb +9 -8
  46. data/lib/puma/reactor.rb +135 -0
  47. data/lib/puma/runner.rb +27 -1
  48. data/lib/puma/server.rb +134 -32
  49. data/lib/puma/single.rb +17 -3
  50. data/lib/puma/thread_pool.rb +67 -20
  51. data/lib/puma/util.rb +1 -5
  52. data/lib/rack/handler/puma.rb +58 -17
  53. data/tools/jungle/README.md +12 -2
  54. data/tools/jungle/init.d/README.md +9 -2
  55. data/tools/jungle/init.d/puma +32 -62
  56. data/tools/jungle/init.d/run-puma +5 -1
  57. data/tools/jungle/rc.d/README.md +74 -0
  58. data/tools/jungle/rc.d/puma +61 -0
  59. data/tools/jungle/rc.d/puma.conf +10 -0
  60. data/tools/trickletest.rb +1 -1
  61. metadata +22 -92
  62. data/Gemfile +0 -13
  63. data/Manifest.txt +0 -77
  64. data/Rakefile +0 -158
  65. data/lib/puma/rack/backports/uri/common_18.rb +0 -59
  66. data/lib/puma/rack/backports/uri/common_192.rb +0 -55
  67. data/puma.gemspec +0 -52
@@ -0,0 +1,36 @@
1
+ # Architecture
2
+
3
+ ## Overview
4
+
5
+ ![http://bit.ly/2iJuFky](images/puma-general-arch.png)
6
+
7
+ Puma is a threaded web server, processing requests across a TCP or UNIX socket.
8
+
9
+ Workers accept connections from the socket and a thread in the worker's thread pool processes the client's request.
10
+
11
+ Clustered mode is shown/discussed here. Single mode is analogous to having a single worker process.
12
+
13
+ ## Connection pipeline
14
+
15
+ ![http://bit.ly/2zwzhEK](images/puma-connection-flow.png)
16
+
17
+ * Upon startup, Puma listens on a TCP or UNIX socket.
18
+ * The backlog of this socket is configured (with a default of 1024), determining how many established but unaccepted connections can exist concurrently.
19
+ * This socket backlog is distinct from the "backlog" of work as reported by the control server stats. The latter is the number of connections in that worker's "todo" set waiting for a worker thread.
20
+ * By default, a single, separate thread is used to receive HTTP requests across the socket.
21
+ * When at least one worker thread is available for work, a connection is accepted and placed in this request buffer
22
+ * This thread waits for entire HTTP requests to be received over the connection
23
+ * Once received, the connection is pushed into the "todo" set
24
+ * Worker threads pop work off the "todo" set for processing
25
+ * The thread processes the request via the rack application (which generates the HTTP response)
26
+ * The thread writes the response to the connection
27
+ * Finally, the thread become available to process another connection in the "todo" set
28
+
29
+ ### Disabling `queue_requests`
30
+
31
+ ![http://bit.ly/2zxCJ1Z](images/puma-connection-flow-no-reactor.png)
32
+
33
+ The `queue_requests` option is `true` by default, enabling the separate thread used to buffer requests as described above.
34
+
35
+ If set to `false`, this buffer will not be used for connections while waiting for the request to arrive.
36
+ In this mode, when a connection is accepted, it is added to the "todo" queue immediately, and a worker will synchronously do any waiting necessary to read the HTTP request from the socket.
File without changes
@@ -0,0 +1,28 @@
1
+ ## Plugins
2
+
3
+ Puma 3.0 added support for plugins that can augment configuration and service operations.
4
+
5
+ 2 canonical plugins to look to aid in development of further plugins:
6
+
7
+ * [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb): Restarts the server if the file `tmp/restart.txt` is touched
8
+ * [heroku](https://github.com/puma/puma-heroku/blob/master/lib/puma/plugin/heroku.rb): Packages up the default configuration used by puma on Heroku
9
+
10
+ Plugins are activated in a puma configuration file (such as `config/puma.rb'`) by adding `plugin "name"`, such as `plugin "heroku"`.
11
+
12
+ Plugins are activated based simply on path requirements so, activating the `heroku` plugin will simply be doing `require "puma/plugin/heroku"`. This allows gems to provide multiple plugins (as well as unrelated gems to provide puma plugins).
13
+
14
+ The `tmp_restart` plugin is bundled with puma, so it can always be used.
15
+
16
+ To use the `heroku` plugin, add `puma-heroku` to your Gemfile or install it.
17
+
18
+ ### API
19
+
20
+ At present, there are 2 hooks that plugins can use: `start` and `config`.
21
+
22
+ `start` runs when the server has started and allows the plugin to start other functionality to augment puma.
23
+
24
+ `config` runs when the server is being configured and is passed a `Puma::DSL` object that can be used to add additional configuration.
25
+
26
+ Any public methods in `Puma::Plugin` are the public API that any plugin may use.
27
+
28
+ In the future, more hooks and APIs will be added.
@@ -0,0 +1,39 @@
1
+ # Restarts
2
+
3
+ To perform a restart, there are 3 builtin mechanisms:
4
+
5
+ * Send the `puma` process the `SIGUSR2` signal
6
+ * Send the `puma` process the `SIGUSR1` signal (rolling restart, cluster mode only)
7
+ * Use the status server and issue `/restart`
8
+
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.
10
+
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.
12
+
13
+ ### Normal vs Hot vs Phased Restart
14
+
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.
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.
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!).
20
+
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
+
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
+
25
+ ### Release Directory
26
+
27
+ 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.
28
+
29
+ ```ruby
30
+ # config/puma.rb
31
+
32
+ directory '/var/www/current'
33
+ ```
34
+
35
+ ### Cleanup Code
36
+
37
+ 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.
38
+
39
+ 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.
@@ -36,8 +36,61 @@ Puma cluster responds to these signals:
36
36
  - `TTIN` increment the worker count by 1
37
37
  - `TTOU` decrement the worker count by 1
38
38
  - `TERM` send `TERM` to worker. Worker will attempt to finish then exit.
39
- - `USR2` restart workers
40
- - `USR1` restart workers in phases, a rolling restart.
41
- - `HUP` reopen log files defined in stdout_redirect configuration parameter
39
+ - `USR2` restart workers. This also reloads puma configuration file, if there is one.
40
+ - `USR1` restart workers in phases, a rolling restart. This will not reload configuration file.
41
+ - `HUP` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided it will behave like `INT`
42
42
  - `INT` equivalent of sending Ctrl-C to cluster. Will attempt to finish then exit.
43
43
  - `CHLD`
44
+
45
+ ## Callbacks order in case of different signals
46
+
47
+ ### Start application
48
+
49
+ ```
50
+ puma configuration file reloaded, if there is one
51
+ * Pruning Bundler environment
52
+ puma configuration file reloaded, if there is one
53
+
54
+ before_fork
55
+ on_worker_fork
56
+ after_worker_fork
57
+
58
+ Gemfile in context
59
+
60
+ on_worker_boot
61
+
62
+ Code of the app is loaded and running
63
+ ```
64
+
65
+ ### Send USR2
66
+
67
+ ```
68
+ on_worker_shutdown
69
+ on_restart
70
+
71
+ puma configuration file reloaded, if there is one
72
+
73
+ before_fork
74
+ on_worker_fork
75
+ after_worker_fork
76
+
77
+ Gemfile in context
78
+
79
+ on_worker_boot
80
+
81
+ Code of the app is loaded and running
82
+ ```
83
+
84
+ ### Send USR1
85
+
86
+ ```
87
+ on_worker_shutdown
88
+ on_worker_fork
89
+ after_worker_fork
90
+
91
+ Gemfile in context
92
+
93
+ on_worker_boot
94
+
95
+ Code of the app is loaded and running
96
+ ```
@@ -3,10 +3,21 @@
3
3
  [systemd](https://www.freedesktop.org/wiki/Software/systemd/) is a
4
4
  commonly available init system (PID 1) on many Linux distributions. It
5
5
  offers process monitoring (including automatic restarts) and other
6
- useful features for running Puma in production. Below is a sample
7
- puma.service configuration file for systemd:
6
+ useful features for running Puma in production.
8
7
 
9
- ~~~~
8
+ ## Service Configuration
9
+
10
+ Below is a sample puma.service configuration file for systemd, which
11
+ can be copied or symlinked to /etc/systemd/system/puma.service, or if
12
+ desired, using an application or instance specific name.
13
+
14
+ Note that this uses the systemd preferred "simple" type where the
15
+ start command remains running in the foreground (does not fork and
16
+ exit). See also, the
17
+ [Alternative Forking Configuration](#alternative-forking-configuration)
18
+ below.
19
+
20
+ ~~~~ ini
10
21
  [Unit]
11
22
  Description=Puma HTTP Server
12
23
  After=network.target
@@ -21,22 +32,21 @@ Type=simple
21
32
  # Preferably configure a non-privileged user
22
33
  # User=
23
34
 
24
- # Specify the path to your puma application root
25
- # WorkingDirectory=
35
+ # The path to the puma application root
36
+ # Also replace the "<WD>" place holders below with this path.
37
+ WorkingDirectory=
26
38
 
27
39
  # Helpful for debugging socket activation, etc.
28
40
  # Environment=PUMA_DEBUG=1
29
41
 
30
- # The command to start Puma
31
- # Here we are using a binstub generated via:
32
- # `bundle binstubs puma --path ./sbin`
33
- # in the WorkingDirectory (replace <WD> below)
34
- # You can alternatively use `bundle exec --keep-file-descriptors puma`
35
- # ExecStart=<WD>/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
36
-
37
- # Alternatively with a config file (in WorkingDirectory) and
38
- # comparable `bind` directives
42
+ # The command to start Puma. This variant uses a binstub generated via
43
+ # `bundle binstubs puma --path ./sbin` in the WorkingDirectory
44
+ # (replace "<WD>" below)
45
+ ExecStart=<WD>/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
46
+
47
+ # Variant: Use config file with `bind` directives instead:
39
48
  # ExecStart=<WD>/sbin/puma -C config.rb
49
+ # Variant: Use `bundle exec --keep-file-descriptors puma` instead of binstub
40
50
 
41
51
  Restart=always
42
52
 
@@ -50,14 +60,22 @@ for additional details.
50
60
  ## Socket Activation
51
61
 
52
62
  systemd and puma also support socket activation, where systemd opens
53
- the listening socket(s) in advance and provides them to the puma master
54
- process on startup. Among other advantages, this keeps listening
55
- sockets open across puma restarts and achieves graceful restarts. To
56
- use socket activation, configure one or more `ListenStream`
57
- sockets in a companion `*.socket` systemd config file. Here is a sample
58
- puma.socket, matching the ports used in the above puma.service:
59
-
60
- ~~~~
63
+ the listening socket(s) in advance and provides them to the puma
64
+ master process on startup. Among other advantages, this keeps
65
+ listening sockets open across puma restarts and achieves graceful
66
+ restarts, including when upgraded puma, and is compatible with both
67
+ clustered mode and application preload.
68
+
69
+ **Note:** Socket activation doesn't currently work on jruby. This is
70
+ tracked in [#1367].
71
+
72
+ To use socket activation, configure one or more `ListenStream` sockets
73
+ in a companion `*.socket` unit file. Also uncomment the associated
74
+ `Requires` directive for the socket unit in the service file (see
75
+ above.) Here is a sample puma.socket, matching the ports used in the
76
+ above puma.service:
77
+
78
+ ~~~~ ini
61
79
  [Unit]
62
80
  Description=Puma HTTP Server Accept Sockets
63
81
 
@@ -84,6 +102,16 @@ for additional configuration details.
84
102
  Note that the above configurations will work with Puma in either
85
103
  single process or cluster mode.
86
104
 
105
+ ### Sockets and symlinks
106
+
107
+ When using releases folders, you should set the socket path using the
108
+ shared folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the
109
+ release folder path (`/srv/projet/releases/1234/tmp/puma.sock`).
110
+
111
+ Puma will detect the release path socket as different than the one provided by
112
+ systemd and attempt to bind it again, resulting in the exception
113
+ `There is already a server bound to:`.
114
+
87
115
  ## Usage
88
116
 
89
117
  Without socket activation, use `systemctl` as root (e.g. via `sudo`) as
@@ -168,3 +196,77 @@ Apr 07 08:40:19 hx puma[28320]: * Activated tcp://0.0.0.0:9233
168
196
  Apr 07 08:40:19 hx puma[28320]: * Activated ssl://0.0.0.0:9234?key=key.pem&cert=cert.pem
169
197
  Apr 07 08:40:19 hx puma[28320]: Use Ctrl-C to stop
170
198
  ~~~~
199
+
200
+ ## Alternative Forking Configuration
201
+
202
+ Other systems/tools might expect or need puma to be run as a
203
+ "traditional" forking server, for example so that the `pumactl`
204
+ command can be used directly and outside of systemd for
205
+ stop/start/restart. This use case is incompatible with systemd socket
206
+ activation, so it should not be configured. Below is an alternative
207
+ puma.service config sample, using `Type=forking` and the `--daemon`
208
+ flag in `ExecStart`. Here systemd is playing a role more equivalent to
209
+ SysV init.d, where it is responsible for starting Puma on boot
210
+ (multi-user.target) and stopping it on shutdown, but is not performing
211
+ continuous restarts. Therefore running Puma in cluster mode, where the
212
+ master can restart workers, is highly recommended. See the systemd
213
+ [Restart] directive for details.
214
+
215
+ ~~~~ ini
216
+ [Unit]
217
+ Description=Puma HTTP Forking Server
218
+ After=network.target
219
+
220
+ [Service]
221
+ # Background process configuration (use with --daemon in ExecStart)
222
+ Type=forking
223
+
224
+ # Preferably configure a non-privileged user
225
+ # User=
226
+
227
+ # The path to the puma application root
228
+ # Also replace the "<WD>" place holders below with this path.
229
+ WorkingDirectory=
230
+
231
+ # The command to start Puma
232
+ # (replace "<WD>" below)
233
+ ExecStart=bundle exec puma -C <WD>/shared/puma.rb --daemon
234
+
235
+ # The command to stop Puma
236
+ # (replace "<WD>" below)
237
+ ExecStop=bundle exec pumactl -S <WD>/shared/tmp/pids/puma.state stop
238
+
239
+ # Path to PID file so that systemd knows which is the master process
240
+ PIDFile=<WD>/shared/tmp/pids/puma.pid
241
+
242
+ # Should systemd restart puma?
243
+ # Use "no" (the default) to ensure no interference when using
244
+ # stop/start/restart via `pumactl`. The "on-failure" setting might
245
+ # work better for this purpose, but you must test it.
246
+ # Use "always" if only `systemctl` is used for start/stop/restart, and
247
+ # reconsider if you actually need the forking config.
248
+ Restart=no
249
+
250
+ [Install]
251
+ WantedBy=multi-user.target
252
+ ~~~~
253
+
254
+ ### capistrano3-puma
255
+
256
+ By default,
257
+ [capistrano3-puma](https://github.com/seuros/capistrano-puma) uses
258
+ `pumactl` for deployment restarts, outside of systemd. To learn the
259
+ exact commands that this tool would use for `ExecStart` and
260
+ `ExecStop`, use the following `cap` commands in dry-run mode, and
261
+ update from the above forking service configuration accordingly. Note
262
+ also that the configured `User` should likely be the same as the
263
+ capistrano3-puma `:puma_user` option.
264
+
265
+ ~~~~ sh
266
+ stage=production # or different stage, as needed
267
+ cap $stage puma:start --dry-run
268
+ cap $stage puma:stop --dry-run
269
+ ~~~~
270
+
271
+ [Restart]: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Restart=
272
+ [#1367]: https://github.com/puma/puma/issues/1367
@@ -3,6 +3,8 @@ require 'mkmf'
3
3
  dir_config("puma_http11")
4
4
 
5
5
  unless ENV["DISABLE_SSL"]
6
+ dir_config("openssl")
7
+
6
8
  if %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} and
7
9
  %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
8
10
 
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * Copyright (c) 2005 Zed A. Shaw
5
5
  * You can redistribute it and/or modify it under the same terms as Ruby.
6
+ * License 3-clause BSD
6
7
  */
7
8
  #include "http11_parser.h"
8
9
  #include <stdio.h>
@@ -30,12 +31,12 @@ static void snake_upcase_char(char *c)
30
31
  /** Machine **/
31
32
 
32
33
 
33
- #line 78 "ext/puma_http11/http11_parser.rl"
34
+ #line 79 "ext/puma_http11/http11_parser.rl"
34
35
 
35
36
 
36
37
  /** Data **/
37
38
 
38
- #line 39 "ext/puma_http11/http11_parser.c"
39
+ #line 40 "ext/puma_http11/http11_parser.c"
39
40
  static const int puma_parser_start = 1;
40
41
  static const int puma_parser_first_final = 47;
41
42
  static const int puma_parser_error = 0;
@@ -43,17 +44,17 @@ static const int puma_parser_error = 0;
43
44
  static const int puma_parser_en_main = 1;
44
45
 
45
46
 
46
- #line 82 "ext/puma_http11/http11_parser.rl"
47
+ #line 83 "ext/puma_http11/http11_parser.rl"
47
48
 
48
49
  int puma_parser_init(puma_parser *parser) {
49
50
  int cs = 0;
50
51
 
51
- #line 52 "ext/puma_http11/http11_parser.c"
52
+ #line 53 "ext/puma_http11/http11_parser.c"
52
53
  {
53
54
  cs = puma_parser_start;
54
55
  }
55
56
 
56
- #line 86 "ext/puma_http11/http11_parser.rl"
57
+ #line 87 "ext/puma_http11/http11_parser.rl"
57
58
  parser->cs = cs;
58
59
  parser->body_start = 0;
59
60
  parser->content_len = 0;
@@ -79,10 +80,10 @@ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len,
79
80
  pe = buffer+len;
80
81
 
81
82
  /* assert(*pe == '\0' && "pointer does not end on NUL"); */
82
- assert(pe - p == len - off && "pointers aren't same distance");
83
+ assert((size_t) (pe - p) == len - off && "pointers aren't same distance");
83
84
 
84
85
 
85
- #line 86 "ext/puma_http11/http11_parser.c"
86
+ #line 87 "ext/puma_http11/http11_parser.c"
86
87
  {
87
88
  if ( p == pe )
88
89
  goto _test_eof;
@@ -106,14 +107,14 @@ st0:
106
107
  cs = 0;
107
108
  goto _out;
108
109
  tr0:
109
- #line 34 "ext/puma_http11/http11_parser.rl"
110
+ #line 35 "ext/puma_http11/http11_parser.rl"
110
111
  { MARK(mark, p); }
111
112
  goto st2;
112
113
  st2:
113
114
  if ( ++p == pe )
114
115
  goto _test_eof2;
115
116
  case 2:
116
- #line 117 "ext/puma_http11/http11_parser.c"
117
+ #line 118 "ext/puma_http11/http11_parser.c"
117
118
  switch( (*p) ) {
118
119
  case 32: goto tr2;
119
120
  case 36: goto st28;
@@ -129,8 +130,8 @@ case 2:
129
130
  goto st28;
130
131
  goto st0;
131
132
  tr2:
132
- #line 47 "ext/puma_http11/http11_parser.rl"
133
- {
133
+ #line 48 "ext/puma_http11/http11_parser.rl"
134
+ {
134
135
  parser->request_method(parser, PTR_TO(mark), LEN(mark, p));
135
136
  }
136
137
  goto st3;
@@ -138,7 +139,7 @@ st3:
138
139
  if ( ++p == pe )
139
140
  goto _test_eof3;
140
141
  case 3:
141
- #line 142 "ext/puma_http11/http11_parser.c"
142
+ #line 143 "ext/puma_http11/http11_parser.c"
142
143
  switch( (*p) ) {
143
144
  case 42: goto tr4;
144
145
  case 43: goto tr5;
@@ -155,68 +156,68 @@ case 3:
155
156
  goto tr5;
156
157
  goto st0;
157
158
  tr4:
158
- #line 34 "ext/puma_http11/http11_parser.rl"
159
+ #line 35 "ext/puma_http11/http11_parser.rl"
159
160
  { MARK(mark, p); }
160
161
  goto st4;
161
162
  st4:
162
163
  if ( ++p == pe )
163
164
  goto _test_eof4;
164
165
  case 4:
165
- #line 166 "ext/puma_http11/http11_parser.c"
166
+ #line 167 "ext/puma_http11/http11_parser.c"
166
167
  switch( (*p) ) {
167
168
  case 32: goto tr8;
168
169
  case 35: goto tr9;
169
170
  }
170
171
  goto st0;
171
172
  tr8:
172
- #line 50 "ext/puma_http11/http11_parser.rl"
173
- {
173
+ #line 51 "ext/puma_http11/http11_parser.rl"
174
+ {
174
175
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
175
176
  }
176
177
  goto st5;
177
178
  tr31:
178
- #line 34 "ext/puma_http11/http11_parser.rl"
179
+ #line 35 "ext/puma_http11/http11_parser.rl"
179
180
  { MARK(mark, p); }
180
- #line 53 "ext/puma_http11/http11_parser.rl"
181
+ #line 54 "ext/puma_http11/http11_parser.rl"
181
182
  {
182
183
  parser->fragment(parser, PTR_TO(mark), LEN(mark, p));
183
184
  }
184
185
  goto st5;
185
186
  tr33:
186
- #line 53 "ext/puma_http11/http11_parser.rl"
187
+ #line 54 "ext/puma_http11/http11_parser.rl"
187
188
  {
188
189
  parser->fragment(parser, PTR_TO(mark), LEN(mark, p));
189
190
  }
190
191
  goto st5;
191
192
  tr37:
192
- #line 66 "ext/puma_http11/http11_parser.rl"
193
+ #line 67 "ext/puma_http11/http11_parser.rl"
193
194
  {
194
195
  parser->request_path(parser, PTR_TO(mark), LEN(mark,p));
195
196
  }
196
- #line 50 "ext/puma_http11/http11_parser.rl"
197
- {
197
+ #line 51 "ext/puma_http11/http11_parser.rl"
198
+ {
198
199
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
199
200
  }
200
201
  goto st5;
201
202
  tr44:
202
- #line 57 "ext/puma_http11/http11_parser.rl"
203
- { MARK(query_start, p); }
204
203
  #line 58 "ext/puma_http11/http11_parser.rl"
205
- {
204
+ { MARK(query_start, p); }
205
+ #line 59 "ext/puma_http11/http11_parser.rl"
206
+ {
206
207
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, p));
207
208
  }
208
- #line 50 "ext/puma_http11/http11_parser.rl"
209
- {
209
+ #line 51 "ext/puma_http11/http11_parser.rl"
210
+ {
210
211
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
211
212
  }
212
213
  goto st5;
213
214
  tr47:
214
- #line 58 "ext/puma_http11/http11_parser.rl"
215
- {
215
+ #line 59 "ext/puma_http11/http11_parser.rl"
216
+ {
216
217
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, p));
217
218
  }
218
- #line 50 "ext/puma_http11/http11_parser.rl"
219
- {
219
+ #line 51 "ext/puma_http11/http11_parser.rl"
220
+ {
220
221
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
221
222
  }
222
223
  goto st5;
@@ -224,19 +225,19 @@ st5:
224
225
  if ( ++p == pe )
225
226
  goto _test_eof5;
226
227
  case 5:
227
- #line 228 "ext/puma_http11/http11_parser.c"
228
+ #line 229 "ext/puma_http11/http11_parser.c"
228
229
  if ( (*p) == 72 )
229
230
  goto tr10;
230
231
  goto st0;
231
232
  tr10:
232
- #line 34 "ext/puma_http11/http11_parser.rl"
233
+ #line 35 "ext/puma_http11/http11_parser.rl"
233
234
  { MARK(mark, p); }
234
235
  goto st6;
235
236
  st6:
236
237
  if ( ++p == pe )
237
238
  goto _test_eof6;
238
239
  case 6:
239
- #line 240 "ext/puma_http11/http11_parser.c"
240
+ #line 241 "ext/puma_http11/http11_parser.c"
240
241
  if ( (*p) == 84 )
241
242
  goto st7;
242
243
  goto st0;
@@ -294,21 +295,21 @@ case 13:
294
295
  goto st13;
295
296
  goto st0;
296
297
  tr18:
297
- #line 62 "ext/puma_http11/http11_parser.rl"
298
- {
298
+ #line 63 "ext/puma_http11/http11_parser.rl"
299
+ {
299
300
  parser->http_version(parser, PTR_TO(mark), LEN(mark, p));
300
301
  }
301
302
  goto st14;
302
303
  tr26:
303
- #line 43 "ext/puma_http11/http11_parser.rl"
304
- { MARK(mark, p); }
305
304
  #line 44 "ext/puma_http11/http11_parser.rl"
305
+ { MARK(mark, p); }
306
+ #line 45 "ext/puma_http11/http11_parser.rl"
306
307
  {
307
308
  parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
308
309
  }
309
310
  goto st14;
310
311
  tr29:
311
- #line 44 "ext/puma_http11/http11_parser.rl"
312
+ #line 45 "ext/puma_http11/http11_parser.rl"
312
313
  {
313
314
  parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
314
315
  }
@@ -317,7 +318,7 @@ st14:
317
318
  if ( ++p == pe )
318
319
  goto _test_eof14;
319
320
  case 14:
320
- #line 321 "ext/puma_http11/http11_parser.c"
321
+ #line 322 "ext/puma_http11/http11_parser.c"
321
322
  if ( (*p) == 10 )
322
323
  goto st15;
323
324
  goto st0;
@@ -357,9 +358,9 @@ case 16:
357
358
  goto tr22;
358
359
  goto st0;
359
360
  tr22:
360
- #line 70 "ext/puma_http11/http11_parser.rl"
361
- {
362
- parser->body_start = p - buffer + 1;
361
+ #line 71 "ext/puma_http11/http11_parser.rl"
362
+ {
363
+ parser->body_start = p - buffer + 1;
363
364
  parser->header_done(parser, p + 1, pe - p - 1);
364
365
  {p++; cs = 47; goto _out;}
365
366
  }
@@ -368,23 +369,23 @@ st47:
368
369
  if ( ++p == pe )
369
370
  goto _test_eof47;
370
371
  case 47:
371
- #line 372 "ext/puma_http11/http11_parser.c"
372
+ #line 373 "ext/puma_http11/http11_parser.c"
372
373
  goto st0;
373
374
  tr21:
374
- #line 37 "ext/puma_http11/http11_parser.rl"
375
- { MARK(field_start, p); }
376
375
  #line 38 "ext/puma_http11/http11_parser.rl"
376
+ { MARK(field_start, p); }
377
+ #line 39 "ext/puma_http11/http11_parser.rl"
377
378
  { snake_upcase_char((char *)p); }
378
379
  goto st17;
379
380
  tr23:
380
- #line 38 "ext/puma_http11/http11_parser.rl"
381
+ #line 39 "ext/puma_http11/http11_parser.rl"
381
382
  { snake_upcase_char((char *)p); }
382
383
  goto st17;
383
384
  st17:
384
385
  if ( ++p == pe )
385
386
  goto _test_eof17;
386
387
  case 17:
387
- #line 388 "ext/puma_http11/http11_parser.c"
388
+ #line 389 "ext/puma_http11/http11_parser.c"
388
389
  switch( (*p) ) {
389
390
  case 33: goto tr23;
390
391
  case 58: goto tr24;
@@ -410,72 +411,72 @@ case 17:
410
411
  goto tr23;
411
412
  goto st0;
412
413
  tr24:
413
- #line 39 "ext/puma_http11/http11_parser.rl"
414
- {
414
+ #line 40 "ext/puma_http11/http11_parser.rl"
415
+ {
415
416
  parser->field_len = LEN(field_start, p);
416
417
  }
417
418
  goto st18;
418
419
  tr27:
419
- #line 43 "ext/puma_http11/http11_parser.rl"
420
+ #line 44 "ext/puma_http11/http11_parser.rl"
420
421
  { MARK(mark, p); }
421
422
  goto st18;
422
423
  st18:
423
424
  if ( ++p == pe )
424
425
  goto _test_eof18;
425
426
  case 18:
426
- #line 427 "ext/puma_http11/http11_parser.c"
427
+ #line 428 "ext/puma_http11/http11_parser.c"
427
428
  switch( (*p) ) {
428
429
  case 13: goto tr26;
429
430
  case 32: goto tr27;
430
431
  }
431
432
  goto tr25;
432
433
  tr25:
433
- #line 43 "ext/puma_http11/http11_parser.rl"
434
+ #line 44 "ext/puma_http11/http11_parser.rl"
434
435
  { MARK(mark, p); }
435
436
  goto st19;
436
437
  st19:
437
438
  if ( ++p == pe )
438
439
  goto _test_eof19;
439
440
  case 19:
440
- #line 441 "ext/puma_http11/http11_parser.c"
441
+ #line 442 "ext/puma_http11/http11_parser.c"
441
442
  if ( (*p) == 13 )
442
443
  goto tr29;
443
444
  goto st19;
444
445
  tr9:
445
- #line 50 "ext/puma_http11/http11_parser.rl"
446
- {
446
+ #line 51 "ext/puma_http11/http11_parser.rl"
447
+ {
447
448
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
448
449
  }
449
450
  goto st20;
450
451
  tr38:
451
- #line 66 "ext/puma_http11/http11_parser.rl"
452
+ #line 67 "ext/puma_http11/http11_parser.rl"
452
453
  {
453
454
  parser->request_path(parser, PTR_TO(mark), LEN(mark,p));
454
455
  }
455
- #line 50 "ext/puma_http11/http11_parser.rl"
456
- {
456
+ #line 51 "ext/puma_http11/http11_parser.rl"
457
+ {
457
458
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
458
459
  }
459
460
  goto st20;
460
461
  tr45:
461
- #line 57 "ext/puma_http11/http11_parser.rl"
462
- { MARK(query_start, p); }
463
462
  #line 58 "ext/puma_http11/http11_parser.rl"
464
- {
463
+ { MARK(query_start, p); }
464
+ #line 59 "ext/puma_http11/http11_parser.rl"
465
+ {
465
466
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, p));
466
467
  }
467
- #line 50 "ext/puma_http11/http11_parser.rl"
468
- {
468
+ #line 51 "ext/puma_http11/http11_parser.rl"
469
+ {
469
470
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
470
471
  }
471
472
  goto st20;
472
473
  tr48:
473
- #line 58 "ext/puma_http11/http11_parser.rl"
474
- {
474
+ #line 59 "ext/puma_http11/http11_parser.rl"
475
+ {
475
476
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, p));
476
477
  }
477
- #line 50 "ext/puma_http11/http11_parser.rl"
478
- {
478
+ #line 51 "ext/puma_http11/http11_parser.rl"
479
+ {
479
480
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, p));
480
481
  }
481
482
  goto st20;
@@ -483,7 +484,7 @@ st20:
483
484
  if ( ++p == pe )
484
485
  goto _test_eof20;
485
486
  case 20:
486
- #line 487 "ext/puma_http11/http11_parser.c"
487
+ #line 488 "ext/puma_http11/http11_parser.c"
487
488
  switch( (*p) ) {
488
489
  case 32: goto tr31;
489
490
  case 60: goto st0;
@@ -497,14 +498,14 @@ case 20:
497
498
  goto st0;
498
499
  goto tr30;
499
500
  tr30:
500
- #line 34 "ext/puma_http11/http11_parser.rl"
501
+ #line 35 "ext/puma_http11/http11_parser.rl"
501
502
  { MARK(mark, p); }
502
503
  goto st21;
503
504
  st21:
504
505
  if ( ++p == pe )
505
506
  goto _test_eof21;
506
507
  case 21:
507
- #line 508 "ext/puma_http11/http11_parser.c"
508
+ #line 509 "ext/puma_http11/http11_parser.c"
508
509
  switch( (*p) ) {
509
510
  case 32: goto tr33;
510
511
  case 60: goto st0;
@@ -518,14 +519,14 @@ case 21:
518
519
  goto st0;
519
520
  goto st21;
520
521
  tr5:
521
- #line 34 "ext/puma_http11/http11_parser.rl"
522
+ #line 35 "ext/puma_http11/http11_parser.rl"
522
523
  { MARK(mark, p); }
523
524
  goto st22;
524
525
  st22:
525
526
  if ( ++p == pe )
526
527
  goto _test_eof22;
527
528
  case 22:
528
- #line 529 "ext/puma_http11/http11_parser.c"
529
+ #line 530 "ext/puma_http11/http11_parser.c"
529
530
  switch( (*p) ) {
530
531
  case 43: goto st22;
531
532
  case 58: goto st23;
@@ -543,14 +544,14 @@ case 22:
543
544
  goto st22;
544
545
  goto st0;
545
546
  tr7:
546
- #line 34 "ext/puma_http11/http11_parser.rl"
547
+ #line 35 "ext/puma_http11/http11_parser.rl"
547
548
  { MARK(mark, p); }
548
549
  goto st23;
549
550
  st23:
550
551
  if ( ++p == pe )
551
552
  goto _test_eof23;
552
553
  case 23:
553
- #line 554 "ext/puma_http11/http11_parser.c"
554
+ #line 555 "ext/puma_http11/http11_parser.c"
554
555
  switch( (*p) ) {
555
556
  case 32: goto tr8;
556
557
  case 34: goto st0;
@@ -563,14 +564,14 @@ case 23:
563
564
  goto st0;
564
565
  goto st23;
565
566
  tr6:
566
- #line 34 "ext/puma_http11/http11_parser.rl"
567
+ #line 35 "ext/puma_http11/http11_parser.rl"
567
568
  { MARK(mark, p); }
568
569
  goto st24;
569
570
  st24:
570
571
  if ( ++p == pe )
571
572
  goto _test_eof24;
572
573
  case 24:
573
- #line 574 "ext/puma_http11/http11_parser.c"
574
+ #line 575 "ext/puma_http11/http11_parser.c"
574
575
  switch( (*p) ) {
575
576
  case 32: goto tr37;
576
577
  case 34: goto st0;
@@ -585,7 +586,7 @@ case 24:
585
586
  goto st0;
586
587
  goto st24;
587
588
  tr39:
588
- #line 66 "ext/puma_http11/http11_parser.rl"
589
+ #line 67 "ext/puma_http11/http11_parser.rl"
589
590
  {
590
591
  parser->request_path(parser, PTR_TO(mark), LEN(mark,p));
591
592
  }
@@ -594,7 +595,7 @@ st25:
594
595
  if ( ++p == pe )
595
596
  goto _test_eof25;
596
597
  case 25:
597
- #line 598 "ext/puma_http11/http11_parser.c"
598
+ #line 599 "ext/puma_http11/http11_parser.c"
598
599
  switch( (*p) ) {
599
600
  case 32: goto tr8;
600
601
  case 34: goto st0;
@@ -608,7 +609,7 @@ case 25:
608
609
  goto st0;
609
610
  goto st25;
610
611
  tr40:
611
- #line 66 "ext/puma_http11/http11_parser.rl"
612
+ #line 67 "ext/puma_http11/http11_parser.rl"
612
613
  {
613
614
  parser->request_path(parser, PTR_TO(mark), LEN(mark,p));
614
615
  }
@@ -617,7 +618,7 @@ st26:
617
618
  if ( ++p == pe )
618
619
  goto _test_eof26;
619
620
  case 26:
620
- #line 621 "ext/puma_http11/http11_parser.c"
621
+ #line 622 "ext/puma_http11/http11_parser.c"
621
622
  switch( (*p) ) {
622
623
  case 32: goto tr44;
623
624
  case 34: goto st0;
@@ -630,14 +631,14 @@ case 26:
630
631
  goto st0;
631
632
  goto tr43;
632
633
  tr43:
633
- #line 57 "ext/puma_http11/http11_parser.rl"
634
+ #line 58 "ext/puma_http11/http11_parser.rl"
634
635
  { MARK(query_start, p); }
635
636
  goto st27;
636
637
  st27:
637
638
  if ( ++p == pe )
638
639
  goto _test_eof27;
639
640
  case 27:
640
- #line 641 "ext/puma_http11/http11_parser.c"
641
+ #line 642 "ext/puma_http11/http11_parser.c"
641
642
  switch( (*p) ) {
642
643
  case 32: goto tr47;
643
644
  case 34: goto st0;
@@ -1032,7 +1033,7 @@ case 46:
1032
1033
  _out: {}
1033
1034
  }
1034
1035
 
1035
- #line 114 "ext/puma_http11/http11_parser.rl"
1036
+ #line 115 "ext/puma_http11/http11_parser.rl"
1036
1037
 
1037
1038
  if (!puma_parser_has_error(parser))
1038
1039
  parser->cs = cs;