http-parser-lite 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.6.0 (2013-01-01)
2
+
3
+ * Added on_status_complete callback (Oscar Del Ben).
4
+ * Updated http_parser.c from joytent/http-parser.
5
+
6
+ == 0.5.1 (2012-07-25)
7
+
8
+ * Updated http_parser.c from joytent/http-parser.
9
+
1
10
  == 0.5.0 (2012-07-21)
2
11
 
3
12
  * merged in pull/118 upstream to support url parsing with username and password.
data/README.md CHANGED
@@ -21,6 +21,10 @@ parser.on_message_complete do
21
21
  puts "message complete"
22
22
  end
23
23
 
24
+ parser.on_status_complete do
25
+ puts "status complete"
26
+ end
27
+
24
28
  parser.on_headers_complete do
25
29
  puts "headers complete"
26
30
  end
@@ -65,6 +69,7 @@ HTTP::Parser
65
69
  #on_message_begin(&block)
66
70
  #on_message_complete(&block)
67
71
  #on_url(&block)
72
+ #on_status_complete(&block)
68
73
  #on_header_field(&block)
69
74
  #on_header_value(&block)
70
75
  #on_headers_complete(&block)
@@ -37,19 +37,24 @@
37
37
  # define MIN(a,b) ((a) < (b) ? (a) : (b))
38
38
  #endif
39
39
 
40
+ #ifndef ARRAY_SIZE
41
+ # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
42
+ #endif
43
+
44
+ #ifndef BIT_AT
45
+ # define BIT_AT(a, i) \
46
+ (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
47
+ (1 << ((unsigned int) (i) & 7))))
48
+ #endif
49
+
50
+ #ifndef ELEM_AT
51
+ # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
52
+ #endif
40
53
 
41
- #if HTTP_PARSER_DEBUG
42
- #define SET_ERRNO(e) \
43
- do { \
44
- parser->http_errno = (e); \
45
- parser->error_lineno = __LINE__; \
46
- } while (0)
47
- #else
48
54
  #define SET_ERRNO(e) \
49
55
  do { \
50
56
  parser->http_errno = (e); \
51
57
  } while(0)
52
- #endif
53
58
 
54
59
 
55
60
  /* Run the notify callback FOR, returning ER if it fails */
@@ -94,7 +99,7 @@ do { \
94
99
  FOR##_mark = NULL; \
95
100
  } \
96
101
  } while (0)
97
-
102
+
98
103
  /* Run the data callback FOR and consume the current byte */
99
104
  #define CALLBACK_DATA(FOR) \
100
105
  CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
@@ -185,45 +190,45 @@ static const int8_t unhex[256] =
185
190
 
186
191
 
187
192
  #if HTTP_PARSER_STRICT
188
- # define T 0
193
+ # define T(v) 0
189
194
  #else
190
- # define T 1
195
+ # define T(v) v
191
196
  #endif
192
197
 
193
198
 
