em-http-request 0.3.0 → 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of em-http-request might be problematic. Click here for more details.
- data/.gitignore +1 -0
- data/Changelog.md +10 -0
- data/README.md +43 -160
- data/Rakefile +2 -73
- data/em-http-request.gemspec +7 -7
- data/examples/fetch.rb +30 -30
- data/examples/fibered-http.rb +38 -38
- data/examples/oauth-tweet.rb +49 -49
- data/lib/em-http.rb +4 -6
- data/lib/em-http/client.rb +101 -522
- data/lib/em-http/http_connection.rb +125 -0
- data/lib/em-http/http_encoding.rb +19 -12
- data/lib/em-http/http_header.rb +2 -17
- data/lib/em-http/http_options.rb +37 -19
- data/lib/em-http/request.rb +33 -66
- data/lib/em-http/version.rb +2 -2
- data/spec/client_spec.rb +575 -0
- data/spec/dns_spec.rb +41 -0
- data/spec/encoding_spec.rb +6 -6
- data/spec/external_spec.rb +99 -0
- data/spec/fixtures/google.ca +13 -17
- data/spec/helper.rb +17 -8
- data/spec/http_proxy_spec.rb +53 -0
- data/spec/middleware_spec.rb +114 -0
- data/spec/multi_spec.rb +11 -38
- data/spec/pipelining_spec.rb +38 -0
- data/spec/redirect_spec.rb +114 -0
- data/spec/socksify_proxy_spec.rb +24 -0
- data/spec/ssl_spec.rb +20 -0
- data/spec/stallion.rb +7 -63
- metadata +59 -39
- data/examples/websocket-handler.rb +0 -28
- data/examples/websocket-server.rb +0 -8
- data/ext/buffer/em_buffer.c +0 -639
- data/ext/buffer/extconf.rb +0 -53
- data/ext/http11_client/ext_help.h +0 -14
- data/ext/http11_client/extconf.rb +0 -6
- data/ext/http11_client/http11_client.c +0 -328
- data/ext/http11_client/http11_parser.c +0 -418
- data/ext/http11_client/http11_parser.h +0 -48
- data/ext/http11_client/http11_parser.rl +0 -170
- data/lib/em-http/mock.rb +0 -137
- data/spec/mock_spec.rb +0 -166
- data/spec/request_spec.rb +0 -1003
@@ -1,48 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Copyright (c) 2005 Zed A. Shaw
|
3
|
-
* You can redistribute it and/or modify it under the same terms as Ruby.
|
4
|
-
*/
|
5
|
-
|
6
|
-
#ifndef http11_parser_h
|
7
|
-
#define http11_parser_h
|
8
|
-
|
9
|
-
#include <sys/types.h>
|
10
|
-
|
11
|
-
#if defined(_WIN32)
|
12
|
-
#include <stddef.h>
|
13
|
-
#endif
|
14
|
-
|
15
|
-
typedef void (*element_cb)(void *data, const char *at, size_t length);
|
16
|
-
typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
|
17
|
-
|
18
|
-
typedef struct httpclient_parser {
|
19
|
-
int cs;
|
20
|
-
size_t body_start;
|
21
|
-
int content_len;
|
22
|
-
size_t nread;
|
23
|
-
size_t mark;
|
24
|
-
size_t field_start;
|
25
|
-
size_t field_len;
|
26
|
-
|
27
|
-
void *data;
|
28
|
-
|
29
|
-
field_cb http_field;
|
30
|
-
element_cb reason_phrase;
|
31
|
-
element_cb status_code;
|
32
|
-
element_cb chunk_size;
|
33
|
-
element_cb http_version;
|
34
|
-
element_cb header_done;
|
35
|
-
element_cb last_chunk;
|
36
|
-
|
37
|
-
|
38
|
-
} httpclient_parser;
|
39
|
-
|
40
|
-
int httpclient_parser_init(httpclient_parser *parser);
|
41
|
-
int httpclient_parser_finish(httpclient_parser *parser);
|
42
|
-
size_t httpclient_parser_execute(httpclient_parser *parser, const char *data, size_t len, size_t off);
|
43
|
-
int httpclient_parser_has_error(httpclient_parser *parser);
|
44
|
-
int httpclient_parser_is_finished(httpclient_parser *parser);
|
45
|
-
|
46
|
-
#define httpclient_parser_nread(parser) (parser)->nread
|
47
|
-
|
48
|
-
#endif
|
@@ -1,170 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Copyright (c) 2005 Zed A. Shaw
|
3
|
-
* You can redistribute it and/or modify it under the same terms as Ruby.
|
4
|
-
*/
|
5
|
-
|
6
|
-
#include "http11_parser.h"
|
7
|
-
#include <stdio.h>
|
8
|
-
#include <assert.h>
|
9
|
-
#include <stdlib.h>
|
10
|
-
#include <ctype.h>
|
11
|
-
#include <string.h>
|
12
|
-
|
13
|
-
#define LEN(AT, FPC) (FPC - buffer - parser->AT)
|
14
|
-
#define MARK(M,FPC) (parser->M = (FPC) - buffer)
|
15
|
-
#define PTR_TO(F) (buffer + parser->F)
|
16
|
-
#define L(M) fprintf(stderr, "" # M "\n");
|
17
|
-
|
18
|
-
|
19
|
-
/** machine **/
|
20
|
-
%%{
|
21
|
-
machine httpclient_parser;
|
22
|
-
|
23
|
-
action mark {MARK(mark, fpc); }
|
24
|
-
|
25
|
-
action start_field { MARK(field_start, fpc); }
|
26
|
-
|
27
|
-
action write_field {
|
28
|
-
parser->field_len = LEN(field_start, fpc);
|
29
|
-
}
|
30
|
-
|
31
|
-
action start_value { MARK(mark, fpc); }
|
32
|
-
|
33
|
-
action write_value {
|
34
|
-
parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
|
35
|
-
}
|
36
|
-
|
37
|
-
action reason_phrase {
|
38
|
-
parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
39
|
-
}
|
40
|
-
|
41
|
-
action status_code {
|
42
|
-
parser->status_code(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
43
|
-
}
|
44
|
-
|
45
|
-
action http_version {
|
46
|
-
parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
47
|
-
}
|
48
|
-
|
49
|
-
action chunk_size {
|
50
|
-
parser->chunk_size(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
51
|
-
}
|
52
|
-
|
53
|
-
action last_chunk {
|
54
|
-
parser->last_chunk(parser->data, NULL, 0);
|
55
|
-
}
|
56
|
-
|
57
|
-
action done {
|
58
|
-
parser->body_start = fpc - buffer + 1;
|
59
|
-
if(parser->header_done != NULL)
|
60
|
-
parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
|
61
|
-
fbreak;
|
62
|
-
}
|
63
|
-
|
64
|
-
# line endings
|
65
|
-
CRLF = ("\r\n" | "\n");
|
66
|
-
|
67
|
-
# character types
|
68
|
-
CTL = (cntrl | 127);
|
69
|
-
tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
|
70
|
-
|
71
|
-
# elements
|
72
|
-
token = (ascii -- (CTL | tspecials));
|
73
|
-
|
74
|
-
Reason_Phrase = (any -- CRLF)* >mark %reason_phrase;
|
75
|
-
Status_Code = digit{3} >mark %status_code;
|
76
|
-
http_number = (digit+ "." digit+) ;
|
77
|
-
HTTP_Version = ("HTTP/" http_number) >mark %http_version ;
|
78
|
-
Status_Line = HTTP_Version " " Status_Code " "? Reason_Phrase :> CRLF;
|
79
|
-
|
80
|
-
field_name = token+ >start_field %write_field;
|
81
|
-
field_value = any* >start_value %write_value;
|
82
|
-
message_header = field_name ":" " "* field_value :> CRLF;
|
83
|
-
|
84
|
-
Response = Status_Line (message_header)* (CRLF @done);
|
85
|
-
|
86
|
-
chunk_ext_val = token+;
|
87
|
-
chunk_ext_name = token+;
|
88
|
-
chunk_extension = (";" chunk_ext_name >start_field %write_field %start_value ("=" chunk_ext_val >start_value)? %write_value )*;
|
89
|
-
last_chunk = "0"? chunk_extension :> (CRLF @last_chunk @done);
|
90
|
-
chunk_size = xdigit+;
|
91
|
-
chunk = chunk_size >mark %chunk_size chunk_extension space* :> (CRLF @done);
|
92
|
-
Chunked_Header = (chunk | last_chunk);
|
93
|
-
|
94
|
-
main := Response | Chunked_Header;
|
95
|
-
}%%
|
96
|
-
|
97
|
-
/** Data **/
|
98
|
-
%% write data;
|
99
|
-
|
100
|
-
int httpclient_parser_init(httpclient_parser *parser) {
|
101
|
-
int cs = 0;
|
102
|
-
%% write init;
|
103
|
-
parser->cs = cs;
|
104
|
-
parser->body_start = 0;
|
105
|
-
parser->content_len = 0;
|
106
|
-
parser->mark = 0;
|
107
|
-
parser->nread = 0;
|
108
|
-
parser->field_len = 0;
|
109
|
-
parser->field_start = 0;
|
110
|
-
|
111
|
-
return(1);
|
112
|
-
}
|
113
|
-
|
114
|
-
|
115
|
-
/** exec **/
|
116
|
-
size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer, size_t len, size_t off) {
|
117
|
-
const char *p, *pe;
|
118
|
-
int cs = parser->cs;
|
119
|
-
|
120
|
-
assert(off <= len && "offset past end of buffer");
|
121
|
-
|
122
|
-
p = buffer+off;
|
123
|
-
pe = buffer+len;
|
124
|
-
|
125
|
-
assert(*pe == '\0' && "pointer does not end on NUL");
|
126
|
-
assert(pe - p == len - off && "pointers aren't same distance");
|
127
|
-
|
128
|
-
|
129
|
-
%% write exec;
|
130
|
-
|
131
|
-
parser->cs = cs;
|
132
|
-
parser->nread += p - (buffer + off);
|
133
|
-
|
134
|
-
assert(p <= pe && "buffer overflow after parsing execute");
|
135
|
-
assert(parser->nread <= len && "nread longer than length");
|
136
|
-
assert(parser->body_start <= len && "body starts after buffer end");
|
137
|
-
assert(parser->mark < len && "mark is after buffer end");
|
138
|
-
assert(parser->field_len <= len && "field has length longer than whole buffer");
|
139
|
-
assert(parser->field_start < len && "field starts after buffer end");
|
140
|
-
|
141
|
-
if(parser->body_start) {
|
142
|
-
/* final \r\n combo encountered so stop right here */
|
143
|
-
parser->nread = parser->body_start;
|
144
|
-
}
|
145
|
-
|
146
|
-
return(parser->nread);
|
147
|
-
}
|
148
|
-
|
149
|
-
int httpclient_parser_finish(httpclient_parser *parser)
|
150
|
-
{
|
151
|
-
int cs = parser->cs;
|
152
|
-
|
153
|
-
parser->cs = cs;
|
154
|
-
|
155
|
-
if (httpclient_parser_has_error(parser) ) {
|
156
|
-
return -1;
|
157
|
-
} else if (httpclient_parser_is_finished(parser) ) {
|
158
|
-
return 1;
|
159
|
-
} else {
|
160
|
-
return 0;
|
161
|
-
}
|
162
|
-
}
|
163
|
-
|
164
|
-
int httpclient_parser_has_error(httpclient_parser *parser) {
|
165
|
-
return parser->cs == httpclient_parser_error;
|
166
|
-
}
|
167
|
-
|
168
|
-
int httpclient_parser_is_finished(httpclient_parser *parser) {
|
169
|
-
return parser->cs == httpclient_parser_first_final;
|
170
|
-
}
|
data/lib/em-http/mock.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
module EventMachine
|
2
|
-
OriginalHttpRequest = HttpRequest unless const_defined?(:OriginalHttpRequest)
|
3
|
-
|
4
|
-
class MockHttpRequest < EventMachine::HttpRequest
|
5
|
-
|
6
|
-
include HttpEncoding
|
7
|
-
|
8
|
-
class RegisteredRequest < Struct.new(:uri, :method, :headers)
|
9
|
-
def self.build(uri, method, headers)
|
10
|
-
new(uri, method.to_s.upcase, headers || {})
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class FakeHttpClient < EventMachine::HttpClient
|
15
|
-
attr_writer :response
|
16
|
-
attr_reader :data
|
17
|
-
def setup(response, uri)
|
18
|
-
@uri = uri
|
19
|
-
if response == :fail
|
20
|
-
fail(self)
|
21
|
-
else
|
22
|
-
if response.respond_to?(:call)
|
23
|
-
response.call(self)
|
24
|
-
@state = :body
|
25
|
-
else
|
26
|
-
receive_data(response)
|
27
|
-
end
|
28
|
-
@state == :body ? succeed(self) : fail(self)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def unbind
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
@@registry = Hash.new
|
37
|
-
@@registry_count = Hash.new{|h,k| h[k] = 0}
|
38
|
-
|
39
|
-
def self.use
|
40
|
-
activate!
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
deactivate!
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.activate!
|
47
|
-
EventMachine.send(:remove_const, :HttpRequest)
|
48
|
-
EventMachine.send(:const_set, :HttpRequest, MockHttpRequest)
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.deactivate!
|
52
|
-
EventMachine.send(:remove_const, :HttpRequest)
|
53
|
-
EventMachine.send(:const_set, :HttpRequest, OriginalHttpRequest)
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.reset_counts!
|
57
|
-
@@registry_count.clear
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.reset_registry!
|
61
|
-
@@registry.clear
|
62
|
-
end
|
63
|
-
|
64
|
-
@@pass_through_requests = true
|
65
|
-
|
66
|
-
def self.pass_through_requests=(pass_through_requests)
|
67
|
-
@@pass_through_requests = pass_through_requests
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.pass_through_requests
|
71
|
-
@@pass_through_requests
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.parse_register_args(args, &proc)
|
75
|
-
args << proc{|client| proc.call(client); ''} if proc
|
76
|
-
headers, data = case args.size
|
77
|
-
when 3
|
78
|
-
args[2].is_a?(Hash) ?
|
79
|
-
[args[2][:headers], args[2][:data]] :
|
80
|
-
[{}, args[2]]
|
81
|
-
when 4
|
82
|
-
[args[2], args[3]]
|
83
|
-
else
|
84
|
-
raise
|
85
|
-
end
|
86
|
-
|
87
|
-
url = args[0]
|
88
|
-
method = args[1]
|
89
|
-
[headers, url, method, data]
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.register(*args, &proc)
|
93
|
-
headers, url, method, data = parse_register_args(args, &proc)
|
94
|
-
@@registry[RegisteredRequest.build(url, method, headers)] = data
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.register_file(*args)
|
98
|
-
headers, url, method, data = parse_register_args(args)
|
99
|
-
@@registry[RegisteredRequest.build(url, method, headers)] = File.read(data)
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.count(url, method, headers = {})
|
103
|
-
@@registry_count[RegisteredRequest.build(url, method, headers)]
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.registered?(url, method, headers = {})
|
107
|
-
@@registry.key?(RegisteredRequest.build(url, method, headers))
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.registered_content(url, method, headers = {})
|
111
|
-
@@registry[RegisteredRequest.build(url, method, headers)]
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.increment_access(url, method, headers = {})
|
115
|
-
@@registry_count[RegisteredRequest.build(url, method, headers)] += 1
|
116
|
-
end
|
117
|
-
|
118
|
-
alias_method :real_send_request, :send_request
|
119
|
-
|
120
|
-
protected
|
121
|
-
def send_request(&blk)
|
122
|
-
query = "#{@req.uri.scheme}://#{@req.uri.host}:#{@req.uri.port}#{encode_query(@req.uri, @req.options[:query])}"
|
123
|
-
headers = @req.options[:head]
|
124
|
-
if self.class.registered?(query, @req.method, headers)
|
125
|
-
self.class.increment_access(query, @req.method, headers)
|
126
|
-
client = FakeHttpClient.new(nil)
|
127
|
-
content = self.class.registered_content(query, @req.method, headers)
|
128
|
-
client.setup(content, @req.uri)
|
129
|
-
client
|
130
|
-
elsif @@pass_through_requests
|
131
|
-
real_send_request
|
132
|
-
else
|
133
|
-
raise "this request #{query} for method #{@req.method} with the headers #{@req.options[:head].inspect} isn't registered, and pass_through_requests is current set to false"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
data/spec/mock_spec.rb
DELETED
@@ -1,166 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe 'em-http mock' do
|
4
|
-
|
5
|
-
before(:all) do
|
6
|
-
EventMachine::MockHttpRequest.activate!
|
7
|
-
end
|
8
|
-
|
9
|
-
after(:all) do
|
10
|
-
EventMachine::MockHttpRequest.deactivate!
|
11
|
-
end
|
12
|
-
|
13
|
-
before(:each) do
|
14
|
-
EventMachine::MockHttpRequest.reset_registry!
|
15
|
-
EventMachine::MockHttpRequest.reset_counts!
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should serve a fake http request from a proc" do
|
19
|
-
EventMachine::HttpRequest.register('http://www.google.ca:80/', :get) { |req|
|
20
|
-
req.response_header.http_status = 200
|
21
|
-
req.response_header['SOME_WACKY_HEADER'] = 'WACKY_HEADER_VALUE'
|
22
|
-
req.response = "Well, now this is fun."
|
23
|
-
}
|
24
|
-
EM.run {
|
25
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
26
|
-
http.errback { fail }
|
27
|
-
http.callback {
|
28
|
-
http.response_header.status.should == 200
|
29
|
-
http.response_header['SOME_WACKY_HEADER'].should == 'WACKY_HEADER_VALUE'
|
30
|
-
http.response.should == "Well, now this is fun."
|
31
|
-
EventMachine.stop
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should serve a fake http request from a proc with raw data" do
|
39
|
-
EventMachine::HttpRequest.register('http://www.google.ca:80/', :get) { |req|
|
40
|
-
req.receive_data(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca')))
|
41
|
-
}
|
42
|
-
EM.run {
|
43
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
44
|
-
http.errback { fail }
|
45
|
-
http.callback {
|
46
|
-
http.response_header.status.should == 200
|
47
|
-
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'), :encoding => 'ISO-8859-1').split("\r\n\r\n", 2).last
|
48
|
-
http.response.encoding.to_s.should == 'ISO-8859-1'
|
49
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
50
|
-
EventMachine.stop
|
51
|
-
}
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should serve a fake http request from a file" do
|
56
|
-
EventMachine::HttpRequest.register_file('http://www.google.ca:80/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
57
|
-
EM.run {
|
58
|
-
|
59
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
60
|
-
http.errback { fail }
|
61
|
-
http.callback {
|
62
|
-
http.response_header.status.should == 200
|
63
|
-
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'), :encoding => 'ISO-8859-1').split("\r\n\r\n", 2).last
|
64
|
-
http.response.encoding.to_s.should == 'ISO-8859-1'
|
65
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
66
|
-
EventMachine.stop
|
67
|
-
}
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should serve a fake http request from a string" do
|
72
|
-
data = <<-HEREDOC
|
73
|
-
HTTP/1.0 200 OK
|
74
|
-
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
75
|
-
Expires: -1
|
76
|
-
Cache-Control: private, max-age=0
|
77
|
-
Content-Type: text/html; charset=ISO-8859-1
|
78
|
-
Set-Cookie: PREF=ID=9454187d21c4a6a6:TM=1258403955:LM=1258403955:S=2-mf1n5oV5yAeT9-; expires=Wed, 16-Nov-2011 20:39:15 GMT; path=/; domain=.google.ca
|
79
|
-
Set-Cookie: NID=28=lvxxVdiBQkCetu_WFaUxLyB7qPlHXS5OdAGYTqge_laVlCKVN8VYYeVBh4bNZiK_Oan2gm8oP9GA-FrZfMPC3ZMHeNq37MG2JH8AIW9LYucU8brOeuggMEbLNNXuiWg4; expires=Tue, 18-May-2010 20:39:15 GMT; path=/; domain=.google.ca; HttpOnly
|
80
|
-
Server: gws
|
81
|
-
X-XSS-Protection: 0
|
82
|
-
X-Cache: MISS from .
|
83
|
-
Via: 1.0 .:80 (squid)
|
84
|
-
Connection: close
|
85
|
-
|
86
|
-
<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"eLgBS4LROqCQedKVvfUL",kEXPI:"17259,21329,21516,22107",kCSI:{e:"17259,21329,21516,22107",ei:"eLgBS4LROqCQedKVvfUL"},kHL:"en",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||"/gen_204?atyp=i&ct="+b+"&cad="+d+"&zx="+google.time();a.src=c;e.li=f+1},lc:[],li:0};
|
87
|
-
window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{}catch(b){}window.google.jsrt_kill=1;
|
88
|
-
var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf("#")==-1){for(var c=0;c<a.length;){var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&&
|
89
|
-
window._gjuc())&&setTimeout(_gjp,500)};
|
90
|
-
window._gjp && _gjp()</script><style>td{line-height:.8em;}.gac_m td{line-height:17px;}form{margin-bottom:20px;}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{font:17px arial,sans-serif;margin-bottom:.2em;vertical-align:bottom;}input{font-family:inherit}.lsb,.gac_sb{font-size:15px;height:1.85em!important;margin:.2em;}#gbar{height:22px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#guser{padding-bottom:7px !important;text-align:right}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb3,a.gb4{color:#00c !important}.gb3{text-decoration:none}</style><script>google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="document.f.q.focus();if(document.images)new Image().src='/images/nav_logo7.png'" topmargin=3 marginheight=3><textarea id=csi style=display:none></textarea><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.ca/imghp?hl=en&tab=wi" class=gb1>Images</a> <a href="http://video.google.ca/?hl=en&tab=wv" class=gb1>Videos</a> <a href="http://maps.google.ca/maps?hl=en&tab=wl" class=gb1>Maps</a> <a href="http://news.google.ca/nwshp?hl=en&tab=wn" class=gb1>News</a> <a href="http://groups.google.ca/grphp?hl=en&tab=wg" class=gb1>Groups</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.ca/intl/en/options/" class=gb3><u>more</u> »</a></nobr></div><div id=guser width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.ca/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNG2Kt7TgMZuV7Fl3FeeTOmTWMvggA" class=gb4>iGoogle</a> | <a href="/preferences?hl=en" class=gb4>Search settings</a> | <a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.ca/" class=gb4>Sign in</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ca/images/logo.gif" width=276 id=logo onload="window.lol&&lol()"><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%> </td><td align=center nowrap><input name=hl type=hidden value=en><input name=source type=hidden value=hp><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 class=lst title="Google Search" value=""><br><input name=btnG type=submit value="Google Search" class=lsb><input name=btnI type=submit value="I'm Feeling Lucky" class=lsb></td><td nowrap width=25% align=left><font size=-2> <a href=/advanced_search?hl=en>Advanced Search</a><br> <a href=/language_tools?hl=en>Language Tools</a></font></td></tr><tr><td align=center colspan=3><font size=-1><span style="text-align:left">Search: <input id=all type=radio name=meta value="" checked><label for=all> the web </label> <input id=cty type=radio name=meta value="cr=countryCA"><label for=cty> pages from Canada </label> </span></font></td></tr></table></form><br><font size=-1>Google.ca offered in: <a href="http://www.google.ca/setprefs?sig=0_XtMil90_yvnNEW8dIglASaHCVhU=&hl=fr">fran?ais</a> </font><br><br><br><font size=-1><a href="/intl/en/ads/">Advertising Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a> - <a href="http://www.google.com/ncr">Go to Google.com</a></font><p><font size=-2>©2009 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];if(google.y)google.y.first=[];google.dstr=[];google.rein=[];window.setTimeout(function(){var a=document.createElement("script");a.src="/extern_js/f/CgJlbhICY2EgACswCjhBQB0sKzAOOAksKzAYOAQsKzAlOMmIASwrMCY4BywrMCc4Aiw/n_sssePDGvc.js";(document.getElementById("xjsd")||document.body).appendChild(a)},0);
|
91
|
-
;google.y.first.push(function(){google.ac.b=true;google.ac.i(document.f,document.f.q,'','')});google.xjs&&google.j&&google.j.xi&&google.j.xi()</script></div><script>(function(){
|
92
|
-
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();
|
93
|
-
})();
|
94
|
-
HEREDOC
|
95
|
-
EventMachine::HttpRequest.register('http://www.google.ca:80/', :get, {}, data)
|
96
|
-
EventMachine.run {
|
97
|
-
|
98
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
99
|
-
http.errback { fail }
|
100
|
-
http.callback {
|
101
|
-
http.response.should == data.split("\n\n", 2).last
|
102
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
103
|
-
EventMachine.stop
|
104
|
-
}
|
105
|
-
}
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
it "should serve a fake failing http request" do
|
110
|
-
EventMachine::HttpRequest.register('http://www.google.ca:80/', :get, {}, :fail)
|
111
|
-
error = false
|
112
|
-
|
113
|
-
EventMachine.run {
|
114
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
115
|
-
http.callback {
|
116
|
-
EventMachine.stop
|
117
|
-
fail
|
118
|
-
}
|
119
|
-
http.errback {
|
120
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
121
|
-
EventMachine.stop
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should distinguish the cache by the given headers" do
|
128
|
-
EventMachine::HttpRequest.register_file('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
129
|
-
EventMachine::HttpRequest.register_file('http://www.google.ca:80/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
130
|
-
EM.run {
|
131
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
132
|
-
http.errback { fail }
|
133
|
-
http.callback {
|
134
|
-
http.response_header.status.should == 200
|
135
|
-
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'), :encoding => 'ISO-8859-1').split("\r\n\r\n", 2).last
|
136
|
-
http.response.encoding.to_s.should == 'ISO-8859-1'
|
137
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {}).should == 1
|
138
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}).should == 0
|
139
|
-
EventMachine.stop
|
140
|
-
}
|
141
|
-
}
|
142
|
-
|
143
|
-
EM.run {
|
144
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get({:head => {:user_agent => 'BERT'}})
|
145
|
-
http.errback { fail }
|
146
|
-
http.callback {
|
147
|
-
http.response_header.status.should == 200
|
148
|
-
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'), :encoding => 'ISO-8859-1').split("\r\n\r\n", 2).last
|
149
|
-
http.response.encoding.to_s.should == 'ISO-8859-1'
|
150
|
-
EventMachine::HttpRequest.count('http://www.google.ca:80/', :get, {:user_agent => 'BERT'}).should == 1
|
151
|
-
EventMachine.stop
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
it "should raise an exception if pass-thru is disabled" do
|
158
|
-
EventMachine::HttpRequest.pass_through_requests = false
|
159
|
-
EventMachine.run {
|
160
|
-
proc {
|
161
|
-
http = EventMachine::HttpRequest.new('http://www.google.ca/').get
|
162
|
-
}.should raise_error
|
163
|
-
EventMachine.stop
|
164
|
-
}
|
165
|
-
end
|
166
|
-
end
|