author | Michael Krelin <hacker@klever.net> | 2008-03-02 20:23:40 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2008-03-02 20:23:40 (UTC) |
commit | da3f84153be2a93da7ffc49af33b29b9725fac38 (patch) (side-by-side diff) | |
tree | bcacc4c38a53b70c679fa69fbf2577da2802a197 /lib | |
parent | f47e336b569739bdde8e9add96ff2c46f97257fb (diff) | |
download | libopkele-da3f84153be2a93da7ffc49af33b29b9725fac38.zip libopkele-da3f84153be2a93da7ffc49af33b29b9725fac38.tar.gz libopkele-da3f84153be2a93da7ffc49af33b29b9725fac38.tar.bz2 |
made util::url_encode refrain from encoding unreserved chars
as per rfc 3986
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | lib/util.cc | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/lib/util.cc b/lib/util.cc index 29e6738..a6e08e2 100644 --- a/lib/util.cc +++ b/lib/util.cc @@ -1,61 +1,60 @@ #include <errno.h> #include <cassert> #include <cctype> #include <cstring> #include <vector> #include <string> #include <stack> #include <algorithm> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/sha.h> #include <openssl/hmac.h> -#include <curl/curl.h> #include <opkele/util.h> #include <opkele/exception.h> #include <opkele/data.h> #include <opkele/debug.h> #include <config.h> #ifdef HAVE_DEMANGLE # include <cxxabi.h> #endif namespace opkele { using namespace std; namespace util { /* * base64 */ string encode_base64(const void *data,size_t length) { BIO *b64 = 0, *bmem = 0; try { b64 = BIO_new(BIO_f_base64()); if(!b64) throw exception_openssl(OPKELE_CP_ "failed to BIO_new() base64 encoder"); BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); bmem = BIO_new(BIO_s_mem()); BIO_set_flags(b64,BIO_CLOSE); if(!bmem) throw exception_openssl(OPKELE_CP_ "failed to BIO_new() memory buffer"); BIO_push(b64,bmem); if(((size_t)BIO_write(b64,data,length))!=length) throw exception_openssl(OPKELE_CP_ "failed to BIO_write()"); if(BIO_flush(b64)!=1) throw exception_openssl(OPKELE_CP_ "failed to BIO_flush()"); char *rvd; long rvl = BIO_get_mem_data(bmem,&rvd); string rv(rvd,rvl); BIO_free_all(b64); return rv; }catch(...) { if(b64) BIO_free_all(b64); throw; } } void decode_base64(const string& data,vector<unsigned char>& rv) { BIO *b64 = 0, *bmem = 0; rv.clear(); @@ -111,102 +110,130 @@ namespace opkele { /* * w3c times */ string time_to_w3c(time_t t) { struct tm tm_t; if(!gmtime_r(&t,&tm_t)) throw failed_conversion(OPKELE_CP_ "failed to BN_dec2bn()"); char rv[25]; if(!strftime(rv,sizeof(rv)-1,"%Y-%m-%dT%H:%M:%SZ",&tm_t)) throw failed_conversion(OPKELE_CP_ "failed to strftime()"); return rv; } time_t w3c_to_time(const string& w) { int fraction; struct tm tm_t; memset(&tm_t,0,sizeof(tm_t)); if( ( sscanf( w.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ", &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec ) != 6 ) && ( sscanf( w.c_str(), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec, &fraction ) != 7 ) ) throw failed_conversion(OPKELE_CP_ "failed to sscanf()"); tm_t.tm_mon--; tm_t.tm_year-=1900; time_t rv = mktime(&tm_t); if(rv==(time_t)-1) throw failed_conversion(OPKELE_CP_ "failed to mktime()"); return rv-timezone; } /* * */ + static inline bool isrfc3986unreserved(int c) { + if(c<'-') return false; + if(c<='.') return true; + if(c<'0') return false; if(c<='9') return true; + if(c<'A') return false; if(c<='Z') return true; + if(c<'_') return false; + if(c=='_') return true; + if(c<'a') return false; if(c<='z') return true; + if(c=='~') return true; + return false; + } + + struct __url_encoder : public unary_function<char,void> { + public: + string& rv; + + __url_encoder(string& r) : rv(r) { } + + result_type operator()(argument_type c) { + if(isrfc3986unreserved(c)) + rv += c; + else{ + char tmp[4]; + snprintf(tmp,sizeof(tmp),"%%%02X", + (c&0xff)); + rv += tmp; + } + } + }; + string url_encode(const string& str) { - char * t = curl_escape(str.c_str(),str.length()); - if(!t) - throw failed_conversion(OPKELE_CP_ "failed to curl_escape()"); - string rv(t); - curl_free(t); + string rv; + for_each(str.begin(),str.end(), + __url_encoder(rv)); return rv; } string attr_escape(const string& str) { static const char *unsafechars = "<>&\n\"'"; string rv; string::size_type p=0; while(true) { string::size_type us = str.find_first_of(unsafechars,p); if(us==string::npos) { if(p!=str.length()) rv.append(str,p,str.length()-p); return rv; } rv.append(str,p,us-p); rv += "&#"; rv += long_to_string((long)str[us]); rv += ';'; p = us+1; } } string long_to_string(long l) { char rv[32]; int r=snprintf(rv,sizeof(rv),"%ld",l); if(r<0 || r>=(int)sizeof(rv)) throw failed_conversion(OPKELE_CP_ "failed to snprintf()"); return rv; } long string_to_long(const string& s) { char *endptr = 0; long rv = strtol(s.c_str(),&endptr,10); if((!endptr) || endptr==s.c_str()) throw failed_conversion(OPKELE_CP_ "failed to strtol()"); return rv; } /* * Normalize URL according to the rules, described in rfc 3986, section 6 * * - uppercase hex triplets (e.g. %ab -> %AB) * - lowercase scheme and host * - decode %-encoded characters, specified as unreserved in rfc 3986, section 2.3, * that is - [:alpha:][:digit:]._~- * - remove dot segments * - remove empty and default ports * - if there's no path component, add '/' |