em-http-request 0.2.14 → 0.2.15

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.

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