puma-simon 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +20 -0
  3. data/.gitignore +18 -0
  4. data/.hoeignore +12 -0
  5. data/.travis.yml +29 -0
  6. data/DEPLOYMENT.md +91 -0
  7. data/Gemfile +12 -0
  8. data/History.md +1254 -0
  9. data/LICENSE +26 -0
  10. data/Manifest.txt +78 -0
  11. data/README.md +353 -0
  12. data/Rakefile +158 -0
  13. data/Release.md +9 -0
  14. data/bin/puma +10 -0
  15. data/bin/puma-wild +31 -0
  16. data/bin/pumactl +12 -0
  17. data/docs/nginx.md +80 -0
  18. data/docs/signals.md +43 -0
  19. data/docs/systemd.md +197 -0
  20. data/examples/CA/cacert.pem +23 -0
  21. data/examples/CA/newcerts/cert_1.pem +19 -0
  22. data/examples/CA/newcerts/cert_2.pem +19 -0
  23. data/examples/CA/private/cakeypair.pem +30 -0
  24. data/examples/CA/serial +1 -0
  25. data/examples/config.rb +200 -0
  26. data/examples/plugins/redis_stop_puma.rb +46 -0
  27. data/examples/puma/cert_puma.pem +19 -0
  28. data/examples/puma/client-certs/ca.crt +19 -0
  29. data/examples/puma/client-certs/ca.key +27 -0
  30. data/examples/puma/client-certs/client.crt +19 -0
  31. data/examples/puma/client-certs/client.key +27 -0
  32. data/examples/puma/client-certs/client_expired.crt +19 -0
  33. data/examples/puma/client-certs/client_expired.key +27 -0
  34. data/examples/puma/client-certs/client_unknown.crt +19 -0
  35. data/examples/puma/client-certs/client_unknown.key +27 -0
  36. data/examples/puma/client-certs/generate.rb +78 -0
  37. data/examples/puma/client-certs/keystore.jks +0 -0
  38. data/examples/puma/client-certs/server.crt +19 -0
  39. data/examples/puma/client-certs/server.key +27 -0
  40. data/examples/puma/client-certs/server.p12 +0 -0
  41. data/examples/puma/client-certs/unknown_ca.crt +19 -0
  42. data/examples/puma/client-certs/unknown_ca.key +27 -0
  43. data/examples/puma/csr_puma.pem +11 -0
  44. data/examples/puma/keystore.jks +0 -0
  45. data/examples/puma/puma_keypair.pem +15 -0
  46. data/examples/qc_config.rb +13 -0
  47. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  48. data/ext/puma_http11/ext_help.h +15 -0
  49. data/ext/puma_http11/extconf.rb +15 -0
  50. data/ext/puma_http11/http11_parser.c +1069 -0
  51. data/ext/puma_http11/http11_parser.h +65 -0
  52. data/ext/puma_http11/http11_parser.java.rl +161 -0
  53. data/ext/puma_http11/http11_parser.rl +147 -0
  54. data/ext/puma_http11/http11_parser_common.rl +54 -0
  55. data/ext/puma_http11/io_buffer.c +155 -0
  56. data/ext/puma_http11/mini_ssl.c +457 -0
  57. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  58. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
  59. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
  60. data/ext/puma_http11/puma_http11.c +500 -0
  61. data/gemfiles/2.1-Gemfile +12 -0
  62. data/lib/puma.rb +15 -0
  63. data/lib/puma/accept_nonblock.rb +23 -0
  64. data/lib/puma/app/status.rb +66 -0
  65. data/lib/puma/binder.rb +402 -0
  66. data/lib/puma/cli.rb +220 -0
  67. data/lib/puma/client.rb +434 -0
  68. data/lib/puma/cluster.rb +510 -0
  69. data/lib/puma/commonlogger.rb +106 -0
  70. data/lib/puma/compat.rb +14 -0
  71. data/lib/puma/configuration.rb +364 -0
  72. data/lib/puma/const.rb +224 -0
  73. data/lib/puma/control_cli.rb +259 -0
  74. data/lib/puma/convenient.rb +23 -0
  75. data/lib/puma/daemon_ext.rb +31 -0
  76. data/lib/puma/delegation.rb +11 -0
  77. data/lib/puma/detect.rb +13 -0
  78. data/lib/puma/dsl.rb +486 -0
  79. data/lib/puma/events.rb +152 -0
  80. data/lib/puma/io_buffer.rb +7 -0
  81. data/lib/puma/java_io_buffer.rb +45 -0
  82. data/lib/puma/jruby_restart.rb +83 -0
  83. data/lib/puma/launcher.rb +410 -0
  84. data/lib/puma/minissl.rb +221 -0
  85. data/lib/puma/null_io.rb +42 -0
  86. data/lib/puma/plugin.rb +115 -0
  87. data/lib/puma/plugin/tmp_restart.rb +35 -0
  88. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  89. data/lib/puma/rack/builder.rb +298 -0
  90. data/lib/puma/rack/urlmap.rb +91 -0
  91. data/lib/puma/rack_default.rb +7 -0
  92. data/lib/puma/reactor.rb +210 -0
  93. data/lib/puma/runner.rb +171 -0
  94. data/lib/puma/server.rb +949 -0
  95. data/lib/puma/single.rb +112 -0
  96. data/lib/puma/state_file.rb +29 -0
  97. data/lib/puma/tcp_logger.rb +39 -0
  98. data/lib/puma/thread_pool.rb +297 -0
  99. data/lib/puma/util.rb +128 -0
  100. data/lib/rack/handler/puma.rb +78 -0
  101. data/puma.gemspec +52 -0
  102. data/test/ab_rs.rb +22 -0
  103. data/test/config.rb +2 -0
  104. data/test/config/app.rb +9 -0
  105. data/test/config/plugin.rb +1 -0
  106. data/test/config/settings.rb +2 -0
  107. data/test/config/state_file_testing_config.rb +14 -0
  108. data/test/hello-bind.ru +2 -0
  109. data/test/hello-delay.ru +3 -0
  110. data/test/hello-map.ru +3 -0
  111. data/test/hello-post.ru +4 -0
  112. data/test/hello-stuck.ru +1 -0
  113. data/test/hello-tcp.ru +5 -0
  114. data/test/hello.ru +1 -0
  115. data/test/hijack.ru +6 -0
  116. data/test/hijack2.ru +5 -0
  117. data/test/lobster.ru +4 -0
  118. data/test/shell/run.sh +24 -0
  119. data/test/shell/t1.rb +19 -0
  120. data/test/shell/t1_conf.rb +3 -0
  121. data/test/shell/t2.rb +17 -0
  122. data/test/shell/t2_conf.rb +6 -0
  123. data/test/shell/t3.rb +25 -0
  124. data/test/shell/t3_conf.rb +5 -0
  125. data/test/slow.ru +4 -0
  126. data/test/ssl_config.rb +4 -0
  127. data/test/test_app_status.rb +93 -0
  128. data/test/test_binder.rb +31 -0
  129. data/test/test_cli.rb +209 -0
  130. data/test/test_config.rb +95 -0
  131. data/test/test_events.rb +161 -0
  132. data/test/test_helper.rb +50 -0
  133. data/test/test_http10.rb +27 -0
  134. data/test/test_http11.rb +186 -0
  135. data/test/test_integration.rb +247 -0
  136. data/test/test_iobuffer.rb +39 -0
  137. data/test/test_minissl.rb +29 -0
  138. data/test/test_null_io.rb +49 -0
  139. data/test/test_persistent.rb +245 -0
  140. data/test/test_puma_server.rb +626 -0
  141. data/test/test_puma_server_ssl.rb +222 -0
  142. data/test/test_rack_handler.rb +57 -0
  143. data/test/test_rack_server.rb +138 -0
  144. data/test/test_tcp_logger.rb +39 -0
  145. data/test/test_tcp_rack.rb +36 -0
  146. data/test/test_thread_pool.rb +250 -0
  147. data/test/test_unix_socket.rb +35 -0
  148. data/test/test_web_server.rb +88 -0
  149. data/tools/jungle/README.md +9 -0
  150. data/tools/jungle/init.d/README.md +59 -0
  151. data/tools/jungle/init.d/puma +421 -0
  152. data/tools/jungle/init.d/run-puma +18 -0
  153. data/tools/jungle/upstart/README.md +61 -0
  154. data/tools/jungle/upstart/puma-manager.conf +31 -0
  155. data/tools/jungle/upstart/puma.conf +69 -0
  156. data/tools/trickletest.rb +45 -0
  157. metadata +297 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ * License 3-clause BSD
