-rw-r--r-- | lib/consumer.cc | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/lib/consumer.cc b/lib/consumer.cc index 8f66688..299b3bc 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc @@ -1,27 +1,34 @@ #include <algorithm> #include <cassert> #include <opkele/util.h> #include <opkele/exception.h> #include <opkele/data.h> #include <opkele/consumer.h> #include <openssl/sha.h> #include <openssl/hmac.h> #include <curl/curl.h> -#include <pcre++.h> #include <iostream> #include "config.h" +#if defined(USE_LIBPCRECPP) +# include <pcrecpp.h> +#elif defined(USE_PCREPP) +# include <pcre++.h> +#else + /* internal implementation won't be built */ +#endif + namespace opkele { using namespace std; class curl_t { public: CURL *_c; curl_t() : _c(0) { } curl_t(CURL *c) : _c(c) { } ~curl_t() throw() { if(_c) curl_easy_cleanup(_c); } curl_t& operator=(CURL *c) { if(_c) curl_easy_cleanup(_c); _c=c; return *this; } @@ -252,69 +259,103 @@ namespace opkele { invalidate_assoc(server,pp.get_param("invalidate_handle")); if(pp.has_param("is_valid")) { if(pp.get_param("is_valid")=="true") return; }else if(pp.has_param("lifetime")) { if(util::string_to_long(pp.get_param("lifetime"))) return; } throw failed_check_authentication(OPKELE_CP_ "failed to verify response"); } void consumer_t::retrieve_links(const string& url,string& server,string& delegate) { +#if defined(USE_LIBPCRECPP) || defined(USE_PCREPP) server.erase(); delegate.erase(); curl_t curl = curl_easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()"); string html; CURLcode r; (r=curl_misc_sets(curl)) || (r=curl_easy_setopt(curl,CURLOPT_URL,url.c_str())) || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring)) || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&html)) ; if(r) throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r); r = curl_easy_perform(curl); if(r && r!=CURLE_WRITE_ERROR) throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r); - pcrepp::Pcre bre("<body\\b",PCRE_CASELESS); // strip out everything past body + static const char *re_hdre = "<head[^>]*>", + *re_lre = "<link\\b([^>]+)>", + *re_rre = "\\brel=['\"]([^'\"]+)['\"]", + *re_hre = "\\bhref=['\"]([^'\"]+)['\"]"; +#if defined(USE_LIBPCRECPP) + static pcrecpp::RE_Options ro(PCRE_CASELESS|PCRE_DOTALL); + static pcrecpp::RE + bre("<body\\b.*",ro), hdre(re_hdre,ro), + lre(re_lre,ro), rre(re_rre), hre(re_hre,ro); + bre.Replace("",&html); + pcrecpp::StringPiece hpiece(html); + if(!hdre.FindAndConsume(&hpiece)) + throw bad_input(OPKELE_CP_ "failed to find head"); + string attrs; + while(lre.FindAndConsume(&hpiece,&attrs)) { + pcrecpp::StringPiece rel, href; + if(!(rre.PartialMatch(attrs,&rel) && hre.PartialMatch(attrs,&href))) + continue; + if(rel=="openid.server") { + href.CopyToString(&server); + if(!delegate.empty()) + break; + }else if(rel=="openid.delegate") { + href.CopyToString(&delegate); + if(!server.empty()) + break; + } + } +#elif defined(USE_PCREPP) + pcrepp::Pcre bre("<body\\b",PCRE_CASELESS); if(bre.search(html)) html.erase(bre.get_match_start()); - pcrepp::Pcre hdre("<head[^>]*>",PCRE_CASELESS); + pcrepp::Pcre hdre(re_hdre,PCRE_CASELESS); if(!hdre.search(html)) throw bad_input(OPKELE_CP_ "failed to find head"); html.erase(0,hdre.get_match_end()+1); - pcrepp::Pcre lre("<link\\b([^>]+)>",PCRE_CASELESS), - rre("\\brel=['\"]([^'\"]+)['\"]",PCRE_CASELESS), - hre("\\bhref=['\"]([^'\"]+)['\"]",PCRE_CASELESS); + pcrepp::Pcre lre(re_lre,PCRE_CASELESS), rre(re_rre,PCRE_CASELESS), hre(re_hre,PCRE_CASELESS); while(lre.search(html)) { string attrs = lre[0]; html.erase(0,lre.get_match_end()+1); if(!(rre.search(attrs)&&hre.search(attrs))) continue; if(rre[0]=="openid.server") { server = hre[0]; if(!delegate.empty()) break; }else if(rre[0]=="openid.delegate") { delegate = hre[0]; if(!server.empty()) break; } } +#else + #error "I must have gone crazy" +#endif if(server.empty()) throw failed_assertion(OPKELE_CP_ "The location has no openid.server declaration"); +#else /* none of the RE bindings enabled */ + throw not_implemented(OPKELE_CP_ "No internal implementation of retrieve_links were provided at compile-time"); +#endif } assoc_t consumer_t::find_assoc(const string& server) { throw failed_lookup(OPKELE_CP_ "no find_assoc() provided"); } string consumer_t::normalize(const string& url) { string rv = url; // strip leading and trailing spaces string::size_type i = rv.find_first_not_of(" \t\r\n"); if(i==string::npos) throw bad_input(OPKELE_CP_ "empty URL"); |