1 /* A ruby binding to the ebb web server
2 * Copyright (c) 2008 Ry Dahl. This software is released under the MIT
3 * License. See README file for details.
13 static VALUE global_http_prefix
;
14 static VALUE global_request_method
;
15 static VALUE global_request_uri
;
16 static VALUE global_fragment
;
17 static VALUE global_request_path
;
18 static VALUE global_query_string
;
19 static VALUE global_http_version
;
20 static VALUE global_request_body
;
21 static VALUE global_server_name
;
22 static VALUE global_server_port
;
23 static VALUE global_path_info
;
24 static VALUE global_content_length
;
25 static VALUE global_http_host
;
27 /* Variables with a leading underscore are C-level variables */
29 #define ASCII_UPPER(ch) ('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch)
31 # define RSTRING_PTR(s) (RSTRING(s)->ptr)
32 # define RSTRING_LEN(s) (RSTRING(s)->len)
35 VALUE
client_new(ebb_client
*_client
)
37 VALUE client
= Data_Wrap_Struct(cClient
, 0, 0, _client
);
42 void request_cb(ebb_client
*_client
, void *data
)
44 VALUE server
= (VALUE
)data
;
45 VALUE waiting_clients
;
46 VALUE client
= client_new(_client
);
48 waiting_clients
= rb_iv_get(server
, "@waiting_clients");
49 rb_ary_push(waiting_clients
, client
);
53 VALUE
server_alloc(VALUE self
)
55 struct ev_loop
*loop
= ev_default_loop (0);
56 ebb_server
*_server
= ebb_server_alloc();
58 server
= Data_Wrap_Struct(cServer
, 0, ebb_server_free
, _server
);
59 ebb_server_init(_server
, loop
, request_cb
, (void*)server
);
64 VALUE
server_listen_on_port(VALUE x
, VALUE server
, VALUE port
)
67 Data_Get_Struct(server
, ebb_server
, _server
);
68 int r
= ebb_server_listen_on_port(_server
, FIX2INT(port
));
69 return r
< 0 ? Qfalse
: Qtrue
;
73 VALUE
server_listen_on_socket(VALUE x
, VALUE server
, VALUE socketpath
)
76 Data_Get_Struct(server
, ebb_server
, _server
);
77 int r
= ebb_server_listen_on_socket(_server
, StringValuePtr(socketpath
));
78 return r
< 0 ? Qfalse
: Qtrue
;
83 oneshot_timeout (struct ev_loop
*loop
, struct ev_timer
*w
, int revents
) {;}
86 VALUE
server_process_connections(VALUE x
, VALUE server
)
91 Data_Get_Struct(server
, ebb_server
, _server
);
94 ev_timer_init (&timeout
, oneshot_timeout
, 0.5, 0.);
95 ev_timer_start (_server
->loop
, &timeout
);
97 ev_loop(_server
->loop
, EVLOOP_ONESHOT
);
98 /* XXX: Need way to know when the loop is finished...
99 * should return true or false */
101 ev_timer_stop(_server
->loop
, &timeout
);
110 VALUE
server_unlisten(VALUE x
, VALUE server
)
113 Data_Get_Struct(server
, ebb_server
, _server
);
114 ebb_server_unlisten(_server
);
119 VALUE
env_field(struct ebb_env_item
*item
)
123 case EBB_FIELD_VALUE_PAIR
:
124 f
= rb_str_new(NULL
, RSTRING_LEN(global_http_prefix
) + item
->field_length
);
125 memcpy( RSTRING_PTR(f
)
126 , RSTRING_PTR(global_http_prefix
)
127 , RSTRING_LEN(global_http_prefix
)
130 for(i
= 0; i
< item
->field_length
; i
++) {
131 char *ch
= RSTRING_PTR(f
) + RSTRING_LEN(global_http_prefix
) + i
;
132 *ch
= item
->field
[i
] == '-' ? '_' : ASCII_UPPER(item
->field
[i
]);
135 case EBB_REQUEST_METHOD
: return global_request_method
;
136 case EBB_REQUEST_URI
: return global_request_uri
;
137 case EBB_FRAGMENT
: return global_fragment
;
138 case EBB_REQUEST_PATH
: return global_request_path
;
139 case EBB_QUERY_STRING
: return global_query_string
;
140 case EBB_HTTP_VERSION
: return global_http_version
;
141 case EBB_SERVER_NAME
: return global_server_name
;
142 case EBB_SERVER_PORT
: return global_server_port
;
143 case EBB_CONTENT_LENGTH
: return global_content_length
;
150 VALUE
env_value(struct ebb_env_item
*item
)
152 if(item
->value_length
> 0)
153 return rb_str_new(item
->value
, item
->value_length
);
159 VALUE
client_env(VALUE x
, VALUE client
)
162 VALUE hash
= rb_hash_new();
164 Data_Get_Struct(client
, ebb_client
, _client
);
166 for(i
=0; i
< _client
->env_size
; i
++) {
167 rb_hash_aset(hash
, env_field(&_client
->env
[i
])
168 , env_value(&_client
->env
[i
])
171 rb_hash_aset(hash
, global_path_info
, rb_hash_aref(hash
, global_request_path
));
176 VALUE
client_read_input(VALUE x
, VALUE client
, VALUE size
)
181 int _size
= FIX2INT(size
);
182 Data_Get_Struct(client
, ebb_client
, _client
);
184 string
= rb_str_buf_new( _size
);
185 int nread
= ebb_client_read(_client
, RSTRING_PTR(string
), _size
);
186 #if RUBY_VERSION_CODE < 190
187 RSTRING(string
)->len
= nread
;
189 rb_str_set_len(string
, nread
);
193 rb_raise(rb_eRuntimeError
,"There was a problem reading from input (bad tmp file?)");
199 VALUE
client_write_status(VALUE x
, VALUE client
, VALUE status
, VALUE human_status
)
202 Data_Get_Struct(client
, ebb_client
, _client
);
203 ebb_client_write_status(_client
, FIX2INT(status
), StringValuePtr(human_status
));
207 VALUE
client_write_header(VALUE x
, VALUE client
, VALUE field
, VALUE value
)
210 Data_Get_Struct(client
, ebb_client
, _client
);
211 ebb_client_write_header(_client
, StringValuePtr(field
), StringValuePtr(value
));
215 VALUE
client_write(VALUE x
, VALUE client
, VALUE string
)
218 Data_Get_Struct(client
, ebb_client
, _client
);
219 ebb_client_write(_client
, RSTRING_PTR(string
), RSTRING_LEN(string
));
224 VALUE
client_finished(VALUE x
, VALUE client
)
227 Data_Get_Struct(client
, ebb_client
, _client
);
228 ebb_client_finished(_client
);
235 VALUE mEbb
= rb_define_module("Ebb");
236 VALUE mFFI
= rb_define_module_under(mEbb
, "FFI");
238 /** Defines global strings in the init method. */
239 #define DEF_GLOBAL(N, val) global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N)
240 DEF_GLOBAL(http_prefix
, "HTTP_");
241 DEF_GLOBAL(request_method
, "REQUEST_METHOD");
242 DEF_GLOBAL(request_uri
, "REQUEST_URI");
243 DEF_GLOBAL(fragment
, "FRAGMENT");
244 DEF_GLOBAL(request_path
, "REQUEST_PATH");
245 DEF_GLOBAL(query_string
, "QUERY_STRING");
246 DEF_GLOBAL(http_version
, "HTTP_VERSION");
247 DEF_GLOBAL(request_body
, "REQUEST_BODY");
248 DEF_GLOBAL(server_name
, "SERVER_NAME");
249 DEF_GLOBAL(server_port
, "SERVER_PORT");
250 DEF_GLOBAL(path_info
, "PATH_INFO");
251 DEF_GLOBAL(content_length
, "CONTENT_LENGTH");
252 DEF_GLOBAL(http_host
, "HTTP_HOST");
254 cServer
= rb_define_class_under(mEbb
, "Server", rb_cObject
);
255 rb_define_alloc_func(cServer
, server_alloc
);
256 rb_define_singleton_method(mFFI
, "server_process_connections", server_process_connections
, 1);
257 rb_define_singleton_method(mFFI
, "server_listen_on_port", server_listen_on_port
, 2);
258 rb_define_singleton_method(mFFI
, "server_listen_on_socket", server_listen_on_socket
, 2);
259 rb_define_singleton_method(mFFI
, "server_unlisten", server_unlisten
, 1);
261 cClient
= rb_define_class_under(mEbb
, "Client", rb_cObject
);
262 rb_define_singleton_method(mFFI
, "client_read_input", client_read_input
, 2);
263 rb_define_singleton_method(mFFI
, "client_write_status", client_write_status
, 3);
264 rb_define_singleton_method(mFFI
, "client_write_header", client_write_header
, 3);
265 rb_define_singleton_method(mFFI
, "client_write", client_write
, 2);
266 rb_define_singleton_method(mFFI
, "client_finished", client_finished
, 1);
267 rb_define_singleton_method(mFFI
, "client_env", client_env
, 1);