evdispatch 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +3 -0
- data/ext/revdispatch/extconf.rb +12 -18
- data/ext/revdispatch/libdispatch-0.1/Makefile.in +76 -62
- data/ext/revdispatch/libdispatch-0.1/aclocal.m4 +94 -82
- data/ext/revdispatch/libdispatch-0.1/configure +4065 -3519
- data/ext/revdispatch/libdispatch-0.1/configure.ac +5 -2
- data/ext/revdispatch/libdispatch-0.1/libev-3.31/Makefile.in +233 -172
- data/ext/revdispatch/libdispatch-0.1/libev-3.31/aclocal.m4 +6412 -6387
- data/ext/revdispatch/libdispatch-0.1/libev-3.31/configure +249 -134
- data/ext/revdispatch/libdispatch-0.1/src/Makefile.in +73 -60
- data/ext/revdispatch/libdispatch-0.1/src/ev_dispatch.cc +1 -1
- data/ext/revdispatch/libdispatch-0.1/src/ev_http.cc +1 -1
- data/ext/revdispatch/libdispatch-0.1/test/Makefile.in +114 -85
- data/ext/revdispatch/revdispatch.cc +136 -40
- data/ext/revdispatch/rhttp.cc +60 -0
- data/ext/revdispatch/rhttp.h +30 -0
- data/ext/revdispatch/stest.rb +47 -20
- data/ext/revdispatch/util.h +26 -0
- data/lib/evdispatch/version.rb +2 -2
- data/test/test_evdispatch.rb +30 -1
- data/website/index.html +8 -2
- data/website/index.txt +7 -1
- metadata +5 -2
@@ -1,15 +1,5 @@
|
|
1
|
-
#include
|
2
|
-
#include "
|
3
|
-
#include "ev_http.h"
|
4
|
-
|
5
|
-
/* ruby 1.9 compat */
|
6
|
-
#ifndef RSTRING_PTR
|
7
|
-
#define RSTRING_PTR(str) RSTRING(str)->ptr
|
8
|
-
#endif
|
9
|
-
|
10
|
-
#ifndef RSTRING_LEN
|
11
|
-
#define RSTRING_LEN(str) RSTRING(str)->len
|
12
|
-
#endif
|
1
|
+
#include "util.h"
|
2
|
+
#include "rhttp.h"
|
13
3
|
|
14
4
|
|
15
5
|
/*
|
@@ -47,6 +37,9 @@
|
|
47
37
|
*/
|
48
38
|
static VALUE rb_Evdispatch;
|
49
39
|
static VALUE rb_Loop;
|
40
|
+
static VALUE rb_Response;
|
41
|
+
|
42
|
+
static void Response_free( rResponse *res );
|
50
43
|
|
51
44
|
/**
|
52
45
|
* call-seq:
|
@@ -77,6 +70,8 @@ VALUE Loop_request_http( VALUE self, VALUE url )
|
|
77
70
|
EVD::Dispatch *d;
|
78
71
|
Data_Get_Struct( self, EVD::Dispatch, d );
|
79
72
|
|
73
|
+
Check_Type( url, T_STRING );
|
74
|
+
|
80
75
|
EVD::request_t id = d->request( new EVD::HttpRequest( *d, RSTRING_PTR(url) ) );
|
81
76
|
|
82
77
|
return rb_int_new(id);
|
@@ -98,6 +93,16 @@ VALUE Loop_request_http( VALUE self, VALUE url )
|
|
98
93
|
req->set_opt(name, RSTRING_PTR(obj));\
|
99
94
|
}\
|
100
95
|
}
|
96
|
+
// set options
|
97
|
+
#define SET_REQ_OPTS \
|
98
|
+
SET_LONG_VAL("port"); \
|
99
|
+
SET_STR_VAL("autoreferer"); \
|
100
|
+
SET_LONG_VAL("followlocation"); \
|
101
|
+
SET_LONG_VAL("maxredirs"); \
|
102
|
+
SET_STR_VAL("referer"); \
|
103
|
+
SET_STR_VAL("useragent"); \
|
104
|
+
SET_STR_VAL("cookie"); \
|
105
|
+
SET_STR_VAL("post");
|
101
106
|
|
102
107
|
/**
|
103
108
|
* call-seq:
|
@@ -107,20 +112,21 @@ VALUE Loop_request_http( VALUE self, VALUE url )
|
|
107
112
|
*
|
108
113
|
* options ( from libcurl ):
|
109
114
|
*
|
110
|
-
* :port: port to connect to host with
|
111
|
-
* :autoreferer: Pass a non-zero parameter to enable this. When enabled, libcurl will automatically set the Referer: field in requests where it follows a Location: redirect.
|
112
|
-
* :followlocation: A non-zero parameter tells the library to follow any Location: header that the server sends as part of an HTTP header.
|
115
|
+
* :port: (Fixnum) port to connect to host with
|
116
|
+
* :autoreferer: (Fixnum) Pass a non-zero parameter to enable this. When enabled, libcurl will automatically set the Referer: field in requests where it follows a Location: redirect.
|
117
|
+
* :followlocation: (Fixnum) A non-zero parameter tells the library to follow any Location: header that the server sends as part of an HTTP header.
|
113
118
|
* This means that the library will re-send the same request on the new location and follow new Location: headers all the way until no more such headers are returned. 'maxredirs' can be used to limit the number of redirects libcurl will follow.
|
114
|
-
* :maxredirs: Pass a long. The set number will be the redirection limit. If that many redirections have been followed, the next redirect will cause an error (CURLE_TOO_MANY_REDIRECTS). This option only makes sense if the CURLOPT_FOLLOWLOCATION is used at the same time. Added in 7.15.1: Setting the limit to 0 will make libcurl refuse any redirect. Set it to -1 for an infinite number of redirects (which is the default)
|
115
|
-
* :referer: Pass a pointer to a zero terminated string as parameter. It will be used to set the Referer: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
|
116
|
-
* :useragent: Pass a pointer to a zero terminated string as parameter. It will be used to set the User-Agent: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
|
117
|
-
* :cookie: Pass a pointer to a zero terminated string as parameter. It will be used to set a cookie in the http request. The format of the string should be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
|
119
|
+
* :maxredirs: (Fixnum) Pass a long. The set number will be the redirection limit. If that many redirections have been followed, the next redirect will cause an error (CURLE_TOO_MANY_REDIRECTS). This option only makes sense if the CURLOPT_FOLLOWLOCATION is used at the same time. Added in 7.15.1: Setting the limit to 0 will make libcurl refuse any redirect. Set it to -1 for an infinite number of redirects (which is the default)
|
120
|
+
* :referer: (String) Pass a pointer to a zero terminated string as parameter. It will be used to set the Referer: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
|
121
|
+
* :useragent: (String) Pass a pointer to a zero terminated string as parameter. It will be used to set the User-Agent: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
|
122
|
+
* :cookie: (String) Pass a pointer to a zero terminated string as parameter. It will be used to set a cookie in the http request. The format of the string should be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
|
118
123
|
* If you need to set multiple cookies, you need to set them all using a single option and thus you need to concatenate them all in one single string. Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
|
119
124
|
* Note that this option sets the cookie header explictly in the outgoing request(s). If multiple requests are done due to authentication, followed redirections or similar, they will all get this cookie passed on.
|
120
125
|
* Using this option multiple times will only make the latest string override the previous ones.
|
121
126
|
*
|
122
|
-
* :post: Pass a string and sets CURLOPT_POST, CURLOPT_POSTFIELDSIZE, and CURLOPT_COPYPOSTFIELDS
|
127
|
+
* :post: (String) Pass a string and sets CURLOPT_POST, CURLOPT_POSTFIELDSIZE, and CURLOPT_COPYPOSTFIELDS
|
123
128
|
*
|
129
|
+
* :stream: (Evdispatch::Response) Send the response to the IO object. Ignore the response id returned it'd invalid
|
124
130
|
*/
|
125
131
|
static
|
126
132
|
VALUE Loop_request( int argc, VALUE *argv, VALUE self )
|
@@ -137,19 +143,34 @@ VALUE Loop_request( int argc, VALUE *argv, VALUE self )
|
|
137
143
|
options = rb_hash_new();
|
138
144
|
}
|
139
145
|
|
140
|
-
|
146
|
+
Check_Type(url, T_STRING );
|
147
|
+
Check_Type(options, T_HASH );
|
141
148
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
SET_STR_VAL("referer");
|
148
|
-
SET_STR_VAL("useragent");
|
149
|
-
SET_STR_VAL("cookie");
|
150
|
-
SET_STR_VAL("post");
|
149
|
+
VALUE response = rb_hash_aref( options, ID2SYM(rb_intern("stream")) );
|
150
|
+
if( !NIL_P(response) && TYPE(response) == T_TRUE ) {
|
151
|
+
|
152
|
+
rResponse *res = new rResponse;
|
153
|
+
VALUE response_object = Data_Wrap_Struct( rb_Response, NULL, Response_free, res );
|
151
154
|
|
152
|
-
|
155
|
+
if( !res->init() ) {
|
156
|
+
rb_raise(rb_eIOError, "Failed to create new pipe");
|
157
|
+
}
|
158
|
+
|
159
|
+
EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url), res->m_pipe[1] );
|
160
|
+
|
161
|
+
SET_REQ_OPTS
|
162
|
+
|
163
|
+
res->m_response = req->m_response;
|
164
|
+
|
165
|
+
d->request(req);
|
166
|
+
return response_object;
|
167
|
+
}
|
168
|
+
else {
|
169
|
+
EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url) );
|
170
|
+
SET_REQ_OPTS
|
171
|
+
|
172
|
+
return rb_int_new( d->request(req) );
|
173
|
+
}
|
153
174
|
}
|
154
175
|
|
155
176
|
static
|
@@ -160,6 +181,10 @@ VALUE Loop_wait_for_response( VALUE self, VALUE id, VALUE timeout_seconds, VALUE
|
|
160
181
|
EVD::request_t rid = FIX2LONG(id);
|
161
182
|
|
162
183
|
Data_Get_Struct( self, EVD::Dispatch, d );
|
184
|
+
|
185
|
+
Check_Type( id, T_FIXNUM );
|
186
|
+
Check_Type( timeout_seconds, T_FIXNUM );
|
187
|
+
Check_Type( timeout_mseconds, T_FIXNUM );
|
163
188
|
|
164
189
|
long seconds = FIX2LONG(timeout_seconds);
|
165
190
|
long nanoseconds = FIX2LONG(timeout_mseconds)*1000*1000;
|
@@ -175,6 +200,7 @@ VALUE Loop_response_for( VALUE self, VALUE id )
|
|
175
200
|
{
|
176
201
|
EVD::Dispatch *d;
|
177
202
|
Data_Get_Struct( self, EVD::Dispatch, d );
|
203
|
+
Check_Type( id, T_FIXNUM );
|
178
204
|
|
179
205
|
EVD::HttpResponse *res = NULL;
|
180
206
|
EVD::request_t rid = FIX2LONG(id);
|
@@ -209,6 +235,8 @@ VALUE Loop_blocking_response_for( int argc, VALUE *argv, VALUE self )
|
|
209
235
|
options = rb_hash_new();
|
210
236
|
rb_hash_aset( options, ID2SYM(rb_intern("timeout")), rb_float_new( 2.0 ) );
|
211
237
|
}
|
238
|
+
Check_Type( req_id, T_FIXNUM );
|
239
|
+
Check_Type( options, T_HASH );
|
212
240
|
|
213
241
|
EVD::request_t id = FIX2LONG(req_id);
|
214
242
|
VALUE timeout_value = rb_hash_aref( options, ID2SYM(rb_intern("timeout")) );
|
@@ -269,7 +297,6 @@ VALUE Loop_stop( VALUE self )
|
|
269
297
|
static
|
270
298
|
void Loop_free( EVD::Dispatch *d )
|
271
299
|
{
|
272
|
-
fprintf(stderr,"Freeing loop\n");
|
273
300
|
delete d;
|
274
301
|
}
|
275
302
|
|
@@ -284,6 +311,65 @@ VALUE Loop_alloc(VALUE klass)
|
|
284
311
|
return object;
|
285
312
|
}
|
286
313
|
|
314
|
+
static
|
315
|
+
void Response_free( rResponse *res )
|
316
|
+
{
|
317
|
+
delete res;
|
318
|
+
}
|
319
|
+
|
320
|
+
static
|
321
|
+
VALUE Response_alloc(VALUE klass)
|
322
|
+
{
|
323
|
+
VALUE object;
|
324
|
+
|
325
|
+
rResponse *res = new rResponse;
|
326
|
+
object = Data_Wrap_Struct( klass, NULL, Response_free, res );
|
327
|
+
|
328
|
+
return object;
|
329
|
+
}
|
330
|
+
|
331
|
+
/*
|
332
|
+
This code might be interesting later if we decide to wire in direct writing to a Ruby socket or file
|
333
|
+
const char *klass_name = rb_class2name(CLASS_OF(stream));
|
334
|
+
if( !strcmp("IO", klass_name) || !strcmp("Socket", klass_name) || !strcmp("File", klass_name) ) {
|
335
|
+
RFile *fstream = RFILE(stream);
|
336
|
+
struct OpenFile *fptr = fstream->fptr;
|
337
|
+
FILE *file = fptr->f;
|
338
|
+
int fd = fileno(file);
|
339
|
+
write(fd,"hi",2);
|
340
|
+
}*/
|
341
|
+
|
342
|
+
static
|
343
|
+
VALUE Response_read( VALUE self )
|
344
|
+
{
|
345
|
+
rResponse *res;
|
346
|
+
Data_Get_Struct( self, rResponse, res );
|
347
|
+
|
348
|
+
int status = res->read_body_partial();
|
349
|
+
|
350
|
+
if( status == -1 ) {
|
351
|
+
rb_raise(rb_eIOError, "Failed to read pipe");
|
352
|
+
}
|
353
|
+
|
354
|
+
return rb_int_new(status);
|
355
|
+
}
|
356
|
+
|
357
|
+
static
|
358
|
+
VALUE Response_body( VALUE self )
|
359
|
+
{
|
360
|
+
rResponse *res;
|
361
|
+
Data_Get_Struct( self, rResponse, res );
|
362
|
+
return rb_str_new(res->m_buffer.c_str(), res->m_buffer.length());
|
363
|
+
}
|
364
|
+
|
365
|
+
static
|
366
|
+
VALUE Response_headers( VALUE self )
|
367
|
+
{
|
368
|
+
rResponse *res;
|
369
|
+
Data_Get_Struct( self, rResponse, res );
|
370
|
+
return rb_str_new(res->m_response->m_header.c_str(), res->m_response->m_header.length() );
|
371
|
+
}
|
372
|
+
|
287
373
|
extern "C" void Init_revdispatch()
|
288
374
|
{
|
289
375
|
rb_Evdispatch = rb_define_module( "Evdispatch" );
|
@@ -292,12 +378,22 @@ extern "C" void Init_revdispatch()
|
|
292
378
|
// setup the Loop object
|
293
379
|
rb_define_alloc_func( rb_Loop, Loop_alloc );
|
294
380
|
|
295
|
-
rb_define_method( rb_Loop, "start",
|
296
|
-
rb_define_method( rb_Loop, "request_http",
|
297
|
-
rb_define_method( rb_Loop, "request",
|
298
|
-
rb_define_method( rb_Loop, "flush",
|
299
|
-
rb_define_method( rb_Loop, "blocking_response_for", (
|
300
|
-
rb_define_method( rb_Loop, "response_for",
|
301
|
-
rb_define_method( rb_Loop, "wait_for_response",
|
302
|
-
rb_define_method( rb_Loop, "stop",
|
381
|
+
rb_define_method( rb_Loop, "start", RB_METHOD(Loop_start), 0 );
|
382
|
+
rb_define_method( rb_Loop, "request_http", RB_METHOD(Loop_request_http), 1 );
|
383
|
+
rb_define_method( rb_Loop, "request", RB_METHOD(Loop_request), -1 );
|
384
|
+
rb_define_method( rb_Loop, "flush", RB_METHOD(Loop_flush), 0 );
|
385
|
+
rb_define_method( rb_Loop, "blocking_response_for", RB_METHOD(Loop_blocking_response_for), -1 );
|
386
|
+
rb_define_method( rb_Loop, "response_for", RB_METHOD(Loop_response_for), 1 );
|
387
|
+
rb_define_method( rb_Loop, "wait_for_response", RB_METHOD(Loop_wait_for_response), 3 );
|
388
|
+
rb_define_method( rb_Loop, "stop", RB_METHOD(Loop_stop), 0 );
|
389
|
+
|
390
|
+
// define the response object
|
391
|
+
rb_Response = rb_define_class_under( rb_Evdispatch, "Response", rb_cObject );
|
392
|
+
|
393
|
+
// setup the Response object
|
394
|
+
rb_define_alloc_func( rb_Response, Response_alloc );
|
395
|
+
|
396
|
+
rb_define_method( rb_Response, "read", RB_METHOD(Response_read), 0 );
|
397
|
+
rb_define_method( rb_Response, "body", RB_METHOD(Response_body), 0 );
|
398
|
+
rb_define_method( rb_Response, "headers", RB_METHOD(Response_headers), 0 );
|
303
399
|
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#include "util.h"
|
2
|
+
|
3
|
+
rResponse::rResponse()
|
4
|
+
: has_headers(false), m_response(NULL), m_use_pipe(false)
|
5
|
+
{
|
6
|
+
}
|
7
|
+
|
8
|
+
rResponse::~rResponse()
|
9
|
+
{
|
10
|
+
if( m_use_pipe) close(m_pipe[0]);
|
11
|
+
if( m_response ) delete m_response;
|
12
|
+
}
|
13
|
+
|
14
|
+
bool rResponse::init()
|
15
|
+
{
|
16
|
+
if( pipe(m_pipe) ) { perror("pipe"); return false; }
|
17
|
+
m_use_pipe = true;
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
|
21
|
+
static const int READ_SIZE = 1024;
|
22
|
+
static char READ_BUFFER[READ_SIZE];
|
23
|
+
|
24
|
+
int rResponse::read_body_partial()
|
25
|
+
{
|
26
|
+
int fd = m_pipe[0];
|
27
|
+
fd_set rd;
|
28
|
+
struct timeval tv;
|
29
|
+
|
30
|
+
tv.tv_sec = 1;
|
31
|
+
tv.tv_usec = 0; //1000000; // timeout within a 10th of a second
|
32
|
+
memset(READ_BUFFER, '\0', READ_SIZE);
|
33
|
+
|
34
|
+
FD_ZERO(&rd);
|
35
|
+
FD_SET(fd, &rd);
|
36
|
+
|
37
|
+
int retval = select( (fd+1), &rd, NULL, NULL, &tv );
|
38
|
+
|
39
|
+
if( retval == 0 ) { printf("select timedout\n"); return 1; } // timeout
|
40
|
+
if( retval == -1 && errno == EINTR ) { return 1; } // not ready yet
|
41
|
+
if( retval < 0 ){ perror("select"); return -1; } // something went wrong
|
42
|
+
|
43
|
+
if( FD_ISSET(fd, &rd) ) {
|
44
|
+
retval = read(fd,READ_BUFFER,READ_SIZE);
|
45
|
+
if( retval >= 0 ) {
|
46
|
+
// write to the string
|
47
|
+
m_buffer.append(READ_BUFFER, retval);
|
48
|
+
if( retval == 0 ) {
|
49
|
+
FD_CLR(fd,&rd); // remove the file descriptor
|
50
|
+
}
|
51
|
+
return retval;
|
52
|
+
}
|
53
|
+
else {
|
54
|
+
perror("read");
|
55
|
+
return -1;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
return 0;
|
60
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#ifndef RUBY_EV_HTTP_H
|
2
|
+
#define RUBY_EV_HTTP_H
|
3
|
+
|
4
|
+
#include <string>
|
5
|
+
#include "ev_dispatch.h"
|
6
|
+
#include "ev_http.h"
|
7
|
+
|
8
|
+
struct rResponse {
|
9
|
+
rResponse();
|
10
|
+
~rResponse();
|
11
|
+
|
12
|
+
volatile bool has_headers;
|
13
|
+
|
14
|
+
// return values
|
15
|
+
// 1: read again
|
16
|
+
// 0: finished
|
17
|
+
// -1: error
|
18
|
+
int read_body_partial();
|
19
|
+
|
20
|
+
bool init();
|
21
|
+
|
22
|
+
EVD::HttpResponse *m_response;
|
23
|
+
int m_pipe[2]; // might use this if the IO object does not have a file descriptor
|
24
|
+
bool m_use_pipe;
|
25
|
+
|
26
|
+
std::string m_buffer;
|
27
|
+
|
28
|
+
};
|
29
|
+
|
30
|
+
#endif
|
data/ext/revdispatch/stest.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
|
3
2
|
$:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
|
4
3
|
require 'evdispatch'
|
5
4
|
|
6
|
-
$d = Evdispatch::Loop.new
|
7
|
-
# start the event loop thread
|
8
|
-
$d.start
|
9
|
-
|
10
5
|
class TestRequests < Test::Unit::TestCase
|
11
6
|
|
7
|
+
def setup
|
8
|
+
@loop = Evdispatch::Loop.new
|
9
|
+
@loop.start
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@loop.stop
|
14
|
+
end
|
15
|
+
|
16
|
+
def loop
|
17
|
+
@loop
|
18
|
+
end
|
19
|
+
|
12
20
|
def test_response
|
13
|
-
id =
|
14
|
-
response =
|
21
|
+
id = loop.request_http("http://127.0.0.1:4044/bytes/10")
|
22
|
+
response = loop.response( id )
|
15
23
|
assert_equal("http://127.0.0.1:4044/bytes/10", response[:name])
|
16
24
|
assert_equal("CCCCCCCCCC", response[:body])
|
17
25
|
assert_match(/Content-Type: text\/json/, response[:header])
|
@@ -22,29 +30,48 @@ class TestRequests < Test::Unit::TestCase
|
|
22
30
|
end
|
23
31
|
|
24
32
|
def test_options_request
|
25
|
-
id =
|
26
|
-
response =
|
33
|
+
id = loop.request("http://127.0.0.1:4044/redir/1", :followlocation => 1, :referer => 'pizza')
|
34
|
+
response = loop.response( id )
|
35
|
+
assert_not_nil( response )
|
27
36
|
assert_match(/ 302 Moved Temporarily/,response[:header])
|
28
37
|
assert_match(/ 200 OK/,response[:header])
|
29
38
|
end
|
30
39
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
res
|
35
|
-
|
36
|
-
if !res or !res2
|
37
|
-
$d.flush # flush because we aborted before we finished, still the issue of the request is still running, but any previous responses that were delayed will be flushed
|
40
|
+
def test_redir_with_stream
|
41
|
+
stream = loop.request("http://127.0.0.1:4044/redir/2", :followlocation => 1, :stream => true )
|
42
|
+
res = stream.read
|
43
|
+
until res == 0
|
44
|
+
res = stream.read
|
38
45
|
end
|
39
|
-
|
40
|
-
|
46
|
+
assert_equal( 0, res )
|
47
|
+
assert_equal( "C"*10, stream.body )
|
48
|
+
headers = stream.headers
|
49
|
+
assert_match( "Content-Length: 10", headers )
|
50
|
+
assert_match( "Content-Type: text/json", headers )
|
51
|
+
assert_match( "HTTP/1.1 200 OK", headers )
|
41
52
|
end
|
42
53
|
|
43
54
|
def test_post
|
44
|
-
id =
|
45
|
-
res =
|
55
|
+
id = loop.request("http://127.0.0.1:4044/test_post_length", :post => "hello there world")
|
56
|
+
res = loop.blocking_response_for( id )
|
46
57
|
assert_not_nil res
|
47
58
|
end
|
59
|
+
|
60
|
+
def test_streaming
|
61
|
+
count = 10000
|
62
|
+
stream = loop.request("http://127.0.0.1:4044/bytes/#{count}", :stream => true )
|
63
|
+
res = stream.read
|
64
|
+
until res == 0
|
65
|
+
res = stream.read
|
66
|
+
end
|
67
|
+
assert_equal( 0, res )
|
68
|
+
assert_equal( "C"*count, stream.body )
|
69
|
+
headers = stream.headers
|
70
|
+
assert_match( "Content-Length: #{count}", headers )
|
71
|
+
assert_match( "Content-Type: text/json", headers )
|
72
|
+
assert_match( "HTTP/1.1 200 OK", headers )
|
73
|
+
end
|
74
|
+
|
48
75
|
end
|
49
76
|
|
50
77
|
# not bothering to cleanup
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#ifndef EVD_UTIL_H
|
2
|
+
#define EVD_UTIL_H
|
3
|
+
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <errno.h>
|
6
|
+
#include <ruby.h>
|
7
|
+
#include <rubyio.h>
|
8
|
+
#include "ev_dispatch.h"
|
9
|
+
#include "ev_http.h"
|
10
|
+
#include "rhttp.h"
|
11
|
+
|
12
|
+
|
13
|
+
/* ruby 1.9 compat */
|
14
|
+
#ifndef RSTRING_PTR
|
15
|
+
#define RSTRING_PTR(str) RSTRING(str)->ptr
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#ifndef RSTRING_LEN
|
19
|
+
#define RSTRING_LEN(str) RSTRING(str)->len
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#ifndef RB_METHOD
|
23
|
+
#define RB_METHOD(f) ((VALUE (*)(...))(f))
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#endif
|
data/lib/evdispatch/version.rb
CHANGED
data/test/test_evdispatch.rb
CHANGED
@@ -2,7 +2,36 @@ require File.dirname(__FILE__) + '/test_helper.rb'
|
|
2
2
|
|
3
3
|
class TestEvdispatch < Test::Unit::TestCase
|
4
4
|
|
5
|
-
def
|
5
|
+
def test_streaming
|
6
|
+
d = Evdispatch::Loop.new
|
7
|
+
d.start
|
8
|
+
|
9
|
+
count = 10000
|
10
|
+
|
11
|
+
streams = []
|
12
|
+
# create 100 streams
|
13
|
+
100.times do|i|
|
14
|
+
stream = d.request("http://127.0.0.1:4044/bytes/#{count}", :stream => true )
|
15
|
+
streams << stream
|
16
|
+
end
|
17
|
+
|
18
|
+
# TODO: we should expose the pipe so someone can select on ready responses
|
19
|
+
for stream in streams do
|
20
|
+
res = stream.read
|
21
|
+
res = stream.read until res == 0
|
22
|
+
|
23
|
+
assert_equal( 0, res )
|
24
|
+
assert_equal( "C"*count, stream.body )
|
25
|
+
headers = stream.headers
|
26
|
+
assert_match( "Content-Length: 10000", headers )
|
27
|
+
assert_match( "Content-Type: text/json", headers )
|
28
|
+
assert_match( "HTTP/1.1 200 OK", headers )
|
29
|
+
end
|
30
|
+
|
31
|
+
d.stop
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_object_allocation
|
6
35
|
d = Evdispatch::Loop.new
|
7
36
|
|
8
37
|
# start the event loop thread
|
data/website/index.html
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
<h1>evdispatch</h1>
|
19
19
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/evdispatch"; return false'>
|
20
20
|
<p>Get Version</p>
|
21
|
-
<a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.
|
21
|
+
<a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.3.0</a>
|
22
22
|
</div>
|
23
23
|
<h4 style="float:right;padding-right:10px;">→ ‘evdispatch’</h4>
|
24
24
|
|
@@ -31,7 +31,13 @@
|
|
31
31
|
<h2>Installing</h2>
|
32
32
|
|
33
33
|
|
34
|
-
<p
|
34
|
+
<p>Download: <a href="http://curl.haxx.se/download/curl-7.18.1.tar.gz">curl-7.18.1.tar.gz</a>
|
35
|
+
<pre class='syntax'>
|
36
|
+
tar -zxf curl-7.18.1.tar.gz
|
37
|
+
cd curl-7.18.1/
|
38
|
+
./configure && make && sudo make install
|
39
|
+
sudo gem install evdispatch
|
40
|
+
</pre></p>
|
35
41
|
|
36
42
|
|
37
43
|
<h2>The basics</h2>
|
data/website/index.txt
CHANGED
@@ -9,7 +9,13 @@ A library for making HTTP requests in parallel.
|
|
9
9
|
|
10
10
|
h2. Installing
|
11
11
|
|
12
|
-
<
|
12
|
+
Download: <a href="http://curl.haxx.se/download/curl-7.18.1.tar.gz">curl-7.18.1.tar.gz</a>
|
13
|
+
<pre syntax="bash">
|
14
|
+
tar -zxf curl-7.18.1.tar.gz
|
15
|
+
cd curl-7.18.1/
|
16
|
+
./configure && make && sudo make install
|
17
|
+
sudo gem install evdispatch
|
18
|
+
</pre>
|
13
19
|
|
14
20
|
h2. The basics
|
15
21
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evdispatch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd A. Fisher
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-04-
|
12
|
+
date: 2008-04-22 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -61,6 +61,9 @@ files:
|
|
61
61
|
- ext/revdispatch/stest.rb
|
62
62
|
- ext/revdispatch/extconf.rb
|
63
63
|
- ext/revdispatch/revdispatch.cc
|
64
|
+
- ext/revdispatch/rhttp.cc
|
65
|
+
- ext/revdispatch/rhttp.h
|
66
|
+
- ext/revdispatch/util.h
|
64
67
|
- ext/revdispatch/libdispatch-0.1/
|
65
68
|
- ext/revdispatch/libdispatch-0.1/src/
|
66
69
|
- ext/revdispatch/libdispatch-0.1/test/
|