5
+ */
6
+
7
+ #ifndef http11_parser_h
8
+ #define http11_parser_h
9
+
10
+ #define RSTRING_NOT_MODIFIED 1
11
+ #include "ruby.h"
12
+
13
+ #include <sys/types.h>
14
+
15
+ #if defined(_WIN32)
16
+ #include <stddef.h>
17
+ #endif
18
+
19
+ #define BUFFER_LEN 1024
20
+
21
+ struct puma_parser;
22
+
23
+ typedef void (*element_cb)(struct puma_parser* hp,
24
+ const char *at, size_t length);
25
+
26
+ typedef void (*field_cb)(struct puma_parser* hp,
27
+ const char *field, size_t flen,
28
+ const char *value, size_t vlen);
29
+
30
+ typedef struct puma_parser {
31
+ int cs;
32
+ size_t body_start;
33
+ int content_len;
34
+ size_t nread;
35
+ size_t mark;
36
+ size_t field_start;
37
+ size_t field_len;
38
+ size_t query_start;
39
+
40
+ VALUE request;
41
+ VALUE body;
42
+
43
+ field_cb http_field;
44
+ element_cb request_method;
45
+ element_cb request_uri;
46
+ element_cb fragment;
47
+ element_cb request_path;
48
+ element_cb query_string;
49
+ element_cb http_version;
50
+ element_cb header_done;
51
+
52
+ char buf[BUFFER_LEN];
53
+
54
+ } puma_parser;
55
+
56
+ int puma_parser_init(puma_parser *parser);
57
+ int puma_parser_finish(puma_parser *parser);
58
+ size_t puma_parser_execute(puma_parser *parser, const char *data,
59
+ size_t len, size_t off);
60
+ int puma_parser_has_error(puma_parser *parser);
61
+ int puma_parser_is_finished(puma_parser *parser);
62
+
63
+ #define puma_parser_nread(parser) (parser)->nread
64
+
65
+ #endif
@@ -0,0 +1,161 @@
1
+ package org.jruby.puma;
2
+
3
+ import org.jruby.util.ByteList;
4
+
5
+ public class Http11Parser {
6
+
7
+ /** Machine **/
8
+
9
+ %%{
10
+
11
+ machine puma_parser;
12
+
13
+ action mark {parser.mark = fpc; }
14
+
15
+ action start_field { parser.field_start = fpc; }
16
+ action snake_upcase_field { /* FIXME stub */ }
17
+ action write_field {
18
+ parser.field_len = fpc-parser.field_start;
19
+ }
20
+
21
+ action start_value { parser.mark = fpc; }
22
+ action write_value {
23
+ if(parser.http_field != null) {
24
+ parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
25
+ }
26
+ }
27
+ action request_method {
28
+ if(parser.request_method != null)
29
+ parser.request_method.call(parser.data, parser.mark, fpc-parser.mark);
30
+ }
31
+ action request_uri {
32
+ if(parser.request_uri != null)
33
+ parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark);
34
+ }
35
+ action fragment {
36
+ if(parser.fragment != null)
37
+ parser.fragment.call(parser.data, parser.mark, fpc-parser.mark);
38
+ }
39
+
40
+ action start_query {parser.query_start = fpc; }
41
+ action query_string {
42
+ if(parser.query_string != null)
43
+ parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start);
44
+ }
45
+
46
+ action http_version {
47
+ if(parser.http_version != null)
48
+ parser.http_version.call(parser.data, parser.mark, fpc-parser.mark);
49
+ }
50
+
51
+ action request_path {
52
+ if(parser.request_path != null)
53
+ parser.request_path.call(parser.data, parser.mark, fpc-parser.mark);
54
+ }
55
+
56
+ action done {
57
+ parser.body_start = fpc + 1;
58
+ if(parser.header_done != null)
59
+ parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1);
60
+ fbreak;
61
+ }
62
+
63
+ include puma_parser_common "http11_parser_common.rl";
64
+
65
+ }%%
66
+
67
+ /** Data **/
68
+ %% write data;
69
+
70
+ public static interface ElementCB {
71
+ public void call(Object data, int at, int length);
72
+ }
73
+
74
+ public static interface FieldCB {
75
+ public void call(Object data, int field, int flen, int value, int vlen);
76
+ }
77
+
78
+ public static class HttpParser {
79
+ int cs;
80
+ int body_start;
81
+ int content_len;
82
+ int nread;
83
+ int mark;
84
+ int field_start;
85
+ int field_len;
86
+ int query_start;
87
+
88
+ Object data;
89
+ ByteList buffer;
90
+
91
+ public FieldCB http_field;
92
+ public ElementCB request_method;
93
+ public ElementCB request_uri;
94
+ public ElementCB fragment;
95
+ public ElementCB request_path;
96
+ public ElementCB query_string;
97
+ public ElementCB http_version;
98
+ public ElementCB header_done;
99
+
100
+ public void init() {
101
+ cs = 0;
102
+
103
+ %% write init;
104
+
105
+ body_start = 0;
106
+ content_len = 0;
107
+ mark = 0;
108
+ nread = 0;
109
+ field_len = 0;
110
+ field_start = 0;
111
+ }
112
+ }
113
+
114
+ public final HttpParser parser = new HttpParser();
115
+
116
+ public int execute(ByteList buffer, int off) {
117
+ int p, pe;
118
+ int cs = parser.cs;
119
+ int len = buffer.length();
120
+ assert off<=len : "offset past end of buffer";
121
+
122
+ p = off;
123
+ pe = len;
124
+ // get a copy of the bytes, since it may not start at 0
125
+ // FIXME: figure out how to just use the bytes in-place
126
+ byte[] data = buffer.bytes();
127
+ parser.buffer = buffer;
128
+
129
+ %% write exec;
130
+
131
+ parser.cs = cs;
132
+ parser.nread += (p - off);
133
+
134
+ assert p <= pe : "buffer overflow after parsing execute";
135
+ assert parser.nread <= len : "nread longer than length";
136
+ assert parser.body_start <= len : "body starts after buffer end";
137
+ assert parser.mark < len : "mark is after buffer end";
138
+ assert parser.field_len <= len : "field has length longer than whole buffer";
139
+ assert parser.field_start < len : "field starts after buffer end";
140
+
141
+ return parser.nread;
142
+ }
143
+
144
+ public int finish() {
145
+ if(has_error()) {
146
+ return -1;
147
+ } else if(is_finished()) {
148
+ return 1;
149
+ } else {
150
+ return 0;
151
+ }
152
+ }
153
+
154
+ public boolean has_error() {
155
+ return parser.cs == puma_parser_error;
156
+ }
157
+
158
+ public boolean is_finished() {
159
+ return parser.cs == puma_parser_first_final;
160
+ }
161
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ * License 3-clause BSD
5
+ */
6
+ #include "http11_parser.h"
7
+ #include <stdio.h>
8
+ #include <assert.h>
9
+ #include <stdlib.h>
10
+ #include <ctype.h>
11
+ #include <string.h>
12
+
13
+ /*
14
+ * capitalizes all lower-case ASCII characters,
15
+ * converts dashes to underscores.
16
+ */
17
+ static void snake_upcase_char(char *c)
18
+ {
19
+ if (*c >= 'a' && *c <= 'z')
20
+ *c &= ~0x20;
21
+ else if (*c == '-')
22
+ *c = '_';
23
+ }
24
+
25
+ #define LEN(AT, FPC) (FPC - buffer - parser->AT)
26
+ #define MARK(M,FPC) (parser->M = (FPC) - buffer)
27
+ #define PTR_TO(F) (buffer + parser->F)
28
+
29
+ /** Machine **/
30
+
31
+ %%{
32
+
33
+ machine puma_parser;
34
+
35
+ action mark { MARK(mark, fpc); }
36
+
37
+
38
+ action start_field { MARK(field_start, fpc); }
39
+ action snake_upcase_field { snake_upcase_char((char *)fpc); }
40
+ action write_field {
41
+ parser->field_len = LEN(field_start, fpc);
42
+ }
43
+
44
+ action start_value { MARK(mark, fpc); }
45
+ action write_value {
46
+ parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
47
+ }
48
+ action request_method {
49
+ parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
50
+ }
51
+ action request_uri {
52
+ parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
53
+ }
54
+ action fragment {
55
+ parser->fragment(parser, PTR_TO(mark), LEN(mark, fpc));
56
+ }
57
+
58
+ action start_query { MARK(query_start, fpc); }
59
+ action query_string {
60
+ parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
61
+ }
62
+
63
+ action http_version {
64
+ parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
65
+ }
66
+
67
+ action request_path {
68
+ parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
69
+ }
70
+
71
+ action done {
72
+ parser->body_start = fpc - buffer + 1;
73
+ parser->header_done(parser, fpc + 1, pe - fpc - 1);
74
+ fbreak;
75
+ }
76
+
77
+ include puma_parser_common "http11_parser_common.rl";
78
+
79
+ }%%
80
+
81
+ /** Data **/
82
+ %% write data;
83
+
84
+ int puma_parser_init(puma_parser *parser) {
85
+ int cs = 0;
86
+ %% write init;
87
+ parser->cs = cs;
88
+ parser->body_start = 0;
89
+ parser->content_len = 0;
90
+ parser->mark = 0;
91
+ parser->nread = 0;
92
+ parser->field_len = 0;
93
+ parser->field_start = 0;
94
+ parser->request = Qnil;
95
+ parser->body = Qnil;
96
+
97
+ return 1;
98
+ }
99
+
100
+
101
+ /** exec **/
102
+ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len, size_t off) {
103
+ const char *p, *pe;
104
+ int cs = parser->cs;
105
+
106
+ assert(off <= len && "offset past end of buffer");
107
+
108
+ p = buffer+off;
109
+ pe = buffer+len;
110
+
111
+ /* assert(*pe == '\0' && "pointer does not end on NUL"); */
112
+ assert(pe - p == len - off && "pointers aren't same distance");
113
+
114
+ %% write exec;
115
+
116
+ if (!puma_parser_has_error(parser))
117
+ parser->cs = cs;
118
+ parser->nread += p - (buffer + off);
119
+
120
+ assert(p <= pe && "buffer overflow after parsing execute");
121
+ assert(parser->nread <= len && "nread longer than length");
122
+ assert(parser->body_start <= len && "body starts after buffer end");
123
+ assert(parser->mark < len && "mark is after buffer end");
124
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
125
+ assert(parser->field_start < len && "field starts after buffer end");
126
+
127
+ return(parser->nread);
128
+ }
129
+
130
+ int puma_parser_finish(puma_parser *parser)
131
+ {
132
+ if (puma_parser_has_error(parser) ) {
133
+ return -1;
134
+ } else if (puma_parser_is_finished(parser) ) {
135
+ return 1;
136
+ } else {
137
+ return 0;
138
+ }
139
+ }
140
+
141
+ int puma_parser_has_error(puma_parser *parser) {
142
+ return parser->cs == puma_parser_error;
143
+ }
144
+
145
+ int puma_parser_is_finished(puma_parser *parser) {
146
+ return parser->cs >= puma_parser_first_final;
147
+ }
@@ -0,0 +1,54 @@
1
+ %%{
2
+
3
+ machine puma_parser_common;
4
+
5
+ #### HTTP PROTOCOL GRAMMAR
6
+ # line endings
7
+ CRLF = "\r\n";
8
+
9
+ # character types
10
+ CTL = (cntrl | 127);
11
+ safe = ("$" | "-" | "_" | ".");
12
+ extra = ("!" | "*" | "'" | "(" | ")" | ",");
13
+ reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
14
+ unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
15
+ national = any -- (alpha | digit | reserved | extra | safe | unsafe);
16
+ unreserved = (alpha | digit | safe | extra | national);
17
+ escape = ("%" xdigit xdigit);
18
+ uchar = (unreserved | escape | "%");
19
+ pchar = (uchar | ":" | "@" | "&" | "=" | "+");
20
+ tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
21
+
22
+ # elements
23
+ token = (ascii -- (CTL | tspecials));
24
+
25
+ # URI schemes and absolute paths
26
+ scheme = ( alpha | digit | "+" | "-" | "." )* ;
27
+ absolute_uri = (scheme ":" (uchar | reserved )*);
28
+
29
+ path = ( pchar+ ( "/" pchar* )* ) ;
30
+ query = ( uchar | reserved )* %query_string ;
31
+ param = ( pchar | "/" )* ;
32
+ params = ( param ( ";" param )* ) ;
33
+ rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
34
+ absolute_path = ( "/"+ rel_path );
35
+
36
+ Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
37
+ Fragment = ( uchar | reserved )* >mark %fragment;
38
+ Method = ( upper | digit | safe ){1,20} >mark %request_method;
39
+
40
+ http_number = ( digit+ "." digit+ ) ;
41
+ HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
42
+ Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
43
+
44
+ field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
45
+
46
+ field_value = any* >start_value %write_value;
47
+
48
+ message_header = field_name ":" " "* field_value :> CRLF;
49
+
50
+ Request = Request_Line ( message_header )* ( CRLF @done );
51
+
52
+ main := Request;
53
+
54
+ }%%
@@ -0,0 +1,155 @@
1
+ #define RSTRING_NOT_MODIFIED 1
2
+ #include "ruby.h"
3
+
4
+ #include <sys/types.h>
5
+
6
+ struct buf_int {
7
+ uint8_t* top;
8
+ uint8_t* cur;
9
+
10
+ size_t size;
11
+ };
12
+
13
+ #define BUF_DEFAULT_SIZE 4096
14
+ #define BUF_TOLERANCE 32
15
+
16
+ static void buf_free(struct buf_int* internal) {
17
+ xfree(internal->top);
18
+ xfree(internal);
19
+ }
20
+
21
+ static VALUE buf_alloc(VALUE self) {
22
+ VALUE buf;
23
+ struct buf_int* internal;
24
+
25
+ buf = Data_Make_Struct(self, struct buf_int, 0, buf_free, internal);
26
+
27
+ internal->size = BUF_DEFAULT_SIZE;
28
+ internal->top = ALLOC_N(uint8_t, BUF_DEFAULT_SIZE);
29
+ internal->cur = internal->top;
30
+
31
+ return buf;
32
+ }
33
+
34
+ static VALUE buf_append(VALUE self, VALUE str) {
35
+ struct buf_int* b;
36
+ size_t used, str_len, new_size;
37
+
38
+ Data_Get_Struct(self, struct buf_int, b);
39
+
40
+ used = b->cur - b->top;
41
+
42
+ StringValue(str);
43
+ str_len = RSTRING_LEN(str);
44
+
45
+ new_size = used + str_len;
46
+
47
+ if(new_size > b->size) {
48
+ size_t n = b->size + (b->size / 2);
49
+ uint8_t* top;
50
+ uint8_t* old;
51
+
52
+ new_size = (n > new_size ? n : new_size + BUF_TOLERANCE);
53
+
54
+ top = ALLOC_N(uint8_t, new_size);
55
+ old = b->top;
56
+ memcpy(top, old, used);
57
+ b->top = top;
58
+ b->cur = top + used;
59
+ b->size = new_size;
60
+ xfree(old);
61
+ }
62
+
63
+ memcpy(b->cur, RSTRING_PTR(str), str_len);
64
+ b->cur += str_len;
65
+
66
+ return self;
67
+ }
68
+
69
+ static VALUE buf_append2(int argc, VALUE* argv, VALUE self) {
70
+ struct buf_int* b;
71
+ size_t used, new_size;
72
+ int i;
73
+ VALUE str;
74
+
75
+ Data_Get_Struct(self, struct buf_int, b);
76
+
77
+ used = b->cur - b->top;
78
+ new_size = used;
79
+
80
+ for(i = 0; i < argc; i++) {
81
+ StringValue(argv[i]);
82
+
83
+ str = argv[i];
84
+
85
+ new_size += RSTRING_LEN(str);
86
+ }
87
+
88
+ if(new_size > b->size) {
89
+ size_t n = b->size + (b->size / 2);
90
+ uint8_t* top;
91
+ uint8_t* old;
92
+
93
+ new_size = (n > new_size ? n : new_size + BUF_TOLERANCE);
94
+
95
+ top = ALLOC_N(uint8_t, new_size);
96
+ old = b->top;
97
+ memcpy(top, old, used);
98
+ b->top = top;
99
+ b->cur = top + used;
100
+ b->size = new_size;
101
+ xfree(old);
102
+ }
103
+
104
+ for(i = 0; i < argc; i++) {
105
+ long str_len;
106
+ str = argv[i];
107
+ str_len = RSTRING_LEN(str);
108
+ memcpy(b->cur, RSTRING_PTR(str), str_len);
109
+ b->cur += str_len;
110
+ }
111
+
112
+ return self;
113
+ }
114
+
115
+ static VALUE buf_to_str(VALUE self) {
116
+ struct buf_int* b;
117
+ Data_Get_Struct(self, struct buf_int, b);
118
+
119
+ return rb_str_new((const char*)(b->top), b->cur - b->top);
120
+ }
121
+
122
+ static VALUE buf_used(VALUE self) {
123
+ struct buf_int* b;
124
+ Data_Get_Struct(self, struct buf_int, b);
125
+
126
+ return INT2FIX(b->cur - b->top);
127
+ }
128
+
129
+ static VALUE buf_capa(VALUE self) {
130
+ struct buf_int* b;
131
+ Data_Get_Struct(self, struct buf_int, b);
132
+
133
+ return INT2FIX(b->size);
134
+ }
135
+
136
+ static VALUE buf_reset(VALUE self) {
137
+ struct buf_int* b;
138
+ Data_Get_Struct(self, struct buf_int, b);
139
+
140
+ b->cur = b->top;
141
+ return self;
142
+ }
143
+
144
+ void Init_io_buffer(VALUE puma) {
145
+ VALUE buf = rb_define_class_under(puma, "IOBuffer", rb_cObject);
146
+
147
+ rb_define_alloc_func(buf, buf_alloc);
148
+ rb_define_method(buf, "<<", buf_append, 1);
149
+ rb_define_method(buf, "append", buf_append2, -1);
150
+ rb_define_method(buf, "to_str", buf_to_str, 0);
151
+ rb_define_method(buf, "to_s", buf_to_str, 0);
152
+ rb_define_method(buf, "used", buf_used, 0);
153
+ rb_define_method(buf, "capacity", buf_capa, 0);
154
+ rb_define_method(buf, "reset", buf_reset, 0);
155
+ }