heventmachine_httpserver 0.2.1

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.
@@ -0,0 +1,117 @@
1
+ /*****************************************************************************
2
+
3
+ File: http.h
4
+ Date: 21Apr06
5
+
6
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
7
+ Gmail: garbagecat10
8
+
9
+ This program is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Public License as published by
11
+ the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ This program is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU General Public License for more details.
18
+
19
+ You should have received a copy of the GNU General Public License
20
+ along with this program; if not, write to the Free Software
21
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
+
23
+ *****************************************************************************/
24
+
25
+
26
+ #ifndef __HttpPersonality__H_
27
+ #define __HttpPersonality__H_
28
+
29
+ #define RESPONSE_CODE_405 "405 Method Not Allowed"
30
+ #define RESPONSE_CODE_406 "406 Not Acceptable"
31
+ #define RESPONSE_CODE_505 "505 HTTP Version Not Supported"
32
+
33
+ /**********************
34
+ class HttpConnection_t
35
+ **********************/
36
+
37
+ class HttpConnection_t
38
+ {
39
+ public:
40
+ HttpConnection_t();
41
+ virtual ~HttpConnection_t();
42
+
43
+ void ConsumeData (const char*, int);
44
+
45
+ virtual void SendData (const char*, int);
46
+ virtual void CloseConnection (bool after_writing);
47
+ virtual void ProcessRequest (const char *method,
48
+ const char *cookie,
49
+ const char *ifnonematch,
50
+ const char *content_type,
51
+ const char *query_string,
52
+ const char *path_info,
53
+ const char *request_uri,
54
+ const char *protocol,
55
+ int postlength,
56
+ const char *postdata,
57
+ const char* hdrblock,
58
+ int hdrblksize);
59
+
60
+ virtual void ReceivePostData(const char *data, int len);
61
+ virtual void SetNoEnvironmentStrings() {bSetEnvironmentStrings = false;}
62
+ virtual void SetDontAccumulatePost() {bAccumulatePost = false;}
63
+
64
+ private:
65
+
66
+ enum {
67
+ BaseState,
68
+ PreheaderState,
69
+ HeaderState,
70
+ ReadingContentState,
71
+ DispatchState,
72
+ EndState
73
+ } ProtocolState;
74
+
75
+ enum {
76
+ MaxLeadingBlanks = 12,
77
+ MaxHeaderLineLength = 8 * 1024,
78
+ MaxContentLength = 20 * 1024 * 1024,
79
+ HeaderBlockSize = 16 * 1024
80
+ };
81
+ int nLeadingBlanks;
82
+
83
+ char HeaderLine [MaxHeaderLineLength];
84
+ int HeaderLinePos;
85
+
86
+ char HeaderBlock [HeaderBlockSize];
87
+ int HeaderBlockPos;
88
+
89
+ int ContentLength;
90
+ int ContentPos;
91
+ char *_Content;
92
+
93
+ bool bSetEnvironmentStrings;
94
+ bool bAccumulatePost;
95
+ bool bRequestSeen;
96
+ bool bContentLengthSeen;
97
+
98
+ const char *RequestMethod;
99
+ std::string Cookie;
100
+ std::string IfNoneMatch;
101
+ std::string ContentType;
102
+ std::string PathInfo;
103
+ std::string RequestUri;
104
+ std::string QueryString;
105
+ std::string Protocol;
106
+
107
+ private:
108
+ bool _InterpretHeaderLine (const char*);
109
+ bool _InterpretRequest (const char*);
110
+ bool _DetectVerbAndSetEnvString (const char*, int);
111
+ void _SendError (const char*);
112
+ };
113
+
114
+ #endif // __HttpPersonality__H_
115
+
116
+
117
+
@@ -0,0 +1,305 @@
1
+ /*****************************************************************************
2
+
3
+ File: libmain.cpp
4
+ Date: 06Apr06
5
+
6
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
7
+ Gmail: garbagecat10
8
+
9
+ This program is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Public License as published by
11
+ the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ This program is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU General Public License for more details.
18
+
19
+ You should have received a copy of the GNU General Public License
20
+ along with this program; if not, write to the Free Software
21
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
+
23
+ *****************************************************************************/
24
+
25
+ #include <iostream>
26
+ #include <string>
27
+ #include <stdexcept>
28
+
29
+ using namespace std;
30
+
31
+ #include <ruby.h>
32
+ #include "http.h"
33
+
34
+
35
+
36
+ /**************************
37
+ class RubyHttpConnection_t
38
+ **************************/
39
+
40
+ class RubyHttpConnection_t: public HttpConnection_t
41
+ {
42
+ public:
43
+ RubyHttpConnection_t (VALUE v): Myself(v) {}
44
+ virtual ~RubyHttpConnection_t() {}
45
+
46
+ virtual void SendData (const char*, int);
47
+ virtual void CloseConnection (bool after_writing);
48
+ virtual void ProcessRequest (const char *request_method,
49
+ const char *cookie,
50
+ const char *ifnonematch,
51
+ const char *contenttype,
52
+ const char *query_string,
53
+ const char *path_info,
54
+ const char *request_uri,
55
+ const char *protocol,
56
+ int postlength,
57
+ const char *postdata,
58
+ const char *hdrblock,
59
+ int hdrblocksize);
60
+ virtual void ReceivePostData (const char *data, int len);
61
+
62
+ private:
63
+ VALUE Myself;
64
+ };
65
+
66
+
67
+ /******************************
68
+ RubyHttpConnection_t::SendData
69
+ ******************************/
70
+
71
+ void RubyHttpConnection_t::SendData (const char *data, int length)
72
+ {
73
+ rb_funcall (Myself, rb_intern ("send_data"), 1, rb_str_new (data, length));
74
+ }
75
+
76
+
77
+ /*************************************
78
+ RubyHttpConnection_t::CloseConnection
79
+ *************************************/
80
+
81
+ void RubyHttpConnection_t::CloseConnection (bool after_writing)
82
+ {
83
+ VALUE v = rb_intern (after_writing ? "close_connection_after_writing" : "close_connection");
84
+ rb_funcall (Myself, v, 0);
85
+ }
86
+
87
+
88
+ /*************************************
89
+ RubyHttpConnection_t::ReceivePostData
90
+ *************************************/
91
+
92
+ void RubyHttpConnection_t::ReceivePostData (const char *data, int len)
93
+ {
94
+ VALUE data_val = Qnil;
95
+
96
+ if ((len > 0) && data) {
97
+ data_val = rb_str_new(data,len);
98
+ rb_funcall (Myself, rb_intern ("receive_post_data"), 1, data_val);
99
+ }
100
+ }
101
+
102
+ /************************************
103
+ RubyHttpConnection_t::ProcessRequest
104
+ ************************************/
105
+
106
+ void RubyHttpConnection_t::ProcessRequest (const char *request_method,
107
+ const char *cookie,
108
+ const char *ifnonematch,
109
+ const char *contenttype,
110
+ const char *query_string,
111
+ const char *path_info,
112
+ const char *request_uri,
113
+ const char *protocol,
114
+ int post_length,
115
+ const char *post_content,
116
+ const char *hdr_block,
117
+ int hdr_block_size)
118
+ {
119
+ VALUE post = Qnil;
120
+ VALUE headers = Qnil;
121
+ VALUE req_method = Qnil;
122
+ VALUE cookie_val = Qnil;
123
+ VALUE ifnonematch_val = Qnil;
124
+ VALUE contenttype_val = Qnil;
125
+ VALUE path_info_val = Qnil;
126
+ VALUE query_string_val = Qnil;
127
+ VALUE request_uri_val = Qnil;
128
+ VALUE protocol_val = Qnil;
129
+
130
+ if ((post_length > 0) && post_content)
131
+ post = rb_str_new (post_content, post_length);
132
+
133
+ if (hdr_block && (hdr_block_size > 0))
134
+ headers = rb_str_new (hdr_block, hdr_block_size);
135
+ else
136
+ headers = rb_str_new ("", 0);
137
+
138
+ if (request_method && *request_method)
139
+ req_method = rb_str_new (request_method, strlen (request_method));
140
+ if (cookie && *cookie)
141
+ cookie_val = rb_str_new (cookie, strlen (cookie));
142
+ if (ifnonematch && *ifnonematch)
143
+ ifnonematch_val = rb_str_new (ifnonematch, strlen (ifnonematch));
144
+ if (contenttype && *contenttype)
145
+ contenttype_val = rb_str_new (contenttype, strlen (contenttype));
146
+ if (path_info && *path_info)
147
+ path_info_val = rb_str_new (path_info, strlen (path_info));
148
+ if (query_string && *query_string)
149
+ query_string_val = rb_str_new (query_string, strlen (query_string));
150
+ if (request_uri && *request_uri)
151
+ request_uri_val = rb_str_new (request_uri, strlen (request_uri));
152
+ if (protocol && *protocol)
153
+ protocol_val = rb_str_new (protocol, strlen (protocol));
154
+
155
+ rb_ivar_set (Myself, rb_intern ("@http_request_method"), req_method);
156
+ rb_ivar_set (Myself, rb_intern ("@http_cookie"), cookie_val);
157
+ rb_ivar_set (Myself, rb_intern ("@http_if_none_match"), ifnonematch_val);
158
+ rb_ivar_set (Myself, rb_intern ("@http_content_type"), contenttype_val);
159
+ rb_ivar_set (Myself, rb_intern ("@http_path_info"), path_info_val);
160
+ rb_ivar_set (Myself, rb_intern ("@http_request_uri"), request_uri_val);
161
+ rb_ivar_set (Myself, rb_intern ("@http_query_string"), query_string_val);
162
+ rb_ivar_set (Myself, rb_intern ("@http_post_content"), post);
163
+ rb_ivar_set (Myself, rb_intern ("@http_headers"), headers);
164
+ rb_ivar_set (Myself, rb_intern ("@http_protocol"), protocol_val);
165
+ rb_funcall (Myself, rb_intern ("process_http_request"), 0);
166
+ }
167
+
168
+
169
+ /*******
170
+ Statics
171
+ *******/
172
+
173
+ VALUE Intern_http_conn;
174
+
175
+ /********************
176
+ t_get_http_connection
177
+ ********************/
178
+
179
+ static RubyHttpConnection_t *t_get_http_connection(VALUE self)
180
+ {
181
+ RubyHttpConnection_t *hc;
182
+ VALUE ivar = rb_ivar_get (self, Intern_http_conn);
183
+ if (ivar != Qnil)
184
+ Data_Get_Struct (ivar, RubyHttpConnection_t, hc);
185
+ else
186
+ hc = NULL;
187
+ return hc;
188
+ }
189
+
190
+ /********************
191
+ t_delete_http_connection
192
+ ********************/
193
+
194
+ void t_delete_http_connection(RubyHttpConnection_t *hc)
195
+ {
196
+ delete hc;
197
+ }
198
+
199
+ /***********
200
+ t_post_init
201
+ ***********/
202
+
203
+ static VALUE t_post_init (VALUE self)
204
+ {
205
+ RubyHttpConnection_t *hc = new RubyHttpConnection_t (self);
206
+ if (!hc)
207
+ throw std::runtime_error ("no http-connection object");
208
+
209
+ /*
210
+ HACK: http_connection should be given an actual type. No one should
211
+ be touching it from inside ruby, but still
212
+ */
213
+ VALUE http_connection = Data_Wrap_Struct(CLASS_OF(self), 0, t_delete_http_connection, hc);
214
+ rb_ivar_set (self, Intern_http_conn, http_connection);
215
+ return Qnil;
216
+ }
217
+
218
+
219
+ /**************
220
+ t_receive_data
221
+ **************/
222
+
223
+ static VALUE t_receive_data (VALUE self, VALUE data)
224
+ {
225
+ int length = NUM2INT (rb_funcall (data, rb_intern ("length"), 0));
226
+ RubyHttpConnection_t *hc = t_get_http_connection (self);
227
+ if (hc)
228
+ hc->ConsumeData (StringValuePtr (data), length);
229
+ return Qnil;
230
+ }
231
+
232
+ /*******************
233
+ t_receive_post_data
234
+ *******************/
235
+
236
+ static VALUE t_receive_post_data (VALUE self, VALUE data)
237
+ {
238
+ /** This is a NOOP. It should be overridden. **/
239
+ return Qnil;
240
+ }
241
+
242
+ /********
243
+ t_unbind
244
+ ********/
245
+
246
+ static VALUE t_unbind (VALUE self)
247
+ {
248
+ return Qnil;
249
+ }
250
+
251
+
252
+ /**********************
253
+ t_process_http_request
254
+ **********************/
255
+
256
+ static VALUE t_process_http_request (VALUE self)
257
+ {
258
+ // This is a stub in case the caller doesn't define it.
259
+ rb_funcall (self, rb_intern ("send_data"), 1, rb_str_new2 ("HTTP/1.1 200 OK\r\nContent-type: text/plain\r\nContent-length: 8\r\n\r\nMonorail"));
260
+ return Qnil;
261
+ }
262
+
263
+ /************************
264
+ t_no_environment_strings
265
+ ************************/
266
+
267
+ static VALUE t_no_environment_strings (VALUE self)
268
+ {
269
+ RubyHttpConnection_t *hc = t_get_http_connection (self);
270
+ if (hc)
271
+ hc->SetNoEnvironmentStrings();
272
+ return Qnil;
273
+ }
274
+
275
+ /**********************
276
+ t_dont_accumulate_post
277
+ **********************/
278
+
279
+ static VALUE t_dont_accumulate_post (VALUE self)
280
+ {
281
+ RubyHttpConnection_t *hc = t_get_http_connection (self);
282
+ if (hc)
283
+ hc->SetDontAccumulatePost();
284
+ return Qnil;
285
+ }
286
+
287
+
288
+ /****************************
289
+ Init_eventmachine_httpserver
290
+ ****************************/
291
+
292
+ extern "C" void Init_eventmachine_httpserver()
293
+ {
294
+ Intern_http_conn = rb_intern ("http_conn");
295
+
296
+ VALUE EmModule = rb_define_module ("EventMachine");
297
+ VALUE HttpServer = rb_define_module_under (EmModule, "HttpServer");
298
+ rb_define_method (HttpServer, "post_init", (VALUE(*)(...))t_post_init, 0);
299
+ rb_define_method (HttpServer, "receive_data", (VALUE(*)(...))t_receive_data, 1);
300
+ rb_define_method (HttpServer, "receive_post_data", (VALUE(*)(...))t_receive_post_data, 1);
301
+ rb_define_method (HttpServer, "unbind", (VALUE(*)(...))t_unbind, 0);
302
+ rb_define_method (HttpServer, "process_http_request", (VALUE(*)(...))t_process_http_request, 0);
303
+ rb_define_method (HttpServer, "no_environment_strings", (VALUE(*)(...))t_no_environment_strings, 0);
304
+ rb_define_method (HttpServer, "dont_accumulate_post", (VALUE(*)(...))t_dont_accumulate_post, 0);
305
+ }
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{heventmachine_httpserver}
5
+ s.version = "0.2.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Francis Cianfrocca"]
9
+ s.cert_chain = []
10
+ s.date = %q{2020-11-13}
11
+ s.description = %q{}
12
+ s.email = %q{hunglkt@gmail.com}
13
+ s.extensions = ["ext/extconf.rb"]
14
+ s.extra_rdoc_files = ["docs/COPYING", "docs/README", "docs/RELEASE_NOTES"]
15
+ s.files = ["README.md", "Rakefile", "docs/COPYING", "docs/README", "docs/RELEASE_NOTES", "heventmachine_httpserver.gemspec", "heventmachine_httpserver.gemspec.tmpl", "ext/extconf.rb", "ext/http.cpp", "ext/http.h", "ext/rubyhttp.cpp", "lib/evma_httpserver.rb", "lib/evma_httpserver/response.rb", "test/test_app.rb", "test/test_delegated.rb", "test/test_response.rb"]
16
+ s.homepage = %q{https://github.com/hunglkt/eventmachine_httpserver}
17
+ s.rdoc_options = ["--title", "EventMachine_HttpServer", "--main", "docs/README", "--line-numbers"]
18
+ s.require_paths = ["lib"]
19
+ s.required_ruby_version = Gem::Requirement.new("> 0.0.0")
20
+ s.rubygems_version = %q{1.3.7}
21
+ s.summary = %q{EventMachine HTTP Server}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 1
26
+
27
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end