libevent 0.0.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,466 @@
1
+ #include "ext.h"
2
+
3
+ static VALUE t_allocate(VALUE klass);
4
+
5
+ static void t_free(Libevent_HttpRequest *http_request);
6
+
7
+ static VALUE t_initialize(VALUE self);
8
+
9
+ static VALUE t_get_remote_host(VALUE self);
10
+
11
+ static VALUE t_get_remote_port(VALUE self);
12
+
13
+ static VALUE t_get_http_version(VALUE self);
14
+
15
+ static VALUE t_get_command(VALUE self);
16
+
17
+ static VALUE t_get_uri(VALUE self);
18
+
19
+ static VALUE t_get_uri_scheme(VALUE self);
20
+
21
+ static VALUE t_get_uri_path(VALUE self);
22
+
23
+ static VALUE t_get_uri_query(VALUE self);
24
+
25
+ static VALUE t_get_host(VALUE self);
26
+
27
+ static VALUE t_get_input_headers(VALUE self);
28
+
29
+ static VALUE t_get_body(VALUE self);
30
+
31
+ static VALUE t_send_reply(VALUE self, VALUE code, VALUE headers, VALUE body);
32
+
33
+ static VALUE t_send_error(VALUE self, VALUE code, VALUE reason);
34
+
35
+ static VALUE t_add_output_header(VALUE self, VALUE key, VALUE value);
36
+
37
+ static VALUE t_set_output_headers(VALUE self, VALUE headers);
38
+
39
+ static VALUE t_clear_output_headers(VALUE self);
40
+
41
+ static VALUE t_send_chunk(VALUE chunk, VALUE self);
42
+
43
+ static VALUE t_send_reply_start(VALUE self, VALUE code, VALUE reason);
44
+
45
+ static VALUE t_send_reply_chunk(VALUE self, VALUE chunk);
46
+
47
+ static VALUE t_send_reply_end(VALUE self);
48
+
49
+ void Init_libevent_http_request() {
50
+ cLibevent_HttpRequest = rb_define_class_under(mLibevent, "HttpRequest", rb_cObject);
51
+
52
+ rb_define_alloc_func(cLibevent_HttpRequest, t_allocate);
53
+
54
+ rb_define_method(cLibevent_HttpRequest, "initialize", t_initialize, 0);
55
+ rb_define_method(cLibevent_HttpRequest, "get_remote_host", t_get_remote_host, 0);
56
+ rb_define_method(cLibevent_HttpRequest, "get_remote_port", t_get_remote_port, 0);
57
+ rb_define_method(cLibevent_HttpRequest, "get_http_version", t_get_http_version, 0);
58
+ rb_define_method(cLibevent_HttpRequest, "get_command", t_get_command, 0);
59
+ rb_define_method(cLibevent_HttpRequest, "get_uri", t_get_uri, 0);
60
+ rb_define_method(cLibevent_HttpRequest, "get_uri_scheme", t_get_uri_scheme, 0);
61
+ rb_define_method(cLibevent_HttpRequest, "get_uri_path", t_get_uri_path, 0);
62
+ rb_define_method(cLibevent_HttpRequest, "get_uri_query", t_get_uri_query, 0);
63
+ rb_define_method(cLibevent_HttpRequest, "get_host", t_get_host, 0);
64
+ rb_define_method(cLibevent_HttpRequest, "get_input_headers", t_get_input_headers, 0);
65
+ rb_define_method(cLibevent_HttpRequest, "get_body", t_get_body, 0);
66
+ rb_define_method(cLibevent_HttpRequest, "add_output_header", t_add_output_header, 2);
67
+ rb_define_method(cLibevent_HttpRequest, "set_output_headers", t_set_output_headers, 1);
68
+ rb_define_method(cLibevent_HttpRequest, "clear_output_headers", t_clear_output_headers, 0);
69
+ rb_define_method(cLibevent_HttpRequest, "send_reply", t_send_reply, 3);
70
+ rb_define_method(cLibevent_HttpRequest, "send_error", t_send_error, 2);
71
+ rb_define_method(cLibevent_HttpRequest, "send_reply_start", t_send_reply_start, 2);
72
+ rb_define_method(cLibevent_HttpRequest, "send_reply_chunk", t_send_reply_chunk, 1);
73
+ rb_define_method(cLibevent_HttpRequest, "send_reply_end", t_send_reply_end, 0);
74
+ }
75
+
76
+ /*
77
+ * Allocate memory
78
+ */
79
+ static VALUE t_allocate(VALUE klass) {
80
+ Libevent_HttpRequest *http_request = ALLOC(Libevent_HttpRequest);
81
+
82
+ http_request->ev_request = NULL;
83
+ http_request->ev_buffer = evbuffer_new();
84
+
85
+ return Data_Wrap_Struct(klass, 0, t_free, http_request);
86
+ }
87
+
88
+ /*
89
+ * Free memory
90
+ */
91
+ static void t_free(Libevent_HttpRequest *http_request) {
92
+ if ( http_request->ev_buffer != NULL ) {
93
+ evbuffer_free(http_request->ev_buffer);
94
+ }
95
+
96
+ xfree(http_request);
97
+ }
98
+
99
+ /*
100
+ * Initialize HttpRequest object
101
+ * @raise [ArgumentError] if object created withot evhttp_request c data
102
+ */
103
+ static VALUE t_initialize(VALUE self) {
104
+ Libevent_HttpRequest *http_request;
105
+
106
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
107
+ if ( !http_request->ev_request )
108
+ rb_raise(rb_eArgError, "http_request C data is not given");
109
+
110
+ return self;
111
+ }
112
+
113
+ /*
114
+ * Add output header
115
+ * @param [String] key a header key
116
+ * @param [String] value a header value
117
+ * @return [true false]
118
+ */
119
+ static VALUE t_add_output_header(VALUE self, VALUE key, VALUE value) {
120
+ Libevent_HttpRequest *http_request;
121
+ struct evkeyvalq *ev_headers;
122
+ int status;
123
+
124
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
125
+ ev_headers = evhttp_request_get_output_headers(http_request->ev_request);
126
+ status = evhttp_add_header(ev_headers, RSTRING_PTR(key), RSTRING_PTR(value));
127
+
128
+ return ( status == -1 ? Qfalse : Qtrue);
129
+ }
130
+
131
+ /*
132
+ * Set request output headers
133
+ * @param [Hash Array] headers
134
+ * @return [nil]
135
+ */
136
+ static VALUE t_set_output_headers(VALUE self, VALUE headers) {
137
+ Libevent_HttpRequest *http_request;
138
+ VALUE pairs;
139
+ VALUE pair;
140
+ VALUE key;
141
+ VALUE val;
142
+ struct evkeyvalq *ev_headers;
143
+ int i;
144
+
145
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
146
+
147
+ ev_headers = evhttp_request_get_output_headers(http_request->ev_request);
148
+
149
+ pairs = rb_funcall(headers, rb_intern("to_a"), 0);
150
+
151
+ for ( i=0 ; i < RARRAY_LEN(pairs); i++ ) {
152
+ pair = rb_ary_entry(pairs, i);
153
+ key = rb_ary_entry(pair, 0);
154
+ val = rb_ary_entry(pair, 1);
155
+ evhttp_add_header(ev_headers, RSTRING_PTR(key), RSTRING_PTR(val));
156
+ }
157
+
158
+ return Qnil;
159
+ }
160
+
161
+ /*
162
+ * Removes all output headers.
163
+ * @return [nil]
164
+ */
165
+ static VALUE t_clear_output_headers(VALUE self) {
166
+ Libevent_HttpRequest *http_request;
167
+ struct evkeyvalq *ev_headers;
168
+
169
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
170
+ ev_headers = evhttp_request_get_output_headers(http_request->ev_request);
171
+ evhttp_clear_headers(ev_headers);
172
+
173
+ return Qnil;
174
+ }
175
+
176
+ /*
177
+ * Get request input headers
178
+ * @return [Hash]
179
+ */
180
+ static VALUE t_get_input_headers(VALUE self) {
181
+ Libevent_HttpRequest *http_request;
182
+ struct evkeyvalq *ev_headers;
183
+ struct evkeyval *ev_header;
184
+ VALUE headers;
185
+
186
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
187
+
188
+ headers = rb_hash_new();
189
+
190
+ ev_headers = evhttp_request_get_input_headers(http_request->ev_request);
191
+
192
+ for ( ev_header = ev_headers->tqh_first; ev_header; ev_header = ev_header->next.tqe_next ) {
193
+ rb_hash_aset(headers, rb_str_new2(ev_header->key), rb_str_new2(ev_header->value));
194
+ }
195
+
196
+ return headers;
197
+ }
198
+
199
+ /*
200
+ * Get the remote address of associated connection
201
+ * @return [String] IP address
202
+ */
203
+ static VALUE t_get_remote_host(VALUE self) {
204
+ Libevent_HttpRequest *http_request;
205
+
206
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
207
+
208
+ return rb_str_new2(http_request->ev_request->remote_host);
209
+ }
210
+
211
+ /*
212
+ * Get the remote port of associated connection
213
+ * @return [Fixnum] port
214
+ */
215
+ static VALUE t_get_remote_port(VALUE self) {
216
+ Libevent_HttpRequest *http_request;
217
+
218
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
219
+
220
+ return INT2FIX(http_request->ev_request->remote_port);
221
+ }
222
+
223
+ /*
224
+ * Get request HTTP version
225
+ * @return [String] http version
226
+ */
227
+ static VALUE t_get_http_version(VALUE self) {
228
+ Libevent_HttpRequest *http_request;
229
+ char http_version[3];
230
+
231
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
232
+ sprintf(http_version, "HTTP/%d.%d", http_request->ev_request->major, http_request->ev_request->minor);
233
+
234
+ return rb_str_new2(http_version);
235
+ }
236
+
237
+ /*
238
+ * Get request command (i.e method)
239
+ *
240
+ * @return [String] http method for known command
241
+ * @return [nil] if method is not supported
242
+ * @example
243
+ * GET
244
+ */
245
+ static VALUE t_get_command(VALUE self) {
246
+ Libevent_HttpRequest *http_request;
247
+ VALUE command;
248
+
249
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
250
+
251
+ switch ( evhttp_request_get_command(http_request->ev_request) ) {
252
+ case EVHTTP_REQ_GET : command = rb_str_new2("GET"); break;
253
+ case EVHTTP_REQ_POST : command = rb_str_new2("POST"); break;
254
+ case EVHTTP_REQ_HEAD : command = rb_str_new2("HEAD"); break;
255
+ case EVHTTP_REQ_PUT : command = rb_str_new2("PUT"); break;
256
+ case EVHTTP_REQ_DELETE : command = rb_str_new2("DELETE"); break;
257
+ case EVHTTP_REQ_OPTIONS : command = rb_str_new2("OPTIONS"); break;
258
+ case EVHTTP_REQ_TRACE : command = rb_str_new2("TRACE"); break;
259
+ case EVHTTP_REQ_CONNECT : command = rb_str_new2("CONNECT"); break;
260
+ case EVHTTP_REQ_PATCH : command = rb_str_new2("PATCH"); break;
261
+ default: command = Qnil; break;
262
+ }
263
+
264
+ return command;
265
+ }
266
+
267
+ /*
268
+ * Returns the host associated with the request. If a client sends an absolute
269
+ * URI, the host part of that is preferred. Otherwise, the input headers are
270
+ * searched for a Host: header. NULL is returned if no absolute URI or Host:
271
+ * header is provided.
272
+ * @return [String] host
273
+ */
274
+ static VALUE t_get_host(VALUE self) {
275
+ Libevent_HttpRequest *http_request;
276
+
277
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
278
+
279
+ return rb_str_new2(evhttp_request_get_host(http_request->ev_request));
280
+ }
281
+
282
+ /*
283
+ * Get request URI
284
+ * @return [String] uri string
285
+ */
286
+ static VALUE t_get_uri(VALUE self) {
287
+ Libevent_HttpRequest *http_request;
288
+
289
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
290
+
291
+ return rb_str_new2(evhttp_request_get_uri(http_request->ev_request));
292
+ }
293
+
294
+ /*
295
+ * Read body from request input buffer.
296
+ * @return [String] body
297
+ */
298
+ static VALUE t_get_body(VALUE self) {
299
+ Libevent_HttpRequest *http_request;
300
+ struct evbuffer *ev_buffer;
301
+ int length;
302
+ VALUE body;
303
+
304
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
305
+
306
+ ev_buffer = evhttp_request_get_input_buffer(http_request->ev_request);
307
+
308
+ length = evbuffer_get_length(ev_buffer);
309
+ body = rb_str_new(0, length);
310
+ evbuffer_copyout(ev_buffer, RSTRING_PTR(body), length);
311
+
312
+ return body;
313
+ }
314
+
315
+ /*
316
+ * Send error to client
317
+ *
318
+ * @param [Fixnum] code HTTP code
319
+ * @param [String] reason (optional) short error descriptor
320
+ * @return [nil]
321
+ */
322
+ static VALUE t_send_error(VALUE self, VALUE code, VALUE reason) {
323
+ Libevent_HttpRequest *http_request;
324
+
325
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
326
+
327
+ evhttp_send_error(http_request->ev_request, FIX2INT(code), reason == Qnil ? NULL : RSTRING_PTR(reason));
328
+
329
+ return Qnil;
330
+ }
331
+
332
+ /*
333
+ * Send reply to client
334
+ * @param [Fixnum] code HTTP code
335
+ * @param [Hash] headers hash of http output headers
336
+ * @param [Object] body object that response to each method that returns strings
337
+ * @return [nil]
338
+ */
339
+ static VALUE t_send_reply(VALUE self, VALUE code, VALUE headers, VALUE body) {
340
+ Libevent_HttpRequest *http_request;
341
+
342
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
343
+ Check_Type(code, T_FIXNUM);
344
+ Check_Type(headers, T_HASH);
345
+
346
+ t_set_output_headers(self, headers);
347
+
348
+ evhttp_send_reply_start(http_request->ev_request, FIX2INT(code), NULL);
349
+ rb_iterate(rb_each, body, t_send_chunk, self);
350
+ evhttp_send_reply_end(http_request->ev_request);
351
+
352
+ return Qnil;
353
+ }
354
+
355
+ /*
356
+ * #send_reply iteration method to send chunk of data to client
357
+ * @param [String] chunk
358
+ * @param [Object] self HttpRequest instance
359
+ * @return [nil]
360
+ */
361
+ static VALUE t_send_chunk(VALUE chunk, VALUE self) {
362
+ Libevent_HttpRequest *http_request;
363
+
364
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
365
+
366
+ evbuffer_add(http_request->ev_buffer, RSTRING_PTR(chunk), RSTRING_LEN(chunk));
367
+ evhttp_send_reply_chunk(http_request->ev_request, http_request->ev_buffer);
368
+
369
+ return Qnil;
370
+ }
371
+
372
+ /*
373
+ * Start reply to client
374
+ * @param [Fixnum] code HTTP code
375
+ * @param [String] reason (optional) response descriptor
376
+ * @return [nil]
377
+ */
378
+ static VALUE t_send_reply_start(VALUE self, VALUE code, VALUE reason) {
379
+ Libevent_HttpRequest *http_request;
380
+
381
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
382
+ Check_Type(code, T_FIXNUM);
383
+
384
+ evhttp_send_reply_start(http_request->ev_request, FIX2INT(code), reason == Qnil ? NULL : RSTRING_PTR(reason));
385
+
386
+ return Qnil;
387
+ }
388
+
389
+ /*
390
+ * Send chunk of data to client
391
+ * @param [String] chunk string
392
+ * @return [nil]
393
+ */
394
+ static VALUE t_send_reply_chunk(VALUE self, VALUE chunk) {
395
+ Libevent_HttpRequest *http_request;
396
+
397
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
398
+
399
+ evbuffer_add(http_request->ev_buffer, RSTRING_PTR(chunk), RSTRING_LEN(chunk));
400
+ evhttp_send_reply_chunk(http_request->ev_request, http_request->ev_buffer);
401
+
402
+ return Qnil;
403
+ }
404
+
405
+ /*
406
+ * Stop reply to client
407
+ * @return [nil]
408
+ */
409
+ static VALUE t_send_reply_end(VALUE self) {
410
+ Libevent_HttpRequest *http_request;
411
+
412
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
413
+ evhttp_send_reply_end(http_request->ev_request);
414
+
415
+ return Qnil;
416
+ }
417
+
418
+ /*
419
+ * Get request URI scheme
420
+ * @return [String] http or https
421
+ * @return [nil]
422
+ */
423
+ static VALUE t_get_uri_scheme(VALUE self) {
424
+ Libevent_HttpRequest *http_request;
425
+ const struct evhttp_uri *ev_uri;
426
+ const char* scheme;
427
+
428
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
429
+
430
+ ev_uri = evhttp_request_get_evhttp_uri(http_request->ev_request);
431
+ scheme = evhttp_uri_get_scheme(ev_uri);
432
+
433
+ return(scheme ? rb_str_new2(scheme) : Qnil);
434
+ }
435
+
436
+ /*
437
+ * Get request URI path
438
+ * @return [String]
439
+ * @return [nil]
440
+ */
441
+ static VALUE t_get_uri_path(VALUE self) {
442
+ Libevent_HttpRequest *http_request;
443
+ const char *path;
444
+
445
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
446
+
447
+ path = evhttp_uri_get_path(http_request->ev_request->uri_elems);
448
+
449
+ return(path ? rb_str_new2(path) : Qnil);
450
+ }
451
+
452
+ /*
453
+ * Get request URI query
454
+ * @return [String]
455
+ * @return [nil]
456
+ */
457
+ static VALUE t_get_uri_query(VALUE self) {
458
+ Libevent_HttpRequest *http_request;
459
+ const char *query;
460
+
461
+ Data_Get_Struct(self, Libevent_HttpRequest, http_request);
462
+
463
+ query = evhttp_uri_get_query(http_request->ev_request->uri_elems);
464
+
465
+ return(query ? rb_str_new2(query) : Qnil);
466
+ }