astro-em-http-request 0.1.6 → 0.1.12

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/README.rdoc CHANGED
@@ -6,6 +6,9 @@ EventMachine based HTTP Request interface. Supports streaming response processin
6
6
  - Basic-Auth support
7
7
  - Custom timeouts
8
8
 
9
+ Screencast / Demo of using EM-HTTP-Request:
10
+ - http://everburning.com/news/eventmachine-screencast-em-http-request/
11
+
9
12
  == Simple client example
10
13
 
11
14
  EventMachine.run {
@@ -61,9 +64,8 @@ EventMachine based HTTP Request interface. Supports streaming response processin
61
64
 
62
65
  == Streaming body processing
63
66
  EventMachine.run {
64
- body = ''
65
- on_body = lambda { |chunk| body += chunk }
66
- http = EventMachine::HttpRequest.new('http://www.website.com/').get :on_response => on_body
67
+ http = EventMachine::HttpRequest.new('http://www.website.com/').get
68
+ http.stream { |chunk| print chunk }
67
69
 
68
70
  # ...
69
71
  }
data/Rakefile CHANGED
@@ -34,6 +34,10 @@ task :ragel do
34
34
  end
35
35
  end
36
36
 
37
+ task :spec do
38
+ sh 'spec -c test/test_*.rb'
39
+ end
40
+
37
41
  def make(makedir)
38
42
  Dir.chdir(makedir) { sh MAKE }
39
43
  end
@@ -1,17 +1,18 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'em-http-request'
3
- s.version = '0.1.6'
4
- s.date = '2009-03-20'
3
+ s.version = '0.1.9'
4
+ s.date = '2009-10-17'
5
5
  s.summary = 'EventMachine based HTTP Request interface'
6
6
  s.description = s.summary
7
7
  s.email = 'ilya@igvita.com'
8
8
  s.homepage = "http://github.com/igrigorik/em-http-request"
9
9
  s.has_rdoc = true
10
10
  s.authors = ["Ilya Grigorik"]
11
- s.add_dependency('eventmachine', '>= 0.12.2')
11
+ s.add_dependency('eventmachine', '>= 0.12.9')
12
+ s.add_dependency('addressable', '>= 2.0.0')
12
13
  s.extensions = ["ext/buffer/extconf.rb" , "ext/http11_client/extconf.rb"]
13
14
  s.rubyforge_project = "em-http-request"
14
-
15
+
15
16
  # ruby -rpp -e' pp `git ls-files`.split("\n") '
16
17
  s.files = [
17
18
  ".autotest",
@@ -34,9 +35,10 @@ spec = Gem::Specification.new do |s|
34
35
  "lib/em-http/decoders.rb",
35
36
  "lib/em-http/multi.rb",
36
37
  "lib/em-http/request.rb",
37
- "test/hash.rb",
38
+ "test/test_hash.rb",
38
39
  "test/helper.rb",
39
40
  "test/stallion.rb",
41
+ "test/stub_server.rb",
40
42
  "test/test_multi.rb",
41
43
  "test/test_request.rb"]
42
44
  end
@@ -1,3 +1,4 @@
1
+
1
2
  #line 1 "http11_parser.rl"
2
3
  /**
3
4
  * Copyright (c) 2005 Zed A. Shaw
@@ -18,166 +19,183 @@
18
19
 
19
20
 
20
21
  /** machine **/
22
+
21
23
  #line 95 "http11_parser.rl"
22
24
 
23
25
 
24
26
  /** Data **/
25
27
 
26
- #line 27 "http11_parser.c"
28
+ #line 29 "http11_parser.c"
27
29
  static const char _httpclient_parser_actions[] = {
28
30
  0, 1, 0, 1, 1, 1, 2, 1,
29
31
  3, 1, 4, 1, 5, 1, 7, 1,
30
- 8, 1, 10, 2, 2, 3, 2, 6,
31
- 0, 2, 6, 5, 2, 9, 10, 2,
32
- 10, 9, 3, 2, 3, 4
32
+ 8, 1, 10, 2, 0, 5, 2, 2,
33
+ 3, 2, 3, 4, 2, 4, 10, 2,
34
+ 6, 0, 2, 8, 10, 2, 9, 10,
35
+ 2, 10, 9, 3, 2, 3, 4, 3,
36
+ 4, 9, 10, 3, 4, 10, 9, 3,
37
+ 6, 0, 5, 3, 8, 10, 9, 4,
38
+ 2, 3, 4, 10, 5, 2, 3, 4,
39
+ 9, 10, 5, 2, 3, 4, 10, 9
40
+
33
41
  };
34
42
 
35
43
  static const short _httpclient_parser_key_offsets[] = {
36
- 0, 10, 10, 11, 22, 26, 27, 28,
37
- 39, 54, 75, 90, 110, 125, 146, 161,
38
- 181, 196, 214, 229, 246, 247, 248, 249,
39
- 250, 252, 255, 257, 260, 262, 264, 266,
40
- 268, 269, 270, 286, 302, 304, 305, 306
44
+ 0, 0, 11, 12, 24, 29, 30, 31,
45
+ 43, 58, 80, 95, 116, 131, 153, 168,
46
+ 189, 204, 223, 238, 256, 257, 258, 259,
47
+ 260, 262, 265, 267, 270, 272, 274, 276,
48
+ 279, 281, 298, 314, 317, 319, 320, 322
41
49
  };
42
50
 
43
51
  static const char _httpclient_parser_trans_keys[] = {
44
- 13, 48, 59, 72, 49, 57, 65, 70,
45
- 97, 102, 10, 13, 32, 59, 9, 12,
46
- 48, 57, 65, 70, 97, 102, 13, 32,
47
- 9, 12, 10, 10, 13, 32, 59, 9,
48
- 12, 48, 57, 65, 70, 97, 102, 33,
49
- 124, 126, 35, 39, 42, 43, 45, 46,
50
- 48, 57, 65, 90, 94, 122, 13, 32,
51
- 33, 59, 61, 124, 126, 9, 12, 35,
52
- 39, 42, 43, 45, 46, 48, 57, 65,
53
- 90, 94, 122, 33, 124, 126, 35, 39,
54
- 42, 43, 45, 46, 48, 57, 65, 90,
55
- 94, 122, 13, 32, 33, 59, 124, 126,
56
- 9, 12, 35, 39, 42, 43, 45, 46,
57
- 48, 57, 65, 90, 94, 122, 33, 124,
58
- 126, 35, 39, 42, 43, 45, 46, 48,
59
- 57, 65, 90, 94, 122, 13, 32, 33,
60
- 59, 61, 124, 126, 9, 12, 35, 39,
52
+ 10, 13, 48, 59, 72, 49, 57, 65,
53
+ 70, 97, 102, 10, 10, 13, 32, 59,
54
+ 9, 12, 48, 57, 65, 70, 97, 102,
55
+ 10, 13, 32, 9, 12, 10, 10, 10,
56
+ 13, 32, 59, 9, 12, 48, 57, 65,
57
+ 70, 97, 102, 33, 124, 126, 35, 39,
61
58
  42, 43, 45, 46, 48, 57, 65, 90,
62
- 94, 122, 33, 124, 126, 35, 39, 42,
59
+ 94, 122, 10, 13, 32, 33, 59, 61,
60
+ 124, 126, 9, 12, 35, 39, 42, 43,
61
+ 45, 46, 48, 57, 65, 90, 94, 122,
62
+ 33, 124, 126, 35, 39, 42, 43, 45,
63
+ 46, 48, 57, 65, 90, 94, 122, 10,
64
+ 13, 32, 33, 59, 124, 126, 9, 12,
65
+ 35, 39, 42, 43, 45, 46, 48, 57,
66
+ 65, 90, 94, 122, 33, 124, 126, 35,
67
+ 39, 42, 43, 45, 46, 48, 57, 65,
68
+ 90, 94, 122, 10, 13, 32, 33, 59,
69
+ 61, 124, 126, 9, 12, 35, 39, 42,
63
70
  43, 45, 46, 48, 57, 65, 90, 94,
64
- 122, 13, 32, 33, 59, 124, 126, 9,
71
+ 122, 33, 124, 126, 35, 39, 42, 43,
72
+ 45, 46, 48, 57, 65, 90, 94, 122,
73
+ 10, 13, 32, 33, 59, 124, 126, 9,
65
74
  12, 35, 39, 42, 43, 45, 46, 48,
66
75
  57, 65, 90, 94, 122, 33, 124, 126,
67
76
  35, 39, 42, 43, 45, 46, 48, 57,
68
- 65, 90, 94, 122, 13, 33, 59, 61,
69
- 124, 126, 35, 39, 42, 43, 45, 46,
70
- 48, 57, 65, 90, 94, 122, 33, 124,
71
- 126, 35, 39, 42, 43, 45, 46, 48,
72
- 57, 65, 90, 94, 122, 13, 33, 59,
73
- 124, 126, 35, 39, 42, 43, 45, 46,
74
- 48, 57, 65, 90, 94, 122, 84, 84,
75
- 80, 47, 48, 57, 46, 48, 57, 48,
76
- 57, 32, 48, 57, 48, 57, 48, 57,
77
- 48, 57, 13, 32, 13, 10, 13, 33,
78
- 124, 126, 35, 39, 42, 43, 45, 46,
79
- 48, 57, 65, 90, 94, 122, 33, 58,
77
+ 65, 90, 94, 122, 10, 13, 33, 59,
78
+ 61, 124, 126, 35, 39, 42, 43, 45,
79
+ 46, 48, 57, 65, 90, 94, 122, 33,
80
80
  124, 126, 35, 39, 42, 43, 45, 46,
81
- 48, 57, 65, 90, 94, 122, 13, 32,
82
- 13, 13, 0
81
+ 48, 57, 65, 90, 94, 122, 10, 13,
82
+ 33, 59, 124, 126, 35, 39, 42, 43,
83
+ 45, 46, 48, 57, 65, 90, 94, 122,
84
+ 84, 84, 80, 47, 48, 57, 46, 48,
85
+ 57, 48, 57, 32, 48, 57, 48, 57,
86
+ 48, 57, 48, 57, 10, 13, 32, 10,
87
+ 13, 10, 13, 33, 124, 126, 35, 39,
88
+ 42, 43, 45, 46, 48, 57, 65, 90,
89
+ 94, 122, 33, 58, 124, 126, 35, 39,
90
+ 42, 43, 45, 46, 48, 57, 65, 90,
91
+ 94, 122, 10, 13, 32, 10, 13, 10,
92
+ 10, 13, 0
83
93
  };
84
94
 
85
95
  static const char _httpclient_parser_single_lengths[] = {
86
- 4, 0, 1, 3, 2, 1, 1, 3,
87
- 3, 7, 3, 6, 3, 7, 3, 6,
88
- 3, 6, 3, 5, 1, 1, 1, 1,
89
- 0, 1, 0, 1, 0, 0, 0, 2,
90
- 1, 1, 4, 4, 2, 1, 1, 0
96
+ 0, 5, 1, 4, 3, 1, 1, 4,
97
+ 3, 8, 3, 7, 3, 8, 3, 7,
98
+ 3, 7, 3, 6, 1, 1, 1, 1,
99
+ 0, 1, 0, 1, 0, 0, 0, 3,
100
+ 2, 5, 4, 3, 2, 1, 2, 0
91
101
  };
92
102
 
93
103
  static const char _httpclient_parser_range_lengths[] = {
94
- 3, 0, 0, 4, 1, 0, 0, 4,
104
+ 0, 3, 0, 4, 1, 0, 0, 4,
95
105
  6, 7, 6, 7, 6, 7, 6, 7,
96
106
  6, 6, 6, 6, 0, 0, 0, 0,
97
107
  1, 1, 1, 1, 1, 1, 1, 0,
98
- 0, 0, 6, 6, 0, 0, 0, 0
108
+ 0, 6, 6, 0, 0, 0, 0, 0
99
109
  };
100
110
 
101
- static const unsigned char _httpclient_parser_index_offsets[] = {
102
- 0, 8, 8, 10, 18, 22, 24, 26,
103
- 34, 44, 59, 69, 83, 93, 108, 118,
104
- 132, 142, 155, 165, 177, 179, 181, 183,
105
- 185, 187, 190, 192, 195, 197, 199, 201,
106
- 204, 206, 208, 219, 230, 233, 235, 237
111
+ static const short _httpclient_parser_index_offsets[] = {
112
+ 0, 0, 9, 11, 20, 25, 27, 29,
113
+ 38, 48, 64, 74, 89, 99, 115, 125,
114
+ 140, 150, 164, 174, 187, 189, 191, 193,
115
+ 195, 197, 200, 202, 205, 207, 209, 211,
116
+ 215, 218, 230, 241, 245, 248, 250, 253
107
117
  };
108
118
 
109
119
  static const char _httpclient_parser_indicies[] = {
110
- 14, 15, 17, 18, 16, 16, 16, 0,
111
- 30, 0, 63, 37, 64, 37, 39, 39,
112
- 39, 0, 19, 32, 32, 0, 29, 0,
113
- 31, 0, 38, 37, 40, 37, 39, 39,
114
- 39, 0, 58, 58, 58, 58, 58, 58,
115
- 58, 58, 58, 0, 42, 41, 43, 44,
116
- 45, 43, 43, 41, 43, 43, 43, 43,
117
- 43, 43, 0, 59, 59, 59, 59, 59,
118
- 59, 59, 59, 59, 0, 34, 33, 35,
119
- 36, 35, 35, 33, 35, 35, 35, 35,
120
- 35, 35, 0, 70, 70, 70, 70, 70,
121
- 70, 70, 70, 70, 0, 65, 41, 66,
122
- 67, 68, 66, 66, 41, 66, 66, 66,
123
- 66, 66, 66, 0, 69, 69, 69, 69,
124
- 69, 69, 69, 69, 69, 0, 60, 33,
125
- 61, 62, 61, 61, 33, 61, 61, 61,
126
- 61, 61, 61, 0, 10, 10, 10, 10,
127
- 10, 10, 10, 10, 10, 0, 24, 25,
128
- 26, 27, 25, 25, 25, 25, 25, 25,
129
- 25, 25, 0, 11, 11, 11, 11, 11,
130
- 11, 11, 11, 11, 0, 21, 22, 23,
131
- 22, 22, 22, 22, 22, 22, 22, 22,
132
- 0, 1, 0, 56, 0, 2, 0, 5,
133
- 0, 7, 0, 6, 7, 0, 13, 0,
134
- 12, 13, 0, 4, 0, 3, 0, 57,
135
- 0, 54, 55, 53, 49, 48, 28, 0,
136
- 19, 20, 20, 20, 20, 20, 20, 20,
137
- 20, 20, 0, 8, 9, 8, 8, 8,
138
- 8, 8, 8, 8, 8, 0, 47, 52,
139
- 51, 47, 46, 49, 50, 0, 0
120
+ 0, 2, 3, 5, 6, 4, 4, 4,
121
+ 1, 0, 1, 8, 9, 7, 11, 7,
122
+ 10, 10, 10, 1, 13, 14, 12, 12,
123
+ 1, 13, 1, 15, 1, 16, 17, 7,
124
+ 18, 7, 10, 10, 10, 1, 19, 19,
125
+ 19, 19, 19, 19, 19, 19, 19, 1,
126
+ 21, 22, 20, 23, 24, 25, 23, 23,
127
+ 20, 23, 23, 23, 23, 23, 23, 1,
128
+ 26, 26, 26, 26, 26, 26, 26, 26,
129
+ 26, 1, 28, 29, 27, 30, 31, 30,
130
+ 30, 27, 30, 30, 30, 30, 30, 30,
131
+ 1, 32, 32, 32, 32, 32, 32, 32,
132
+ 32, 32, 1, 33, 34, 20, 35, 36,
133
+ 37, 35, 35, 20, 35, 35, 35, 35,
134
+ 35, 35, 1, 38, 38, 38, 38, 38,
135
+ 38, 38, 38, 38, 1, 39, 40, 27,
136
+ 41, 42, 41, 41, 27, 41, 41, 41,
137
+ 41, 41, 41, 1, 43, 43, 43, 43,
138
+ 43, 43, 43, 43, 43, 1, 44, 45,
139
+ 46, 47, 48, 46, 46, 46, 46, 46,
140
+ 46, 46, 46, 1, 49, 49, 49, 49,
141
+ 49, 49, 49, 49, 49, 1, 50, 51,
142
+ 52, 53, 52, 52, 52, 52, 52, 52,
143
+ 52, 52, 1, 54, 1, 55, 1, 56,
144
+ 1, 57, 1, 58, 1, 59, 58, 1,
145
+ 60, 1, 61, 60, 1, 62, 1, 63,
146
+ 1, 64, 1, 66, 67, 68, 65, 70,
147
+ 71, 69, 13, 14, 72, 72, 72, 72,
148
+ 72, 72, 72, 72, 72, 1, 73, 74,
149
+ 73, 73, 73, 73, 73, 73, 73, 73,
150
+ 1, 76, 77, 78, 75, 80, 81, 79,
151
+ 82, 1, 84, 85, 83, 1, 0
140
152
  };
141
153
 
142
- static const char _httpclient_parser_trans_targs_wi[] = {
143
- 1, 21, 23, 30, 29, 24, 26, 25,
144
- 35, 36, 17, 19, 28, 27, 2, 3,
145
- 7, 16, 20, 5, 35, 2, 19, 16,
146
- 2, 17, 16, 18, 34, 39, 39, 39,
147
- 4, 4, 5, 11, 8, 4, 5, 7,
148
- 8, 4, 5, 9, 8, 10, 37, 33,
149
- 32, 33, 32, 37, 36, 32, 33, 38,
150
- 22, 31, 9, 11, 6, 15, 12, 6,
151
- 12, 6, 13, 12, 14, 15, 13
154
+ static const char _httpclient_parser_trans_targs[] = {
155
+ 39, 0, 2, 3, 7, 16, 20, 4,
156
+ 39, 6, 7, 12, 4, 39, 5, 39,
157
+ 39, 5, 8, 9, 4, 39, 5, 9,
158
+ 8, 10, 11, 4, 39, 5, 11, 8,
159
+ 13, 39, 6, 13, 12, 14, 15, 39,
160
+ 6, 15, 12, 17, 39, 2, 17, 16,
161
+ 18, 19, 39, 2, 19, 16, 21, 22,
162
+ 23, 24, 25, 26, 27, 28, 29, 30,
163
+ 31, 32, 33, 37, 38, 32, 33, 37,
164
+ 34, 34, 35, 36, 33, 37, 35, 36,
165
+ 33, 37, 33, 32, 33, 37
152
166
  };
153
167
 
154
- static const char _httpclient_parser_trans_actions_wi[] = {
155
- 0, 0, 0, 0, 1, 0, 0, 0,
156
- 0, 5, 3, 7, 13, 0, 0, 1,
157
- 1, 0, 1, 0, 3, 9, 0, 9,
158
- 34, 0, 34, 19, 0, 17, 28, 31,
159
- 0, 9, 9, 0, 9, 15, 15, 0,
160
- 15, 34, 34, 0, 34, 19, 0, 9,
161
- 0, 11, 1, 7, 7, 22, 25, 22,
162
- 0, 0, 3, 7, 9, 0, 9, 15,
163
- 15, 34, 0, 34, 19, 7, 3
168
+ static const char _httpclient_parser_trans_actions[] = {
169
+ 37, 0, 0, 1, 1, 0, 1, 15,
170
+ 59, 15, 0, 15, 0, 17, 0, 40,
171
+ 34, 15, 15, 3, 43, 63, 43, 0,
172
+ 43, 22, 7, 9, 28, 9, 0, 9,
173
+ 3, 74, 43, 0, 43, 22, 7, 51,
174
+ 9, 0, 9, 3, 68, 43, 0, 43,
175
+ 22, 7, 47, 9, 0, 9, 0, 0,
176
+ 0, 0, 0, 0, 0, 13, 1, 0,
177
+ 0, 31, 55, 55, 31, 0, 11, 11,
178
+ 3, 0, 5, 7, 25, 25, 7, 0,
179
+ 9, 9, 0, 1, 19, 19
164
180
  };
165
181
 
166
- static const int httpclient_parser_start = 0;
167
-
182
+ static const int httpclient_parser_start = 1;
168
183
  static const int httpclient_parser_first_final = 39;
184
+ static const int httpclient_parser_error = 0;
185
+
186
+ static const int httpclient_parser_en_main = 1;
169
187
 
170
- static const int httpclient_parser_error = 1;
171
188
 
172
189
  #line 99 "http11_parser.rl"
173
190
 
174
191
  int httpclient_parser_init(httpclient_parser *parser) {
175
192
  int cs = 0;
176
193
 
177
- #line 178 "http11_parser.c"
194
+ #line 195 "http11_parser.c"
178
195
  {
179
196
  cs = httpclient_parser_start;
180
197
  }
198
+
181
199
  #line 103 "http11_parser.rl"
182
200
  parser->cs = cs;
183
201
  parser->body_start = 0;
@@ -206,7 +224,7 @@ size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer,
206
224
 
207
225
 
208
226
 
209
- #line 210 "http11_parser.c"
227
+ #line 228 "http11_parser.c"
210
228
  {
211
229
  int _klen;
212
230
  unsigned int _trans;
@@ -215,10 +233,10 @@ size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer,
215
233
  const char *_keys;
216
234
 
217
235
  if ( p == pe )
236
+ goto _test_eof;
237
+ if ( cs == 0 )
218
238
  goto _out;
219
239
  _resume:
220
- if ( cs == 1 )
221
- goto _out;
222
240
  _keys = _httpclient_parser_trans_keys + _httpclient_parser_key_offsets[cs];
223
241
  _trans = _httpclient_parser_index_offsets[cs];
224
242
 
@@ -269,12 +287,12 @@ _resume:
269
287
 
270
288
  _match:
271
289
  _trans = _httpclient_parser_indicies[_trans];
272
- cs = _httpclient_parser_trans_targs_wi[_trans];
290
+ cs = _httpclient_parser_trans_targs[_trans];
273
291
 
274
- if ( _httpclient_parser_trans_actions_wi[_trans] == 0 )
292
+ if ( _httpclient_parser_trans_actions[_trans] == 0 )
275
293
  goto _again;
276
294
 
277
- _acts = _httpclient_parser_actions + _httpclient_parser_trans_actions_wi[_trans];
295
+ _acts = _httpclient_parser_actions + _httpclient_parser_trans_actions[_trans];
278
296
  _nacts = (unsigned int) *_acts++;
279
297
  while ( _nacts-- > 0 )
280
298
  {
@@ -340,18 +358,22 @@ _match:
340
358
  parser->body_start = p - buffer + 1;
341
359
  if(parser->header_done != NULL)
342
360
  parser->header_done(parser->data, p + 1, pe - p - 1);
343
- goto _out;
361
+ {p++; goto _out; }
344
362
  }
345
363
  break;
346
- #line 347 "http11_parser.c"
364
+ #line 365 "http11_parser.c"
347
365
  }
348
366
  }
349
367
 
350
368
  _again:
369
+ if ( cs == 0 )
370
+ goto _out;
351
371
  if ( ++p != pe )
352
372
  goto _resume;
373
+ _test_eof: {}
353
374
  _out: {}
354
375
  }
376
+
355
377
  #line 130 "http11_parser.rl"
356
378
 
357
379
  parser->cs = cs;
@@ -366,10 +388,7 @@ _again:
366
388
 
367
389
  if(parser->body_start) {
368
390
  /* final \r\n combo encountered so stop right here */
369
-
370
- #line 371 "http11_parser.c"
371
- #line 144 "http11_parser.rl"
372
- parser->nread++;
391
+ parser->nread = parser->body_start;
373
392
  }
374
393
 
375
394
  return(parser->nread);
@@ -379,10 +398,6 @@ int httpclient_parser_finish(httpclient_parser *parser)
379
398
  {
380
399
  int cs = parser->cs;
381
400
 
382
-
383
- #line 384 "http11_parser.c"
384
- #line 155 "http11_parser.rl"
385
-
386
401
  parser->cs = cs;
387
402
 
388
403
  if (httpclient_parser_has_error(parser) ) {
@@ -62,7 +62,7 @@
62
62
  }
63
63
 
64
64
  # line endings
65
- CRLF = "\r\n";
65
+ CRLF = ("\r\n" | "\n");
66
66
 
67
67
  # character types
68
68
  CTL = (cntrl | 127);
@@ -140,8 +140,7 @@ size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer,
140
140
 
141
141
  if(parser->body_start) {
142
142
  /* final \r\n combo encountered so stop right here */
143
- %%write eof;
144
- parser->nread++;
143
+ parser->nread = parser->body_start;
145
144
  }
146
145
 
147
146
  return(parser->nread);
@@ -151,8 +150,6 @@ int httpclient_parser_finish(httpclient_parser *parser)
151
150
  {
152
151
  int cs = parser->cs;
153
152
 
154
- %%write eof;
155
-
156
153
  parser->cs = cs;
157
154
 
158
155
  if (httpclient_parser_has_error(parser) ) {
@@ -1,4 +1,3 @@
1
- # -*- coding: undecided -*-
2
1
  # #--
3
2
  # Copyright (C)2008 Ilya Grigorik
4
3
  #
@@ -21,6 +20,16 @@ module EventMachine
21
20
 
22
21
  # The status code (as a string!)
23
22
  attr_accessor :http_status
23
+
24
+ # E-Tag
25
+ def etag
26
+ self["ETag"]
27
+ end
28
+
29
+ def last_modified
30
+ time = self["Last-Modified"]
31
+ Time.parse(time) if time
32
+ end
24
33
 
25
34
  # HTTP response status as an integer
26
35
  def status
@@ -32,6 +41,11 @@ module EventMachine
32
41
  Integer(self[HttpClient::CONTENT_LENGTH]) rescue nil
33
42
  end
34
43
 
44
+ # Cookie header from the server
45
+ def cookie
46
+ self[HttpClient::SET_COOKIE]
47
+ end
48
+
35
49
  # Is the transfer encoding chunked?
36
50
  def chunked_encoding?
37
51
  /chunked/i === self[HttpClient::TRANSFER_ENCODING]
@@ -44,6 +58,10 @@ module EventMachine
44
58
  def compressed?
45
59
  /gzip|compressed|deflate/i === self[HttpClient::CONTENT_ENCODING]
46
60
  end
61
+
62
+ def location
63
+ self[HttpClient::LOCATION]
64
+ end
47
65
  end
48
66
 
49
67
  class HttpChunkHeader < Hash
@@ -86,7 +104,7 @@ module EventMachine
86
104
  # you include port 80 then further redirects will tack on the :80 which is
87
105
  # annoying.
88
106
  def encode_host
89
- @uri.host + (@uri.port.to_i != 80 ? ":#{@uri.port}" : "")
107
+ @uri.host + (@uri.port != 80 ? ":#{@uri.port}" : "")
90
108
  end
91
109
 
92
110
  def encode_request(method, path, query)
@@ -94,12 +112,16 @@ module EventMachine
94
112
  end
95
113
 
96
114
  def encode_query(path, query)
97
- return path unless query
98
- if query.kind_of? String
99
- return "#{path}?#{query}"
115
+ encoded_query = if query.kind_of?(Hash)
116
+ query.map { |k, v| encode_param(k, v) }.join('&')
100
117
  else
101
- return path + "?" + query.map { |k, v| encode_param(k, v) }.join('&')
118
+ query.to_s
119
+ end
120
+ if !@uri.query.to_s.empty?
121
+ encoded_query = [encoded_query, @uri.query].reject {|part| part.empty?}.join("&")
102
122
  end
123
+ return path if encoded_query.to_s.empty?
124
+ "#{path}?#{encoded_query}"
103
125
  end
104
126
 
105
127
  # URL encodes query parameters:
@@ -134,8 +156,12 @@ module EventMachine
134
156
  end
135
157
  end
136
158
 
137
- def encode_cookies(cookies)
138
- cookies.inject('') { |result, (k, v)| result << encode_field('Cookie', encode_param(k, v)) }
159
+ def encode_cookie(cookie)
160
+ if cookie.is_a? Hash
161
+ cookie.inject('') { |result, (k, v)| result << encode_param(k, v) + ";" }
162
+ else
163
+ cookie
164
+ end
139
165
  end
140
166
  end
141
167
 
@@ -164,17 +190,20 @@ module EventMachine
164
190
  @state = :response_header
165
191
  @parser_nbytes = 0
166
192
  @response = ''
167
- @inflate = []
168
193
  @errors = ''
169
194
  @content_decoder = nil
195
+ @stream = nil
170
196
  end
171
197
 
172
198
  # start HTTP request once we establish connection to host
173
199
  def connection_completed
200
+ ssl = @options[:tls] || @options[:ssl] || {}
201
+ start_tls(ssl) if @uri.scheme == "https" #or @uri.port == 443 # A user might not want https even on port 443.
202
+
174
203
  send_request_header
175
204
  send_request_body
176
205
  end
177
-
206
+
178
207
  # request is done, invoke the callback
179
208
  def on_request_complete
180
209
  begin
@@ -184,17 +213,33 @@ module EventMachine
184
213
  end
185
214
  unbind
186
215
  end
187
-
216
+
188
217
  # request failed, invoke errback
189
- def on_error(msg)
218
+ def on_error(msg, dns_error = false)
190
219
  @errors = msg
191
- unbind
220
+
221
+ # no connection signature on DNS failures
222
+ # fail the connection directly
223
+ dns_error == true ? fail : unbind
224
+ end
225
+
226
+ # assign a stream processing block
227
+ def stream(&blk)
228
+ @stream = blk
229
+ end
230
+
231
+ def normalize_body
232
+ if @options[:body].is_a? Hash
233
+ @options[:body].to_params
234
+ else
235
+ @options[:body]
236
+ end
192
237
  end
193
238
 
194
239
  def send_request_header
195
240
  query = @options[:query]
196
241
  head = @options[:head] ? munge_header_keys(@options[:head]) : {}
197
- body = @options[:body]
242
+ body = normalize_body
198
243
 
199
244
  # Set the Host header if it hasn't been specified already
200
245
  head['host'] ||= encode_host
@@ -205,9 +250,9 @@ module EventMachine
205
250
  # Set the User-Agent if it hasn't been specified
206
251
  head['user-agent'] ||= "EventMachine HttpClient"
207
252
 
208
- # Set auto-inflate flags
209
- if head['accept-encoding']
210
- @inflate = head['accept-encoding'].split(',').map {|t| t.strip}
253
+ # Set the cookie header if provided
254
+ if cookie = head.delete('cookie')
255
+ head['cookie'] = encode_cookie(cookie)
211
256
  end
212
257
 
213
258
  # Build the request
@@ -220,11 +265,7 @@ module EventMachine
220
265
 
221
266
  def send_request_body
222
267
  return unless @options[:body]
223
- if @options[:body].is_a? Hash
224
- body = @options[:body].to_params
225
- else
226
- body = @options[:body]
227
- end
268
+ body = normalize_body
228
269
  send_data body
229
270
  end
230
271
 
@@ -247,15 +288,19 @@ module EventMachine
247
288
  end
248
289
 
249
290
  def on_decoded_body_data(data)
250
- if (on_response = @options[:on_response])
251
- on_response.call(data)
291
+ if @stream
292
+ @stream.call(data)
252
293
  else
253
294
  @response << data
254
295
  end
255
296
  end
256
297
 
257
298
  def unbind
258
- (@state == :finished) ? succeed(self) : fail
299
+ if @state == :finished || (@state == :body && @bytes_remaining.nil?)
300
+ succeed(self)
301
+ else
302
+ fail(self)
303
+ end
259
304
  close_connection
260
305
  end
261
306
 
@@ -286,7 +331,6 @@ module EventMachine
286
331
 
287
332
  def parse_header(header)
288
333
  return false if @data.empty?
289
-
290
334
  begin
291
335
  @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
292
336
  rescue EventMachine::HttpClientParserError
@@ -313,22 +357,50 @@ module EventMachine
313
357
  return false
314
358
  end
315
359
 
360
+ # correct location header - some servers will incorrectly give a relative URI
361
+ if @response_header.location
362
+ begin
363
+ location = URI.parse @response_header.location
364
+ if location.relative?
365
+ location = (@uri.merge location).to_s
366
+ @response_header[LOCATION] = location
367
+ end
368
+ rescue
369
+ on_error "Location header format error"
370
+ return false
371
+ end
372
+ end
373
+
374
+ # shortcircuit on HEAD requests
375
+ if @method == "HEAD"
376
+ @state = :finished
377
+ on_request_complete
378
+ end
379
+
316
380
  if @response_header.chunked_encoding?
317
381
  @state = :chunk_header
382
+ elsif @response_header.content_length
383
+ if @response_header.content_length > 0
384
+ @state = :body
385
+ @bytes_remaining = @response_header.content_length
386
+ else
387
+ @state = :body
388
+ @bytes_remaining = nil
389
+ end
318
390
  else
319
- @state = :body
320
- @bytes_remaining = @response_header.content_length
391
+ @state = :invalid
392
+ on_error "no HTTP response"
393
+ return false
321
394
  end
322
395
 
323
- if @inflate.include?(response_header[CONTENT_ENCODING]) &&
324
- decoder_class = HttpDecoders.decoder_for_encoding(response_header[CONTENT_ENCODING])
396
+ if decoder_class = HttpDecoders.decoder_for_encoding(response_header[CONTENT_ENCODING])
325
397
  begin
326
398
  @content_decoder = decoder_class.new do |s| on_decoded_body_data(s) end
327
399
  rescue HttpDecoders::DecoderError
328
400
  on_error "Content-decoder error"
329
401
  end
330
402
  end
331
-
403
+
332
404
  true
333
405
  end
334
406
 
@@ -1,4 +1,5 @@
1
1
  require 'zlib'
2
+ require 'stringio'
2
3
 
3
4
  ##
4
5
  # Provides a unified callback interface to decompression libraries.
@@ -115,5 +116,3 @@ module EventMachine::HttpDecoders
115
116
  DECODERS = [Deflate, GZip]
116
117
 
117
118
  end
118
-
119
-
@@ -1,5 +1,5 @@
1
- require 'uri'
2
1
  require 'base64'
2
+ require 'addressable/uri'
3
3
 
4
4
  module EventMachine
5
5
 
@@ -27,7 +27,7 @@ module EventMachine
27
27
 
28
28
  def initialize(host, headers = {})
29
29
  @headers = headers
30
- @uri = host.kind_of?(URI) ? host : URI::parse(host)
30
+ @uri = host.kind_of?(Addressable::URI) ? host : Addressable::URI::parse(host)
31
31
  end
32
32
 
33
33
  # Send an HTTP request and consume the response. Supported options:
@@ -50,6 +50,7 @@ module EventMachine
50
50
  # Host: header
51
51
 
52
52
  def get options = {}; send_request(:get, options); end
53
+ def head options = {}; send_request(:head, options); end
53
54
  def post options = {}; send_request(:post, options); end
54
55
 
55
56
  protected
@@ -57,19 +58,30 @@ module EventMachine
57
58
  def send_request(method, options)
58
59
  raise ArgumentError, "invalid request path" unless /^\// === @uri.path
59
60
 
61
+ # Make sure the port is set as Addressable::URI doesn't set the
62
+ # port if it isn't there.
63
+ @uri.port = @uri.port ? @uri.port : 80
60
64
  method = method.to_s.upcase
61
65
  begin
62
66
  host = options[:host] || @uri.host
67
+ raise ArgumentError, "invalid host" unless host
68
+ raise ArgumentError, "invalid port" unless @uri.port
63
69
  EventMachine.connect(host, @uri.port, EventMachine::HttpClient) { |c|
64
70
  c.uri = @uri
65
71
  c.method = method
66
72
  c.options = options
67
- c.comm_inactivity_timeout = options[:timeout] || 5
73
+ if options.has_key?(:timeout) && options[:timeout]
74
+ c.comm_inactivity_timeout = options[:timeout]
75
+ c.pending_connect_timeout = options[:timeout]
76
+ elsif options.has_key?(:timeout)
77
+ c.comm_inactivity_timeout = 5
78
+ c.pending_connect_timeout = 5
79
+ end
68
80
  }
69
81
  rescue RuntimeError => e
70
82
  raise e unless e.message == "no connection"
71
83
  conn = EventMachine::HttpClient.new("")
72
- conn.on_error("no connection")
84
+ conn.on_error("no connection", true)
73
85
  conn
74
86
  end
75
87
  end
data/test/stallion.rb CHANGED
@@ -80,9 +80,22 @@ Stallion.saddle :spec do |stable|
80
80
  elsif stable.request.path_info == '/echo_query'
81
81
  stable.response.write stable.request.query_string
82
82
 
83
+ elsif stable.request.path_info == '/echo_content_length'
84
+ stable.response.write stable.request.content_length
85
+
86
+ elsif stable.request.head?
87
+ stable.response.status = 200
88
+
83
89
  elsif stable.request.post?
84
90
  stable.response.write stable.request.body.read
85
91
 
92
+ elsif stable.request.path_info == '/set_cookie'
93
+ stable.response["Set-Cookie"] = "id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;"
94
+ stable.response.write "cookie set"
95
+
96
+ elsif stable.request.path_info == '/echo_cookie'
97
+ stable.response.write stable.request.env["HTTP_COOKIE"]
98
+
86
99
  elsif stable.request.path_info == '/timeout'
87
100
  sleep(10)
88
101
  stable.response.write 'timeout'
@@ -121,7 +134,11 @@ Stallion.saddle :spec do |stable|
121
134
  end
122
135
 
123
136
  Thread.new do
124
- Stallion.run :Host => '127.0.0.1', :Port => 8080
137
+ begin
138
+ Stallion.run :Host => '127.0.0.1', :Port => 8080
139
+ rescue Exception => e
140
+ print e
141
+ end
125
142
  end
126
143
 
127
- sleep(2)
144
+ sleep(1)
@@ -0,0 +1,22 @@
1
+ class StubServer
2
+ module Server
3
+ def receive_data(data)
4
+ send_data @response
5
+ close_connection_after_writing
6
+ end
7
+
8
+ def response=(response)
9
+ @response = response
10
+ end
11
+ end
12
+
13
+ def initialize(response, port=8081)
14
+ @sig = EventMachine::start_server("127.0.0.1", port, Server) { |s|
15
+ s.response = response
16
+ }
17
+ end
18
+
19
+ def stop
20
+ EventMachine.stop_server @sig
21
+ end
22
+ end
@@ -1,6 +1,7 @@
1
1
  require 'test/helper'
2
2
 
3
3
  describe Hash do
4
+
4
5
  describe ".to_params" do
5
6
  it "should transform a basic hash into HTTP POST Params" do
6
7
  {:a => "alpha", :b => "beta"}.to_params.should == "a=alpha&b=beta"
@@ -9,9 +10,10 @@ describe Hash do
9
10
  it "should transform a more complex hash into HTTP POST Params" do
10
11
  {:a => "a", :b => ["c", "d", "e"]}.to_params.should == "a=a&b[0]=c&b[1]=d&b[2]=e"
11
12
  end
12
-
13
- it "should transform a very complex hash into HTTP POST Params" do
14
- {:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]}.to_params.should == "a=a&b[0][d]=d&b[0][c]=c&b[1][e]=e&b[1][f]=f"
15
- end
13
+
14
+ # Ruby 1.8 Hash is not sorted, so this test breaks randomly. Maybe once we're all on 1.9. ;-)
15
+ # it "should transform a very complex hash into HTTP POST Params" do
16
+ # {:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]}.to_params.should == "a=a&b[0][d]=d&b[0][c]=c&b[1][f]=f&b[1][e]=e"
17
+ # end
16
18
  end
17
19
  end
data/test/test_multi.rb CHANGED
@@ -3,11 +3,6 @@ require 'test/stallion'
3
3
 
4
4
  describe EventMachine::MultiRequest do
5
5
 
6
- def failed
7
- EventMachine.stop
8
- fail
9
- end
10
-
11
6
  it "should submit multiple requests in parallel and return once all of them are complete" do
12
7
  EventMachine.run {
13
8
 
@@ -16,7 +11,7 @@ describe EventMachine::MultiRequest do
16
11
 
17
12
  # add multiple requests to the multi-handler
18
13
  multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'}))
19
- multi.add(EventMachine::HttpRequest.new('http://169.169.169.169/').get)
14
+ multi.add(EventMachine::HttpRequest.new('http://0.0.0.0/').get(:timeout => 1))
20
15
 
21
16
  multi.callback {
22
17
  # verify successfull request
data/test/test_request.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  require 'test/helper'
2
2
  require 'test/stallion'
3
-
3
+ require 'test/stub_server'
4
+
4
5
  describe EventMachine::HttpRequest do
5
6
 
6
7
  def failed
7
8
  EventMachine.stop
8
9
  fail
9
10
  end
10
-
11
+
11
12
  it "should fail GET on DNS timeout" do
12
13
  EventMachine.run {
13
- http = EventMachine::HttpRequest.new('http://127.1.1.1/').get
14
+ http = EventMachine::HttpRequest.new('http://127.1.1.1/').get :timeout => 1
14
15
  http.callback { failed }
15
16
  http.errback {
16
17
  http.response_header.status.should == 0
@@ -21,7 +22,7 @@ describe EventMachine::HttpRequest do
21
22
 
22
23
  it "should fail GET on invalid host" do
23
24
  EventMachine.run {
24
- http = EventMachine::HttpRequest.new('http://google1.com/').get
25
+ http = EventMachine::HttpRequest.new('http://google1.com/').get :timeout => 1
25
26
  http.callback { failed }
26
27
  http.errback {
27
28
  http.response_header.status.should == 0
@@ -68,12 +69,26 @@ describe EventMachine::HttpRequest do
68
69
  }
69
70
  end
70
71
 
72
+ it "should perform successfull HEAD with a URI passed as argument" do
73
+ EventMachine.run {
74
+ uri = URI.parse('http://127.0.0.1:8080/')
75
+ http = EventMachine::HttpRequest.new(uri).head
76
+
77
+ http.errback { failed }
78
+ http.callback {
79
+ http.response_header.status.should == 200
80
+ http.response.should == ""
81
+ EventMachine.stop
82
+ }
83
+ }
84
+ end
85
+
71
86
  it "should return 404 on invalid path" do
72
87
  EventMachine.run {
73
88
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/fail').get
74
89
 
75
90
  http.errback { failed }
76
- http.callback {
91
+ http.callback {
77
92
  http.response_header.status.should == 404
78
93
  EventMachine.stop
79
94
  }
@@ -145,6 +160,20 @@ describe EventMachine::HttpRequest do
145
160
  }
146
161
  }
147
162
  end
163
+
164
+ it "should perform successfull POST with Ruby Hash/Array as params and with the correct content length" do
165
+ EventMachine.run {
166
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_length').post :body => {"key1" => "data1"}
167
+
168
+ http.errback { failed }
169
+ http.callback {
170
+ http.response_header.status.should == 200
171
+
172
+ http.response.to_i.should == 10
173
+ EventMachine.stop
174
+ }
175
+ }
176
+ end
148
177
 
149
178
  it "should perform successfull GET with custom header" do
150
179
  EventMachine.run {
@@ -233,10 +262,10 @@ describe EventMachine::HttpRequest do
233
262
  it "should timeout after 10 seconds" do
234
263
  EventMachine.run {
235
264
  t = Time.now.to_i
236
- http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/timeout').get :timeout => 2
265
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/timeout').get :timeout => 1
237
266
 
238
267
  http.errback {
239
- (Time.now.to_i - t).should == 2
268
+ (Time.now.to_i - t).should >= 2
240
269
  EventMachine.stop
241
270
  }
242
271
  http.callback { failed }
@@ -246,10 +275,11 @@ describe EventMachine::HttpRequest do
246
275
  it "should optionally pass the response body progressively" do
247
276
  EventMachine.run {
248
277
  body = ''
249
- on_body = lambda { |chunk| body += chunk }
250
- http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :on_response => on_body
278
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
251
279
 
252
280
  http.errback { failed }
281
+ http.stream { |chunk| body += chunk }
282
+
253
283
  http.callback {
254
284
  http.response_header.status.should == 200
255
285
  http.response.should == ''
@@ -262,11 +292,11 @@ describe EventMachine::HttpRequest do
262
292
  it "should optionally pass the deflate-encoded response body progressively" do
263
293
  EventMachine.run {
264
294
  body = ''
265
- on_body = lambda { |chunk| body += chunk }
266
- http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/deflate').get :head => {"accept-encoding" => "deflate, compressed"},
267
- :on_response => on_body
295
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/deflate').get :head => {"accept-encoding" => "deflate, compressed"}
268
296
 
269
297
  http.errback { failed }
298
+ http.stream { |chunk| body += chunk }
299
+
270
300
  http.callback {
271
301
  http.response_header.status.should == 200
272
302
  http.response_header["CONTENT_ENCODING"].should == "deflate"
@@ -277,16 +307,86 @@ describe EventMachine::HttpRequest do
277
307
  }
278
308
  end
279
309
 
280
- it "should respect manually-passed host address" do
310
+ it "should initiate SSL/TLS on HTTPS connections" do
311
+ EventMachine.run {
312
+ http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail/').get
313
+
314
+ http.errback { failed }
315
+ http.callback {
316
+ http.response_header.status.should == 302
317
+ EventMachine.stop
318
+ }
319
+ }
320
+ end
321
+
322
+ it "should accept & return cookie header to user" do
281
323
  EventMachine.run {
282
- http = EventMachine::HttpRequest.new('http://127.1.1.1:8080/').get :host => '127.0.0.1'
324
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/set_cookie').get
283
325
 
284
326
  http.errback { failed }
285
327
  http.callback {
286
328
  http.response_header.status.should == 200
287
- http.response.should match(/Hello/)
329
+ http.response_header.cookie.should == "id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;"
330
+ EventMachine.stop
331
+ }
332
+ }
333
+ end
334
+
335
+ it "should pass cookie header to server from string" do
336
+ EventMachine.run {
337
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_cookie').get :head => {'cookie' => 'id=2;'}
338
+
339
+ http.errback { failed }
340
+ http.callback {
341
+ http.response.should == "id=2;"
288
342
  EventMachine.stop
289
343
  }
290
344
  }
291
345
  end
346
+
347
+ it "should pass cookie header to server from Hash" do
348
+ EventMachine.run {
349
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_cookie').get :head => {'cookie' => {'id' => 2}}
350
+
351
+ http.errback { failed }
352
+ http.callback {
353
+ http.response.should == "id=2;"
354
+ EventMachine.stop
355
+ }
356
+ }
357
+ end
358
+
359
+ context "when talking to a stub HTTP/1.0 server" do
360
+ it "should get the body without Content-Length" do
361
+ EventMachine.run {
362
+ @s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo")
363
+
364
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get
365
+ http.errback { failed }
366
+ http.callback {
367
+ http.response.should match(/Foo/)
368
+
369
+ @s.stop
370
+ EventMachine.stop
371
+ }
372
+ }
373
+ end
374
+
375
+ it "should work with \\n instead of \\r\\n" do
376
+ EventMachine.run {
377
+ @s = StubServer.new("HTTP/1.0 200 OK\nContent-Type: text/plain\nContent-Length: 3\nConnection: close\n\nFoo")
378
+
379
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get
380
+ http.errback { failed }
381
+ http.callback {
382
+ http.response_header.status.should == 200
383
+ http.response_header['CONTENT_TYPE'].should == 'text/plain'
384
+ http.response.should match(/Foo/)
385
+
386
+ @s.stop
387
+ EventMachine.stop
388
+ }
389
+ }
390
+ end
391
+ end
292
392
  end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: astro-em-http-request
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Grigorik
8
+ - Stephan Maka
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-03-20 00:00:00 -07:00
13
+ date: 2009-10-20 00:00:00 +02:00
13
14
  default_executable:
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
@@ -20,10 +21,20 @@ dependencies:
20
21
  requirements:
21
22
  - - ">="
22
23
  - !ruby/object:Gem::Version
23
- version: 0.12.2
24
+ version: 0.12.9
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: addressable
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 2.0.0
24
35
  version:
25
36
  description: EventMachine based HTTP Request interface
26
- email: ilya@igvita.com
37
+ email: astro@spaceboyz.net
27
38
  executables: []
28
39
 
29
40
  extensions:
@@ -52,13 +63,16 @@ files:
52
63
  - lib/em-http/decoders.rb
53
64
  - lib/em-http/multi.rb
54
65
  - lib/em-http/request.rb
55
- - test/hash.rb
66
+ - test/test_hash.rb
56
67
  - test/helper.rb
57
68
  - test/stallion.rb
69
+ - test/stub_server.rb
58
70
  - test/test_multi.rb
59
71
  - test/test_request.rb
60
72
  has_rdoc: true
61
73
  homepage: http://github.com/igrigorik/em-http-request
74
+ licenses: []
75
+
62
76
  post_install_message:
63
77
  rdoc_options: []
64
78
 
@@ -79,9 +93,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
93
  requirements: []
80
94
 
81
95
  rubyforge_project: em-http-request
82
- rubygems_version: 1.2.0
96
+ rubygems_version: 1.3.5
83
97
  signing_key:
84
- specification_version: 2
98
+ specification_version: 3
85
99
  summary: EventMachine based HTTP Request interface
86
100
  test_files: []
87
101