puma 4.2.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.
- checksums.yaml +7 -0
- data/History.md +1513 -0
- data/LICENSE +26 -0
- data/README.md +309 -0
- data/bin/puma +10 -0
- data/bin/puma-wild +31 -0
- data/bin/pumactl +12 -0
- data/docs/architecture.md +37 -0
- data/docs/deployment.md +111 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/nginx.md +80 -0
- data/docs/plugins.md +28 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +96 -0
- data/docs/systemd.md +290 -0
- data/ext/puma_http11/PumaHttp11Service.java +19 -0
- data/ext/puma_http11/ext_help.h +15 -0
- data/ext/puma_http11/extconf.rb +23 -0
- data/ext/puma_http11/http11_parser.c +1044 -0
- data/ext/puma_http11/http11_parser.h +65 -0
- data/ext/puma_http11/http11_parser.java.rl +161 -0
- data/ext/puma_http11/http11_parser.rl +147 -0
- data/ext/puma_http11/http11_parser_common.rl +54 -0
- data/ext/puma_http11/io_buffer.c +155 -0
- data/ext/puma_http11/mini_ssl.c +553 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +470 -0
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +363 -0
- data/ext/puma_http11/puma_http11.c +500 -0
- data/lib/puma.rb +31 -0
- data/lib/puma/accept_nonblock.rb +29 -0
- data/lib/puma/app/status.rb +80 -0
- data/lib/puma/binder.rb +439 -0
- data/lib/puma/cli.rb +239 -0
- data/lib/puma/client.rb +494 -0
- data/lib/puma/cluster.rb +555 -0
- data/lib/puma/commonlogger.rb +108 -0
- data/lib/puma/configuration.rb +362 -0
- data/lib/puma/const.rb +235 -0
- data/lib/puma/control_cli.rb +281 -0
- data/lib/puma/convenient.rb +25 -0
- data/lib/puma/delegation.rb +13 -0
- data/lib/puma/detect.rb +15 -0
- data/lib/puma/dsl.rb +738 -0
- data/lib/puma/events.rb +156 -0
- data/lib/puma/io_buffer.rb +4 -0
- data/lib/puma/jruby_restart.rb +84 -0
- data/lib/puma/launcher.rb +478 -0
- data/lib/puma/minissl.rb +278 -0
- data/lib/puma/null_io.rb +44 -0
- data/lib/puma/plugin.rb +120 -0
- data/lib/puma/plugin/tmp_restart.rb +36 -0
- data/lib/puma/rack/builder.rb +301 -0
- data/lib/puma/rack/urlmap.rb +93 -0
- data/lib/puma/rack_default.rb +9 -0
- data/lib/puma/reactor.rb +399 -0
- data/lib/puma/runner.rb +185 -0
- data/lib/puma/server.rb +1033 -0
- data/lib/puma/single.rb +124 -0
- data/lib/puma/state_file.rb +31 -0
- data/lib/puma/tcp_logger.rb +41 -0
- data/lib/puma/thread_pool.rb +328 -0
- data/lib/puma/util.rb +124 -0
- data/lib/rack/handler/puma.rb +115 -0
- data/tools/docker/Dockerfile +16 -0
- data/tools/jungle/README.md +19 -0
- data/tools/jungle/init.d/README.md +61 -0
- data/tools/jungle/init.d/puma +421 -0
- data/tools/jungle/init.d/run-puma +18 -0
- data/tools/jungle/rc.d/README.md +74 -0
- data/tools/jungle/rc.d/puma +61 -0
- data/tools/jungle/rc.d/puma.conf +10 -0
- data/tools/jungle/upstart/README.md +61 -0
- data/tools/jungle/upstart/puma-manager.conf +31 -0
- data/tools/jungle/upstart/puma.conf +69 -0
- data/tools/trickletest.rb +44 -0
- metadata +144 -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((size_t) (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 ) ("?" %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
|
+
}
|