em-http-request 0.2.14 → 0.2.15

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.

@@ -1,170 +1,170 @@
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
- }
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
+ }
@@ -68,10 +68,14 @@ module EventMachine
68
68
  # When parsing chunked encodings this is set
69
69
  attr_accessor :http_chunk_size
70
70
 
71
+ def initialize
72
+ super
73
+ @http_chunk_size = '0'
74
+ end
75
+
71
76
  # Size of the chunk as an integer
72
77
  def chunk_size
73
- return @chunk_size unless @chunk_size.nil?
74
- @chunk_size = @http_chunk_size ? @http_chunk_size.to_i(base=16) : 0
78
+ @http_chunk_size.to_i(base=16)
75
79
  end
76
80
  end
77
81
 
@@ -221,6 +225,7 @@ module EventMachine
221
225
  TRANSFER_ENCODING="TRANSFER_ENCODING"
222
226
  CONTENT_ENCODING="CONTENT_ENCODING"
223
227
  CONTENT_LENGTH="CONTENT_LENGTH"
228
+ CONTENT_TYPE="CONTENT_TYPE".freeze
224
229
  LAST_MODIFIED="LAST_MODIFIED"
225
230
  KEEP_ALIVE="CONNECTION"
226
231
  SET_COOKIE="SET_COOKIE"
@@ -242,8 +247,10 @@ module EventMachine
242
247
  @redirects = 0
243
248
  @response = ''
244
249
  @error = ''
250
+ @headers = nil
245
251
  @last_effective_url = nil
246
252
  @content_decoder = nil
253
+ @content_charset = nil
247
254
  @stream = nil
248
255
  @disconnect = nil
249
256
  @state = :response_header
@@ -467,6 +474,7 @@ module EventMachine
467
474
  end
468
475
 
469
476
  def on_decoded_body_data(data)
477
+ data.force_encoding @content_charset if @content_charset
470
478
  if @stream
471
479
  @stream.call(data)
472
480
  else
@@ -474,8 +482,12 @@ module EventMachine
474
482
  end
475
483
  end
476
484
 
485
+ def finished?
486
+ @state == :finished || (@state == :body && @bytes_remaining.nil?)
487
+ end
488
+
477
489
  def unbind
478
- if (@state == :finished) && (@last_effective_url != @uri) && (@redirects < @options[:redirects])
490
+ if finished? && (@last_effective_url != @uri) && (@redirects < @options[:redirects])
479
491
  begin
480
492
  # update uri to redirect location if we're allowed to traverse deeper
481
493
  @uri = @last_effective_url
@@ -495,7 +507,7 @@ module EventMachine
495
507
  on_error(e.message, true)
496
508
  end
497
509
  else
498
- if @state == :finished || (@state == :body && @bytes_remaining.nil?)
510
+ if finished?
499
511
  succeed(self)
500
512
  else
501
513
  @disconnect.call(self) if @state == :websocket and @disconnect
@@ -639,6 +651,10 @@ module EventMachine
639
651
  end
640
652
  end
641
653
 
654
+ if ''.respond_to?(:force_encoding) && /;\s*charset=\s*(.+?)\s*(;|$)/.match(response_header[CONTENT_TYPE])
655
+ @content_charset = Encoding.find $1
656
+ end
657
+
642
658
  true
643
659
  end
644
660
 
@@ -1,55 +1,55 @@
1
- module EventMachine
2
-
3
- # EventMachine based Multi request client, based on a streaming HTTPRequest class,
4
- # which allows you to open multiple parallel connections and return only when all
5
- # of them finish. (i.e. ideal for parallelizing workloads)
6
- #
7
- # == Example
8
- #
9
- # EventMachine.run {
10
- #
11
- # multi = EventMachine::MultiRequest.new
12
- #
13
- # # add multiple requests to the multi-handler
14
- # multi.add(EventMachine::HttpRequest.new('http://www.google.com/').get)
15
- # multi.add(EventMachine::HttpRequest.new('http://www.yahoo.com/').get)
16
- #
17
- # multi.callback {
18
- # p multi.responses[:succeeded]
19
- # p multi.responses[:failed]
20
- #
21
- # EventMachine.stop
22
- # }
23
- # }
24
- #
25
-
26
- class MultiRequest
27
- include EventMachine::Deferrable
28
-
29
- attr_reader :requests, :responses
30
-
31
- def initialize(conns=[], &block)
32
- @requests = []
33
- @responses = {:succeeded => [], :failed => []}
34
-
35
- conns.each {|conn| add(conn)}
36
- callback(&block) if block_given?
37
- end
38
-
39
- def add(conn)
40
- @requests.push(conn)
41
-
42
- conn.callback { @responses[:succeeded].push(conn); check_progress }
43
- conn.errback { @responses[:failed].push(conn); check_progress }
44
- end
45
-
46
- protected
47
-
48
- # invoke callback if all requests have completed
49
- def check_progress
50
- succeed(self) if (@responses[:succeeded].size +
51
- @responses[:failed].size) == @requests.size
52
- end
53
-
54
- end
55
- end
1
+ module EventMachine
2
+
3
+ # EventMachine based Multi request client, based on a streaming HTTPRequest class,
4
+ # which allows you to open multiple parallel connections and return only when all
5
+ # of them finish. (i.e. ideal for parallelizing workloads)
6
+ #
7
+ # == Example
8
+ #
9
+ # EventMachine.run {
10
+ #
11
+ # multi = EventMachine::MultiRequest.new
12
+ #
13
+ # # add multiple requests to the multi-handler
14
+ # multi.add(EventMachine::HttpRequest.new('http://www.google.com/').get)
15
+ # multi.add(EventMachine::HttpRequest.new('http://www.yahoo.com/').get)
16
+ #
17
+ # multi.callback {
18
+ # p multi.responses[:succeeded]
19
+ # p multi.responses[:failed]
20
+ #
21
+ # EventMachine.stop
22
+ # }
23
+ # }
24
+ #
25
+
26
+ class MultiRequest
27
+ include EventMachine::Deferrable
28
+
29
+ attr_reader :requests, :responses
30
+
31
+ def initialize(conns=[], &block)
32
+ @requests = []
33
+ @responses = {:succeeded => [], :failed => []}
34
+
35
+ conns.each {|conn| add(conn)}
36
+ callback(&block) if block_given?
37
+ end
38
+
39
+ def add(conn)
40
+ @requests.push(conn)
41
+
42
+ conn.callback { @responses[:succeeded].push(conn); check_progress }
43
+ conn.errback { @responses[:failed].push(conn); check_progress }
44
+ end
45
+
46
+ protected
47
+
48
+ # invoke callback if all requests have completed
49
+ def check_progress
50
+ succeed(self) if (@responses[:succeeded].size +
51
+ @responses[:failed].size) == @requests.size
52
+ end
53
+
54
+ end
55
+ end