evdispatch 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ == 0.3.1 2008-04-23
2
+ * Add support to set arbitrary HTTP headers
3
+
1
4
  == 0.3.0 2008-04-22
2
5
  * Add type checking
3
6
  * Add support to stream responses directly to Ruby main thread over a pipe
@@ -11,6 +11,9 @@
11
11
  #include <queue>
12
12
  #include <map>
13
13
 
14
+ // declare ahead of time
15
+ struct curl_slist;
16
+
14
17
  namespace EVD {
15
18
 
16
19
  // unique id to represent a request
@@ -42,6 +45,7 @@ namespace EVD {
42
45
 
43
46
  // by default this does nothing, each real request object can do as it pleases with this feature
44
47
  virtual void set_opt( const std::string &key, const std::string &value ){}
48
+ virtual void set_opt( const std::string &key, struct curl_slist *slist ){}
45
49
 
46
50
  virtual void set_key( request_t key ){ this->key = key; }
47
51
 
@@ -287,6 +287,10 @@ HttpRequest::HttpRequest( Dispatch &dispatch, const std::string &url, int fd )
287
287
  m_client(dispatch.getHttpClient())
288
288
  {
289
289
  assert(m_client);
290
+ // prevent libcurl from sending signals or installing signal handles
291
+ curl_easy_setopt(m_handle,CURLOPT_NOSIGNAL,1);
292
+ // we won't be sending progress
293
+ curl_easy_setopt(m_handle,CURLOPT_NOPROGRESS,1);
290
294
  init_curl();
291
295
  }
292
296
 
@@ -346,6 +350,28 @@ void HttpRequest::set_key( request_t key )
346
350
  m_response->id = key;
347
351
  }
348
352
 
353
+ void HttpRequest::set_opt( const std::string &key, struct curl_slist *slist )
354
+ {
355
+ Request::set_opt(key,slist);
356
+ std::map<std::string,CURLoption> key_loopup;
357
+ key_loopup["headers"] = CURLOPT_HTTPHEADER;
358
+ std::map<std::string,CURLoption>::iterator loc = key_loopup.find(key);
359
+ if( loc != key_loopup.end() ) {
360
+ CURLoption val_type = loc->second;
361
+ if( key == "headers" ) {
362
+ // construct a slist of headers
363
+ curl_easy_setopt( m_handle, val_type, slist );
364
+ if( slist ) {
365
+ // we need to keep a reference to the options slist so we can cleanup after the request completes
366
+ this->m_response->add_to_free_list( slist );
367
+ }
368
+ }
369
+ }
370
+ else {
371
+ printf("invalid option: %s", key.c_str() );
372
+ }
373
+ }
374
+
349
375
  void HttpRequest::set_opt( const std::string &key, const std::string &value )
350
376
  {
351
377
  Request::set_opt(key,value);
@@ -367,7 +393,7 @@ void HttpRequest::set_opt( const std::string &key, const std::string &value )
367
393
  key_loopup["post"] = CURLOPT_POSTFIELDS;
368
394
 
369
395
  std::map<std::string,CURLoption>::iterator loc = key_loopup.find(key);
370
- if( loc != key_loopup.end() ){
396
+ if( loc != key_loopup.end() ) {
371
397
  CURLoption val_type = loc->second;
372
398
  if( val_type >= CURLOPTTYPE_LONG && val_type < CURLOPTTYPE_OBJECTPOINT ) {
373
399
  long val = atoi(value.c_str());
@@ -391,6 +417,9 @@ void HttpRequest::set_opt( const std::string &key, const std::string &value )
391
417
  }
392
418
  }
393
419
  }
420
+ else {
421
+ printf("invalid option: %s", key.c_str() );
422
+ }
394
423
  }
395
424
 
396
425
  HttpResponse::HttpResponse( const std::string &url )
@@ -401,6 +430,14 @@ HttpResponse::HttpResponse( const std::string &url, int fd )
401
430
  : Response(url), m_fd(fd)
402
431
  {
403
432
  }
433
+ HttpResponse::~HttpResponse()
434
+ {
435
+ for( std::set<struct curl_slist*>::iterator it = m_request_opts.begin();
436
+ it != m_request_opts.end(); ++it ) {
437
+ curl_slist_free_all( *it );
438
+ }
439
+ m_request_opts.clear();
440
+ }
404
441
  void HttpResponse::write( void *ptr, size_t realsize, size_t size, size_t nmemb )
405
442
  {
406
443
  // printf( " write: %s, %d\n", this->name.c_str(), realsize );
@@ -4,6 +4,7 @@
4
4
  #include "config.h"
5
5
  #include "ev_dispatch.h"
6
6
  #include <curl/curl.h>
7
+ #include <set>
7
8
 
8
9
  namespace EVD {
9
10
 
@@ -57,6 +58,7 @@ namespace EVD {
57
58
 
58
59
  virtual void set_key( request_t key );
59
60
  virtual void set_opt( const std::string &key, const std::string &value );
61
+ virtual void set_opt( const std::string &key, struct curl_slist *slist );
60
62
 
61
63
  static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data);
62
64
  static size_t header_write_cb(void *ptr, size_t size, size_t nmemb, void *data);
@@ -74,13 +76,19 @@ namespace EVD {
74
76
  struct HttpResponse : public Response {
75
77
  HttpResponse( const std::string &url );
76
78
  HttpResponse( const std::string &url, int fd );
79
+ virtual ~HttpResponse();
77
80
 
78
81
  void write( void *ptr, size_t realsize, size_t size, size_t nmemb );
79
82
  void write_header( void *ptr, size_t realsize, size_t size, size_t nmemb );
80
83
  void finish( HttpClient *client, CURLcode rc );
84
+
85
+ void add_to_free_list( struct curl_slist *opts ){ m_request_opts.insert(opts); }
81
86
 
82
87
  int m_fd;
83
88
  std::string m_header;
89
+ private:
90
+ // keep these around to free, everytime someone calls set_opt("header", slist) we store the pointer here
91
+ std::set<struct curl_slist*> m_request_opts;
84
92
  };
85
93
 
86
94
  }
@@ -25,6 +25,12 @@ static void run_tests( Dispatch &dispatcher, int count )
25
25
  req->set_opt("useragent", "users are us");
26
26
  req->set_opt("cookie", "name1=content1; name2=content2;");
27
27
 
28
+ // set some arbitry headers
29
+ struct curl_slist *slist = NULL;
30
+ slist = curl_slist_append(slist, "x-my-header1: hi");
31
+ slist = curl_slist_append(slist, "x-my-header2: hello");
32
+ req->set_opt("headers", slist );
33
+
28
34
  request_t id = dispatcher.request( req );
29
35
 
30
36
  while( dispatcher.wait_for_response_by_id( id, Timer(1,5) ) ) {
@@ -1,5 +1,6 @@
1
1
  #include "util.h"
2
2
  #include "rhttp.h"
3
+ #include <st.h>
3
4
 
4
5
 
5
6
  /*
@@ -93,8 +94,35 @@ VALUE Loop_request_http( VALUE self, VALUE url )
93
94
  req->set_opt(name, RSTRING_PTR(obj));\
94
95
  }\
95
96
  }
97
+
98
+ static int
99
+ build_header_list(VALUE key, VALUE value, struct curl_slist **slist )
100
+ {
101
+ if (key == Qundef) return ST_CONTINUE;
102
+ VALUE str = rb_str_new(RSTRING_PTR(key),RSTRING_LEN(key));
103
+ str = rb_str_cat2(str,":");
104
+ *slist = curl_slist_append(*slist, RSTRING_PTR(rb_str_append(str,value)) );
105
+ return ST_CONTINUE;
106
+ }
107
+
108
+ static struct curl_slist *build_headers( VALUE hash )
109
+ {
110
+ struct curl_slist *slist = NULL;
111
+ rb_hash_foreach( hash, (int (*)(...))build_header_list, (VALUE)&slist );
112
+ return slist;
113
+ }
114
+
115
+ static void set_headers( VALUE options, EVD::HttpRequest *req )
116
+ {
117
+ VALUE hash = rb_hash_aref( options, ID2SYM(rb_intern("headers")) );
118
+ if( !NIL_P(hash) && TYPE(hash) == T_HASH ) {
119
+ struct curl_slist *headers = build_headers( hash );
120
+ req->set_opt( "headers", headers );
121
+ }
122
+ }
123
+
96
124
  // set options
97
- #define SET_REQ_OPTS \
125
+ #define SET_REQ_OPTS(options,req) \
98
126
  SET_LONG_VAL("port"); \
99
127
  SET_STR_VAL("autoreferer"); \
100
128
  SET_LONG_VAL("followlocation"); \
@@ -102,7 +130,9 @@ VALUE Loop_request_http( VALUE self, VALUE url )
102
130
  SET_STR_VAL("referer"); \
103
131
  SET_STR_VAL("useragent"); \
104
132
  SET_STR_VAL("cookie"); \
105
- SET_STR_VAL("post");
133
+ SET_STR_VAL("post"); \
134
+ set_headers(options, req)
135
+
106
136
 
107
137
  /**
108
138
  * call-seq:
@@ -123,6 +153,7 @@ VALUE Loop_request_http( VALUE self, VALUE url )
123
153
  * 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.
124
154
  * 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.
125
155
  * Using this option multiple times will only make the latest string override the previous ones.
156
+ * :headers: (Hash) An arbitrary list of HTTP Headers. Set any HTTP header or override the defaults. see libcurl's documentation for more details.
126
157
  *
127
158
  * :post: (String) Pass a string and sets CURLOPT_POST, CURLOPT_POSTFIELDSIZE, and CURLOPT_COPYPOSTFIELDS
128
159
  *
@@ -158,8 +189,8 @@ VALUE Loop_request( int argc, VALUE *argv, VALUE self )
158
189
 
159
190
  EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url), res->m_pipe[1] );
160
191
 
161
- SET_REQ_OPTS
162
-
192
+ SET_REQ_OPTS(options,req);
193
+
163
194
  res->m_response = req->m_response;
164
195
 
165
196
  d->request(req);
@@ -167,7 +198,8 @@ VALUE Loop_request( int argc, VALUE *argv, VALUE self )
167
198
  }
168
199
  else {
169
200
  EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url) );
170
- SET_REQ_OPTS
201
+
202
+ SET_REQ_OPTS(options,req);
171
203
 
172
204
  return rb_int_new( d->request(req) );
173
205
  }
@@ -30,7 +30,12 @@ class TestRequests < Test::Unit::TestCase
30
30
  end
31
31
 
32
32
  def test_options_request
33
- id = loop.request("http://127.0.0.1:4044/redir/1", :followlocation => 1, :referer => 'pizza')
33
+ id = loop.request("http://127.0.0.1:4044/redir/1",
34
+ :followlocation => 1,
35
+ :referer => 'pizza',
36
+ :headers => {
37
+ 'Simple' => 'Thoughts'
38
+ })
34
39
  response = loop.response( id )
35
40
  assert_not_nil( response )
36
41
  assert_match(/ 302 Moved Temporarily/,response[:header])
@@ -2,7 +2,7 @@ module Evdispatch #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/website/index.html CHANGED
@@ -18,7 +18,7 @@
18
18
  <h1>evdispatch</h1>
19
19
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/evdispatch"; return false'>
20
20
  <p>Get Version</p>
21
- <a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.3.0</a>
21
+ <a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.3.1</a>
22
22
  </div>
23
23
  <h4 style="float:right;padding-right:10px;">&#x2192; &#8216;evdispatch&#8217;</h4>
24
24
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evdispatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd A. Fisher
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-22 00:00:00 -04:00
12
+ date: 2008-04-23 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15