fotonauts-eventmachine_httpserver 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,115 @@
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
+
30
+
31
+ /**********************
32
+ class HttpConnection_t
33
+ **********************/
34
+
35
+ class HttpConnection_t
36
+ {
37
+ public:
38
+ HttpConnection_t();
39
+ virtual ~HttpConnection_t();
40
+
41
+ void ConsumeData (const char*, int);
42
+
43
+ virtual void SendData (const char*, int);
44
+ virtual void CloseConnection (bool after_writing);
45
+ virtual void ProcessRequest (const char *method,
46
+ const char *cookie,
47
+ const char *ifnonematch,
48
+ const char *content_type,
49
+ const char *query_string,
50
+ const char *path_info,
51
+ const char *request_uri,
52
+ const char *protocol,
53
+ int postlength,
54
+ const char *postdata,
55
+ const char* hdrblock,
56
+ int hdrblksize);
57
+
58
+ virtual void ReceivePostData(const char *data, int len);
59
+ virtual void SetNoEnvironmentStrings() {bSetEnvironmentStrings = false;}
60
+ virtual void SetDontAccumulatePost() {bAccumulatePost = false;}
61
+
62
+ private:
63
+
64
+ enum {
65
+ BaseState,
66
+ PreheaderState,
67
+ HeaderState,
68
+ ReadingContentState,
69
+ DispatchState,
70
+ EndState
71
+ } ProtocolState;
72
+
73
+ enum {
74
+ MaxLeadingBlanks = 12,
75
+ MaxHeaderLineLength = 8 * 1024,
76
+ MaxContentLength = 20 * 1024 * 1024,
77
+ HeaderBlockSize = 16 * 1024
78
+ };
79
+ int nLeadingBlanks;
80
+
81
+ char HeaderLine [MaxHeaderLineLength];
82
+ int HeaderLinePos;
83
+
84
+ char HeaderBlock [HeaderBlockSize];
85
+ int HeaderBlockPos;
86
+
87
+ int ContentLength;
88
+ int ContentPos;
89
+ char *_Content;
90
+
91
+ bool bSetEnvironmentStrings;
92
+ bool bAccumulatePost;
93
+ bool bRequestSeen;
94
+ bool bContentLengthSeen;
95
+
96
+ const char *RequestMethod;
97
+ std::string Cookie;
98
+ std::string IfNoneMatch;
99
+ std::string ContentType;
100
+ std::string PathInfo;
101
+ std::string RequestUri;
102
+ std::string QueryString;
103
+ std::string Protocol;
104
+
105
+ private:
106
+ bool _InterpretHeaderLine (const char*);
107
+ bool _InterpretRequest (const char*);
108
+ bool _DetectVerbAndSetEnvString (const char*, int);
109
+ void _SendError (int);
110
+ };
111
+
112
+ #endif // __HttpPersonality__H_
113
+
114
+
115
+
@@ -0,0 +1,148 @@
1
+
2
+
3
+
4
+
5
+ --- http.cpp 1969-12-31 18:00:00.000000000 -0600
6
+ +++ /usr/local/ruby185/lib/ruby/gems/1.8/gems/eventmachine_httpserver-0.0.1/ext/http.cpp 2007-03-10 08:13:24.000000000 -0600
7
+ @@ -29,6 +29,7 @@
8
+ #include <string>
9
+ #include <sstream>
10
+ #include <stdexcept>
11
+ +#include <stdio.h>
12
+
13
+ #ifdef OS_WIN32
14
+ #include <windows.h>
15
+ @@ -66,6 +67,7 @@
16
+ // (This is primarily beneficial because it lets the caller use Ruby's CGI classes.)
17
+ // The caller can switch this off in Ruby code, which greatly improves performance.
18
+ bSetEnvironmentStrings = true;
19
+ + bAccumulatePost = true;
20
+ }
21
+
22
+
23
+ @@ -112,6 +114,7 @@
24
+ const char *query_string,
25
+ const char *path_info,
26
+ const char *request_uri,
27
+ + const char *protocol,
28
+ int post_length,
29
+ const char *post_content,
30
+ const char *hdrblock,
31
+ @@ -121,7 +124,14 @@
32
+ }
33
+
34
+
35
+ +/********************************
36
+ +HttpConnection_t::ReceivePostData
37
+ +********************************/
38
+
39
+ +void HttpConnection_t::ReceivePostData (const char *data, int len)
40
+ +{
41
+ + cerr << "UNIMPLEMENTED ReceivePostData" << endl;
42
+ +}
43
+
44
+ /*****************************
45
+ HttpConnection_t::ConsumeData
46
+ @@ -159,6 +169,7 @@
47
+ PathInfo.clear();
48
+ RequestUri.clear();
49
+ QueryString.clear();
50
+ + Protocol.clear();
51
+
52
+ if (bSetEnvironmentStrings) {
53
+ unsetenv ("REQUEST_METHOD");
54
+ @@ -168,6 +179,7 @@
55
+ unsetenv ("PATH_INFO");
56
+ unsetenv ("REQUEST_URI");
57
+ unsetenv ("QUERY_STRING");
58
+ + unsetenv ("PROTOCOL");
59
+ }
60
+ }
61
+
62
+ @@ -202,9 +214,15 @@
63
+ if (ContentLength > 0) {
64
+ if (_Content)
65
+ free (_Content);
66
+ - _Content = (char*) malloc (ContentLength + 1);
67
+ - if (!_Content)
68
+ - throw std::runtime_error ("resource exhaustion");
69
+ + if (bAccumulatePost) {
70
+ + _Content = (char*) malloc (ContentLength + 1);
71
+ + if (!_Content)
72
+ + throw std::runtime_error ("resource exhaustion");
73
+ + }
74
+ + else {
75
+ + _Content = (char*) malloc (1);
76
+ + _Content = 0;
77
+ + }
78
+ ContentPos = 0;
79
+ ProtocolState = ReadingContentState;
80
+ }
81
+ @@ -241,12 +259,19 @@
82
+ int len = ContentLength - ContentPos;
83
+ if (len > length)
84
+ len = length;
85
+ - memcpy (_Content + ContentPos, data, len);
86
+ + if (bAccumulatePost) {
87
+ + memcpy (_Content + ContentPos, data, len);
88
+ + } else {
89
+ + ReceivePostData(data,len);
90
+ + }
91
+ data += len;
92
+ length -= len;
93
+ ContentPos += len;
94
+ if (ContentPos == ContentLength) {
95
+ - _Content[ContentPos] = 0;
96
+ + if (bAccumulatePost) {
97
+ + _Content[ContentPos] = 0;
98
+ + } else {
99
+ + }
100
+ ProtocolState = DispatchState;
101
+ }
102
+ }
103
+ @@ -254,7 +279,7 @@
104
+
105
+ //----------------------------------- DispatchState
106
+ if (ProtocolState == DispatchState) {
107
+ - ProcessRequest (RequestMethod, Cookie.c_str(), IfNoneMatch.c_str(), ContentType.c_str(), QueryString.c_str(), PathInfo.c_str(), RequestUri.c_str(), ContentLength, _Content, HeaderBlock, HeaderBlockPos);
108
+ + ProcessRequest (RequestMethod, Cookie.c_str(), IfNoneMatch.c_str(), ContentType.c_str(), QueryString.c_str(), PathInfo.c_str(), RequestUri.c_str(), Protocol.c_str(), ContentLength, _Content, HeaderBlock, HeaderBlockPos);
109
+ ProtocolState = BaseState;
110
+ }
111
+ }
112
+ @@ -424,6 +449,9 @@
113
+ return false;
114
+ }
115
+
116
+ + string prot (blank2+1);
117
+ + Protocol = prot.c_str();
118
+ +
119
+ // Here, the request starts at blank and ends just before blank2.
120
+ // Find the query-string (?) and/or fragment (#,;), if either are present.
121
+ const char *questionmark = strchr (blank, '?');
122
+ @@ -444,6 +472,7 @@
123
+ setenv ("PATH_INFO", req.c_str(), true);
124
+ setenv ("REQUEST_URI", req.c_str(), true);
125
+ setenv ("QUERY_STRING", qs.c_str(), true);
126
+ + setenv ("PROTOCOL", prot.c_str(), true);
127
+ }
128
+ }
129
+ else if (fragment) {
130
+ @@ -455,6 +484,7 @@
131
+ setenv ("PATH_INFO", req.c_str(), true);
132
+ setenv ("REQUEST_URI", req.c_str(), true);
133
+ setenv ("QUERY_STRING", "", true);
134
+ + setenv ("PROTOCOL", prot.c_str(), true);
135
+ }
136
+ }
137
+ else {
138
+ @@ -466,9 +496,9 @@
139
+ setenv ("PATH_INFO", req.c_str(), true);
140
+ setenv ("REQUEST_URI", req.c_str(), true);
141
+ setenv ("QUERY_STRING", "", true);
142
+ + setenv ("PROTOCOL", prot.c_str(), true);
143
+ }
144
+ }
145
+ -
146
+
147
+ return true;
148
+ }
@@ -0,0 +1,276 @@
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
+ void RubyHttpConnection_t::ReceivePostData (const char *data, int len)
89
+ {
90
+ VALUE data_val = Qnil;
91
+
92
+ if ((len > 0) && data) {
93
+ data_val = rb_str_new(data,len);
94
+ rb_funcall (Myself, rb_intern ("receive_post_data"), 1, data_val);
95
+ }
96
+ }
97
+
98
+ /************************************
99
+ RubyHttpConnection_t::ProcessRequest
100
+ ************************************/
101
+
102
+ void RubyHttpConnection_t::ProcessRequest (const char *request_method,
103
+ const char *cookie,
104
+ const char *ifnonematch,
105
+ const char *contenttype,
106
+ const char *query_string,
107
+ const char *path_info,
108
+ const char *request_uri,
109
+ const char *protocol,
110
+ int post_length,
111
+ const char *post_content,
112
+ const char *hdr_block,
113
+ int hdr_block_size)
114
+ {
115
+ VALUE post = Qnil;
116
+ VALUE headers = Qnil;
117
+ VALUE req_method = Qnil;
118
+ VALUE cookie_val = Qnil;
119
+ VALUE ifnonematch_val = Qnil;
120
+ VALUE contenttype_val = Qnil;
121
+ VALUE path_info_val = Qnil;
122
+ VALUE query_string_val = Qnil;
123
+ VALUE request_uri_val = Qnil;
124
+ VALUE protocol_val = Qnil;
125
+
126
+ if ((post_length > 0) && post_content)
127
+ post = rb_str_new (post_content, post_length);
128
+
129
+ if (hdr_block && (hdr_block_size > 0))
130
+ headers = rb_str_new (hdr_block, hdr_block_size);
131
+ else
132
+ headers = rb_str_new ("", 0);
133
+
134
+ if (request_method && *request_method)
135
+ req_method = rb_str_new (request_method, strlen (request_method));
136
+ if (cookie && *cookie)
137
+ cookie_val = rb_str_new (cookie, strlen (cookie));
138
+ if (ifnonematch && *ifnonematch)
139
+ ifnonematch_val = rb_str_new (ifnonematch, strlen (ifnonematch));
140
+ if (contenttype && *contenttype)
141
+ contenttype_val = rb_str_new (contenttype, strlen (contenttype));
142
+ if (path_info && *path_info)
143
+ path_info_val = rb_str_new (path_info, strlen (path_info));
144
+ if (query_string && *query_string)
145
+ query_string_val = rb_str_new (query_string, strlen (query_string));
146
+ if (request_uri && *request_uri)
147
+ request_uri_val = rb_str_new (request_uri, strlen (request_uri));
148
+ if (protocol && *protocol)
149
+ protocol_val = rb_str_new (protocol, strlen (protocol));
150
+
151
+ rb_ivar_set (Myself, rb_intern ("@http_request_method"), req_method);
152
+ rb_ivar_set (Myself, rb_intern ("@http_cookie"), cookie_val);
153
+ rb_ivar_set (Myself, rb_intern ("@http_if_none_match"), ifnonematch_val);
154
+ rb_ivar_set (Myself, rb_intern ("@http_content_type"), contenttype_val);
155
+ rb_ivar_set (Myself, rb_intern ("@http_path_info"), path_info_val);
156
+ rb_ivar_set (Myself, rb_intern ("@http_request_uri"), request_uri_val);
157
+ rb_ivar_set (Myself, rb_intern ("@http_query_string"), query_string_val);
158
+ rb_ivar_set (Myself, rb_intern ("@http_post_content"), post);
159
+ rb_ivar_set (Myself, rb_intern ("@http_headers"), headers);
160
+ rb_ivar_set (Myself, rb_intern ("@http_protocol"), protocol_val);
161
+ rb_funcall (Myself, rb_intern ("process_http_request"), 0);
162
+ }
163
+
164
+
165
+ /*******
166
+ Statics
167
+ *******/
168
+
169
+
170
+
171
+ /***********
172
+ t_post_init
173
+ ***********/
174
+
175
+ static VALUE t_post_init (VALUE self)
176
+ {
177
+ RubyHttpConnection_t *hc = new RubyHttpConnection_t (self);
178
+ if (!hc)
179
+ throw std::runtime_error ("no http-connection object");
180
+
181
+ rb_ivar_set (self, rb_intern ("@http______conn"), INT2NUM ((long)hc));
182
+ return Qnil;
183
+ }
184
+
185
+
186
+ /**************
187
+ t_receive_data
188
+ **************/
189
+
190
+ static VALUE t_receive_data (VALUE self, VALUE data)
191
+ {
192
+ int length = NUM2INT (rb_funcall (data, rb_intern ("length"), 0));
193
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
194
+ if (hc)
195
+ hc->ConsumeData (StringValuePtr (data), length);
196
+ return Qnil;
197
+ }
198
+
199
+ /*******************
200
+ t_receive_post_data
201
+ *******************/
202
+
203
+ static VALUE t_receive_post_data (VALUE self, VALUE data)
204
+ {
205
+ /** This is a NOOP. It should be overridden. **/
206
+ }
207
+
208
+ /********
209
+ t_unbind
210
+ ********/
211
+
212
+ static VALUE t_unbind (VALUE self)
213
+ {
214
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
215
+ if (hc)
216
+ delete hc;
217
+ return Qnil;
218
+ }
219
+
220
+
221
+ /**********************
222
+ t_process_http_request
223
+ **********************/
224
+
225
+ static VALUE t_process_http_request (VALUE self)
226
+ {
227
+ // This is a stub in case the caller doesn't define it.
228
+ rb_funcall (self, rb_intern ("send_data"), 1, rb_str_new2 ("HTTP/1.1 200 ...\r\nContent-type: text/plain\r\nContent-length: 8\r\n\r\nMonorail"));
229
+ return Qnil;
230
+ }
231
+
232
+ /************************
233
+ t_no_environment_strings
234
+ ************************/
235
+
236
+ static VALUE t_no_environment_strings (VALUE self)
237
+ {
238
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
239
+ if (hc)
240
+ hc->SetNoEnvironmentStrings();
241
+ return Qnil;
242
+ }
243
+
244
+ /**********************
245
+ t_dont_accumulate_post
246
+ **********************/
247
+
248
+ static VALUE t_dont_accumulate_post (VALUE self)
249
+ {
250
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
251
+ if (hc)
252
+ hc->SetDontAccumulatePost();
253
+ return Qnil;
254
+ }
255
+
256
+
257
+ /****************************
258
+ Init_eventmachine_httpserver
259
+ ****************************/
260
+
261
+ extern "C" void Init_eventmachine_httpserver()
262
+ {
263
+ // INCOMPLETE, we need to define class Connections inside module EventMachine
264
+
265
+ VALUE Monorail = rb_define_module ("EventMachine");
266
+ VALUE EmModule = rb_define_module_under (Monorail, "HttpServer");
267
+ rb_define_method (EmModule, "post_init", (VALUE(*)(...))t_post_init, 0);
268
+ rb_define_method (EmModule, "receive_data", (VALUE(*)(...))t_receive_data, 1);
269
+ rb_define_method (EmModule, "receive_post_data", (VALUE(*)(...))t_receive_post_data, 1);
270
+ rb_define_method (EmModule, "unbind", (VALUE(*)(...))t_unbind, 0);
271
+ rb_define_method (EmModule, "process_http_request", (VALUE(*)(...))t_process_http_request, 0);
272
+ rb_define_method (EmModule, "no_environment_strings", (VALUE(*)(...))t_no_environment_strings, 0);
273
+ rb_define_method (EmModule, "dont_accumulate_post", (VALUE(*)(...))t_dont_accumulate_post, 0);
274
+ }
275
+
276
+