194
- static const uint8_t normal_url_char[256] = {
199
+ static const uint8_t normal_url_char[32] = {
195
200
  /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
196
- 0, 0, 0, 0, 0, 0, 0, 0,
201
+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
197
202
  /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
198
- 0, T, 0, 0, T, 0, 0, 0,
203
+ 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
199
204
  /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
200
- 0, 0, 0, 0, 0, 0, 0, 0,
205
+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
201
206
  /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
202
- 0, 0, 0, 0, 0, 0, 0, 0,
207
+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
203
208
  /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
204
- 0, 1, 1, 0, 1, 1, 1, 1,
209
+ 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
205
210
  /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
206
- 1, 1, 1, 1, 1, 1, 1, 1,
211
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
207
212
  /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
208
- 1, 1, 1, 1, 1, 1, 1, 1,
213
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
209
214
  /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
210
- 1, 1, 1, 1, 1, 1, 1, 0,
215
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
211
216
  /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
212
- 1, 1, 1, 1, 1, 1, 1, 1,
217
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
213
218
  /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
214
- 1, 1, 1, 1, 1, 1, 1, 1,
219
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
215
220
  /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
216
- 1, 1, 1, 1, 1, 1, 1, 1,
221
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
217
222
  /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
218
- 1, 1, 1, 1, 1, 1, 1, 1,
223
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
219
224
  /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
220
- 1, 1, 1, 1, 1, 1, 1, 1,
225
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
221
226
  /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
222
- 1, 1, 1, 1, 1, 1, 1, 1,
227
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
223
228
  /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
224
- 1, 1, 1, 1, 1, 1, 1, 1,
229
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
225
230
  /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
226
- 1, 1, 1, 1, 1, 1, 1, 0, };
231
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
227
232
 
228
233
  #undef T
229
234
 
@@ -364,12 +369,12 @@ enum http_host_state
364
369
 
365
370
  #if HTTP_PARSER_STRICT
366
371
  #define TOKEN(c) (tokens[(unsigned char)c])
367
- #define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
372
+ #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
368
373
  #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
369
374
  #else
370
375
  #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
371
376
  #define IS_URL_CHAR(c) \
372
- (normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
377
+ (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
373
378
  #define IS_HOST_CHAR(c) \
374
379
  (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
375
380
  #endif
@@ -403,7 +408,7 @@ static struct {
403
408
  };
404
409
  #undef HTTP_STRERROR_GEN
405
410
 
406
- int http_message_needs_eof(http_parser *parser);
411
+ int http_message_needs_eof(const http_parser *parser);
407
412
 
408
413
  /* Our URL parser.
409
414
  *
@@ -861,6 +866,7 @@ size_t http_parser_execute (http_parser *parser,
861
866
  case s_res_line_almost_done:
862
867
  STRICT_CHECK(ch != LF);
863
868
  parser->state = s_header_field_start;
869
+ CALLBACK_NOTIFY(status_complete);
864
870
  break;
865
871
 
866
872
  case s_start_req:
@@ -1841,7 +1847,7 @@ error:
1841
1847
 
1842
1848
  /* Does the parser need to see an EOF to find the end of the message? */
1843
1849
  int
1844
- http_message_needs_eof (http_parser *parser)
1850
+ http_message_needs_eof (const http_parser *parser)
1845
1851
  {
1846
1852
  if (parser->type == HTTP_REQUEST) {
1847
1853
  return 0;
@@ -1864,7 +1870,7 @@ http_message_needs_eof (http_parser *parser)
1864
1870
 
1865
1871
 
1866
1872
  int
1867
- http_should_keep_alive (http_parser *parser)
1873
+ http_should_keep_alive (const http_parser *parser)
1868
1874
  {
1869
1875
  if (parser->http_major > 0 && parser->http_minor > 0) {
1870
1876
  /* HTTP/1.1 */
@@ -1882,9 +1888,10 @@ http_should_keep_alive (http_parser *parser)
1882
1888
  }
1883
1889
 
1884
1890
 
1885
- const char * http_method_str (enum http_method m)
1891
+ const char *
1892
+ http_method_str (enum http_method m)
1886
1893
  {
1887
- return method_strings[m];
1894
+ return ELEM_AT(method_strings, m, "<unknown>");
1888
1895
  }
1889
1896
 
1890
1897
 
@@ -1956,7 +1963,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
1956
1963
 
1957
1964
  /* FALLTHROUGH */
1958
1965
  case s_http_host_v6_start:
1959
- if (IS_HEX(ch) || ch == ':') {
1966
+ if (IS_HEX(ch) || ch == ':' || ch == '.') {
1960
1967
  return s_http_host_v6;
1961
1968
  }
1962
1969
 
@@ -2161,3 +2168,8 @@ http_parser_pause(http_parser *parser, int paused) {
2161
2168
  assert(0 && "Attempting to pause parser in error state");
2162
2169
  }
2163
2170
  }
2171
+
2172
+ int
2173
+ http_body_is_final(const struct http_parser *parser) {
2174
+ return parser->state == s_message_done;
2175
+ }
@@ -24,12 +24,13 @@
24
24
  extern "C" {
25
25
  #endif
26
26
 
27
- #define HTTP_PARSER_VERSION_MAJOR 1
27
+ #define HTTP_PARSER_VERSION_MAJOR 2
28
28
  #define HTTP_PARSER_VERSION_MINOR 0
29
29
 
30
30
  #include <sys/types.h>
31
31
  #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
32
32
  #include <BaseTsd.h>
33
+ #include <stddef.h>
33
34
  typedef __int8 int8_t;
34
35
  typedef unsigned __int8 uint8_t;
35
36
  typedef __int16 int16_t;
@@ -38,8 +39,6 @@ typedef __int32 int32_t;
38
39
  typedef unsigned __int32 uint32_t;
39
40
  typedef __int64 int64_t;
40
41
  typedef unsigned __int64 uint64_t;
41
- typedef SIZE_T size_t;
42
- typedef SSIZE_T ssize_t;
43
42
  #else
44
43
  #include <stdint.h>
45
44
  #endif
@@ -51,14 +50,6 @@ typedef SSIZE_T ssize_t;
51
50
  # define HTTP_PARSER_STRICT 1
52
51
  #endif
53
52
 
54
- /* Compile with -DHTTP_PARSER_DEBUG=1 to add extra debugging information to
55
- * the error reporting facility.
56
- */
57
- #ifndef HTTP_PARSER_DEBUG
58
- # define HTTP_PARSER_DEBUG 0
59
- #endif
60
-
61
-
62
53
  /* Maximium header size allowed */
63
54
  #define HTTP_MAX_HEADER_SIZE (80*1024)
64
55
 
@@ -77,7 +68,7 @@ typedef struct http_parser_settings http_parser_settings;
77
68
  * chunked' headers that indicate the presence of a body.
78
69
  *
79
70
  * http_data_cb does not return data chunks. It will be call arbitrarally
80
- * many times for each string. E.G. you might get 10 callbacks for "on_path"
71
+ * many times for each string. E.G. you might get 10 callbacks for "on_url"
81
72
  * each providing just a few characters more data.
82
73
  */
83
74
  typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
@@ -141,7 +132,7 @@ enum flags
141
132
 
142
133
 
143
134
  /* Map for errno-related constants
144
- *
135
+ *
145
136
  * The provided argument should be a macro that takes 2 arguments.
146
137
  */
147
138
  #define HTTP_ERRNO_MAP(XX) \
@@ -150,6 +141,7 @@ enum flags
150
141
  \
151
142
  /* Callback-related errors */ \
152
143
  XX(CB_message_begin, "the on_message_begin callback failed") \
144
+ XX(CB_status_complete, "the on_status_complete callback failed") \
153
145
  XX(CB_url, "the on_url callback failed") \
154
146
  XX(CB_header_field, "the on_header_field callback failed") \
155
147
  XX(CB_header_value, "the on_header_value callback failed") \
@@ -196,13 +188,6 @@ enum http_errno {
196
188
  /* Get an http_errno value from an http_parser */
197
189
  #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
198
190
 
199
- /* Get the line number that generated the current error */
200
- #if HTTP_PARSER_DEBUG
201
- #define HTTP_PARSER_ERRNO_LINE(p) ((p)->error_lineno)
202
- #else
203
- #define HTTP_PARSER_ERRNO_LINE(p) 0
204
- #endif
205
-
206
191
 
207
192
  struct http_parser {
208
193
  /** PRIVATE **/
@@ -229,10 +214,6 @@ struct http_parser {
229
214
  */
230
215
  unsigned char upgrade : 1;
231
216
 
232
- #if HTTP_PARSER_DEBUG
233
- uint32_t error_lineno;
234
- #endif
235
-
236
217
  /** PUBLIC **/
237
218
  void *data; /* A pointer to get hook to the "connection" or "socket" object */
238
219
  };
@@ -241,6 +222,7 @@ struct http_parser {
241
222
  struct http_parser_settings {
242
223
  http_cb on_message_begin;
243
224
  http_data_cb on_url;
225
+ http_cb on_status_complete;
244
226
  http_data_cb on_header_field;
245
227
  http_data_cb on_header_value;
246
228
  http_cb on_headers_complete;
@@ -289,12 +271,12 @@ size_t http_parser_execute(http_parser *parser,
289
271
 
290
272
 
291
273
  /* If http_should_keep_alive() in the on_headers_complete or
292
- * on_message_complete callback returns true, then this should be
274
+ * on_message_complete callback returns 0, then this should be
293
275
  * the last message on the connection.
294
276
  * If you are the server, respond with the "Connection: close" header.
295
277
  * If you are the client, close the connection.
296
278
  */
297
- int http_should_keep_alive(http_parser *parser);
279
+ int http_should_keep_alive(const http_parser *parser);
298
280
 
299
281
  /* Returns a string version of the HTTP method. */
300
282
  const char *http_method_str(enum http_method m);
@@ -313,6 +295,9 @@ int http_parser_parse_url(const char *buf, size_t buflen,
313
295
  /* Pause or un-pause the parser; a nonzero value pauses */
314
296
  void http_parser_pause(http_parser *parser, int paused);
315
297
 
298
+ /* Checks if this is the final chunk of the body. */
299
+ int http_body_is_final(const http_parser *parser);
300
+
316
301
  #ifdef __cplusplus
317
302
  }
318
303
  #endif
@@ -41,6 +41,12 @@ int rb_parser_on_url(http_parser *parser, char *data, size_t length) {
41
41
  return 0;
42
42
  }
43
43
 
44
+ int rb_parser_on_status_complete(http_parser *parser) {
45
+ VALUE self = (VALUE)parser->data;
46
+ rb_parser_callback_call(self, "on_status_complete", 0, 0);
47
+ return 0;
48
+ }
49
+
44
50
  int rb_parser_on_header_field(http_parser *parser, char *data, size_t length) {
45
51
  VALUE self = (VALUE)parser->data;
46
52
  rb_parser_callback_call(self, "on_header_field", data, length);
@@ -81,6 +87,7 @@ VALUE rb_parser_parse(VALUE self, VALUE data) {
81
87
  http_parser *parser = rb_http_parser_handle(self);
82
88
  http_parser_settings settings = {
83
89
  .on_url = (http_data_cb)rb_parser_on_url,
90
+ .on_status_complete = (http_cb)rb_parser_on_status_complete,
84
91
  .on_header_field = (http_data_cb)rb_parser_on_header_field,
85
92
  .on_header_value = (http_data_cb)rb_parser_on_header_value,
86
93
  .on_headers_complete = (http_cb)rb_parser_on_headers_complete,
@@ -146,7 +153,7 @@ VALUE rb_parser_error(VALUE self) {
146
153
  return errno != HPE_OK ? rb_str_new2(http_errno_description(errno)) : Qnil;
147
154
  }
148
155
 
149
- Init_http_parser() {
156
+ void Init_http_parser() {
150
157
  mHTTP = rb_define_module("HTTP");
151
158
  cParser = rb_define_class_under(mHTTP, "Parser", rb_cObject);
152
159
  eParserError = rb_define_class_under(cParser, "Error", rb_eStandardError);
@@ -5,7 +5,16 @@ module HTTP
5
5
  TYPE_REQUEST = 0
6
6
  TYPE_RESPONSE = 1
7
7
  TYPE_BOTH = 2
8
- CALLBACKS = %w(on_url on_header_field on_header_value on_headers_complete on_body on_message_begin on_message_complete)
8
+ CALLBACKS = %w(
9
+ on_body
10
+ on_header_field
11
+ on_header_value
12
+ on_headers_complete
13
+ on_message_begin
14
+ on_message_complete
15
+ on_status_complete
16
+ on_url
17
+ )
9
18
 
10
19
  CALLBACKS.each do |name|
11
20
  define_method(name) do |&block|
@@ -33,7 +33,7 @@ describe 'http-parser' do
33
33
  end
34
34
 
35
35
 
36
- it 'should call callbacks' do
36
+ it 'should call callbacks on requests' do
37
37
  got = []
38
38
  parser.on_message_begin {got << 's'}
39
39
  parser.on_message_complete {got << 'e'}
@@ -43,10 +43,30 @@ describe 'http-parser' do
43
43
  parser.on_headers_complete {got << 'h'}
44
44
  parser.on_body {got << 'b'}
45
45
 
46
+ # Should not be called
47
+ parser.on_status_complete {got << 'X'}
48
+
46
49
  parser << "POST / HTTP/1.0\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
47
50
  assert_equal %w(s u f v f v h b e), got
48
51
  end
49
52
 
53
+ it 'should call callbacks on responses' do
54
+ got = []
55
+ parser.on_message_begin {got << 's'}
56
+ parser.on_message_complete {got << 'e'}
57
+ parser.on_status_complete {got << 'S'}
58
+ parser.on_header_field {got << 'f'}
59
+ parser.on_header_value {got << 'v'}
60
+ parser.on_headers_complete {got << 'h'}
61
+ parser.on_body {got << 'b'}
62
+
63
+ # Should not be called
64
+ parser.on_url {got << 'X'}
65
+
66
+ parser << "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
67
+ assert_equal %w(s S f v f v h b e), got
68
+ end
69
+
50
70
  it 'should parse chunked response' do
51
71
  got = []
52
72
  parser.on_url {|data| got << data}
metadata CHANGED
@@ -1,25 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-parser-lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
5
4
  prerelease:
5
+ version: 0.6.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Bharanee Rathna
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-25 00:00:00.000000000 Z
12
+ date: 2013-01-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rake
15
+ type: :development
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
- type: :development
23
22
  prerelease: false
24
23
  version_requirements: !ruby/object:Gem::Requirement
25
24
  none: false
@@ -27,6 +26,7 @@ dependencies:
27
26
  - - ! '>='
28
27
  - !ruby/object:Gem::Version
29
28
  version: '0'
29
+ name: rake
30
30
  description: A lite ruby wrapper around Joyent http-parser
31
31
  email:
32
32
  - deepfryed@gmail.com
@@ -35,14 +35,14 @@ extensions:
35
35
  - ext/http-parser/extconf.rb
36
36
  extra_rdoc_files: []
37
37
  files:
38
- - ext/http-parser/ruby_http_parser.c
39
38
  - ext/http-parser/http_parser.c
39
+ - ext/http-parser/ruby_http_parser.c
40
40
  - ext/http-parser/http_parser.h
41
41
  - ext/http-parser/extconf.rb
42
42
  - test/helper.rb
43
43
  - test/test_http_parser.rb
44
- - lib/http-parser.rb
45
44
  - lib/http-parser-lite.rb
45
+ - lib/http-parser.rb
46
46
  - README.md
47
47
  - CHANGELOG
48
48
  homepage: http://github.com/deepfryed/http-parser-lite
@@ -71,4 +71,3 @@ signing_key:
71
71
  specification_version: 3
72
72
  summary: Simple wrapper around Joyent http-parser
73
73
  test_files: []
74
- has_rdoc: