aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Uri.cpp146
1 files changed, 141 insertions, 5 deletions
diff --git a/src/Uri.cpp b/src/Uri.cpp
index e218ecd..ba04298 100644
--- a/src/Uri.cpp
+++ b/src/Uri.cpp
@@ -305,13 +305,149 @@ namespace Uri {
}
// Next, parsing host and port from authority and path.
- const auto portDelimiter = hostPortString.find(':');
- if (portDelimiter == std::string::npos) {
- host = hostPortString;
+ std::string portString;
+ size_t decoderState = 0;
+ int decodedCharacter = 0;
+ host.clear();
+ for (const auto c: hostPortString) {
+ switch(decoderState) {
+ case 0: { // first character
+ if (c == '[') {
+ host.push_back(c);
+ decoderState = 4;
+ break;
+ } else {
+ decoderState = 1;
+ }
+ }
+
+ case 1: { // reg-name or IPv4Address
+ if (c == '%') {
+ decoderState = 2;
+ } else if (c == ':') {
+ decoderState = 9;
+ } else {
+ if (
+ IsCharacterInSet(
+ c,
+ {
+ // unreserved
+ 'a','z', 'A','Z', // ALPHA
+ '0','9', // DIGIT
+ '-','-', '.','.', '_','_', '~','~',
+
+ // sub-delims
+ '!','!', '$','$', '&','&', '\'','\'', '(','(', ')',')',
+ '*','*', '+','+', ',',',', ';',';', '=','=',
+
+ // (also allowed in reg-name)
+ ':',':',
+ }
+ )
+ ) {
+ host.push_back(c);
+ } else {
+ return false;
+ }
+ }
+ } break;
+
+ case 2: { // % ...
+ decoderState = 3;
+ decodedCharacter <<= 4;
+ if (IsCharacterInSet(c, {'0','9'})) {
+ decodedCharacter += (int)(c - '0');
+ } else if (IsCharacterInSet(c, {'A','F'})) {
+ decodedCharacter += (int)(c - 'A') + 10;
+ } else {
+ return false;
+ }
+ } break;
+
+ case 3: { // %[0-9A-F] ...
+ decoderState = 1;
+ decodedCharacter <<= 4;
+ if (IsCharacterInSet(c, {'0','9'})) {
+ decodedCharacter += (int)(c - '0');
+ } else if (IsCharacterInSet(c, {'A','F'})) {
+ decodedCharacter += (int)(c - 'A') + 10;
+ } else {
+ return false;
+ }
+ host.push_back((char)decodedCharacter);
+ } break;
+
+ case 4: { // IP-literal
+ if (c == 'v') {
+ host.push_back(c);
+ decoderState = 6;
+ break;
+ } else {
+ decoderState = 5;
+ }
+ }
+
+ case 5: { // IPv6Address
+ // TODO: research this offline first
+ // before attempting to code it
+ host.push_back(c);
+ if (c == ']') {
+ decoderState = 8;
+ }
+ } break;
+
+ case 6: { // IPvFuture: v ...
+ if (c == '.') {
+ decoderState = 7;
+ } else if (!IsCharacterInSet(c, {'0','9', 'A','F'})) {
+ return false;
+ }
+ host.push_back(c);
+ } break;
+
+ case 7: { // IPvFuture v 1*HEXDIG . ...
+ host.push_back(c);
+ if (c == ']') {
+ decoderState = 8;
+ } else if (
+ !IsCharacterInSet(
+ c,
+ {
+ // unreserved
+ 'a','z', 'A','Z', // ALPHA
+ '0','9', // DIGIT
+ '-','-', '.','.', '_','_', '~','~',
+
+ // sub-delims
+ '!','!', '$','$', '&','&', '\'','\'', '(','(', ')',')',
+ '*','*', '+','+', ',',',', ';',';', '=','=',
+
+ // (also allowed in IPvFuture)
+ ':',':',
+ }
+ )
+ ) {
+ return false;
+ }
+ } break;
+
+ case 8: { // illegal to have anything else, unless it's a colon,
+ // in which case it's a port delimiter
+ if (c == ':') {
+ decoderState = 9;
+ } else {
+ return false;
+ }
+ } break;
+
+ case 9: { // port
+ portString.push_back(c);
+ } break;
+ }
+ }
+ if (portString.empty()) {
hasPort = false;
} else {
- host = hostPortString.substr(0, portDelimiter);
- const auto portString = hostPortString.substr(portDelimiter + 1);
if (!ParseUint16(portString, port)) {
return false;
}