-rw-r--r-- | lib/util.cc | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/lib/util.cc b/lib/util.cc index bb8a2e8..29e6738 100644 --- a/lib/util.cc +++ b/lib/util.cc @@ -1,39 +1,40 @@ #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); @@ -190,61 +191,60 @@ namespace opkele { 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 '/' */ string rfc_3986_normalize_uri(const string& uri) { - static const char *whitespace = " \t\r\n"; string rv; - string::size_type ns = uri.find_first_not_of(whitespace); + string::size_type ns = uri.find_first_not_of(data::_whitespace_chars); if(ns==string::npos) throw bad_input(OPKELE_CP_ "Can't normalize empty URI"); string::size_type colon = uri.find(':',ns); if(colon==string::npos) throw bad_input(OPKELE_CP_ "No scheme specified in URI"); transform( uri.begin()+ns, uri.begin()+colon+1, back_inserter(rv), ::tolower ); bool s; - string::size_type ul = uri.find_last_not_of(whitespace)+1; + string::size_type ul = uri.find_last_not_of(data::_whitespace_chars)+1; if(ul <= (colon+3)) throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered"); if(uri[colon+1]!='/' || uri[colon+2]!='/') throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component"); if(rv=="http:") s = false; else if(rv=="https:") s = true; else{ /* TODO: support more schemes. e.g. xri. How do we normalize * xri? */ rv.append(uri,colon+1,ul-colon-1); return rv; } rv += "//"; string::size_type interesting = uri.find_first_of(":/#?",colon+3); if(interesting==string::npos) { transform( uri.begin()+colon+3,uri.begin()+ul, back_inserter(rv), ::tolower ); rv += '/'; return rv; } transform( @@ -409,27 +409,62 @@ namespace opkele { kv += ':'; kv += om.get_field(f); kv += '\n'; if(co==string::npos) break; p = co+1; } const secret_t& secret = assoc->secret(); const EVP_MD *evpmd; const string& at = assoc->assoc_type(); if(at=="HMAC-SHA256") evpmd = EVP_sha256(); else if(at=="HMAC-SHA1") evpmd = EVP_sha1(); else throw unsupported(OPKELE_CP_ "unknown association type"); unsigned int md_len = 0; unsigned char md[SHA256_DIGEST_LENGTH]; HMAC(evpmd, &(secret.front()),secret.size(), (const unsigned char*)kv.data(),kv.length(), md,&md_len); return encode_base64(md,md_len); } + string normalize_identifier(const string& usi,bool strip_fragment) { + if(usi.empty()) + return usi; + string rv; + string::size_type fsc = usi.find_first_not_of(data::_whitespace_chars); + if(fsc==string::npos) + return rv; + string::size_type lsc = usi.find_last_not_of(data::_whitespace_chars); + assert(lsc!=string::npos); + if(!strncasecmp(usi.c_str()+fsc,"xri://",sizeof("xri://")-1)) + fsc += sizeof("xri://")-1; + if( (fsc+1) >= lsc ) + return rv; + rv.assign(usi,fsc,lsc-fsc+1); + if(strchr(data::_iname_leaders,rv[0])) { + /* TODO: further normalize xri identity, fold case or + * whatever... */ + }else{ + if(rv.find("://")==string::npos) + rv.insert(0,"http://"); + if(strip_fragment) { + string::size_type fp = rv.find('#'); + if(fp!=string::npos) { + string::size_type qp = rv.find('?'); + if(qp==string::npos || qp<fp) + rv.erase(fp); + else if(qp>fp) + rv.erase(fp,qp-fp); + } + } + rv = rfc_3986_normalize_uri(rv); + } + return rv; + } + } } |