예제 #1
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParseQuery(string text, int length, int current, out nextStep next, out KeyValuePair <string, string>[] @params)
        {
            next    = nextStep.Error;
            @params = null;
            var    last       = current;
            var    paramsList = new List <KeyValuePair <string, string> >(16);
            string paramsKey  = null;
            var    decode     = false;
            var    parsingKey = true;
            char   c;

            for (; ; ++current)
            {
                if (current < length)
                {
                    c = text[current];
                    switch (c)
                    {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                }
                else
                {
                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
                if (
                    ((c >= 'a') && (c <= '~')) ||  // one of: abcdefghijklmnopqrstuvwxyz{|}~
                    ((c >= '?') && (c <= '_')) ||  // one of: ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
                    ((c >= '\'') && (c <= ';')) || // one of: '()*+,-./0123456789:;
                    (c == '$') || (c == '%') || (c == '!') ||
                    char.IsLetterOrDigit(c)
                    )
                {
                    // valid character, keep parsing
                }
                else if ((c == '&') || (c == '#') || (c == END_OF_STRING))
                {
                    if (parsingKey)
                    {
                        if (current != last)
                        {
                            // add non-empty key with empty value
                            paramsKey = text.Substring(last, current - last);
                            if (decode)
                            {
                                paramsKey = Decode(paramsKey);
                                decode    = false;
                            }
                            paramsList.Add(new KeyValuePair <string, string>(paramsKey, null));
                        }
                        else if (c == '&')
                        {
                            // this occurs in the degenerate case of two consecutive ampersands (e.g. "&&")
                            paramsList.Add(new KeyValuePair <string, string>("", null));
                        }
                    }
                    else
                    {
                        // add key with value
                        var paramsValue = text.Substring(last, current - last);
                        if (decode)
                        {
                            paramsValue = Decode(paramsValue);
                            decode      = false;
                        }
                        paramsList.Add(new KeyValuePair <string, string>(paramsKey, paramsValue));
                        parsingKey = true;
                    }

                    // check if we found a query parameter separator
                    if (c == '&')
                    {
                        last = current + 1;
                        continue;
                    }

                    // we're done parsing the query string
                    break;
                }
                else if (c == '=')
                {
                    if (parsingKey)
                    {
                        paramsKey = text.Substring(last, current - last);
                        if (decode)
                        {
                            paramsKey = Decode(paramsKey);
                            decode    = false;
                        }
                        last       = current + 1;
                        parsingKey = false;
                    }
                }
                else
                {
                    return(-1);
                }
            }

            // initialize return values
            next    = (nextStep)c;
            @params = paramsList.ToArray();
            return(current + 1);
        }
예제 #2
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParsePath(string text, int length, int current, out nextStep next, ref bool trailingSlash, out string[] segments)
        {
            next     = nextStep.Error;
            segments = null;
            var  last = current;
            var  hasLeadingBackslashes = false;
            var  segmentList           = new List <string>(16);
            var  leading = true;
            char c;

            for (; ; ++current)
            {
                c = (current < length) ? text[current] : END_OF_STRING;
                if ((c == '/') || (c == '\\'))
                {
                    if (leading)
                    {
                        hasLeadingBackslashes = hasLeadingBackslashes || (c == '\\');
                    }
                    else
                    {
                        var segment = text.Substring(last, current - last);
                        if (hasLeadingBackslashes)
                        {
                            segment = segment.Replace('\\', '/');
                            hasLeadingBackslashes = false;
                        }
                        segmentList.Add(segment);
                        last    = current + 1;
                        leading = true;
                    }
                }
                else if (
                    ((c >= 'a') && (c <= '~')) ||   // one of: abcdefghijklmnopqrstuvwxyz{|}~
                    ((c >= '@') && (c <= '_')) ||   // one of: @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
                    ((c >= '$') && (c <= ';')) ||   // one of: $%&'()*+,-./0123456789:;
                    (c == '=') || (c == '!') ||
                    char.IsLetterOrDigit(c)
                    )
                {
                    // no longer accept leading '/' or '\' characters
                    leading = false;
                }
                else if ((c == '?') || (c == '#') || (c == END_OF_STRING))
                {
                    if (last == current)
                    {
                        trailingSlash = true;
                    }
                    else
                    {
                        var segment = text.Substring(last, current - last);
                        if (hasLeadingBackslashes)
                        {
                            segment = segment.Replace('\\', '/');
                        }
                        segmentList.Add(segment);
                    }

                    // we're done parsing the path string
                    break;
                }
                else
                {
                    return(-1);
                }
            }

            // initialize return values
            segments = segmentList.ToArray();
            next     = (nextStep)c;
            return(current + 1);
        }
예제 #3
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParseAuthority(string text, int length, int current, out nextStep next, out string user, out string password, out string hostname, out int port)
        {
            var last = current;

            next     = nextStep.Error;
            user     = null;
            password = null;
            hostname = null;
            port     = -1;

            // check first character; it could tell us if we're parsing an IPv6 address
            var  decode = false;
            char c;

            if (current < length)
            {
                c = text[current];
                switch (c)
                {
                case '%':
                case '+':
                    decode = true;
                    break;

                case '[':
                    goto ipv6;
                }
            }
            else
            {
                // use '\uFFFF' as end-of-string marker
                c = END_OF_STRING;
            }

            // parse hostname -OR- user-info
            string hostnameOrUsername;

            for (;;)
            {
                if (
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                    )
                {
                    // valid character, keep parsing
                }
                else if (c == ':')
                {
                    // part before ':' is either a username or hostname
                    hostnameOrUsername = text.Substring(last, current - last);
                    last = current + 1;
                    goto hostnameOrUserInfoAfterColon;
                }
                else if (c == '@')
                {
                    // part before '@' must be username since we didn't find ':'
                    user = text.Substring(last, current - last);
                    if (decode)
                    {
                        user   = Decode(user);
                        decode = false;
                    }
                    last = current + 1;
                    goto hostnameOrIPv6Address;
                }
                else if ((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING))
                {
                    // part before '/', '\', '?', '#' must be hostname
                    if (decode)
                    {
                        // hostname cannot contain encoded characters
                        return(-1);
                    }
                    hostname = text.Substring(last, current - last);
                    next     = (nextStep)c;
                    return(current + 1);
                }
                else
                {
                    return(-1);
                }

                // continue on by reading the next character
                ++current;
                if (current < length)
                {
                    c = text[current];
                    switch (c)
                    {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                }
                else
                {
                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
            }
            throw new ShouldNeverHappenException("hostnameOrUsername");

            // parse hostname -OR- user-info AFTER we're parsed a colon (':')
hostnameOrUserInfoAfterColon:
            for (;;)
            {
                ++current;
                if (current < length)
                {
                    c = text[current];
                    switch (c)
                    {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                }
                else
                {
                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
                if (
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                    )
                {
                    // valid character, keep parsing
                }
                else if (c == '@')
                {
                    // part before ':' was username
                    user = hostnameOrUsername;
                    if (decode)
                    {
                        user = Decode(user);
                    }

                    // part after ':' is password
                    password = text.Substring(last, current - last);
                    if (decode)
                    {
                        password = Decode(password);
                    }
                    last   = current + 1;
                    decode = false;
                    goto hostnameOrIPv6Address;
                }
                else if ((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING))
                {
                    // part before ':' was hostname
                    if (decode)
                    {
                        // hostname cannot contain encoded characters
                        return(-1);
                    }
                    hostname = hostnameOrUsername;

                    // part after ':' is port, parse and validate it
                    if (!int.TryParse(text.Substring(last, current - last), out port) || (port < 0) || (port > ushort.MaxValue))
                    {
                        return(-1);
                    }
                    next = (nextStep)c;
                    return(current + 1);
                }
                else
                {
                    return(-1);
                }
            }
            throw new ShouldNeverHappenException("hostnameOrUserInfoAfterColon");

hostnameOrIPv6Address:
            ++current;
            if (current < length)
            {
                c = text[current];
                switch (c)
                {
                case '%':
                case '+':
                    decode = true;
                    break;

                case '[':

                    // NOTE (steveb): we want to include the leading character in the final result
                    last = current;

                    // IPv6 addresses start with '['
                    goto ipv6;
                }
            }
            else
            {
                // use '\uFFFF' as end-of-string marker
                c = END_OF_STRING;
            }
            for (;;)
            {
                if (
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                    )
                {
                    // valid character, keep parsing
                }
                else if (c == ':')
                {
                    if (decode)
                    {
                        // hostname cannot contain encoded characters
                        return(-1);
                    }
                    hostname = text.Substring(last, current - last);
                    last     = current + 1;
                    goto portNumber;
                }
                else if ((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING))
                {
                    if (decode)
                    {
                        // hostname cannot contain encoded characters
                        return(-1);
                    }
                    hostname = text.Substring(last, current - last);
                    next     = (nextStep)c;
                    return(current + 1);
                }
                else
                {
                    return(-1);
                }

                // continue on by reading the next character
                ++current;
                if (current < length)
                {
                    c = text[current];
                    switch (c)
                    {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                }
                else
                {
                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
            }
            throw new ShouldNeverHappenException("hostname");

portNumber:
            for (;;)
            {
                ++current;
                c = (current < length) ? text[current] : END_OF_STRING;
                if ((c >= '0') && (c <= '9'))
                {
                    // valid character, keep parsing
                }
                else if ((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING))
                {
                    if (!int.TryParse(text.Substring(last, current - last), out port) || (port < 0) || (port > ushort.MaxValue))
                    {
                        return(-1);
                    }
                    next = (nextStep)c;
                    return(current + 1);
                }
                else
                {
                    return(-1);
                }
            }
            throw new ShouldNeverHappenException("portNumber");

ipv6:
            for (;;)
            {
                ++current;
                c = (current < length) ? text[current] : END_OF_STRING;
                if (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')) || ((c >= '0') && (c <= '9')) || (c == ':') || (c == '.'))
                {
                    // valid character, keep parsing
                }
                else if (c == ']')
                {
                    hostname = text.Substring(last, current - last + 1);

                    // check next character to determine correct state to transition to
                    ++current;
                    c = (current < length) ? text[current] : END_OF_STRING;
                    if (c == ':')
                    {
                        last = current + 1;
                        goto portNumber;
                    }
                    else if ((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING))
                    {
                        next = (nextStep)c;
                        return(current + 1);
                    }
                    else
                    {
                        return(-1);
                    }
                }
                else
                {
                    return(-1);
                }
            }
            throw new ShouldNeverHappenException("ipv6");
        }
예제 #4
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParseQuery(string text, int length, int current, out nextStep next, out KeyValuePair<string, string>[] @params)
        {
            next = nextStep.Error;
            @params = null;
            var last = current;
            var paramsList = new List<KeyValuePair<string, string>>(16);
            string paramsKey = null;
            var decode = false;
            var parsingKey = true;
            char c;
            for(; ; ++current) {
                if(current < length) {
                    c = text[current];
                    switch(c) {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                } else {

                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
                if(
                    ((c >= 'a') && (c <= '~')) || // one of: abcdefghijklmnopqrstuvwxyz{|}~
                    ((c >= '?') && (c <= '_')) || // one of: ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
                    ((c >= '\'') && (c <= ';')) || // one of: '()*+,-./0123456789:;
                    (c == '$') || (c == '%') || (c == '!') ||
                    char.IsLetterOrDigit(c)
                ) {

                    // valid character, keep parsing
                } else if((c == '&') || (c == '#') || (c == END_OF_STRING)) {
                    if(parsingKey) {
                        if(current != last) {

                            // add non-empty key with empty value
                            paramsKey = text.Substring(last, current - last);
                            if(decode) {
                                paramsKey = Decode(paramsKey);
                                decode = false;
                            }
                            paramsList.Add(new KeyValuePair<string, string>(paramsKey, null));
                        } else if(c == '&') {

                            // this occurs in the degenerate case of two consecutive ampersands (e.g. "&&")
                            paramsList.Add(new KeyValuePair<string, string>("", null));
                        }
                    } else {

                        // add key with value
                        var paramsValue = text.Substring(last, current - last);
                        if(decode) {
                            paramsValue = Decode(paramsValue);
                            decode = false;
                        }
                        paramsList.Add(new KeyValuePair<string, string>(paramsKey, paramsValue));
                        parsingKey = true;
                    }

                    // check if we found a query parameter separator
                    if(c == '&') {
                        last = current + 1;
                        continue;
                    }

                    // we're done parsing the query string
                    break;
                } else if(c == '=') {
                    if(parsingKey) {
                        paramsKey = text.Substring(last, current - last);
                        if(decode) {
                            paramsKey = Decode(paramsKey);
                            decode = false;
                        }
                        last = current + 1;
                        parsingKey = false;
                    }
                } else {
                    return -1;
                }
            }

            // initialize return values
            next = (nextStep)c;
            @params = paramsList.ToArray();
            return current + 1;
        }
예제 #5
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParsePath(string text, int length, int current, out nextStep next, ref bool trailingSlash, out string[] segments)
        {
            next = nextStep.Error;
            segments = null;
            var last = current;
            var hasLeadingBackslashes = false;
            var segmentList = new List<string>(16);
            var leading = true;
            char c;
            for(; ; ++current) {
                c = (current < length) ? text[current] : END_OF_STRING;
                if((c == '/') || (c == '\\')) {
                    if(leading) {
                        hasLeadingBackslashes = hasLeadingBackslashes || (c == '\\');
                    } else {
                        var segment = text.Substring(last, current - last);
                        if(hasLeadingBackslashes) {
                            segment = segment.Replace('\\', '/');
                            hasLeadingBackslashes = false;
                        }
                        segmentList.Add(segment);
                        last = current + 1;
                        leading = true;
                    }
                } else if(
                    ((c >= 'a') && (c <= '~')) ||   // one of: abcdefghijklmnopqrstuvwxyz{|}~
                    ((c >= '@') && (c <= '_')) ||   // one of: @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
                    ((c >= '$') && (c <= ';')) ||   // one of: $%&'()*+,-./0123456789:;
                    (c == '=') || (c == '!') ||
                    char.IsLetterOrDigit(c)
                ) {

                    // no longer accept leading '/' or '\' characters
                    leading = false;
                } else if((c == '?') || (c == '#') || (c == END_OF_STRING)) {
                    if(last == current) {
                        trailingSlash = true;
                    } else {
                        var segment = text.Substring(last, current - last);
                        if(hasLeadingBackslashes) {
                            segment = segment.Replace('\\', '/');
                        }
                        segmentList.Add(segment);
                    }

                    // we're done parsing the path string
                    break;
                } else {
                    return -1;
                }
            }

            // initialize return values
            segments = segmentList.ToArray();
            next = (nextStep)c;
            return current + 1;
        }
예제 #6
0
파일: XUriParser.cs 프로젝트: nataren/DReAM
        public static int TryParseAuthority(string text, int length, int current, out nextStep next, out string user, out string password, out string hostname, out int port)
        {
            var last = current;
            next = nextStep.Error;
            user = null;
            password = null;
            hostname = null;
            port = -1;

            // check first character; it could tell us if we're parsing an IPv6 address
            var decode = false;
            char c;
            if(current < length) {
                c = text[current];
                switch(c) {
                case '%':
                case '+':
                    decode = true;
                    break;
                case '[':
                    goto ipv6;
                }
            } else {

                // use '\uFFFF' as end-of-string marker
                c = END_OF_STRING;
            }

            // parse hostname -OR- user-info
            string hostnameOrUsername;
            for(;;) {
                if(
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                ) {

                    // valid character, keep parsing
                } else if(c == ':') {

                    // part before ':' is either a username or hostname
                    hostnameOrUsername = text.Substring(last, current - last);
                    last = current + 1;
                    goto hostnameOrUserInfoAfterColon;
                } else if(c == '@') {

                    // part before '@' must be username since we didn't find ':'
                    user = text.Substring(last, current - last);
                    if(decode) {
                        user = Decode(user);
                        decode = false;
                    }
                    last = current + 1;
                    goto hostnameOrIPv6Address;
                } else if((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING)) {

                    // part before '/', '\', '?', '#' must be hostname
                    if(decode) {

                        // hostname cannot contain encoded characters
                        return -1;
                    }
                    hostname = text.Substring(last, current - last);
                    next = (nextStep)c;
                    return current + 1;
                } else {
                    return -1;
                }

                // continue on by reading the next character
                ++current;
                if(current < length) {
                    c = text[current];
                    switch(c) {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                } else {

                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
            }
            throw new ShouldNeverHappenException("hostnameOrUsername");

            // parse hostname -OR- user-info AFTER we're parsed a colon (':')
            hostnameOrUserInfoAfterColon:
            for(;;) {
                ++current;
                if(current < length) {
                    c = text[current];
                    switch(c) {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                } else {

                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
                if(
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                ) {

                    // valid character, keep parsing
                } else if(c == '@') {

                    // part before ':' was username
                    user = hostnameOrUsername;
                    if(decode) {
                        user = Decode(user);
                    }

                    // part after ':' is password
                    password = text.Substring(last, current - last);
                    if(decode) {
                        password = Decode(password);
                    }
                    last = current + 1;
                    decode = false;
                    goto hostnameOrIPv6Address;
                } else if((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING)) {

                    // part before ':' was hostname
                    if(decode) {

                        // hostname cannot contain encoded characters
                        return -1;
                    }
                    hostname = hostnameOrUsername;

                    // part after ':' is port, parse and validate it
                    if(!int.TryParse(text.Substring(last, current - last), out port) || (port < 0) || (port > ushort.MaxValue)) {
                        return -1;
                    }
                    next = (nextStep)c;
                    return current + 1;
                } else {
                    return -1;
                }
            }
            throw new ShouldNeverHappenException("hostnameOrUserInfoAfterColon");

            hostnameOrIPv6Address:
            ++current;
            if(current < length) {
                c = text[current];
                switch(c) {
                case '%':
                case '+':
                    decode = true;
                    break;
                case '[':

                    // NOTE (steveb): we want to include the leading character in the final result
                    last = current;

                    // IPv6 addresses start with '['
                    goto ipv6;
                }
            } else {

                // use '\uFFFF' as end-of-string marker
                c = END_OF_STRING;
            }
            for(;;) {
                if(
                    ((c >= 'a') && (c <= 'z')) ||
                    ((c >= 'A') && (c <= 'Z')) ||
                    ((c >= '0') && (c <= '9')) ||
                    ((c >= '$') && (c <= '.')) ||   // one of: $%&'()*+,-.
                    (c == '!') || (c == ';') || (c == '=') || (c == '_') || (c == '~') ||
                    char.IsLetterOrDigit(c)
                ) {

                    // valid character, keep parsing
                } else if(c == ':') {
                    if(decode) {

                        // hostname cannot contain encoded characters
                        return -1;
                    }
                    hostname = text.Substring(last, current - last);
                    last = current + 1;
                    goto portNumber;
                } else if((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING)) {
                    if(decode) {

                        // hostname cannot contain encoded characters
                        return -1;
                    }
                    hostname = text.Substring(last, current - last);
                    next = (nextStep)c;
                    return current + 1;
                } else {
                    return -1;
                }

                // continue on by reading the next character
                ++current;
                if(current < length) {
                    c = text[current];
                    switch(c) {
                    case '%':
                    case '+':
                        decode = true;
                        break;
                    }
                } else {

                    // use '\uFFFF' as end-of-string marker
                    c = END_OF_STRING;
                }
            }
            throw new ShouldNeverHappenException("hostname");

            portNumber:
            for(;;) {
                ++current;
                c = (current < length) ? text[current] : END_OF_STRING;
                if((c >= '0') && (c <= '9')) {

                    // valid character, keep parsing
                } else if((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING)) {
                    if(!int.TryParse(text.Substring(last, current - last), out port) || (port < 0) || (port > ushort.MaxValue)) {
                        return -1;
                    }
                    next = (nextStep)c;
                    return current + 1;
                } else {
                    return -1;
                }
            }
            throw new ShouldNeverHappenException("portNumber");

            ipv6:
            for(;;) {
                ++current;
                c = (current < length) ? text[current] : END_OF_STRING;
                if(((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')) || ((c >= '0') && (c <= '9')) || (c == ':') || (c == '.')) {

                    // valid character, keep parsing
                } else if(c == ']') {
                    hostname = text.Substring(last, current - last + 1);

                    // check next character to determine correct state to transition to
                    ++current;
                    c = (current < length) ? text[current] : END_OF_STRING;
                    if(c == ':') {
                        last = current + 1;
                        goto portNumber;
                    } else if((c == '/') || (c == '\\') || (c == '?') || (c == '#') || (c == END_OF_STRING)) {
                        next = (nextStep)c;
                        return current + 1;
                    } else {
                        return -1;
                    }
                } else {
                    return -1;
                }
            }
            throw new ShouldNeverHappenException("ipv6");
        }