oversip 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#ifndef ws_http_parser_h
|
|
2
|
+
#define ws_http_parser_h
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
#include <sys/types.h>
|
|
6
|
+
|
|
7
|
+
#if defined(_WIN32)
|
|
8
|
+
#include <stddef.h>
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
enum method {
|
|
13
|
+
method_GET = 1,
|
|
14
|
+
method_POST,
|
|
15
|
+
method_OPTIONS,
|
|
16
|
+
method_unknown
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
enum uri_scheme {
|
|
20
|
+
uri_scheme_http = 1,
|
|
21
|
+
uri_scheme_https,
|
|
22
|
+
uri_scheme_unknown
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
typedef void (*msg_method_cb)(void *data, const char *at, size_t length, enum method method);
|
|
26
|
+
typedef void (*uri_scheme_cb)(void *data, const char *at, size_t length, enum uri_scheme);
|
|
27
|
+
typedef void (*msg_element_cb)(void *data, const char *at, size_t length);
|
|
28
|
+
typedef void (*header_cb)(void *data, const char *hdr_field, size_t hdr_field_len, const char *hdr_value, size_t hdr_value_len);
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
typedef struct struct_request {
|
|
32
|
+
msg_method_cb method;
|
|
33
|
+
uri_scheme_cb uri_scheme;
|
|
34
|
+
msg_element_cb request_uri;
|
|
35
|
+
msg_element_cb request_path;
|
|
36
|
+
msg_element_cb query;
|
|
37
|
+
msg_element_cb fragment;
|
|
38
|
+
msg_element_cb http_version;
|
|
39
|
+
msg_element_cb host;
|
|
40
|
+
msg_element_cb port;
|
|
41
|
+
msg_element_cb content_length;
|
|
42
|
+
msg_element_cb hdr_connection_value;
|
|
43
|
+
msg_element_cb hdr_upgrade;
|
|
44
|
+
msg_element_cb hdr_origin;
|
|
45
|
+
msg_element_cb hdr_sec_websocket_version;
|
|
46
|
+
msg_element_cb hdr_sec_websocket_key;
|
|
47
|
+
msg_element_cb hdr_sec_websocket_protocol_value;
|
|
48
|
+
} struct_request;
|
|
49
|
+
|
|
50
|
+
typedef struct ws_http_request_parser {
|
|
51
|
+
/* Parser stuf. */
|
|
52
|
+
int cs;
|
|
53
|
+
size_t nread;
|
|
54
|
+
char * error_start;
|
|
55
|
+
size_t error_len;
|
|
56
|
+
int error_pos;
|
|
57
|
+
|
|
58
|
+
size_t mark;
|
|
59
|
+
size_t hdr_field_start;
|
|
60
|
+
size_t hdr_field_len;
|
|
61
|
+
size_t hdr_value_start;
|
|
62
|
+
size_t hdr_value_len;
|
|
63
|
+
size_t query_start;
|
|
64
|
+
|
|
65
|
+
/* Request method. */
|
|
66
|
+
enum method method;
|
|
67
|
+
/* URI scheme type. */
|
|
68
|
+
enum uri_scheme uri_scheme;
|
|
69
|
+
|
|
70
|
+
header_cb header;
|
|
71
|
+
struct_request request;
|
|
72
|
+
|
|
73
|
+
/* OverSIP::WebSocket::Request instance. */
|
|
74
|
+
void * data;
|
|
75
|
+
} ws_http_request_parser;
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
int ws_http_request_parser_init(ws_http_request_parser *parser);
|
|
79
|
+
int ws_http_request_parser_finish(ws_http_request_parser *parser);
|
|
80
|
+
size_t ws_http_request_parser_execute(ws_http_request_parser *parser, const char *buffer, size_t len, size_t off);
|
|
81
|
+
int ws_http_request_parser_has_error(ws_http_request_parser *parser);
|
|
82
|
+
int ws_http_request_parser_is_finished(ws_http_request_parser *parser);
|
|
83
|
+
#define ws_http_request_parser_nread(parser) (parser)->nread
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
#endif
|
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include "ext_help.h"
|
|
3
|
+
#include "ws_http_parser.h"
|
|
4
|
+
#include "../utils/utils_ruby.h"
|
|
5
|
+
#include "../common/c_util.h"
|
|
6
|
+
#include "../common/ruby_c_util.h"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
static VALUE headerize(const char*, size_t);
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
static VALUE mOverSIP;
|
|
13
|
+
static VALUE eOverSIPError;
|
|
14
|
+
|
|
15
|
+
static VALUE mWebSocket;
|
|
16
|
+
static VALUE cHttpRequestParser;
|
|
17
|
+
static VALUE eHttpRequestParserError;
|
|
18
|
+
|
|
19
|
+
static ID id_http_method;
|
|
20
|
+
static ID id_is_unknown_method;
|
|
21
|
+
static ID id_http_version;
|
|
22
|
+
static ID id_uri_scheme;
|
|
23
|
+
static ID id_uri;
|
|
24
|
+
static ID id_uri_path;
|
|
25
|
+
static ID id_uri_query;
|
|
26
|
+
static ID id_uri_fragment;
|
|
27
|
+
static ID id_host;
|
|
28
|
+
static ID id_port;
|
|
29
|
+
static ID id_content_length;
|
|
30
|
+
static ID id_hdr_connection;
|
|
31
|
+
static ID id_hdr_upgrade;
|
|
32
|
+
static ID id_hdr_sec_websocket_version;
|
|
33
|
+
static ID id_hdr_sec_websocket_key;
|
|
34
|
+
static ID id_hdr_sec_websocket_protocol;
|
|
35
|
+
static ID id_hdr_origin;
|
|
36
|
+
|
|
37
|
+
static VALUE symbol_GET;
|
|
38
|
+
static VALUE symbol_POST;
|
|
39
|
+
static VALUE symbol_OPTIONS;
|
|
40
|
+
static VALUE symbol_http;
|
|
41
|
+
static VALUE symbol_https;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
static void header(void *data, const char *hdr_field, size_t hdr_field_len, const char *hdr_value, size_t hdr_value_len)
|
|
46
|
+
{
|
|
47
|
+
TRACE();
|
|
48
|
+
char *ch, *end;
|
|
49
|
+
VALUE parsed = (VALUE)data;
|
|
50
|
+
VALUE v, f, el;
|
|
51
|
+
|
|
52
|
+
/* Header name. */
|
|
53
|
+
f = headerize(hdr_field, hdr_field_len);
|
|
54
|
+
|
|
55
|
+
/* Header value. */
|
|
56
|
+
v = RB_STR_UTF8_NEW(hdr_value, hdr_value_len);
|
|
57
|
+
|
|
58
|
+
/* Here we have the header name capitalized in variable f. */
|
|
59
|
+
el = rb_hash_lookup(parsed, f);
|
|
60
|
+
switch(TYPE(el)) {
|
|
61
|
+
case T_ARRAY:
|
|
62
|
+
rb_ary_push(el, v);
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
rb_hash_aset(parsed, f, rb_ary_new3(1, v));
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
static void req_method(void *data, const char *at, size_t length, enum method method)
|
|
72
|
+
{
|
|
73
|
+
TRACE();
|
|
74
|
+
VALUE parsed = (VALUE)data;
|
|
75
|
+
VALUE v;
|
|
76
|
+
|
|
77
|
+
switch(method) {
|
|
78
|
+
/* If the method is known store it as a symbol (i.e. :GET). */
|
|
79
|
+
case method_GET:
|
|
80
|
+
rb_ivar_set(parsed, id_http_method, symbol_GET);
|
|
81
|
+
break;
|
|
82
|
+
case method_POST:
|
|
83
|
+
rb_ivar_set(parsed, id_http_method, symbol_POST);
|
|
84
|
+
break;
|
|
85
|
+
case method_OPTIONS:
|
|
86
|
+
rb_ivar_set(parsed, id_http_method, symbol_OPTIONS);
|
|
87
|
+
break;
|
|
88
|
+
/* If the method is unknown store it as a string (i.e. "CHICKEN") and set the
|
|
89
|
+
attribute @is_unknown_method to true. */
|
|
90
|
+
case method_unknown:
|
|
91
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
92
|
+
rb_ivar_set(parsed, id_http_method, v);
|
|
93
|
+
rb_ivar_set(parsed, id_is_unknown_method, Qtrue);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
static void req_uri_scheme(void *data, const char *at, size_t length, enum uri_scheme scheme)
|
|
100
|
+
{
|
|
101
|
+
TRACE();
|
|
102
|
+
VALUE parsed = (VALUE)data;
|
|
103
|
+
VALUE v;
|
|
104
|
+
|
|
105
|
+
switch(scheme) {
|
|
106
|
+
case uri_scheme_http: v = symbol_http; break;
|
|
107
|
+
case uri_scheme_https: v = symbol_https; break;
|
|
108
|
+
case uri_scheme_unknown: v = my_rb_str_downcase(at, length); break;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
rb_ivar_set(parsed, id_uri_scheme, v);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
static void req_request_uri(void *data, const char *at, size_t length)
|
|
116
|
+
{
|
|
117
|
+
TRACE();
|
|
118
|
+
VALUE parsed = (VALUE)data;
|
|
119
|
+
VALUE v;
|
|
120
|
+
|
|
121
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
122
|
+
rb_ivar_set(parsed, id_uri, v);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
static void req_request_path(void *data, const char *at, size_t length)
|
|
127
|
+
{
|
|
128
|
+
TRACE();
|
|
129
|
+
VALUE parsed = (VALUE)data;
|
|
130
|
+
VALUE v;
|
|
131
|
+
|
|
132
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
133
|
+
rb_ivar_set(parsed, id_uri_path, v);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
static void req_query(void *data, const char *at, size_t length)
|
|
138
|
+
{
|
|
139
|
+
TRACE();
|
|
140
|
+
VALUE parsed = (VALUE)data;
|
|
141
|
+
VALUE v;
|
|
142
|
+
|
|
143
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
144
|
+
rb_ivar_set(parsed, id_uri_query, v);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
static void req_fragment(void *data, const char *at, size_t length)
|
|
149
|
+
{
|
|
150
|
+
TRACE();
|
|
151
|
+
VALUE parsed = (VALUE)data;
|
|
152
|
+
VALUE v;
|
|
153
|
+
|
|
154
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
155
|
+
rb_ivar_set(parsed, id_uri_fragment, v);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
static void req_http_version(void *data, const char *at, size_t length)
|
|
160
|
+
{
|
|
161
|
+
TRACE();
|
|
162
|
+
VALUE parsed = (VALUE)data;
|
|
163
|
+
VALUE v;
|
|
164
|
+
|
|
165
|
+
v = RB_STR_UTF8_NEW(at, length);
|
|
166
|
+
rb_ivar_set(parsed, id_http_version, v);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
static void req_host(void *data, const char *at, size_t length)
|
|
171
|
+
{
|
|
172
|
+
TRACE();
|
|
173
|
+
VALUE parsed = (VALUE)data;
|
|
174
|
+
VALUE v;
|
|
175
|
+
|
|
176
|
+
/* If it's a domain and ends with ".", remove it. */
|
|
177
|
+
if (at[length-1] == '.')
|
|
178
|
+
length--;
|
|
179
|
+
|
|
180
|
+
v = my_rb_str_downcase(at, length);
|
|
181
|
+
rb_ivar_set(parsed, id_host, v);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
static void req_port(void *data, const char *at, size_t length)
|
|
186
|
+
{
|
|
187
|
+
TRACE();
|
|
188
|
+
VALUE parsed = (VALUE)data;
|
|
189
|
+
VALUE v;
|
|
190
|
+
|
|
191
|
+
v = INT2FIX(str_to_int(at, length));
|
|
192
|
+
rb_ivar_set(parsed, id_port, v);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
static void req_content_length(void *data, const char *at, size_t length)
|
|
197
|
+
{
|
|
198
|
+
TRACE();
|
|
199
|
+
VALUE parsed = (VALUE)data;
|
|
200
|
+
VALUE v;
|
|
201
|
+
|
|
202
|
+
v = LONG2FIX(strtol(at,NULL,0));
|
|
203
|
+
rb_ivar_set(parsed, id_content_length, v);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
static void req_hdr_connection_value(void *data, const char *at, size_t length)
|
|
208
|
+
{
|
|
209
|
+
TRACE();
|
|
210
|
+
VALUE parsed = (VALUE)data;
|
|
211
|
+
VALUE v;
|
|
212
|
+
VALUE array;
|
|
213
|
+
|
|
214
|
+
v = my_rb_str_downcase(at, length);
|
|
215
|
+
|
|
216
|
+
array = rb_ivar_get(parsed, id_hdr_connection);
|
|
217
|
+
switch(TYPE(array)) {
|
|
218
|
+
case T_ARRAY:
|
|
219
|
+
rb_ary_push(array, v);
|
|
220
|
+
break;
|
|
221
|
+
default:
|
|
222
|
+
rb_ivar_set(parsed, id_hdr_connection, rb_ary_new3(1, v));
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
static void req_hdr_upgrade(void *data, const char *at, size_t length)
|
|
229
|
+
{
|
|
230
|
+
TRACE();
|
|
231
|
+
VALUE parsed = (VALUE)data;
|
|
232
|
+
VALUE v;
|
|
233
|
+
|
|
234
|
+
v = my_rb_str_downcase(at, length);
|
|
235
|
+
rb_ivar_set(parsed, id_hdr_upgrade, v);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
static void req_hdr_sec_websocket_version(void *data, const char *at, size_t length)
|
|
240
|
+
{
|
|
241
|
+
TRACE();
|
|
242
|
+
VALUE parsed = (VALUE)data;
|
|
243
|
+
VALUE v;
|
|
244
|
+
|
|
245
|
+
v = INT2FIX(str_to_int(at, length));
|
|
246
|
+
rb_ivar_set(parsed, id_hdr_sec_websocket_version, v);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
static void req_hdr_sec_websocket_key(void *data, const char *at, size_t length)
|
|
251
|
+
{
|
|
252
|
+
TRACE();
|
|
253
|
+
VALUE parsed = (VALUE)data;
|
|
254
|
+
VALUE v;
|
|
255
|
+
|
|
256
|
+
v = rb_str_new(at, length);
|
|
257
|
+
rb_ivar_set(parsed, id_hdr_sec_websocket_key, v);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
static void req_hdr_sec_websocket_protocol_value(void *data, const char *at, size_t length)
|
|
262
|
+
{
|
|
263
|
+
TRACE();
|
|
264
|
+
VALUE parsed = (VALUE)data;
|
|
265
|
+
VALUE v;
|
|
266
|
+
VALUE array;
|
|
267
|
+
|
|
268
|
+
v = rb_str_new(at, length);
|
|
269
|
+
|
|
270
|
+
array = rb_ivar_get(parsed, id_hdr_sec_websocket_protocol);
|
|
271
|
+
switch(TYPE(array)) {
|
|
272
|
+
case T_ARRAY:
|
|
273
|
+
rb_ary_push(array, v);
|
|
274
|
+
break;
|
|
275
|
+
default:
|
|
276
|
+
rb_ivar_set(parsed, id_hdr_sec_websocket_protocol, rb_ary_new3(1, v));
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
static void req_hdr_origin(void *data, const char *at, size_t length)
|
|
283
|
+
{
|
|
284
|
+
TRACE();
|
|
285
|
+
VALUE parsed = (VALUE)data;
|
|
286
|
+
VALUE v;
|
|
287
|
+
|
|
288
|
+
v = my_rb_str_downcase(at, length);
|
|
289
|
+
rb_ivar_set(parsed, id_hdr_origin, v);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
/*************** Custom C funcions (helpers) ****************/
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
/*
|
|
298
|
+
* Normalizes it (by capitalizing the first letter and each letter
|
|
299
|
+
* under a "-" or "_" symbol).
|
|
300
|
+
*/
|
|
301
|
+
static VALUE headerize(const char* hname, size_t hname_len)
|
|
302
|
+
{
|
|
303
|
+
TRACE();
|
|
304
|
+
VALUE headerized;
|
|
305
|
+
char* str;
|
|
306
|
+
int i;
|
|
307
|
+
|
|
308
|
+
headerized = rb_str_new(hname, hname_len);
|
|
309
|
+
str = RSTRING_PTR(headerized);
|
|
310
|
+
if (*str >= 'a' && *str <= 'z')
|
|
311
|
+
*str &= ~0x20;
|
|
312
|
+
|
|
313
|
+
for(i = 1; i < hname_len; i++) {
|
|
314
|
+
if (str[i-1] == '-' || str[i-1] == '_') {
|
|
315
|
+
if (str[i] >= 'a' && str[i] <= 'z')
|
|
316
|
+
str[i] &= ~0x20;
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
if (str[i] >= 'A' && str[i] <= 'Z')
|
|
320
|
+
str[i] += 32;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return(headerized);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
/*************** Ruby functions ****************/
|
|
331
|
+
|
|
332
|
+
static void HttpRequestParser_free(void *parser)
|
|
333
|
+
{
|
|
334
|
+
TRACE();
|
|
335
|
+
if(parser) {
|
|
336
|
+
/* NOTE: Use always xfree() rather than free():
|
|
337
|
+
* http://www.mail-archive.com/libxml-devel@rubyforge.org/msg00242.html */
|
|
338
|
+
xfree(parser);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
VALUE HttpRequestParser_alloc(VALUE klass)
|
|
344
|
+
{
|
|
345
|
+
TRACE();
|
|
346
|
+
VALUE obj;
|
|
347
|
+
/* NOTE: Use always ALLOC/ALLOC_N rather than malloc().
|
|
348
|
+
* ALLOC uses xmalloc:
|
|
349
|
+
* ALLOC(type) (type*)xmalloc(sizeof(type))
|
|
350
|
+
* ALLOC_N(type, n) (type*)xmalloc(sizeof(type)*(n))
|
|
351
|
+
*/
|
|
352
|
+
ws_http_request_parser *parser = ALLOC(ws_http_request_parser);
|
|
353
|
+
|
|
354
|
+
parser->header = header;
|
|
355
|
+
parser->request.method = req_method;
|
|
356
|
+
parser->request.uri_scheme = req_uri_scheme;
|
|
357
|
+
parser->request.request_uri = req_request_uri;
|
|
358
|
+
parser->request.request_path = req_request_path;
|
|
359
|
+
parser->request.query = req_query;
|
|
360
|
+
parser->request.fragment = req_fragment;
|
|
361
|
+
parser->request.http_version = req_http_version;
|
|
362
|
+
parser->request.host = req_host;
|
|
363
|
+
parser->request.port = req_port;
|
|
364
|
+
parser->request.content_length = req_content_length;
|
|
365
|
+
parser->request.hdr_connection_value = req_hdr_connection_value;
|
|
366
|
+
parser->request.hdr_upgrade = req_hdr_upgrade;
|
|
367
|
+
parser->request.hdr_sec_websocket_version = req_hdr_sec_websocket_version;
|
|
368
|
+
parser->request.hdr_sec_websocket_key = req_hdr_sec_websocket_key;
|
|
369
|
+
parser->request.hdr_sec_websocket_protocol_value = req_hdr_sec_websocket_protocol_value;
|
|
370
|
+
parser->request.hdr_origin = req_hdr_origin;
|
|
371
|
+
|
|
372
|
+
ws_http_request_parser_init(parser);
|
|
373
|
+
|
|
374
|
+
obj = Data_Wrap_Struct(klass, NULL, HttpRequestParser_free, parser);
|
|
375
|
+
return obj;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* call-seq:
|
|
381
|
+
* parser.new -> parser
|
|
382
|
+
*
|
|
383
|
+
* Creates a new parser.
|
|
384
|
+
*/
|
|
385
|
+
VALUE HttpRequestParser_init(VALUE self)
|
|
386
|
+
{
|
|
387
|
+
TRACE();
|
|
388
|
+
ws_http_request_parser *parser = NULL;
|
|
389
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
390
|
+
ws_http_request_parser_init(parser);
|
|
391
|
+
|
|
392
|
+
return self;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* call-seq:
|
|
398
|
+
* parser.reset -> nil
|
|
399
|
+
*
|
|
400
|
+
* Resets the parser to it's initial state so that you can reuse it
|
|
401
|
+
* rather than making new ones.
|
|
402
|
+
*/
|
|
403
|
+
VALUE HttpRequestParser_reset(VALUE self)
|
|
404
|
+
{
|
|
405
|
+
TRACE();
|
|
406
|
+
ws_http_request_parser *parser = NULL;
|
|
407
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
408
|
+
ws_http_request_parser_init(parser);
|
|
409
|
+
|
|
410
|
+
return Qnil;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* call-seq:
|
|
416
|
+
* parser.finish -> true/false
|
|
417
|
+
*
|
|
418
|
+
* Finishes a parser early which could put in a "good" or bad state.
|
|
419
|
+
* You should call reset after finish it or bad things will happen.
|
|
420
|
+
*/
|
|
421
|
+
VALUE HttpRequestParser_finish(VALUE self)
|
|
422
|
+
{
|
|
423
|
+
TRACE();
|
|
424
|
+
ws_http_request_parser *parser = NULL;
|
|
425
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
426
|
+
ws_http_request_parser_finish(parser);
|
|
427
|
+
|
|
428
|
+
return ws_http_request_parser_is_finished(parser) ? Qtrue : Qfalse;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
VALUE HttpRequestParser_execute(VALUE self, VALUE req_hash, VALUE buffer, VALUE start)
|
|
433
|
+
{
|
|
434
|
+
TRACE();
|
|
435
|
+
ws_http_request_parser *parser = NULL;
|
|
436
|
+
int from = 0;
|
|
437
|
+
char *dptr = NULL;
|
|
438
|
+
long dlen = 0;
|
|
439
|
+
|
|
440
|
+
REQUIRE_TYPE(req_hash, T_HASH);
|
|
441
|
+
REQUIRE_TYPE(buffer, T_STRING);
|
|
442
|
+
REQUIRE_TYPE(start, T_FIXNUM);
|
|
443
|
+
|
|
444
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
445
|
+
|
|
446
|
+
from = FIX2INT(start);
|
|
447
|
+
dptr = RSTRING_PTR(buffer);
|
|
448
|
+
dlen = RSTRING_LEN(buffer);
|
|
449
|
+
|
|
450
|
+
/* This should never occur or there is an error in the parser. */
|
|
451
|
+
if(from >= dlen)
|
|
452
|
+
rb_raise(eHttpRequestParserError, "requested start is after buffer end.");
|
|
453
|
+
|
|
454
|
+
parser->data = (void *)req_hash;
|
|
455
|
+
ws_http_request_parser_execute(parser, dptr, dlen, from);
|
|
456
|
+
|
|
457
|
+
if(ws_http_request_parser_has_error(parser))
|
|
458
|
+
return Qfalse;
|
|
459
|
+
else
|
|
460
|
+
return INT2FIX(ws_http_request_parser_nread(parser));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* call-seq:
|
|
466
|
+
* parser.error? -> true/false
|
|
467
|
+
*
|
|
468
|
+
* Tells you whether the parser is in an error state.
|
|
469
|
+
*/
|
|
470
|
+
VALUE HttpRequestParser_has_error(VALUE self)
|
|
471
|
+
{
|
|
472
|
+
TRACE();
|
|
473
|
+
ws_http_request_parser *parser = NULL;
|
|
474
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
475
|
+
|
|
476
|
+
return ws_http_request_parser_has_error(parser) ? Qtrue : Qfalse;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* call-seq:
|
|
482
|
+
* parser.error -> String
|
|
483
|
+
*
|
|
484
|
+
* Returns a String showing the error by enclosing the exact wrong char between {{{ }}}.
|
|
485
|
+
*/
|
|
486
|
+
VALUE HttpRequestParser_error(VALUE self)
|
|
487
|
+
{
|
|
488
|
+
TRACE();
|
|
489
|
+
ws_http_request_parser *parser = NULL;
|
|
490
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
491
|
+
|
|
492
|
+
if(ws_http_request_parser_has_error(parser)) {
|
|
493
|
+
char *parsing_error_str;
|
|
494
|
+
int parsing_error_str_len;
|
|
495
|
+
int i;
|
|
496
|
+
int j;
|
|
497
|
+
VALUE rb_error_str;
|
|
498
|
+
|
|
499
|
+
/* Duplicate error string length so '\r' and '\n' are displayed as CR and LF.
|
|
500
|
+
Let 6 chars more for allocating {{{ and }}}. */
|
|
501
|
+
parsing_error_str = ALLOC_N(char, 2*parser->error_len + 6);
|
|
502
|
+
|
|
503
|
+
parsing_error_str_len=0;
|
|
504
|
+
for(i=0, j=0; i < parser->error_len; i++) {
|
|
505
|
+
if (i != parser->error_pos) {
|
|
506
|
+
if (parser->error_start[i] == '\r') {
|
|
507
|
+
parsing_error_str[j++] = '\\';
|
|
508
|
+
parsing_error_str[j++] = 'r';
|
|
509
|
+
parsing_error_str_len += 2;
|
|
510
|
+
}
|
|
511
|
+
else if (parser->error_start[i] == '\n') {
|
|
512
|
+
parsing_error_str[j++] = '\\';
|
|
513
|
+
parsing_error_str[j++] = 'n';
|
|
514
|
+
parsing_error_str_len += 2;
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
parsing_error_str[j++] = parser->error_start[i];
|
|
518
|
+
parsing_error_str_len++;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
parsing_error_str[j++] = '{';
|
|
523
|
+
parsing_error_str[j++] = '{';
|
|
524
|
+
parsing_error_str[j++] = '{';
|
|
525
|
+
if (parser->error_start[i] == '\r') {
|
|
526
|
+
parsing_error_str[j++] = '\\';
|
|
527
|
+
parsing_error_str[j++] = 'r';
|
|
528
|
+
parsing_error_str_len += 2;
|
|
529
|
+
}
|
|
530
|
+
else if (parser->error_start[i] == '\n') {
|
|
531
|
+
parsing_error_str[j++] = '\\';
|
|
532
|
+
parsing_error_str[j++] = 'n';
|
|
533
|
+
parsing_error_str_len += 2;
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
parsing_error_str[j++] = parser->error_start[i];
|
|
537
|
+
parsing_error_str_len++;
|
|
538
|
+
}
|
|
539
|
+
parsing_error_str[j++] = '}';
|
|
540
|
+
parsing_error_str[j++] = '}';
|
|
541
|
+
parsing_error_str[j++] = '}';
|
|
542
|
+
parsing_error_str_len += 6;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
rb_error_str = rb_str_new(parsing_error_str, parsing_error_str_len);
|
|
547
|
+
xfree(parsing_error_str);
|
|
548
|
+
return rb_error_str;
|
|
549
|
+
}
|
|
550
|
+
else
|
|
551
|
+
return Qnil;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* call-seq:
|
|
557
|
+
* parser.finished? -> true/false
|
|
558
|
+
*
|
|
559
|
+
* Tells you whether the parser is finished or not and in a good state.
|
|
560
|
+
*/
|
|
561
|
+
VALUE HttpRequestParser_is_finished(VALUE self)
|
|
562
|
+
{
|
|
563
|
+
TRACE();
|
|
564
|
+
ws_http_request_parser *parser = NULL;
|
|
565
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
566
|
+
|
|
567
|
+
return ws_http_request_parser_is_finished(parser) ? Qtrue : Qfalse;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* call-seq:
|
|
573
|
+
* parser.nread -> Integer
|
|
574
|
+
*
|
|
575
|
+
* Returns the amount of data processed so far during this processing cycle. It is
|
|
576
|
+
* set to 0 on initialize or reset calls and is incremented each time execute is called.
|
|
577
|
+
*/
|
|
578
|
+
VALUE HttpRequestParser_nread(VALUE self)
|
|
579
|
+
{
|
|
580
|
+
TRACE();
|
|
581
|
+
ws_http_request_parser *parser = NULL;
|
|
582
|
+
DATA_GET(self, ws_http_request_parser, parser);
|
|
583
|
+
|
|
584
|
+
return INT2FIX(parser->nread);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
void Init_ws_http_parser()
|
|
589
|
+
{
|
|
590
|
+
mOverSIP = rb_define_module("OverSIP");
|
|
591
|
+
eOverSIPError = rb_define_class_under(mOverSIP, "Error", rb_eStandardError);
|
|
592
|
+
|
|
593
|
+
mWebSocket = rb_define_module_under(mOverSIP, "WebSocket");
|
|
594
|
+
cHttpRequestParser = rb_define_class_under(mWebSocket, "HttpRequestParser", rb_cObject);
|
|
595
|
+
eHttpRequestParserError = rb_define_class_under(mWebSocket, "HttpRequestParserError", eOverSIPError);
|
|
596
|
+
|
|
597
|
+
rb_define_alloc_func(cHttpRequestParser, HttpRequestParser_alloc);
|
|
598
|
+
rb_define_method(cHttpRequestParser, "initialize", HttpRequestParser_init,0);
|
|
599
|
+
rb_define_method(cHttpRequestParser, "reset", HttpRequestParser_reset,0);
|
|
600
|
+
rb_define_method(cHttpRequestParser, "finish", HttpRequestParser_finish,0);
|
|
601
|
+
rb_define_method(cHttpRequestParser, "execute", HttpRequestParser_execute,3);
|
|
602
|
+
rb_define_method(cHttpRequestParser, "error?", HttpRequestParser_has_error,0);
|
|
603
|
+
rb_define_method(cHttpRequestParser, "error", HttpRequestParser_error,0);
|
|
604
|
+
rb_define_method(cHttpRequestParser, "finished?", HttpRequestParser_is_finished,0);
|
|
605
|
+
rb_define_method(cHttpRequestParser, "nread", HttpRequestParser_nread,0);
|
|
606
|
+
|
|
607
|
+
id_http_method = rb_intern("@http_method");
|
|
608
|
+
id_is_unknown_method = rb_intern("is_unknown_method");
|
|
609
|
+
id_http_version = rb_intern("@http_version");
|
|
610
|
+
id_uri_scheme = rb_intern("@uri_scheme");
|
|
611
|
+
id_uri = rb_intern("@uri");
|
|
612
|
+
id_uri_path = rb_intern("@uri_path");
|
|
613
|
+
id_uri_query = rb_intern("@uri_query");
|
|
614
|
+
id_uri_fragment = rb_intern("@uri_fragment");
|
|
615
|
+
id_host = rb_intern("@host");
|
|
616
|
+
id_port = rb_intern("@port");
|
|
617
|
+
id_content_length = rb_intern("@content_length");
|
|
618
|
+
id_hdr_connection = rb_intern("@hdr_connection");
|
|
619
|
+
id_hdr_upgrade = rb_intern("@hdr_upgrade");
|
|
620
|
+
id_hdr_sec_websocket_version = rb_intern("@hdr_sec_websocket_version");
|
|
621
|
+
id_hdr_sec_websocket_key = rb_intern("@hdr_sec_websocket_key");
|
|
622
|
+
id_hdr_sec_websocket_protocol = rb_intern("@hdr_sec_websocket_protocol");
|
|
623
|
+
id_hdr_origin = rb_intern("@hdr_origin");
|
|
624
|
+
|
|
625
|
+
symbol_GET = ID2SYM(rb_intern("GET"));
|
|
626
|
+
symbol_POST = ID2SYM(rb_intern("POST"));
|
|
627
|
+
symbol_OPTIONS = ID2SYM(rb_intern("OPTIONS"));
|
|
628
|
+
symbol_http = ID2SYM(rb_intern("http"));
|
|
629
|
+
symbol_https = ID2SYM(rb_intern("https"));
|
|
630
|
+
}
|