astro-em-http-request 0.2.8 → 0.2.9
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/Rakefile +1 -1
- data/VERSION +1 -1
- data/astro-em-http-request.gemspec +11 -12
- data/ext/buffer/em_buffer.c +74 -65
- data/lib/em-http-request.rb +1 -0
- data/lib/em-http/client.rb +9 -5
- data/lib/em-http/mock.rb +31 -12
- data/lib/em-http/multi.rb +3 -3
- data/lib/em-http/request.rb +4 -4
- data/lib/em_buffer.so +0 -0
- data/lib/http11_client.so +0 -0
- data/spec/mock_spec.rb +33 -4
- data/spec/multi_spec.rb +24 -2
- data/spec/request_spec.rb +3 -3
- metadata +9 -17
- data/test/another_test.rb +0 -21
data/Rakefile
CHANGED
@@ -92,9 +92,9 @@ begin
|
|
92
92
|
gemspec.email = "ilya@igvita.com"
|
93
93
|
gemspec.homepage = "http://github.com/igrigorik/em-http-request"
|
94
94
|
gemspec.authors = ["Ilya Grigorik", "Stephan Maka", "Julien Genestoux"]
|
95
|
+
gemspec.required_ruby_version = ">= 1.8.7"
|
95
96
|
gemspec.extensions = ["ext/buffer/extconf.rb" , "ext/http11_client/extconf.rb"]
|
96
97
|
gemspec.add_dependency('eventmachine', '>= 0.12.9')
|
97
|
-
gemspec.add_dependency('addressable', '>= 2.0.0')
|
98
98
|
gemspec.rubyforge_project = "astro-em-http-request"
|
99
99
|
gemspec.files = FileList[`git ls-files`.split]
|
100
100
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.9
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{astro-em-http-request}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ilya Grigorik", "Stephan Maka", "Julien Genestoux"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-04-07}
|
13
13
|
s.description = %q{EventMachine based, async HTTP Request interface}
|
14
14
|
s.email = %q{ilya@igvita.com}
|
15
15
|
s.extensions = ["ext/buffer/extconf.rb", "ext/http11_client/extconf.rb"]
|
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
"ext/http11_client/http11_parser.c",
|
36
36
|
"ext/http11_client/http11_parser.h",
|
37
37
|
"ext/http11_client/http11_parser.rl",
|
38
|
+
"lib/em-http-request.rb",
|
38
39
|
"lib/em-http.rb",
|
39
40
|
"lib/em-http/client.rb",
|
40
41
|
"lib/em-http/core_ext/hash.rb",
|
@@ -42,6 +43,8 @@ Gem::Specification.new do |s|
|
|
42
43
|
"lib/em-http/mock.rb",
|
43
44
|
"lib/em-http/multi.rb",
|
44
45
|
"lib/em-http/request.rb",
|
46
|
+
"lib/em_buffer.so",
|
47
|
+
"lib/http11_client.so",
|
45
48
|
"spec/fixtures/google.ca",
|
46
49
|
"spec/hash_spec.rb",
|
47
50
|
"spec/helper.rb",
|
@@ -54,20 +57,20 @@ Gem::Specification.new do |s|
|
|
54
57
|
s.homepage = %q{http://github.com/igrigorik/em-http-request}
|
55
58
|
s.rdoc_options = ["--charset=UTF-8"]
|
56
59
|
s.require_paths = ["lib"]
|
60
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
57
61
|
s.rubyforge_project = %q{astro-em-http-request}
|
58
62
|
s.rubygems_version = %q{1.3.5}
|
59
63
|
s.summary = %q{EventMachine based, async HTTP Request interface}
|
60
64
|
s.test_files = [
|
61
65
|
"spec/hash_spec.rb",
|
62
66
|
"spec/helper.rb",
|
67
|
+
"spec/stub_server.rb",
|
68
|
+
"spec/stallion.rb",
|
63
69
|
"spec/mock_spec.rb",
|
64
70
|
"spec/multi_spec.rb",
|
65
71
|
"spec/request_spec.rb",
|
66
|
-
"spec/stallion.rb",
|
67
|
-
"spec/stub_server.rb",
|
68
|
-
"test/another_test.rb",
|
69
|
-
"examples/fetch.rb",
|
70
72
|
"examples/fibered-http.rb",
|
73
|
+
"examples/fetch.rb",
|
71
74
|
"examples/oauth-tweet.rb"
|
72
75
|
]
|
73
76
|
|
@@ -77,14 +80,10 @@ Gem::Specification.new do |s|
|
|
77
80
|
|
78
81
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
79
82
|
s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.9"])
|
80
|
-
s.add_runtime_dependency(%q<addressable>, [">= 2.0.0"])
|
81
83
|
else
|
82
84
|
s.add_dependency(%q<eventmachine>, [">= 0.12.9"])
|
83
|
-
s.add_dependency(%q<addressable>, [">= 2.0.0"])
|
84
85
|
end
|
85
86
|
else
|
86
87
|
s.add_dependency(%q<eventmachine>, [">= 0.12.9"])
|
87
|
-
s.add_dependency(%q<addressable>, [">= 2.0.0"])
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
data/ext/buffer/em_buffer.c
CHANGED
@@ -29,15 +29,15 @@
|
|
29
29
|
#define PURGE_INTERVAL 10
|
30
30
|
|
31
31
|
struct buffer {
|
32
|
-
|
32
|
+
time_t last_purged_at;
|
33
33
|
unsigned size, node_size;
|
34
34
|
struct buffer_node *head, *tail;
|
35
35
|
struct buffer_node *pool_head, *pool_tail;
|
36
|
-
|
36
|
+
|
37
37
|
};
|
38
38
|
|
39
39
|
struct buffer_node {
|
40
|
-
|
40
|
+
time_t last_used_at;
|
41
41
|
unsigned start, end;
|
42
42
|
struct buffer_node *next;
|
43
43
|
unsigned char data[0];
|
@@ -72,7 +72,7 @@ static void buffer_copy(struct buffer *buf, char *str, unsigned len);
|
|
72
72
|
static int buffer_read_from(struct buffer *buf, int fd);
|
73
73
|
static int buffer_write_to(struct buffer *buf, int fd);
|
74
74
|
|
75
|
-
/*
|
75
|
+
/*
|
76
76
|
* High speed buffering geared towards non-blocking I/O.
|
77
77
|
*
|
78
78
|
* Data is stored in a byte queue implemented as a linked list of equal size
|
@@ -94,8 +94,8 @@ void Init_em_buffer()
|
|
94
94
|
rb_define_method(cEm_Buffer, "append", Em_Buffer_append, 1);
|
95
95
|
rb_define_method(cEm_Buffer, "prepend", Em_Buffer_prepend, 1);
|
96
96
|
rb_define_method(cEm_Buffer, "read", Em_Buffer_read, -1);
|
97
|
-
|
98
|
-
|
97
|
+
rb_define_method(cEm_Buffer, "to_str", Em_Buffer_to_str, 0);
|
98
|
+
rb_define_method(cEm_Buffer, "read_from", Em_Buffer_read_from, 1);
|
99
99
|
rb_define_method(cEm_Buffer, "write_to", Em_Buffer_write_to, 1);
|
100
100
|
}
|
101
101
|
|
@@ -118,7 +118,7 @@ static void Em_Buffer_free(struct buffer *buf)
|
|
118
118
|
/**
|
119
119
|
* call-seq:
|
120
120
|
* EventMachine::Buffer.new(size = DEFAULT_NODE_SIZE) -> EventMachine::Buffer
|
121
|
-
*
|
121
|
+
*
|
122
122
|
* Create a new EventMachine::Buffer with linked segments of the given size
|
123
123
|
*/
|
124
124
|
static VALUE Em_Buffer_initialize(int argc, VALUE *argv, VALUE self)
|
@@ -147,7 +147,7 @@ static VALUE Em_Buffer_initialize(int argc, VALUE *argv, VALUE self)
|
|
147
147
|
/**
|
148
148
|
* call-seq:
|
149
149
|
* EventMachine::Buffer#clear -> nil
|
150
|
-
*
|
150
|
+
*
|
151
151
|
* Clear all data from the EventMachine::Buffer
|
152
152
|
*/
|
153
153
|
static VALUE Em_Buffer_clear(VALUE self)
|
@@ -163,10 +163,10 @@ static VALUE Em_Buffer_clear(VALUE self)
|
|
163
163
|
/**
|
164
164
|
* call-seq:
|
165
165
|
* EventMachine::Buffer#size -> Integer
|
166
|
-
*
|
166
|
+
*
|
167
167
|
* Return the size of the buffer in bytes
|
168
168
|
*/
|
169
|
-
static VALUE Em_Buffer_size(VALUE self)
|
169
|
+
static VALUE Em_Buffer_size(VALUE self)
|
170
170
|
{
|
171
171
|
struct buffer *buf;
|
172
172
|
Data_Get_Struct(self, struct buffer, buf);
|
@@ -177,21 +177,21 @@ static VALUE Em_Buffer_size(VALUE self)
|
|
177
177
|
/**
|
178
178
|
* call-seq:
|
179
179
|
* EventMachine::Buffer#empty? -> Boolean
|
180
|
-
*
|
180
|
+
*
|
181
181
|
* Is the buffer empty?
|
182
182
|
*/
|
183
|
-
static VALUE Em_Buffer_empty(VALUE self)
|
183
|
+
static VALUE Em_Buffer_empty(VALUE self)
|
184
184
|
{
|
185
185
|
struct buffer *buf;
|
186
186
|
Data_Get_Struct(self, struct buffer, buf);
|
187
187
|
|
188
|
-
return buf->size > 0 ? Qfalse : Qtrue;
|
188
|
+
return buf->size > 0 ? Qfalse : Qtrue;
|
189
189
|
}
|
190
190
|
|
191
191
|
/**
|
192
192
|
* call-seq:
|
193
193
|
* EventMachine::Buffer#append(data) -> String
|
194
|
-
*
|
194
|
+
*
|
195
195
|
* Append the given data to the end of the buffer
|
196
196
|
*/
|
197
197
|
static VALUE Em_Buffer_append(VALUE self, VALUE data)
|
@@ -209,7 +209,7 @@ static VALUE Em_Buffer_append(VALUE self, VALUE data)
|
|
209
209
|
/**
|
210
210
|
* call-seq:
|
211
211
|
* EventMachine::Buffer#prepend(data) -> String
|
212
|
-
*
|
212
|
+
*
|
213
213
|
* Prepend the given data to the beginning of the buffer
|
214
214
|
*/
|
215
215
|
static VALUE Em_Buffer_prepend(VALUE self, VALUE data)
|
@@ -226,7 +226,7 @@ static VALUE Em_Buffer_prepend(VALUE self, VALUE data)
|
|
226
226
|
/**
|
227
227
|
* call-seq:
|
228
228
|
* EventMachine::Buffer#read(length = nil) -> String
|
229
|
-
*
|
229
|
+
*
|
230
230
|
* Read the specified abount of data from the buffer. If no value
|
231
231
|
* is given the entire contents of the buffer are returned. Any data
|
232
232
|
* read from the buffer is cleared.
|
@@ -263,31 +263,31 @@ static VALUE Em_Buffer_read(int argc, VALUE *argv, VALUE self)
|
|
263
263
|
/**
|
264
264
|
* call-seq:
|
265
265
|
* EventMachine::Buffer#to_str -> String
|
266
|
-
*
|
266
|
+
*
|
267
267
|
* Convert the Buffer to a String. The original buffer is unmodified.
|
268
268
|
*/
|
269
269
|
static VALUE Em_Buffer_to_str(VALUE self) {
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
270
|
+
VALUE str;
|
271
|
+
struct buffer *buf;
|
272
|
+
|
273
|
+
Data_Get_Struct(self, struct buffer, buf);
|
274
|
+
|
275
|
+
str = rb_str_new(0, buf->size);
|
276
|
+
buffer_copy(buf, RSTRING_PTR(str), buf->size);
|
277
|
+
|
278
278
|
return str;
|
279
279
|
}
|
280
280
|
|
281
281
|
/**
|
282
282
|
* call-seq:
|
283
283
|
* EventMachine::Buffer#read_from(io) -> Integer
|
284
|
-
*
|
284
|
+
*
|
285
285
|
* Perform a nonblocking read of the the given IO object and fill
|
286
286
|
* the buffer with any data received. The call will read as much
|
287
287
|
* data as it can until the read would block.
|
288
288
|
*/
|
289
289
|
static VALUE Em_Buffer_read_from(VALUE self, VALUE io) {
|
290
|
-
|
290
|
+
struct buffer *buf;
|
291
291
|
#if HAVE_RB_IO_T
|
292
292
|
rb_io_t *fptr;
|
293
293
|
#else
|
@@ -298,20 +298,24 @@ static VALUE Em_Buffer_read_from(VALUE self, VALUE io) {
|
|
298
298
|
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
299
299
|
rb_io_set_nonblock(fptr);
|
300
300
|
|
301
|
+
#ifdef HAVE_RB_IO_FD
|
302
|
+
return INT2NUM(buffer_read_from(buf, rb_io_fd(io)));
|
303
|
+
#else
|
301
304
|
return INT2NUM(buffer_read_from(buf, FPTR_TO_FD(fptr)));
|
305
|
+
#endif
|
302
306
|
}
|
303
307
|
|
304
308
|
/**
|
305
309
|
* call-seq:
|
306
310
|
* EventMachine::Buffer#write_to(io) -> Integer
|
307
|
-
*
|
311
|
+
*
|
308
312
|
* Perform a nonblocking write of the buffer to the given IO object.
|
309
313
|
* As much data as possible is written until the call would block.
|
310
314
|
* Any data which is written is removed from the buffer.
|
311
315
|
*/
|
312
316
|
static VALUE Em_Buffer_write_to(VALUE self, VALUE io) {
|
313
317
|
struct buffer *buf;
|
314
|
-
#if HAVE_RB_IO_T
|
318
|
+
#if HAVE_RB_IO_T
|
315
319
|
rb_io_t *fptr;
|
316
320
|
#else
|
317
321
|
OpenFile *fptr;
|
@@ -321,11 +325,16 @@ static VALUE Em_Buffer_write_to(VALUE self, VALUE io) {
|
|
321
325
|
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
322
326
|
rb_io_set_nonblock(fptr);
|
323
327
|
|
324
|
-
|
328
|
+
#ifdef HAVE_RB_IO_FD
|
329
|
+
return INT2NUM(buffer_read_from(buf, rb_io_fd(io)));
|
330
|
+
#else
|
331
|
+
return INT2NUM(buffer_read_from(buf, FPTR_TO_FD(fptr)));
|
332
|
+
#endif
|
333
|
+
|
325
334
|
}
|
326
335
|
|
327
336
|
/*
|
328
|
-
* Ruby bindings end here. Below is the actual implementation of
|
337
|
+
* Ruby bindings end here. Below is the actual implementation of
|
329
338
|
* the underlying data structures.
|
330
339
|
*/
|
331
340
|
|
@@ -338,8 +347,8 @@ static struct buffer *buffer_new(void)
|
|
338
347
|
buf->head = buf->tail = buf->pool_head = buf->pool_tail = 0;
|
339
348
|
buf->size = 0;
|
340
349
|
buf->node_size = DEFAULT_NODE_SIZE;
|
341
|
-
|
342
|
-
|
350
|
+
time(&buf->last_purged_at);
|
351
|
+
|
343
352
|
return buf;
|
344
353
|
}
|
345
354
|
|
@@ -359,7 +368,7 @@ static void buffer_clear(struct buffer *buf)
|
|
359
368
|
}
|
360
369
|
|
361
370
|
/* Free a buffer */
|
362
|
-
static void buffer_free(struct buffer *buf)
|
371
|
+
static void buffer_free(struct buffer *buf)
|
363
372
|
{
|
364
373
|
struct buffer_node *tmp;
|
365
374
|
|
@@ -381,11 +390,11 @@ static void buffer_gc(struct buffer *buf)
|
|
381
390
|
time_t now;
|
382
391
|
time(&now);
|
383
392
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
393
|
+
/* Only purge if we've passed the purge interval */
|
394
|
+
if(now - buf->last_purged_at < PURGE_INTERVAL)
|
395
|
+
return;
|
396
|
+
|
397
|
+
buf->last_purged_at = now;
|
389
398
|
|
390
399
|
while(buf->pool_head && now - buf->pool_head->last_used_at >= MAX_AGE) {
|
391
400
|
tmp = buf->pool_head;
|
@@ -394,7 +403,7 @@ static void buffer_gc(struct buffer *buf)
|
|
394
403
|
}
|
395
404
|
|
396
405
|
if(!buf->pool_head)
|
397
|
-
|
406
|
+
buf->pool_tail = 0;
|
398
407
|
}
|
399
408
|
|
400
409
|
/* Create a new buffer_node (or pull one from the memory pool) */
|
@@ -494,11 +503,11 @@ static void buffer_append(struct buffer *buf, char *str, unsigned len)
|
|
494
503
|
while(len > 0) {
|
495
504
|
nbytes = buf->node_size - buf->tail->end;
|
496
505
|
if(len < nbytes) nbytes = len;
|
497
|
-
|
506
|
+
|
498
507
|
memcpy(buf->tail->data + buf->tail->end, str, nbytes);
|
499
|
-
str += nbytes;
|
508
|
+
str += nbytes;
|
500
509
|
len -= nbytes;
|
501
|
-
|
510
|
+
|
502
511
|
buf->tail->end += nbytes;
|
503
512
|
|
504
513
|
if(len > 0) {
|
@@ -541,7 +550,7 @@ static void buffer_copy(struct buffer *buf, char *str, unsigned len)
|
|
541
550
|
unsigned nbytes;
|
542
551
|
struct buffer_node *node;
|
543
552
|
|
544
|
-
|
553
|
+
node = buf->head;
|
545
554
|
while(node && len > 0) {
|
546
555
|
nbytes = node->end - node->start;
|
547
556
|
if(len < nbytes) nbytes = len;
|
@@ -551,7 +560,7 @@ static void buffer_copy(struct buffer *buf, char *str, unsigned len)
|
|
551
560
|
len -= nbytes;
|
552
561
|
|
553
562
|
if(node->start + nbytes == node->end)
|
554
|
-
|
563
|
+
node = node->next;
|
555
564
|
}
|
556
565
|
}
|
557
566
|
|
@@ -596,7 +605,7 @@ static int buffer_write_to(struct buffer *buf, int fd)
|
|
596
605
|
/* Append data to the front of the buffer */
|
597
606
|
static int buffer_read_from(struct buffer *buf, int fd)
|
598
607
|
{
|
599
|
-
|
608
|
+
int bytes_read, total_bytes_read = 0;
|
600
609
|
unsigned nbytes;
|
601
610
|
|
602
611
|
/* Empty list needs initialized */
|
@@ -605,26 +614,26 @@ static int buffer_read_from(struct buffer *buf, int fd)
|
|
605
614
|
buf->tail = buf->head;
|
606
615
|
}
|
607
616
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
617
|
+
do {
|
618
|
+
nbytes = buf->node_size - buf->tail->end;
|
619
|
+
bytes_read = read(fd, buf->tail->data + buf->tail->end, nbytes);
|
620
|
+
|
621
|
+
if(bytes_read < 1) {
|
622
|
+
if(errno != EAGAIN)
|
614
623
|
rb_sys_fail("read");
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
+
|
625
|
+
return total_bytes_read;
|
626
|
+
}
|
627
|
+
|
628
|
+
total_bytes_read += bytes_read;
|
629
|
+
buf->tail->end += nbytes;
|
630
|
+
buf->size += nbytes;
|
631
|
+
|
632
|
+
if(buf->tail->end == buf->node_size) {
|
624
633
|
buf->tail->next = buffer_node_new(buf);
|
625
634
|
buf->tail = buf->tail->next;
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
635
|
+
}
|
636
|
+
} while(bytes_read == nbytes);
|
637
|
+
|
638
|
+
return total_bytes_read;
|
630
639
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'em-http'
|
data/lib/em-http/client.rb
CHANGED
@@ -84,7 +84,7 @@ module EventMachine
|
|
84
84
|
# Escapes a URI.
|
85
85
|
def escape(s)
|
86
86
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
87
|
-
'%'+$1.unpack('H2'*$1.
|
87
|
+
'%'+$1.unpack('H2'*$1.bytesize).join('%').upcase
|
88
88
|
}.tr(' ', '+')
|
89
89
|
end
|
90
90
|
|
@@ -104,7 +104,11 @@ module EventMachine
|
|
104
104
|
# you include port 80 then further redirects will tack on the :80 which is
|
105
105
|
# annoying.
|
106
106
|
def encode_host
|
107
|
-
|
107
|
+
if @uri.port == 80 || @uri.port == 443
|
108
|
+
return @uri.host
|
109
|
+
else
|
110
|
+
@uri.host + ":#{@uri.port}"
|
111
|
+
end
|
108
112
|
end
|
109
113
|
|
110
114
|
def encode_request(method, path, query, uri_query)
|
@@ -313,7 +317,7 @@ module EventMachine
|
|
313
317
|
|
314
318
|
else
|
315
319
|
# Set the Content-Length if body is given
|
316
|
-
head['content-length'] = body.
|
320
|
+
head['content-length'] = body.bytesize if body
|
317
321
|
|
318
322
|
# Set the cookie header if provided
|
319
323
|
if cookie = head.delete('cookie')
|
@@ -473,9 +477,9 @@ module EventMachine
|
|
473
477
|
# correct location header - some servers will incorrectly give a relative URI
|
474
478
|
if @response_header.location
|
475
479
|
begin
|
476
|
-
location =
|
480
|
+
location = URI.parse @response_header.location
|
477
481
|
if location.relative?
|
478
|
-
location = (@uri.
|
482
|
+
location = (@uri.merge location).to_s
|
479
483
|
@response_header[LOCATION] = location
|
480
484
|
end
|
481
485
|
rescue
|
data/lib/em-http/mock.rb
CHANGED
@@ -20,11 +20,15 @@ module EventMachine
|
|
20
20
|
@@registry_count = nil
|
21
21
|
|
22
22
|
def self.reset_counts!
|
23
|
-
@@registry_count = Hash.new
|
23
|
+
@@registry_count = Hash.new do |registry,query|
|
24
|
+
registry[query] = Hash.new{|h,k| h[k] = Hash.new(0)}
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.reset_registry!
|
27
|
-
@@registry = Hash.new
|
29
|
+
@@registry = Hash.new do |registry,query|
|
30
|
+
registry[query] = Hash.new{|h,k| h[k] = {}}
|
31
|
+
end
|
28
32
|
end
|
29
33
|
|
30
34
|
reset_counts!
|
@@ -40,18 +44,32 @@ module EventMachine
|
|
40
44
|
@@pass_through_requests
|
41
45
|
end
|
42
46
|
|
43
|
-
def self.register(uri, method, data)
|
47
|
+
def self.register(uri, method, headers, data)
|
44
48
|
method = method.to_s.upcase
|
45
|
-
|
49
|
+
headers = headers.to_s
|
50
|
+
@@registry[uri][method][headers] = data
|
46
51
|
end
|
47
52
|
|
48
|
-
def self.register_file(uri, method, file)
|
49
|
-
register(uri, method, File.read(file))
|
53
|
+
def self.register_file(uri, method, headers, file)
|
54
|
+
register(uri, method, headers, File.read(file))
|
50
55
|
end
|
51
56
|
|
52
|
-
def self.count(uri, method)
|
57
|
+
def self.count(uri, method, headers)
|
53
58
|
method = method.to_s.upcase
|
54
|
-
|
59
|
+
headers = headers.to_s
|
60
|
+
@@registry_count[uri][method][headers] rescue 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.registered?(query, method, headers)
|
64
|
+
@@registry[query] and @@registry[query][method] and @@registry[query][method][headers]
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.registered_content(query, method, headers)
|
68
|
+
@@registry[query][method][headers]
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.increment_access(query, method, headers)
|
72
|
+
@@registry_count[query][method][headers] += 1
|
55
73
|
end
|
56
74
|
|
57
75
|
alias_method :real_send_request, :send_request
|
@@ -59,15 +77,16 @@ module EventMachine
|
|
59
77
|
protected
|
60
78
|
def send_request(&blk)
|
61
79
|
query = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}#{encode_query(@uri.path, @options[:query], @uri.query)}"
|
62
|
-
|
63
|
-
|
80
|
+
headers = @options[:head].to_s
|
81
|
+
if self.class.registered?(query, @method, headers)
|
82
|
+
self.class.increment_access(query, @method, headers)
|
64
83
|
client = FakeHttpClient.new(nil)
|
65
|
-
client.setup(
|
84
|
+
client.setup(self.class.registered_content(query, @method, headers), @uri)
|
66
85
|
client
|
67
86
|
elsif @@pass_through_requests
|
68
87
|
real_send_request
|
69
88
|
else
|
70
|
-
raise "this request #{query} for method #{@method} isn't registered, and pass_through_requests is current set to false"
|
89
|
+
raise "this request #{query} for method #{@method} with the headers #{@options[:head].inspect} isn't registered, and pass_through_requests is current set to false"
|
71
90
|
end
|
72
91
|
end
|
73
92
|
end
|
data/lib/em-http/multi.rb
CHANGED
@@ -34,10 +34,10 @@ module EventMachine
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def add(conn)
|
37
|
+
@requests.push(conn)
|
38
|
+
|
37
39
|
conn.callback { @responses[:succeeded].push(conn); check_progress }
|
38
40
|
conn.errback { @responses[:failed].push(conn); check_progress }
|
39
|
-
|
40
|
-
@requests.push(conn)
|
41
41
|
end
|
42
42
|
|
43
43
|
protected
|
@@ -48,4 +48,4 @@ module EventMachine
|
|
48
48
|
end
|
49
49
|
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end
|
data/lib/em-http/request.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require '
|
2
|
+
require 'uri'
|
3
3
|
|
4
4
|
module EventMachine
|
5
5
|
|
@@ -28,7 +28,7 @@ module EventMachine
|
|
28
28
|
|
29
29
|
def initialize(host, headers = {})
|
30
30
|
@headers = headers
|
31
|
-
@uri = host.kind_of?(
|
31
|
+
@uri = host.kind_of?(URI) ? host : URI::parse(host)
|
32
32
|
end
|
33
33
|
|
34
34
|
# Send an HTTP request and consume the response. Supported options:
|
@@ -70,7 +70,7 @@ module EventMachine
|
|
70
70
|
# default connect & inactivity timeouts
|
71
71
|
@options[:timeout] = 10 if not @options[:timeout]
|
72
72
|
|
73
|
-
# Make sure the ports are set as
|
73
|
+
# Make sure the ports are set as URI doesn't
|
74
74
|
# set the port if it isn't there
|
75
75
|
if @uri.scheme == "https"
|
76
76
|
@uri.port ||= 443
|
@@ -109,4 +109,4 @@ module EventMachine
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
|
-
end
|
112
|
+
end
|
data/lib/em_buffer.so
ADDED
Binary file
|
Binary file
|
data/spec/mock_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe 'em-http mock' do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should serve a fake http request from a file" do
|
11
|
-
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
11
|
+
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
12
12
|
EM.run {
|
13
13
|
|
14
14
|
http = EventMachine::MockHttpRequest.new('http://www.google.ca/').get
|
@@ -19,7 +19,7 @@ describe 'em-http mock' do
|
|
19
19
|
}
|
20
20
|
}
|
21
21
|
|
22
|
-
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get).should == 1
|
22
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should serve a fake http request from a string" do
|
@@ -46,7 +46,7 @@ window._gjp && _gjp()</script><style>td{line-height:.8em;}.gac_m td{line-height:
|
|
46
46
|
function a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.timers.load.t.xjs&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",a,false);else if(window.attachEvent)window.attachEvent("onload",a);google.timers.load.t.prt=(new Date).getTime();
|
47
47
|
})();
|
48
48
|
HEREDOC
|
49
|
-
EventMachine::MockHttpRequest.register('http://www.google.ca:80/', :get, data)
|
49
|
+
EventMachine::MockHttpRequest.register('http://www.google.ca:80/', :get, {}, data)
|
50
50
|
EventMachine.run {
|
51
51
|
|
52
52
|
http = EventMachine::MockHttpRequest.new('http://www.google.ca/').get
|
@@ -57,7 +57,36 @@ function a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.
|
|
57
57
|
}
|
58
58
|
}
|
59
59
|
|
60
|
-
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get).should == 1
|
60
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should distinguish the cache by the given headers" do
|
64
|
+
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
65
|
+
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
66
|
+
EM.run {
|
67
|
+
|
68
|
+
http = EventMachine::MockHttpRequest.new('http://www.google.ca/').get
|
69
|
+
http.errback { fail }
|
70
|
+
http.callback {
|
71
|
+
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca')).split("\n\n", 2).last
|
72
|
+
EventMachine.stop
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
77
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}).should == 0
|
78
|
+
|
79
|
+
EM.run {
|
80
|
+
|
81
|
+
http = EventMachine::MockHttpRequest.new('http://www.google.ca/').get({:head => {:user_agent => 'BERT'}})
|
82
|
+
http.errback { fail }
|
83
|
+
http.callback {
|
84
|
+
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca')).split("\n\n", 2).last
|
85
|
+
EventMachine.stop
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}).should == 1
|
61
90
|
end
|
62
91
|
|
63
92
|
it "should raise an exception if pass-thru is disabled" do
|
data/spec/multi_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe EventMachine::MultiRequest do
|
|
14
14
|
multi.add(EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1))
|
15
15
|
|
16
16
|
multi.callback {
|
17
|
-
# verify
|
17
|
+
# verify successful request
|
18
18
|
multi.responses[:succeeded].size.should == 1
|
19
19
|
multi.responses[:succeeded].first.response.should match(/test/)
|
20
20
|
|
@@ -26,4 +26,26 @@ describe EventMachine::MultiRequest do
|
|
26
26
|
}
|
27
27
|
}
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
|
+
it "should handle multiple mock requests" do
|
31
|
+
EventMachine::MockHttpRequest.register_file('http://127.0.0.1:8080/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
32
|
+
EventMachine::MockHttpRequest.register_file('http://0.0.0.0:8083/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
33
|
+
|
34
|
+
EventMachine.run {
|
35
|
+
|
36
|
+
# create an instance of multi-request handler, and the requests themselves
|
37
|
+
multi = EventMachine::MultiRequest.new
|
38
|
+
|
39
|
+
# add multiple requests to the multi-handler
|
40
|
+
multi.add(EventMachine::MockHttpRequest.new('http://127.0.0.1:8080/').get)
|
41
|
+
multi.add(EventMachine::MockHttpRequest.new('http://0.0.0.0:8083/').get)
|
42
|
+
|
43
|
+
multi.callback {
|
44
|
+
# verify successful request
|
45
|
+
multi.responses[:succeeded].size.should == 2
|
46
|
+
|
47
|
+
EventMachine.stop
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
data/spec/request_spec.rb
CHANGED
@@ -501,14 +501,14 @@ describe EventMachine::HttpRequest do
|
|
501
501
|
client.should be_kind_of(EventMachine::HttpClient)
|
502
502
|
http.response_header.status.should == 200
|
503
503
|
http.response.should match(/callback_run=yes/)
|
504
|
-
client.normalize_uri.should ==
|
504
|
+
client.normalize_uri.should == URI.parse('http://127.0.0.1:8080/')
|
505
505
|
EventMachine.stop
|
506
506
|
}
|
507
507
|
}
|
508
508
|
end
|
509
509
|
|
510
510
|
it "should retrieve multiple cookies" do
|
511
|
-
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
511
|
+
EventMachine::MockHttpRequest.register_file('http://www.google.ca:80/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
512
512
|
EventMachine.run {
|
513
513
|
|
514
514
|
http = EventMachine::MockHttpRequest.new('http://www.google.ca/').get
|
@@ -522,7 +522,7 @@ describe EventMachine::HttpRequest do
|
|
522
522
|
}
|
523
523
|
}
|
524
524
|
|
525
|
-
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get).should == 1
|
525
|
+
EventMachine::MockHttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
526
526
|
end
|
527
527
|
|
528
528
|
context "connections via proxy" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: astro-em-http-request
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Grigorik
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2010-
|
14
|
+
date: 2010-04-07 00:00:00 +02:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -24,16 +24,6 @@ dependencies:
|
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: 0.12.9
|
26
26
|
version:
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: addressable
|
29
|
-
type: :runtime
|
30
|
-
version_requirement:
|
31
|
-
version_requirements: !ruby/object:Gem::Requirement
|
32
|
-
requirements:
|
33
|
-
- - ">="
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: 2.0.0
|
36
|
-
version:
|
37
27
|
description: EventMachine based, async HTTP Request interface
|
38
28
|
email: ilya@igvita.com
|
39
29
|
executables: []
|
@@ -62,6 +52,7 @@ files:
|
|
62
52
|
- ext/http11_client/http11_parser.c
|
63
53
|
- ext/http11_client/http11_parser.h
|
64
54
|
- ext/http11_client/http11_parser.rl
|
55
|
+
- lib/em-http-request.rb
|
65
56
|
- lib/em-http.rb
|
66
57
|
- lib/em-http/client.rb
|
67
58
|
- lib/em-http/core_ext/hash.rb
|
@@ -69,6 +60,8 @@ files:
|
|
69
60
|
- lib/em-http/mock.rb
|
70
61
|
- lib/em-http/multi.rb
|
71
62
|
- lib/em-http/request.rb
|
63
|
+
- lib/em_buffer.so
|
64
|
+
- lib/http11_client.so
|
72
65
|
- spec/fixtures/google.ca
|
73
66
|
- spec/hash_spec.rb
|
74
67
|
- spec/helper.rb
|
@@ -90,7 +83,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
83
|
requirements:
|
91
84
|
- - ">="
|
92
85
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
86
|
+
version: 1.8.7
|
94
87
|
version:
|
95
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
89
|
requirements:
|
@@ -108,12 +101,11 @@ summary: EventMachine based, async HTTP Request interface
|
|
108
101
|
test_files:
|
109
102
|
- spec/hash_spec.rb
|
110
103
|
- spec/helper.rb
|
104
|
+
- spec/stub_server.rb
|
105
|
+
- spec/stallion.rb
|
111
106
|
- spec/mock_spec.rb
|
112
107
|
- spec/multi_spec.rb
|
113
108
|
- spec/request_spec.rb
|
114
|
-
- spec/stallion.rb
|
115
|
-
- spec/stub_server.rb
|
116
|
-
- test/another_test.rb
|
117
|
-
- examples/fetch.rb
|
118
109
|
- examples/fibered-http.rb
|
110
|
+
- examples/fetch.rb
|
119
111
|
- examples/oauth-tweet.rb
|
data/test/another_test.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'test/helper'
|
2
|
-
|
3
|
-
describe EventMachine::HttpRequest do
|
4
|
-
|
5
|
-
def failed
|
6
|
-
EventMachine.stop
|
7
|
-
fail
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should return and error if the response side exceeds the :max_bytes option" do
|
11
|
-
EventMachine.run {
|
12
|
-
http = EventMachine::HttpRequest.new("http://updates.sixapart.com/atom-stream.xml").get(:timeout => 10)
|
13
|
-
http.errback { |http|
|
14
|
-
http.errors.should match /Max Connection Duration Exceeded/
|
15
|
-
EventMachine.stop
|
16
|
-
}
|
17
|
-
http.callback { failed }
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|