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,117 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: http.h 3966 2007-03-16 11:52:05Z francis $
4
+
5
+ File: http.h
6
+ Date: 21Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat10
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation; either version 2 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ *****************************************************************************/
26
+
27
+
28
+ #ifndef __HttpPersonality__H_
29
+ #define __HttpPersonality__H_
30
+
31
+
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 (int);
112
+ };
113
+
114
+ #endif // __HttpPersonality__H_
115
+
116
+
117
+
@@ -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,278 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: rubyhttp.cpp 3966 2007-03-16 11:52:05Z francis $
4
+
5
+ File: libmain.cpp
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat10
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation; either version 2 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ *****************************************************************************/
26
+
27
+ #include <iostream>
28
+ #include <string>
29
+ #include <stdexcept>
30
+
31
+ using namespace std;
32
+
33
+ #include <ruby.h>
34
+ #include "http.h"
35
+
36
+
37
+
38
+ /**************************
39
+ class RubyHttpConnection_t
40
+ **************************/
41
+
42
+ class RubyHttpConnection_t: public HttpConnection_t
43
+ {
44
+ public:
45
+ RubyHttpConnection_t (VALUE v): Myself(v) {}
46
+ virtual ~RubyHttpConnection_t() {}
47
+
48
+ virtual void SendData (const char*, int);
49
+ virtual void CloseConnection (bool after_writing);
50
+ virtual void ProcessRequest (const char *request_method,
51
+ const char *cookie,
52
+ const char *ifnonematch,
53
+ const char *contenttype,
54
+ const char *query_string,
55
+ const char *path_info,
56
+ const char *request_uri,
57
+ const char *protocol,
58
+ int postlength,
59
+ const char *postdata,
60
+ const char *hdrblock,
61
+ int hdrblocksize);
62
+ virtual void ReceivePostData (const char *data, int len);
63
+
64
+ private:
65
+ VALUE Myself;
66
+ };
67
+
68
+
69
+ /******************************
70
+ RubyHttpConnection_t::SendData
71
+ ******************************/
72
+
73
+ void RubyHttpConnection_t::SendData (const char *data, int length)
74
+ {
75
+ rb_funcall (Myself, rb_intern ("send_data"), 1, rb_str_new (data, length));
76
+ }
77
+
78
+
79
+ /*************************************
80
+ RubyHttpConnection_t::CloseConnection
81
+ *************************************/
82
+
83
+ void RubyHttpConnection_t::CloseConnection (bool after_writing)
84
+ {
85
+ VALUE v = rb_intern (after_writing ? "close_connection_after_writing" : "close_connection");
86
+ rb_funcall (Myself, v, 0);
87
+ }
88
+
89
+
90
+ void RubyHttpConnection_t::ReceivePostData (const char *data, int len)
91
+ {
92
+ VALUE data_val = Qnil;
93
+
94
+ if ((len > 0) && data) {
95
+ data_val = rb_str_new(data,len);
96
+ rb_funcall (Myself, rb_intern ("receive_post_data"), 1, data_val);
97
+ }
98
+ }
99
+
100
+ /************************************
101
+ RubyHttpConnection_t::ProcessRequest
102
+ ************************************/
103
+
104
+ void RubyHttpConnection_t::ProcessRequest (const char *request_method,
105
+ const char *cookie,
106
+ const char *ifnonematch,
107
+ const char *contenttype,
108
+ const char *query_string,
109
+ const char *path_info,
110
+ const char *request_uri,
111
+ const char *protocol,
112
+ int post_length,
113
+ const char *post_content,
114
+ const char *hdr_block,
115
+ int hdr_block_size)
116
+ {
117
+ VALUE post = Qnil;
118
+ VALUE headers = Qnil;
119
+ VALUE req_method = Qnil;
120
+ VALUE cookie_val = Qnil;
121
+ VALUE ifnonematch_val = Qnil;
122
+ VALUE contenttype_val = Qnil;
123
+ VALUE path_info_val = Qnil;
124
+ VALUE query_string_val = Qnil;
125
+ VALUE request_uri_val = Qnil;
126
+ VALUE protocol_val = Qnil;
127
+
128
+ if ((post_length > 0) && post_content)
129
+ post = rb_str_new (post_content, post_length);
130
+
131
+ if (hdr_block && (hdr_block_size > 0))
132
+ headers = rb_str_new (hdr_block, hdr_block_size);
133
+ else
134
+ headers = rb_str_new ("", 0);
135
+
136
+ if (request_method && *request_method)
137
+ req_method = rb_str_new (request_method, strlen (request_method));
138
+ if (cookie && *cookie)
139
+ cookie_val = rb_str_new (cookie, strlen (cookie));
140
+ if (ifnonematch && *ifnonematch)
141
+ ifnonematch_val = rb_str_new (ifnonematch, strlen (ifnonematch));
142
+ if (contenttype && *contenttype)
143
+ contenttype_val = rb_str_new (contenttype, strlen (contenttype));
144
+ if (path_info && *path_info)
145
+ path_info_val = rb_str_new (path_info, strlen (path_info));
146
+ if (query_string && *query_string)
147
+ query_string_val = rb_str_new (query_string, strlen (query_string));
148
+ if (request_uri && *request_uri)
149
+ request_uri_val = rb_str_new (request_uri, strlen (request_uri));
150
+ if (protocol && *protocol)
151
+ protocol_val = rb_str_new (protocol, strlen (protocol));
152
+
153
+ rb_ivar_set (Myself, rb_intern ("@http_request_method"), req_method);
154
+ rb_ivar_set (Myself, rb_intern ("@http_cookie"), cookie_val);
155
+ rb_ivar_set (Myself, rb_intern ("@http_if_none_match"), ifnonematch_val);
156
+ rb_ivar_set (Myself, rb_intern ("@http_content_type"), contenttype_val);
157
+ rb_ivar_set (Myself, rb_intern ("@http_path_info"), path_info_val);
158
+ rb_ivar_set (Myself, rb_intern ("@http_request_uri"), request_uri_val);
159
+ rb_ivar_set (Myself, rb_intern ("@http_query_string"), query_string_val);
160
+ rb_ivar_set (Myself, rb_intern ("@http_post_content"), post);
161
+ rb_ivar_set (Myself, rb_intern ("@http_headers"), headers);
162
+ rb_ivar_set (Myself, rb_intern ("@http_protocol"), protocol_val);
163
+ rb_funcall (Myself, rb_intern ("process_http_request"), 0);
164
+ }
165
+
166
+
167
+ /*******
168
+ Statics
169
+ *******/
170
+
171
+
172
+
173
+ /***********
174
+ t_post_init
175
+ ***********/
176
+
177
+ static VALUE t_post_init (VALUE self)
178
+ {
179
+ RubyHttpConnection_t *hc = new RubyHttpConnection_t (self);
180
+ if (!hc)
181
+ throw std::runtime_error ("no http-connection object");
182
+
183
+ rb_ivar_set (self, rb_intern ("@http______conn"), INT2NUM ((long)hc));
184
+ return Qnil;
185
+ }
186
+
187
+
188
+ /**************
189
+ t_receive_data
190
+ **************/
191
+
192
+ static VALUE t_receive_data (VALUE self, VALUE data)
193
+ {
194
+ int length = NUM2INT (rb_funcall (data, rb_intern ("length"), 0));
195
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
196
+ if (hc)
197
+ hc->ConsumeData (StringValuePtr (data), length);
198
+ return Qnil;
199
+ }
200
+
201
+ /*******************
202
+ t_receive_post_data
203
+ *******************/
204
+
205
+ static VALUE t_receive_post_data (VALUE self, VALUE data)
206
+ {
207
+ /** This is a NOOP. It should be overridden. **/
208
+ }
209
+
210
+ /********
211
+ t_unbind
212
+ ********/
213
+
214
+ static VALUE t_unbind (VALUE self)
215
+ {
216
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
217
+ if (hc)
218
+ delete hc;
219
+ return Qnil;
220
+ }
221
+
222
+
223
+ /**********************
224
+ t_process_http_request
225
+ **********************/
226
+
227
+ static VALUE t_process_http_request (VALUE self)
228
+ {
229
+ // This is a stub in case the caller doesn't define it.
230
+ 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"));
231
+ return Qnil;
232
+ }
233
+
234
+ /************************
235
+ t_no_environment_strings
236
+ ************************/
237
+
238
+ static VALUE t_no_environment_strings (VALUE self)
239
+ {
240
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
241
+ if (hc)
242
+ hc->SetNoEnvironmentStrings();
243
+ return Qnil;
244
+ }
245
+
246
+ /**********************
247
+ t_dont_accumulate_post
248
+ **********************/
249
+
250
+ static VALUE t_dont_accumulate_post (VALUE self)
251
+ {
252
+ RubyHttpConnection_t *hc = (RubyHttpConnection_t*)(NUM2INT (rb_ivar_get (self, rb_intern ("@http______conn"))));
253
+ if (hc)
254
+ hc->SetDontAccumulatePost();
255
+ return Qnil;
256
+ }
257
+
258
+
259
+ /****************************
260
+ Init_eventmachine_httpserver
261
+ ****************************/
262
+
263
+ extern "C" void Init_eventmachine_httpserver()
264
+ {
265
+ // INCOMPLETE, we need to define class Connections inside module EventMachine
266
+
267
+ VALUE Monorail = rb_define_module ("EventMachine");
268
+ VALUE EmModule = rb_define_module_under (Monorail, "HttpServer");
269
+ rb_define_method (EmModule, "post_init", (VALUE(*)(...))t_post_init, 0);
270
+ rb_define_method (EmModule, "receive_data", (VALUE(*)(...))t_receive_data, 1);
271
+ rb_define_method (EmModule, "receive_post_data", (VALUE(*)(...))t_receive_post_data, 1);
272
+ rb_define_method (EmModule, "unbind", (VALUE(*)(...))t_unbind, 0);
273
+ rb_define_method (EmModule, "process_http_request", (VALUE(*)(...))t_process_http_request, 0);
274
+ rb_define_method (EmModule, "no_environment_strings", (VALUE(*)(...))t_no_environment_strings, 0);
275
+ rb_define_method (EmModule, "dont_accumulate_post", (VALUE(*)(...))t_dont_accumulate_post, 0);
276
+ }
277
+
278
+