sensu-em 2.4.1-java → 2.5.0.beta-java
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.
- checksums.yaml +4 -4
- data/.travis.yml +15 -5
- data/CHANGELOG.md +41 -1
- data/README.md +2 -3
- data/eventmachine.gemspec +2 -1
- data/ext/cmain.cpp +19 -3
- data/ext/ed.cpp +22 -8
- data/ext/em.cpp +123 -76
- data/ext/em.h +40 -6
- data/ext/eventmachine.h +2 -0
- data/ext/extconf.rb +16 -2
- data/ext/fastfilereader/extconf.rb +3 -0
- data/ext/fastfilereader/mapper.cpp +1 -1
- data/ext/project.h +11 -7
- data/ext/rubymain.cpp +38 -2
- data/ext/ssl.cpp +4 -1
- data/ext/ssl.h +4 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +8 -1
- data/lib/em/buftok.rb +34 -85
- data/lib/em/protocols/httpclient.rb +31 -11
- data/lib/em/protocols/line_and_text.rb +2 -3
- data/lib/em/protocols/linetext2.rb +0 -1
- data/lib/em/protocols/smtpserver.rb +32 -9
- data/lib/em/pure_ruby.rb +2 -2
- data/lib/em/tick_loop.rb +19 -19
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +12 -4
- data/lib/jeventmachine.rb +22 -6
- data/lib/rubyeventmachine.jar +0 -0
- data/rakelib/package.rake +1 -1
- data/tests/em_test_helper.rb +4 -0
- data/tests/test_attach.rb +1 -0
- data/tests/test_basic.rb +14 -16
- data/tests/test_completion.rb +1 -0
- data/tests/test_connection_count.rb +1 -0
- data/tests/test_connection_write.rb +35 -0
- data/tests/test_epoll.rb +11 -14
- data/tests/test_httpclient.rb +43 -0
- data/tests/test_iterator.rb +6 -6
- data/tests/test_kb.rb +19 -25
- data/tests/test_many_fds.rb +22 -0
- data/tests/test_pause.rb +7 -2
- data/tests/test_pool.rb +2 -0
- data/tests/test_process_watch.rb +2 -0
- data/tests/test_processes.rb +7 -7
- data/tests/test_resolver.rb +33 -7
- data/tests/test_ssl_methods.rb +3 -4
- data/tests/test_ssl_verify.rb +62 -62
- data/tests/test_threaded_resource.rb +8 -0
- data/tmp/java/rubyeventmachine/.build +0 -0
- metadata +27 -10
data/ext/em.h
CHANGED
@@ -22,10 +22,10 @@ See the file COPYING for complete licensing information.
|
|
22
22
|
|
23
23
|
#ifdef BUILD_FOR_RUBY
|
24
24
|
#include <ruby.h>
|
25
|
-
|
26
25
|
#ifdef HAVE_RB_THREAD_FD_SELECT
|
27
26
|
#define EmSelect rb_thread_fd_select
|
28
27
|
#else
|
28
|
+
// ruby 1.9.1 and below
|
29
29
|
#define EmSelect rb_thread_select
|
30
30
|
#endif
|
31
31
|
|
@@ -69,9 +69,33 @@ See the file COPYING for complete licensing information.
|
|
69
69
|
#define EmSelect select
|
70
70
|
#endif
|
71
71
|
|
72
|
+
#if !defined(HAVE_RB_FDSET_T)
|
73
|
+
#define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n)))
|
74
|
+
// These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3,
|
75
|
+
// with this change: any macros that read or write the nth element of an
|
76
|
+
// fdset first call fd_check to make sure n is in bounds.
|
77
|
+
typedef fd_set rb_fdset_t;
|
78
|
+
#define rb_fd_zero(f) FD_ZERO(f)
|
79
|
+
#define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0)
|
80
|
+
#define rb_fd_clr(n, f) do { if (fd_check(n)) FD_CLR((n), (f)); } while(0)
|
81
|
+
#define rb_fd_isset(n, f) (fd_check(n) ? FD_ISSET((n), (f)) : 0)
|
82
|
+
#define rb_fd_copy(d, s, n) (*(d) = *(s))
|
83
|
+
#define rb_fd_dup(d, s) (*(d) = *(s))
|
84
|
+
#define rb_fd_resize(n, f) ((void)(f))
|
85
|
+
#define rb_fd_ptr(f) (f)
|
86
|
+
#define rb_fd_init(f) FD_ZERO(f)
|
87
|
+
#define rb_fd_init_copy(d, s) (*(d) = *(s))
|
88
|
+
#define rb_fd_term(f) ((void)(f))
|
89
|
+
#define rb_fd_max(f) FD_SETSIZE
|
90
|
+
#define rb_fd_select(n, rfds, wfds, efds, timeout) \
|
91
|
+
select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
|
92
|
+
#define rb_thread_fd_select(n, rfds, wfds, efds, timeout) \
|
93
|
+
rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
|
94
|
+
#endif
|
95
|
+
|
72
96
|
class EventableDescriptor;
|
73
97
|
class InotifyDescriptor;
|
74
|
-
|
98
|
+
struct SelectData_t;
|
75
99
|
|
76
100
|
/********************
|
77
101
|
class EventMachine_t
|
@@ -83,6 +107,9 @@ class EventMachine_t
|
|
83
107
|
static int GetMaxTimerCount();
|
84
108
|
static void SetMaxTimerCount (int);
|
85
109
|
|
110
|
+
static int GetSimultaneousAcceptCount();
|
111
|
+
static void SetSimultaneousAcceptCount (int);
|
112
|
+
|
86
113
|
public:
|
87
114
|
EventMachine_t (EMCallback);
|
88
115
|
virtual ~EventMachine_t();
|
@@ -175,7 +202,7 @@ class EventMachine_t
|
|
175
202
|
public:
|
176
203
|
void _ReadLoopBreaker();
|
177
204
|
void _ReadInotifyEvents();
|
178
|
-
|
205
|
+
int NumCloseScheduled;
|
179
206
|
|
180
207
|
private:
|
181
208
|
enum {
|
@@ -213,8 +240,13 @@ class EventMachine_t
|
|
213
240
|
unsigned LastTickCount;
|
214
241
|
#endif
|
215
242
|
|
243
|
+
#ifdef OS_DARWIN
|
244
|
+
mach_timebase_info_data_t mach_timebase;
|
245
|
+
#endif
|
246
|
+
|
216
247
|
private:
|
217
248
|
bool bTerminateSignalReceived;
|
249
|
+
SelectData_t *SelectData;
|
218
250
|
|
219
251
|
bool bEpoll;
|
220
252
|
int epfd; // Epoll file-descriptor
|
@@ -239,13 +271,15 @@ struct SelectData_t
|
|
239
271
|
struct SelectData_t
|
240
272
|
{
|
241
273
|
SelectData_t();
|
274
|
+
~SelectData_t();
|
242
275
|
|
243
276
|
int _Select();
|
277
|
+
void _Clear();
|
244
278
|
|
245
279
|
int maxsocket;
|
246
|
-
|
247
|
-
|
248
|
-
|
280
|
+
rb_fdset_t fdreads;
|
281
|
+
rb_fdset_t fdwrites;
|
282
|
+
rb_fdset_t fderrors;
|
249
283
|
timeval tv;
|
250
284
|
int nSockets;
|
251
285
|
};
|
data/ext/eventmachine.h
CHANGED
@@ -96,6 +96,8 @@ extern "C" {
|
|
96
96
|
void evma_set_timer_quantum (int);
|
97
97
|
int evma_get_max_timer_count();
|
98
98
|
void evma_set_max_timer_count (int);
|
99
|
+
int evma_get_simultaneous_accept_count();
|
100
|
+
void evma_set_simultaneous_accept_count (int);
|
99
101
|
void evma_setuid_string (const char *username);
|
100
102
|
void evma_stop_machine();
|
101
103
|
float evma_get_heartbeat_interval();
|
data/ext/extconf.rb
CHANGED
@@ -39,10 +39,13 @@ def manual_ssl_config
|
|
39
39
|
check_libs(libs) and check_heads(heads)
|
40
40
|
end
|
41
41
|
|
42
|
+
# Eager check devs tools
|
43
|
+
have_devel? if respond_to?(:have_devel?)
|
44
|
+
|
42
45
|
if ENV['CROSS_COMPILING']
|
43
|
-
openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.
|
46
|
+
openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.1i")
|
44
47
|
openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/")
|
45
|
-
if File.
|
48
|
+
if File.exist?(openssl_dir)
|
46
49
|
FileUtils.mkdir_p Dir.pwd+"/openssl/"
|
47
50
|
FileUtils.cp Dir[openssl_dir+"/include/openssl/*.h"], Dir.pwd+"/openssl/", :verbose => true
|
48
51
|
FileUtils.cp Dir[openssl_dir+"/lib*.a"], Dir.pwd, :verbose => true
|
@@ -72,6 +75,7 @@ add_define "HAVE_INOTIFY" if inotify = have_func('inotify_init', 'sys/inotify.h'
|
|
72
75
|
add_define "HAVE_OLD_INOTIFY" if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h')
|
73
76
|
add_define 'HAVE_WRITEV' if have_func('writev', 'sys/uio.h')
|
74
77
|
add_define 'HAVE_RB_THREAD_FD_SELECT' if have_func('rb_thread_fd_select')
|
78
|
+
add_define 'HAVE_RB_FDSET_T' if have_type('rb_fdset_t', 'ruby/intern.h')
|
75
79
|
|
76
80
|
have_func('rb_wait_for_single_fd')
|
77
81
|
have_func('rb_enable_interrupt')
|
@@ -139,6 +143,8 @@ when /openbsd/
|
|
139
143
|
CONFIG['LDSHAREDXX'] = "$(CXX) -shared -lstdc++ -fPIC"
|
140
144
|
|
141
145
|
when /darwin/
|
146
|
+
add_define 'OS_DARWIN'
|
147
|
+
|
142
148
|
# on Unix we need a g++ link, not gcc.
|
143
149
|
# Ff line contributed by Daniel Harple.
|
144
150
|
CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
|
@@ -166,6 +172,14 @@ else
|
|
166
172
|
CONFIG['LDSHARED'] = "$(CXX) -shared"
|
167
173
|
end
|
168
174
|
|
175
|
+
# Platform-specific time functions
|
176
|
+
if have_func('clock_gettime')
|
177
|
+
# clock_gettime is POSIX, but the monotonic clocks are not
|
178
|
+
have_const('CLOCK_MONOTONIC_RAW', 'time.h') # Linux
|
179
|
+
have_const('CLOCK_MONOTONIC', 'time.h') # Linux, Solaris, BSDs
|
180
|
+
else
|
181
|
+
have_func('gethrtime') # Older Solaris and HP-UX
|
182
|
+
end
|
169
183
|
|
170
184
|
# solaris c++ compiler doesn't have make_pair()
|
171
185
|
TRY_LINK.sub!('$(CC)', '$(CXX)')
|
data/ext/project.h
CHANGED
@@ -78,6 +78,11 @@ typedef int SOCKET;
|
|
78
78
|
#endif
|
79
79
|
#endif /* _AIX */
|
80
80
|
|
81
|
+
#ifdef OS_DARWIN
|
82
|
+
#include <mach/mach.h>
|
83
|
+
#include <mach/mach_time.h>
|
84
|
+
#endif /* OS_DARWIN */
|
85
|
+
|
81
86
|
#endif /* OS_UNIX */
|
82
87
|
|
83
88
|
#ifdef OS_WIN32
|
@@ -85,7 +90,9 @@ typedef int SOCKET;
|
|
85
90
|
// 18Jun12: fd_setsize must be changed in the ruby binary (not in this extension). redefining it also causes segvs, see eventmachine/eventmachine#333
|
86
91
|
//#define FD_SETSIZE 1024
|
87
92
|
|
93
|
+
// WIN32_LEAN_AND_MEAN excludes APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets.
|
88
94
|
#define WIN32_LEAN_AND_MEAN
|
95
|
+
|
89
96
|
#include <windows.h>
|
90
97
|
#include <winsock2.h>
|
91
98
|
#include <ws2tcpip.h>
|
@@ -93,13 +100,10 @@ typedef int SOCKET;
|
|
93
100
|
#include <fcntl.h>
|
94
101
|
#include <assert.h>
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
#
|
100
|
-
#define _PID_T_
|
101
|
-
typedef int pid_t;
|
102
|
-
#endif /* _PID_T_ */
|
103
|
+
// Use the Win32 wrapper library that Ruby owns to be able to close sockets with the close() function
|
104
|
+
#define RUBY_EXPORT
|
105
|
+
#include <ruby/defines.h>
|
106
|
+
#include <ruby/win32.h>
|
103
107
|
#endif /* OS_WIN32 */
|
104
108
|
|
105
109
|
#if !defined(_MSC_VER) || _MSC_VER > 1500
|
data/ext/rubymain.cpp
CHANGED
@@ -408,8 +408,22 @@ static VALUE t_get_subprocess_status (VALUE self, VALUE signature)
|
|
408
408
|
if (evma_get_subprocess_status (NUM2ULONG (signature), &status)) {
|
409
409
|
if (evma_get_subprocess_pid (NUM2ULONG (signature), &pid)) {
|
410
410
|
proc_status = rb_obj_alloc(rb_cProcStatus);
|
411
|
+
|
412
|
+
/* MRI Ruby uses hidden instance vars */
|
411
413
|
rb_iv_set(proc_status, "status", INT2FIX(status));
|
412
414
|
rb_iv_set(proc_status, "pid", INT2FIX(pid));
|
415
|
+
|
416
|
+
#ifdef RUBINIUS
|
417
|
+
/* Rubinius uses standard instance vars */
|
418
|
+
rb_iv_set(proc_status, "@pid", INT2FIX(pid));
|
419
|
+
if (WIFEXITED(status)) {
|
420
|
+
rb_iv_set(proc_status, "@status", INT2FIX(WEXITSTATUS(status)));
|
421
|
+
} else if(WIFSIGNALED(status)) {
|
422
|
+
rb_iv_set(proc_status, "@termsig", INT2FIX(WTERMSIG(status)));
|
423
|
+
} else if(WIFSTOPPED(status)){
|
424
|
+
rb_iv_set(proc_status, "@stopsig", INT2FIX(WSTOPSIG(status)));
|
425
|
+
}
|
426
|
+
#endif
|
413
427
|
}
|
414
428
|
}
|
415
429
|
|
@@ -611,7 +625,7 @@ static VALUE t_set_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optna
|
|
611
625
|
int fd = evma_get_file_descriptor (NUM2ULONG (signature));
|
612
626
|
int level = NUM2INT(lev), option = NUM2INT(optname);
|
613
627
|
int i;
|
614
|
-
void *v;
|
628
|
+
const void *v;
|
615
629
|
socklen_t len;
|
616
630
|
|
617
631
|
switch (TYPE(optval)) {
|
@@ -799,6 +813,21 @@ static VALUE t_set_max_timer_count (VALUE self, VALUE ct)
|
|
799
813
|
return Qnil;
|
800
814
|
}
|
801
815
|
|
816
|
+
/********************
|
817
|
+
t_get/set_simultaneous_accept_count
|
818
|
+
********************/
|
819
|
+
|
820
|
+
static VALUE t_get_simultaneous_accept_count (VALUE self)
|
821
|
+
{
|
822
|
+
return INT2FIX (evma_get_simultaneous_accept_count());
|
823
|
+
}
|
824
|
+
|
825
|
+
static VALUE t_set_simultaneous_accept_count (VALUE self, VALUE ct)
|
826
|
+
{
|
827
|
+
evma_set_simultaneous_accept_count (FIX2INT (ct));
|
828
|
+
return Qnil;
|
829
|
+
}
|
830
|
+
|
802
831
|
/***************
|
803
832
|
t_setuid_string
|
804
833
|
***************/
|
@@ -833,7 +862,12 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
|
|
833
862
|
}
|
834
863
|
strings[len] = NULL;
|
835
864
|
|
836
|
-
|
865
|
+
unsigned long f = 0;
|
866
|
+
try {
|
867
|
+
f = evma_popen (strings);
|
868
|
+
} catch (std::runtime_error e) {
|
869
|
+
f = 0; // raise exception below
|
870
|
+
}
|
837
871
|
if (!f) {
|
838
872
|
char *err = strerror (errno);
|
839
873
|
char buf[100];
|
@@ -1271,6 +1305,8 @@ extern "C" void Init_rubyeventmachine()
|
|
1271
1305
|
rb_define_module_function (EmModule, "set_timer_quantum", (VALUE(*)(...))t_set_timer_quantum, 1);
|
1272
1306
|
rb_define_module_function (EmModule, "get_max_timer_count", (VALUE(*)(...))t_get_max_timer_count, 0);
|
1273
1307
|
rb_define_module_function (EmModule, "set_max_timer_count", (VALUE(*)(...))t_set_max_timer_count, 1);
|
1308
|
+
rb_define_module_function (EmModule, "get_simultaneous_accept_count", (VALUE(*)(...))t_get_simultaneous_accept_count, 0);
|
1309
|
+
rb_define_module_function (EmModule, "set_simultaneous_accept_count", (VALUE(*)(...))t_set_simultaneous_accept_count, 1);
|
1274
1310
|
rb_define_module_function (EmModule, "setuid_string", (VALUE(*)(...))t_setuid_string, 1);
|
1275
1311
|
rb_define_module_function (EmModule, "invoke_popen", (VALUE(*)(...))t_invoke_popen, 1);
|
1276
1312
|
rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2);
|
data/ext/ssl.cpp
CHANGED
@@ -400,13 +400,16 @@ int SslBox_t::PutPlaintext (const char *buf, int bufsize)
|
|
400
400
|
|
401
401
|
bool fatal = false;
|
402
402
|
bool did_work = false;
|
403
|
+
int pending = BIO_pending(pbioWrite);
|
403
404
|
|
404
|
-
while (OutboundQ.HasPages()) {
|
405
|
+
while (OutboundQ.HasPages() && pending < SSLBOX_WRITE_BUFFER_SIZE) {
|
405
406
|
const char *page;
|
406
407
|
int length;
|
407
408
|
OutboundQ.Front (&page, &length);
|
408
409
|
assert (page && (length > 0));
|
409
410
|
int n = SSL_write (pSSL, page, length);
|
411
|
+
pending = BIO_pending(pbioWrite);
|
412
|
+
|
410
413
|
if (n > 0) {
|
411
414
|
did_work = true;
|
412
415
|
OutboundQ.PopFront();
|
data/ext/ssl.h
CHANGED
@@ -73,7 +73,14 @@ public abstract class EventableChannel<OutboundPacketType> {
|
|
73
73
|
|
74
74
|
public void setCommInactivityTimeout (long seconds) {
|
75
75
|
// TODO
|
76
|
-
|
76
|
+
/**
|
77
|
+
* A proper fix will require implementing a heartbeat in
|
78
|
+
* the java reactor similar to the one used for connect
|
79
|
+
* timeouts in the c++ reactor. You could also emulate
|
80
|
+
* it with timers in the jeventmachine.rb wrapper.
|
81
|
+
*
|
82
|
+
* https://github.com/igrigorik/em-http-request/issues/85
|
83
|
+
*/
|
77
84
|
}
|
78
85
|
|
79
86
|
public abstract Object[] getPeerName();
|
data/lib/em/buftok.rb
CHANGED
@@ -1,110 +1,59 @@
|
|
1
1
|
# BufferedTokenizer takes a delimiter upon instantiation, or acts line-based
|
2
2
|
# by default. It allows input to be spoon-fed from some outside source which
|
3
3
|
# receives arbitrary length datagrams which may-or-may-not contain the token
|
4
|
-
# by which entities are delimited.
|
5
|
-
#
|
6
|
-
# By default, new BufferedTokenizers will operate on lines delimited by "\n" by default
|
7
|
-
# or allow you to specify any delimiter token you so choose, which will then
|
8
|
-
# be used by String#split to tokenize the input data
|
9
|
-
#
|
10
|
-
# @example Using BufferedTokernizer to parse lines out of incoming data
|
11
|
-
#
|
12
|
-
# module LineBufferedConnection
|
13
|
-
# def receive_data(data)
|
14
|
-
# (@buffer ||= BufferedTokenizer.new).extract(data).each do |line|
|
15
|
-
# receive_line(line)
|
16
|
-
# end
|
17
|
-
# end
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# @author Tony Arcieri
|
21
|
-
# @author Martin Emde
|
4
|
+
# by which entities are delimited. In this respect it's ideally paired with
|
5
|
+
# something like EventMachine (http://rubyeventmachine.com/).
|
22
6
|
class BufferedTokenizer
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# number of objects required for the operation.
|
7
|
+
# New BufferedTokenizers will operate on lines delimited by a delimiter,
|
8
|
+
# which is by default the global input delimiter $/ ("\n").
|
9
|
+
#
|
10
|
+
# The input buffer is stored as an array. This is by far the most efficient
|
11
|
+
# approach given language constraints (in C a linked list would be a more
|
12
|
+
# appropriate data structure). Segments of input data are stored in a list
|
13
|
+
# which is only joined when a token is reached, substantially reducing the
|
14
|
+
# number of objects required for the operation.
|
15
|
+
def initialize(delimiter = $/)
|
16
|
+
@delimiter = delimiter
|
34
17
|
@input = []
|
35
|
-
|
36
|
-
|
37
|
-
@input_size = 0
|
18
|
+
@tail = ''
|
19
|
+
@trim = @delimiter.length - 1
|
38
20
|
end
|
39
21
|
|
40
22
|
# Extract takes an arbitrary string of input data and returns an array of
|
41
|
-
# tokenized entities, provided there were any available to extract.
|
42
|
-
#
|
43
|
-
# @example
|
23
|
+
# tokenized entities, provided there were any available to extract. This
|
24
|
+
# makes for easy processing of datagrams using a pattern like:
|
44
25
|
#
|
45
|
-
# tokenizer.extract(data).
|
46
|
-
# map { |entity| Decode(entity) }.each { ... }
|
26
|
+
# tokenizer.extract(data).map { |entity| Decode(entity) }.each do ...
|
47
27
|
#
|
48
|
-
#
|
28
|
+
# Using -1 makes split to return "" if the token is at the end of
|
29
|
+
# the string, meaning the last element is the start of the next chunk.
|
49
30
|
def extract(data)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# input buffer or not (i.e. a literal edge case) Specifying -1 forces split to
|
54
|
-
# return "" in this case, meaning that the last entry in the list represents a
|
55
|
-
# new segment of data where the token has not been encountered
|
56
|
-
entities = data.split @delimiter, -1
|
57
|
-
|
58
|
-
# Check to see if the buffer has exceeded capacity, if we're imposing a limit
|
59
|
-
if @size_limit
|
60
|
-
raise 'input buffer full' if @input_size + entities.first.size > @size_limit
|
61
|
-
@input_size += entities.first.size
|
31
|
+
if @trim > 0
|
32
|
+
tail_end = @tail.slice!(-@trim, @trim) # returns nil if string is too short
|
33
|
+
data = tail_end + data if tail_end
|
62
34
|
end
|
63
35
|
|
64
|
-
|
65
|
-
|
66
|
-
@
|
67
|
-
|
68
|
-
# If the resulting array from the split is empty, the token was not encountered
|
69
|
-
# (not even at the end of the buffer). Since we've encountered no token-delimited
|
70
|
-
# entities this go-around, return an empty array.
|
71
|
-
return [] if entities.empty?
|
72
|
-
|
73
|
-
# At this point, we've hit a token, or potentially multiple tokens. Now we can bring
|
74
|
-
# together all the data we've buffered from earlier calls without hitting a token,
|
75
|
-
# and add it to our list of discovered entities.
|
76
|
-
entities.unshift @input.join
|
36
|
+
@input << @tail
|
37
|
+
entities = data.split(@delimiter, -1)
|
38
|
+
@tail = entities.shift
|
77
39
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# passed to split. It represents the beginning of a new list of as-yet-untokenized
|
85
|
-
# data, so we add it to the start of the list.
|
86
|
-
@input << entities.pop
|
87
|
-
|
88
|
-
# Set the new input buffer size, provided we're keeping track
|
89
|
-
@input_size = @input.first.size if @size_limit
|
40
|
+
unless entities.empty?
|
41
|
+
@input << @tail
|
42
|
+
entities.unshift @input.join
|
43
|
+
@input.clear
|
44
|
+
@tail = entities.pop
|
45
|
+
end
|
90
46
|
|
91
|
-
# Now we're left with the list of extracted token-delimited entities we wanted
|
92
|
-
# in the first place. Hooray!
|
93
47
|
entities
|
94
48
|
end
|
95
49
|
|
96
50
|
# Flush the contents of the input buffer, i.e. return the input buffer even though
|
97
|
-
# a token has not yet been encountered
|
98
|
-
#
|
99
|
-
# @return [String]
|
51
|
+
# a token has not yet been encountered
|
100
52
|
def flush
|
53
|
+
@input << @tail
|
101
54
|
buffer = @input.join
|
102
55
|
@input.clear
|
56
|
+
@tail = "" # @tail.clear is slightly faster, but not supported on 1.8.7
|
103
57
|
buffer
|
104
58
|
end
|
105
|
-
|
106
|
-
# @return [Boolean]
|
107
|
-
def empty?
|
108
|
-
@input.empty?
|
109
|
-
end
|
110
59
|
end
|
@@ -23,8 +23,6 @@
|
|
23
23
|
#
|
24
24
|
#
|
25
25
|
|
26
|
-
|
27
|
-
|
28
26
|
module EventMachine
|
29
27
|
module Protocols
|
30
28
|
|
@@ -52,7 +50,6 @@ module EventMachine
|
|
52
50
|
# DNS: Some way to cache DNS lookups for hostnames we connect to. Ruby's
|
53
51
|
# DNS lookups are unbelievably slow.
|
54
52
|
# HEAD requests.
|
55
|
-
# Chunked transfer encoding.
|
56
53
|
# Convenience methods for requests. get, post, url, etc.
|
57
54
|
# SSL.
|
58
55
|
# Handle status codes like 304, 100, etc.
|
@@ -184,6 +181,8 @@ module EventMachine
|
|
184
181
|
@content_length = nil # not zero
|
185
182
|
@content = ""
|
186
183
|
@status = nil
|
184
|
+
@chunked = false
|
185
|
+
@chunk_length = nil
|
187
186
|
@read_state = :header
|
188
187
|
@connection_close = nil
|
189
188
|
when :header
|
@@ -191,7 +190,7 @@ module EventMachine
|
|
191
190
|
if ary.length == 2
|
192
191
|
data = ary.last
|
193
192
|
if ary.first == ""
|
194
|
-
if (@content_length and @content_length > 0) || @connection_close
|
193
|
+
if (@content_length and @content_length > 0) || @chunked || @connection_close
|
195
194
|
@read_state = :content
|
196
195
|
else
|
197
196
|
dispatch_response
|
@@ -211,6 +210,8 @@ module EventMachine
|
|
211
210
|
@content_length ||= $'.to_i
|
212
211
|
elsif ary.first =~ /\Aconnection:\s*close/i
|
213
212
|
@connection_close = true
|
213
|
+
elsif ary.first =~ /\Atransfer-encoding:\s*chunked/i
|
214
|
+
@chunked = true
|
214
215
|
end
|
215
216
|
end
|
216
217
|
else
|
@@ -218,12 +219,32 @@ module EventMachine
|
|
218
219
|
data = ""
|
219
220
|
end
|
220
221
|
when :content
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
222
|
+
if @chunked && @chunk_length
|
223
|
+
bytes_needed = @chunk_length - @chunk_read
|
224
|
+
new_data = data[0, bytes_needed]
|
225
|
+
@chunk_read += new_data.length
|
226
|
+
@content += new_data
|
227
|
+
data = data[bytes_needed..-1] || ""
|
228
|
+
if @chunk_length == @chunk_read && data[0,2] == "\r\n"
|
229
|
+
@chunk_length = nil
|
230
|
+
data = data[2..-1]
|
231
|
+
end
|
232
|
+
elsif @chunked
|
233
|
+
if (m = data.match(/\A(\S*)\r\n/m))
|
234
|
+
data = data[m[0].length..-1]
|
235
|
+
@chunk_length = m[1].to_i(16)
|
236
|
+
@chunk_read = 0
|
237
|
+
if @chunk_length == 0
|
238
|
+
dispatch_response
|
239
|
+
@read_state = :base
|
240
|
+
end
|
241
|
+
end
|
242
|
+
elsif @content_length
|
243
|
+
# If there was no content-length header, we have to wait until the connection
|
244
|
+
# closes. Everything we get until that point is content.
|
245
|
+
# TODO: Must impose a content-size limit, and also must implement chunking.
|
246
|
+
# Also, must support either temporary files for large content, or calling
|
247
|
+
# a content-consumer block supplied by the user.
|
227
248
|
bytes_needed = @content_length - @content.length
|
228
249
|
@content += data[0, bytes_needed]
|
229
250
|
data = data[bytes_needed..-1] || ""
|
@@ -274,6 +295,5 @@ module EventMachine
|
|
274
295
|
end
|
275
296
|
end
|
276
297
|
end
|
277
|
-
|
278
298
|
end
|
279
299
|
end
|
@@ -32,7 +32,6 @@ module EventMachine
|
|
32
32
|
# for a version which is optimized for correctness with regard to binary text blocks
|
33
33
|
# that can switch back to line mode.
|
34
34
|
class LineAndTextProtocol < Connection
|
35
|
-
MaxLineLength = 16*1024
|
36
35
|
MaxBinaryLength = 32*1024*1024
|
37
36
|
|
38
37
|
def initialize *args
|
@@ -42,7 +41,7 @@ module EventMachine
|
|
42
41
|
def receive_data data
|
43
42
|
if @lbp_mode == :lines
|
44
43
|
begin
|
45
|
-
@lpb_buffer.extract(data).each do |line|
|
44
|
+
@lpb_buffer.extract(data).each do |line|
|
46
45
|
receive_line(line.chomp) if respond_to?(:receive_line)
|
47
46
|
end
|
48
47
|
rescue Exception
|
@@ -116,7 +115,7 @@ module EventMachine
|
|
116
115
|
#--
|
117
116
|
# For internal use, establish protocol baseline for handling lines.
|
118
117
|
def lbp_init_line_state
|
119
|
-
@lpb_buffer = BufferedTokenizer.new("\n"
|
118
|
+
@lpb_buffer = BufferedTokenizer.new("\n")
|
120
119
|
@lbp_mode = :lines
|
121
120
|
end
|
122
121
|
private :lbp_init_line_state
|