ext/revdispatch/revdispatch.cc in evdispatch-0.2.2 vs ext/revdispatch/revdispatch.cc in evdispatch-0.2.4
- old
+ new
@@ -22,19 +22,16 @@
* d = Evdispatch::Loop.new
*
* # start the event loop thread
*
* # send a dispatch http request and store a handle to the request
- * google_id = d.request_http("http://www.google.com/")
+ * google_id = d.request("http://www.google.com/")
*
* # do some processing and later on check for the response
- * while d.wait_for_response( google_id, 1, 0 )
- * res = d.response_for( google_id )
- * break if res
- * end
- * res = d.response_for( google_id ) unless res
*
+ * res = d.response( google_id )
+ *
* puts res[:body]
*
* # sometime later you can stop the event loop
* d.stop
*
@@ -49,10 +46,16 @@
*
*/
static VALUE rb_Evdispatch;
static VALUE rb_Loop;
+/**
+ * call-seq:
+ * loop.start -> loop
+ *
+ * Starts up the background event loop
+ */
static
VALUE Loop_start( VALUE self )
{
EVD::Dispatch *d;
Data_Get_Struct( self, EVD::Dispatch, d );
@@ -60,10 +63,16 @@
d->start();
return self;
}
+/**
+ * call-seq:
+ * loop.request_http(url) -> request_id
+ *
+ * Notifies the background thread of a new request. Call this method to start a basic HTTP GET request.
+ */
static
VALUE Loop_request_http( VALUE self, VALUE url )
{
EVD::Dispatch *d;
Data_Get_Struct( self, EVD::Dispatch, d );
@@ -75,11 +84,11 @@
#define SET_LONG_VAL(name)\
{\
VALUE obj = rb_hash_aref( options, ID2SYM(rb_intern(name)) ); \
if( !NIL_P(obj) ) {\
- snprintf( VALUE_BUFFER, VALUE_BUFFER_SIZE, "%d", FIX2LONG(obj) );\
+ snprintf( VALUE_BUFFER, VALUE_BUFFER_SIZE, "%ld", FIX2LONG(obj) );\
req->set_opt(name, VALUE_BUFFER);\
}\
}
#define SET_STR_VAL(name)\
@@ -88,10 +97,33 @@
if( !NIL_P(obj) ) {\
req->set_opt(name, RSTRING_PTR(obj));\
}\
}
+/**
+ * call-seq:
+ * loop.request( url, options ) -> request_id
+ *
+ * Notify the background of a new request. Can send a few options to influence the request:
+ *
+ * options ( from libcurl ):
+ *
+ * :port: port to connect to host with
+ * :autoreferer: Pass a non-zero parameter to enable this. When enabled, libcurl will automatically set the Referer: field in requests where it follows a Location: redirect.
+ * :followlocation: A non-zero parameter tells the library to follow any Location: header that the server sends as part of an HTTP header.
+ * This means that the library will re-send the same request on the new location and follow new Location: headers all the way until no more such headers are returned. 'maxredirs' can be used to limit the number of redirects libcurl will follow.
+ * :maxredirs: Pass a long. The set number will be the redirection limit. If that many redirections have been followed, the next redirect will cause an error (CURLE_TOO_MANY_REDIRECTS). This option only makes sense if the CURLOPT_FOLLOWLOCATION is used at the same time. Added in 7.15.1: Setting the limit to 0 will make libcurl refuse any redirect. Set it to -1 for an infinite number of redirects (which is the default)
+ * :referer: Pass a pointer to a zero terminated string as parameter. It will be used to set the Referer: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
+ * :useragent: Pass a pointer to a zero terminated string as parameter. It will be used to set the User-Agent: header in the http request sent to the remote server. This can be used to fool servers or scripts. You can also set any custom header with CURLOPT_HTTPHEADER.
+ * :cookie: Pass a pointer to a zero terminated string as parameter. It will be used to set a cookie in the http request. The format of the string should be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
+ * If you need to set multiple cookies, you need to set them all using a single option and thus you need to concatenate them all in one single string. Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
+ * Note that this option sets the cookie header explictly in the outgoing request(s). If multiple requests are done due to authentication, followed redirections or similar, they will all get this cookie passed on.
+ * Using this option multiple times will only make the latest string override the previous ones.
+ *
+ * :post: Pass a string and sets CURLOPT_POST, CURLOPT_POSTFIELDSIZE, and CURLOPT_COPYPOSTFIELDS
+ *
+ */
static
VALUE Loop_request( int argc, VALUE *argv, VALUE self )
{
EVD::Dispatch *d;
const int VALUE_BUFFER_SIZE = 1024;
@@ -113,10 +145,11 @@
SET_LONG_VAL("followlocation");
SET_LONG_VAL("maxredirs");
SET_STR_VAL("referer");
SET_STR_VAL("useragent");
SET_STR_VAL("cookie");
+ SET_STR_VAL("post");
return rb_int_new( d->request(req) );
}
static
@@ -126,12 +159,16 @@
EVD::Queue<EVD::Response>::POP_STATE rstate;
EVD::request_t rid = FIX2LONG(id);
Data_Get_Struct( self, EVD::Dispatch, d );
- rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), (FIX2LONG(timeout_mseconds)*1000*1000)) );
+ long seconds = FIX2LONG(timeout_seconds);
+ long nanoseconds = FIX2LONG(timeout_mseconds)*1000*1000;
+ //printf( "wait seconds %ld, nanoseconds %ld\n", seconds, nanoseconds );
+ rstate = d->wait_for_response_by_id( rid, EVD::Timer(seconds, nanoseconds) );
+
return rb_int_new(rstate);
}
static
VALUE Loop_response_for( VALUE self, VALUE id )
@@ -158,10 +195,58 @@
return result;
}
return Qnil;
}
+static
+VALUE Loop_blocking_response_for( int argc, VALUE *argv, VALUE self )
+{
+ VALUE req_id, options;
+ EVD::Dispatch *dispatcher;
+ Data_Get_Struct( self, EVD::Dispatch, dispatcher );
+
+ // required 1 argument the 'url' and 1 optional the hash of options
+ if( rb_scan_args( argc, argv, "11", &req_id, &options ) == 1 ) {
+ options = rb_hash_new();
+ rb_hash_aset( options, ID2SYM(rb_intern("timeout")), rb_float_new( 2.0 ) );
+ }
+
+ EVD::request_t id = FIX2LONG(req_id);
+ VALUE timeout_value = rb_hash_aref( options, ID2SYM(rb_intern("timeout")) );
+ double timeout = RFLOAT( timeout_value )->value;
+
+ struct timeval start;
+ EVD::Timer::current_time(&start);
+ long int secs = (int)timeout;
+ long int msecs = (secs == 0) ? 500 : 0; // XXX: timer hack for small timeout
+
+ //printf( "waiting on id: %d, %d:%d\n", id, secs, msecs );
+
+ while( dispatcher->wait_for_response_by_id( id, EVD::Timer(secs,msecs*1000*1000) ) ) {
+ if( EVD::Timer::elapsed_time( &start ) > timeout ){
+ printf("exceeded max elasped time...\n");
+ break;
+ }
+ }
+ EVD::HttpResponse *res = (EVD::HttpResponse *)dispatcher->response_for( id );
+ if( res ) {
+
+ VALUE result = rb_hash_new();
+
+ rb_hash_aset( result, ID2SYM(rb_intern("name")), rb_str_new( res->name.c_str(), res->name.length() ) );
+ rb_hash_aset( result, ID2SYM(rb_intern("body")), rb_str_new( res->body.c_str(), res->body.length() ) );
+ rb_hash_aset( result, ID2SYM(rb_intern("id")), rb_int_new( res->id ) );
+ rb_hash_aset( result, ID2SYM(rb_intern("response_time")), rb_float_new( res->response_time ) );
+ rb_hash_aset( result, ID2SYM(rb_intern("header")), rb_str_new( res->m_header.c_str(), res->m_header.length() ) );
+
+ delete res;
+
+ return result;
+ }
+ return Qnil;
+}
+
static
VALUE Loop_flush( VALUE self )
{
EVD::Dispatch *d;
Data_Get_Struct( self, EVD::Dispatch, d );
@@ -175,16 +260,18 @@
{
EVD::Dispatch *d;
Data_Get_Struct( self, EVD::Dispatch, d );
d->stop();
+
return Qnil;
}
static
void Loop_free( EVD::Dispatch *d )
{
+ fprintf(stderr,"Freeing loop\n");
delete d;
}
static
VALUE Loop_alloc(VALUE klass)
@@ -207,9 +294,10 @@
rb_define_method( rb_Loop, "start", (VALUE (*)(...))Loop_start, 0 );
rb_define_method( rb_Loop, "request_http", (VALUE (*)(...))Loop_request_http, 1 );
rb_define_method( rb_Loop, "request", (VALUE (*)(...))Loop_request, -1 );
rb_define_method( rb_Loop, "flush", (VALUE (*)(...))Loop_flush, 0 );
+ rb_define_method( rb_Loop, "blocking_response_for", (VALUE (*)(...))Loop_blocking_response_for, -1 );
rb_define_method( rb_Loop, "response_for", (VALUE (*)(...))Loop_response_for, 1 );
rb_define_method( rb_Loop, "wait_for_response", (VALUE (*)(...))Loop_wait_for_response, 3 );
rb_define_method( rb_Loop, "stop", (VALUE (*)(...))Loop_stop, 0 );
}