summaryrefslogtreecommitdiffabout
path: root/lib/util.cc
Side-by-side diff
Diffstat (limited to 'lib/util.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/util.cc16
1 files changed, 12 insertions, 4 deletions
diff --git a/lib/util.cc b/lib/util.cc
index ac70938..69d37b5 100644
--- a/lib/util.cc
+++ b/lib/util.cc
@@ -160,56 +160,64 @@ namespace opkele {
throw failed_conversion(OPKELE_CP_ "failed to strtol()");
return rv;
}
/*
* Normalize URL according to the rules, described in rfc 3986, section 6
*
* - uppercase hext 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 colon = uri.find(':');
+ string::size_type ns = uri.find_first_not_of(whitespace);
+ 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(), uri.begin()+colon+1,
+ uri.begin()+ns, uri.begin()+colon+1,
back_inserter(rv), ::tolower );
bool s;
if(rv=="http:")
s = false;
else if(rv=="https:")
s = true;
+#ifndef NDEBUG
+ else if(rv=="file:")
+ s = false;
+#endif /* XXX: or try to make tests work some other way */
else
throw not_implemented(OPKELE_CP_ "Only http(s) URIs can be normalized here");
- string::size_type ul = uri.length();
+ string::size_type ul = uri.find_last_not_of(whitespace)+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");
rv += "//";
string::size_type interesting = uri.find_first_of(":/#?",colon+3);
if(interesting==string::npos) {
transform(
- uri.begin()+colon+3,uri.end(),
+ uri.begin()+colon+3,uri.begin()+ul,
back_inserter(rv), ::tolower );
rv += '/'; return rv;
}
transform(
uri.begin()+colon+3,uri.begin()+interesting,
back_inserter(rv), ::tolower );
bool qf = false;
char ic = uri[interesting];
if(ic==':') {
string::size_type ni = uri.find_first_of("/#?%",interesting+1);
const char *nptr = uri.data()+interesting+1;
char *eptr = 0;
long port = strtol(nptr,&eptr,10);
if( (port>0) && (port<65535) && port!=(s?443:80) ) {
char tmp[6];
snprintf(tmp,sizeof(tmp),"%ld",port);