libevent 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }