noderb-http 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,194 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+ #ifndef http_parser_h
22
+ #define http_parser_h
23
+ #ifdef __cplusplus
24
+ extern "C" {
25
+ #endif
26
+
27
+ #define HTTP_PARSER_VERSION_MAJOR 1
28
+ #define HTTP_PARSER_VERSION_MINOR 0
29
+
30
+ #include <sys/types.h>
31
+ #if defined(_WIN32) && !defined(__MINGW32__)
32
+ typedef __int8 int8_t;
33
+ typedef unsigned __int8 uint8_t;
34
+ typedef __int16 int16_t;
35
+ typedef unsigned __int16 uint16_t;
36
+ typedef __int32 int32_t;
37
+ typedef unsigned __int32 uint32_t;
38
+ typedef __int64 int64_t;
39
+ typedef unsigned __int64 uint64_t;
40
+
41
+ typedef unsigned int size_t;
42
+ typedef int ssize_t;
43
+ #else
44
+ #include <stdint.h>
45
+ #endif
46
+
47
+ /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
48
+ * faster
49
+ */
50
+ #ifndef HTTP_PARSER_STRICT
51
+ # define HTTP_PARSER_STRICT 1
52
+ #endif
53
+
54
+
55
+ /* Maximium header size allowed */
56
+ #define HTTP_MAX_HEADER_SIZE (80*1024)
57
+
58
+
59
+ typedef struct http_parser http_parser;
60
+ typedef struct http_parser_settings http_parser_settings;
61
+
62
+
63
+ /* Callbacks should return non-zero to indicate an error. The parser will
64
+ * then halt execution.
65
+ *
66
+ * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
67
+ * returning '1' from on_headers_complete will tell the parser that it
68
+ * should not expect a body. This is used when receiving a response to a
69
+ * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
70
+ * chunked' headers that indicate the presence of a body.
71
+ *
72
+ * http_data_cb does not return data chunks. It will be call arbitrarally
73
+ * many times for each string. E.G. you might get 10 callbacks for "on_path"
74
+ * each providing just a few characters more data.
75
+ */
76
+ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
77
+ typedef int (*http_cb) (http_parser*);
78
+
79
+
80
+ /* Request Methods */
81
+ enum http_method
82
+ { HTTP_DELETE = 0
83
+ , HTTP_GET
84
+ , HTTP_HEAD
85
+ , HTTP_POST
86
+ , HTTP_PUT
87
+ /* pathological */
88
+ , HTTP_CONNECT
89
+ , HTTP_OPTIONS
90
+ , HTTP_TRACE
91
+ /* webdav */
92
+ , HTTP_COPY
93
+ , HTTP_LOCK
94
+ , HTTP_MKCOL
95
+ , HTTP_MOVE
96
+ , HTTP_PROPFIND
97
+ , HTTP_PROPPATCH
98
+ , HTTP_UNLOCK
99
+ /* subversion */
100
+ , HTTP_REPORT
101
+ , HTTP_MKACTIVITY
102
+ , HTTP_CHECKOUT
103
+ , HTTP_MERGE
104
+ /* upnp */
105
+ , HTTP_MSEARCH
106
+ , HTTP_NOTIFY
107
+ , HTTP_SUBSCRIBE
108
+ , HTTP_UNSUBSCRIBE
109
+ /* RFC-5789 */
110
+ , HTTP_PATCH
111
+ };
112
+
113
+
114
+ enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
115
+
116
+
117
+ /* Flag values for http_parser.flags field */
118
+ enum flags
119
+ { F_CHUNKED = 1 << 0
120
+ , F_CONNECTION_KEEP_ALIVE = 1 << 1
121
+ , F_CONNECTION_CLOSE = 1 << 2
122
+ , F_TRAILING = 1 << 3
123
+ , F_UPGRADE = 1 << 4
124
+ , F_SKIPBODY = 1 << 5
125
+ };
126
+
127
+
128
+ struct http_parser {
129
+ /** PRIVATE **/
130
+ unsigned char type : 2;
131
+ unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
132
+ unsigned char state;
133
+ unsigned char header_state;
134
+ unsigned char index;
135
+
136
+ uint32_t nread;
137
+ int64_t content_length;
138
+
139
+ /** READ-ONLY **/
140
+ unsigned short http_major;
141
+ unsigned short http_minor;
142
+ unsigned short status_code; /* responses only */
143
+ unsigned char method; /* requests only */
144
+
145
+ /* 1 = Upgrade header was present and the parser has exited because of that.
146
+ * 0 = No upgrade header present.
147
+ * Should be checked when http_parser_execute() returns in addition to
148
+ * error checking.
149
+ */
150
+ char upgrade;
151
+
152
+ /** PUBLIC **/
153
+ void *data; /* A pointer to get hook to the "connection" or "socket" object */
154
+ };
155
+
156
+
157
+ struct http_parser_settings {
158
+ http_cb on_message_begin;
159
+ http_data_cb on_path;
160
+ http_data_cb on_query_string;
161
+ http_data_cb on_url;
162
+ http_data_cb on_fragment;
163
+ http_data_cb on_header_field;
164
+ http_data_cb on_header_value;
165
+ http_cb on_headers_complete;
166
+ http_data_cb on_body;
167
+ http_cb on_message_complete;
168
+ };
169
+
170
+
171
+ void http_parser_init(http_parser *parser, enum http_parser_type type);
172
+
173
+
174
+ size_t http_parser_execute(http_parser *parser,
175
+ const http_parser_settings *settings,
176
+ const char *data,
177
+ size_t len);
178
+
179
+
180
+ /* If http_should_keep_alive() in the on_headers_complete or
181
+ * on_message_complete callback returns true, then this will be should be
182
+ * the last message on the connection.
183
+ * If you are the server, respond with the "Connection: close" header.
184
+ * If you are the client, close the connection.
185
+ */
186
+ int http_should_keep_alive(http_parser *parser);
187
+
188
+ /* Returns a string version of the HTTP method. */
189
+ const char *http_method_str(enum http_method);
190
+
191
+ #ifdef __cplusplus
192
+ }
193
+ #endif
194
+ #endif
@@ -0,0 +1,165 @@
1
+ #include <noderb_http.h>
2
+
3
+ typedef struct {
4
+ long parser;
5
+ } nodeRb_http;
6
+
7
+ VALUE nodeRbHttpParser;
8
+
9
+ VALUE nodeRb_get_object_from_id(long id) {
10
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, rb_int2inum(id));
11
+ }
12
+
13
+ int nodeRb_http_on_message_begin(http_parser* parser) {
14
+ nodeRb_http* client = parser->data;
15
+ VALUE self = nodeRb_get_object_from_id(client->parser);
16
+ rb_funcall(self, rb_intern("on_message_begin"), 0);
17
+ return 0;
18
+ }
19
+
20
+ int nodeRb_http_on_message_complete(http_parser* parser) {
21
+ nodeRb_http* client = parser->data;
22
+ VALUE self = nodeRb_get_object_from_id(client->parser);
23
+ if (http_should_keep_alive(parser)) {
24
+ rb_funcall(self, rb_intern("on_close_keep_alive"), 0);
25
+ };
26
+ rb_funcall(self, rb_intern("on_message_complete"), 0);
27
+ return 0;
28
+ }
29
+
30
+ int nodeRb_http_on_headers_complete(http_parser* parser) {
31
+ nodeRb_http* client = parser->data;
32
+ VALUE self = nodeRb_get_object_from_id(client->parser);
33
+ rb_funcall(self, rb_intern("on_headers_complete_internal"), 0);
34
+ return 0;
35
+ }
36
+
37
+ int nodeRb_http_on_header_field(http_parser* parser, const char *buf, size_t len) {
38
+ nodeRb_http* client = parser->data;
39
+ VALUE self = nodeRb_get_object_from_id(client->parser);
40
+ rb_funcall(self, rb_intern("on_header_field_internal"), 1, rb_str_new(buf, len));
41
+ return 0;
42
+ }
43
+
44
+ int nodeRb_http_on_header_value(http_parser* parser, const char *buf, size_t len) {
45
+ nodeRb_http* client = parser->data;
46
+ VALUE self = nodeRb_get_object_from_id(client->parser);
47
+ rb_funcall(self, rb_intern("on_header_value_internal"), 1, rb_str_new(buf, len));
48
+ return 0;
49
+ }
50
+
51
+ int nodeRb_http_on_path(http_parser* parser, const char *buf, size_t len) {
52
+ nodeRb_http* client = parser->data;
53
+ VALUE self = nodeRb_get_object_from_id(client->parser);
54
+ rb_funcall(self, rb_intern("on_method"), 1, rb_str_new2(http_method_str(parser->method)));
55
+ rb_funcall(self, rb_intern("on_path"), 1, rb_str_new(buf, len));
56
+ return 0;
57
+ }
58
+
59
+ int nodeRb_http_on_query_string(http_parser* parser, const char *buf, size_t len) {
60
+ nodeRb_http* client = parser->data;
61
+ VALUE self = nodeRb_get_object_from_id(client->parser);
62
+ rb_funcall(self, rb_intern("on_query_string"), 1, rb_str_new(buf, len));
63
+ return 0;
64
+ }
65
+
66
+ int nodeRb_http_on_url(http_parser* parser, const char *buf, size_t len) {
67
+ nodeRb_http* client = parser->data;
68
+ VALUE self = nodeRb_get_object_from_id(client->parser);
69
+ rb_funcall(self, rb_intern("on_url"), 1, rb_str_new(buf, len));
70
+ return 0;
71
+ }
72
+
73
+ int nodeRb_http_on_fragment(http_parser* parser, const char *buf, size_t len) {
74
+ nodeRb_http* client = parser->data;
75
+ VALUE self = nodeRb_get_object_from_id(client->parser);
76
+ rb_funcall(self, rb_intern("on_fragment"), 1, rb_str_new(buf, len));
77
+ return 0;
78
+ }
79
+
80
+ int nodeRb_http_on_body(http_parser* parser, const char *buf, size_t len) {
81
+ nodeRb_http* client = parser->data;
82
+ VALUE self = nodeRb_get_object_from_id(client->parser);
83
+ rb_funcall(self, rb_intern("on_body"), 1, rb_str_new(buf, len));
84
+ return 0;
85
+ }
86
+
87
+ VALUE nodeRb_http_setup(VALUE self) {
88
+ http_parser_settings* settings = malloc(sizeof (http_parser_settings));
89
+
90
+ settings->on_message_begin = nodeRb_http_on_message_begin;
91
+ settings->on_message_complete = nodeRb_http_on_message_complete;
92
+ settings->on_headers_complete = nodeRb_http_on_headers_complete;
93
+
94
+ settings->on_path = nodeRb_http_on_path;
95
+ settings->on_query_string = nodeRb_http_on_query_string;
96
+ settings->on_url = nodeRb_http_on_url;
97
+
98
+ settings->on_header_field = nodeRb_http_on_header_field;
99
+ settings->on_header_value = nodeRb_http_on_header_value;
100
+
101
+ settings->on_fragment = nodeRb_http_on_fragment;
102
+ settings->on_body = nodeRb_http_on_body;
103
+
104
+
105
+ http_parser* parser = malloc(sizeof (http_parser));
106
+ http_parser_init(parser, HTTP_REQUEST);
107
+
108
+ nodeRb_http* client = malloc(sizeof (nodeRb_http));
109
+ parser->data = client;
110
+
111
+ client->parser = rb_num2long(rb_obj_id(self));
112
+
113
+ rb_iv_set(self, "@settings", Data_Wrap_Struct(nodeRbHttpParser, 0, NULL, settings));
114
+ rb_iv_set(self, "@parser", Data_Wrap_Struct(nodeRbHttpParser, 0, NULL, parser));
115
+ };
116
+
117
+ VALUE nodeRb_http_parse(VALUE self, VALUE data) {
118
+
119
+ http_parser_settings* settings;
120
+ http_parser* parser;
121
+
122
+ VALUE rsettings = rb_iv_get(self, "@settings");
123
+ VALUE rparser = rb_iv_get(self, "@parser");
124
+
125
+
126
+ Data_Get_Struct(rsettings, http_parser_settings, settings);
127
+ Data_Get_Struct(rparser, http_parser, parser);
128
+
129
+ nodeRb_http* client = parser->data;
130
+
131
+ size_t parsed = http_parser_execute(parser, settings, rb_string_value_cstr(&data), RSTRING_LEN(data));
132
+
133
+ if (parser->upgrade) {
134
+ rb_funcall(self, rb_intern("on_upgrade"), 0);
135
+ } else if (parsed != RSTRING_LEN(data)) {
136
+ rb_funcall(self, rb_intern("on_error"), 0);
137
+ };
138
+ };
139
+
140
+ VALUE nodeRb_http_dispose(VALUE self) {
141
+ http_parser_settings* settings;
142
+ http_parser* parser;
143
+
144
+ Data_Get_Struct(rb_iv_get(self, "@settings"), http_parser_settings, settings);
145
+ Data_Get_Struct(rb_iv_get(self, "@parser"), http_parser, parser);
146
+
147
+ free(parser->data);
148
+ free(settings);
149
+ free(parser);
150
+ };
151
+
152
+ void Init_noderb_http() {
153
+ // Define module
154
+ VALUE nodeRb = rb_define_module("NodeRb");
155
+ // Modules
156
+ VALUE nodeRbModules = rb_define_module_under(nodeRb, "Modules");
157
+ // Http
158
+ VALUE nodeRbHttp = rb_define_module_under(nodeRbModules, "Http");
159
+ // Http parser
160
+ nodeRbHttpParser = rb_define_class_under(nodeRbHttp, "Parser", rb_cObject);
161
+ // Methods
162
+ rb_define_method(nodeRbHttpParser, "setup", nodeRb_http_setup, 0);
163
+ rb_define_method(nodeRbHttpParser, "parse", nodeRb_http_parse, 1);
164
+ rb_define_method(nodeRbHttpParser, "dispose", nodeRb_http_dispose, 0);
165
+ }
@@ -0,0 +1,2 @@
1
+ #include <http_parser.h>
2
+ #include <ruby.h>
@@ -0,0 +1,99 @@
1
+ module NodeRb
2
+ module Modules
3
+ module Http
4
+
5
+ module Rack
6
+
7
+ def initialize
8
+ @env = {}
9
+ end
10
+
11
+ def on_header name, value
12
+ end
13
+
14
+ end
15
+
16
+ class Parser
17
+
18
+ def on_message_begin
19
+ end
20
+
21
+ def on_method method
22
+ end
23
+
24
+ def on_path path
25
+ end
26
+
27
+ def on_query_string query_string
28
+ end
29
+
30
+ def on_url url
31
+ end
32
+
33
+ def on_fragment fragment
34
+ end
35
+
36
+ def on_header_field_internal name
37
+ if @_header_state == :value
38
+ on_header_value(@_header_value)
39
+ on_header(@_header_name, @_header_value)
40
+ @_header_name = nil
41
+ @_header_value = nil
42
+ end
43
+ @_header_state = :field
44
+ @_header_name ||= ""
45
+ @_header_name << name
46
+ end
47
+
48
+ def on_header_field name
49
+
50
+ end
51
+
52
+ def on_header_value_internal value
53
+ if @_header_state == :field
54
+ on_header_field(@_header_name)
55
+ end
56
+ @_header_state = :value
57
+ @_header_value ||= ""
58
+ @_header_value << value
59
+ end
60
+
61
+ def on_header_value value
62
+
63
+ end
64
+
65
+ def on_header name, value
66
+ end
67
+
68
+ def on_headers_complete_internal
69
+ on_header_value(@_header_value)
70
+ on_header(@_header_name, @_header_value)
71
+ @_header_name = nil
72
+ @_header_value = nil
73
+ on_headers_complete
74
+ end
75
+
76
+ def on_headers_complete
77
+
78
+ end
79
+
80
+ def on_close_keep_alive
81
+ end
82
+
83
+ def on_upgrade
84
+ end
85
+
86
+ def on_body body
87
+ end
88
+
89
+ def on_message_complete
90
+ end
91
+
92
+ def on_error
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,2 @@
1
+ require 'noderb_http_extension/noderb_http'
2
+ require "noderb/modules/http"
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: noderb-http
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marek Jelen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-24 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Fast and full-featured HTTP parser.
15
+ email:
16
+ - marek@jelen.biz
17
+ executables: []
18
+ extensions:
19
+ - ext/noderb_http_extension/extconf.rb
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/noderb/modules/http.rb
23
+ - lib/noderb-http.rb
24
+ - ext/http_parser.o
25
+ - ext/noderb_http.o
26
+ - ext/noderb_http_extension/extconf.rb
27
+ - ext/noderb_http_extension/http_parser.c
28
+ - ext/noderb_http_extension/http_parser.h
29
+ - ext/noderb_http_extension/noderb_http.c
30
+ - ext/noderb_http_extension/noderb_http.h
31
+ - LICENSE
32
+ - README.md
33
+ homepage: http://github.com/noderb/noderb-http
34
+ licenses: []
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ - ext
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: 1.3.6
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.5
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: Fast and full-featured HTTP parser
58
+ test_files: []