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.
- data/.gitignore +6 -0
- data/Gemfile +5 -0
- data/README.md +146 -0
- data/Rakefile +4 -0
- data/ext/libevent_ext/base.c +94 -0
- data/ext/libevent_ext/ext.c +10 -0
- data/ext/libevent_ext/ext.h +40 -0
- data/ext/libevent_ext/extconf.rb +7 -0
- data/ext/libevent_ext/http.c +184 -0
- data/ext/libevent_ext/http_request.c +466 -0
- data/ext/libevent_ext/ruby18_compat.h +14 -0
- data/ext/libevent_ext/signal.c +107 -0
- data/lib/libevent.rb +9 -0
- data/lib/libevent/base.rb +18 -0
- data/lib/libevent/builder.rb +32 -0
- data/lib/libevent/http.rb +23 -0
- data/lib/libevent/http_request.rb +4 -0
- data/lib/libevent/signal.rb +6 -0
- data/lib/libevent/version.rb +3 -0
- data/lib/rack/handler/libevent.rb +97 -0
- data/libevent.gemspec +22 -0
- data/samples/rack_request_inspect +28 -0
- data/samples/simple.rb +22 -0
- data/samples/virtual_hosts +63 -0
- metadata +70 -0
@@ -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
|
+
}
|