Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-2565

HTTP2 sets exchange.queryString unencoded with allow unescaped characters in URL

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 2.3.19.Final, 2.2.38.Final
    • None
    • None
    • None

      The cause of this is the Connector.setExchangeRequestPath method, that does not check for special characters in the query string. This method uses the requiresDecode to decide whether to decode the query string. Mistakenly, this is done without evaluating the characters in the query string:

      for (int i = 0; i < encodedPath.length(); ++i) {
          char c = encodedPath.charAt(i);
          if(!allowUnescapedCharactersInUrl && !HttpRequestParser.isTargetCharacterAllowed(c)) {
              throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(c));
          }
          if (c == '?') {
              String part;
              String encodedPart = encodedPath.substring(currentPathPartIndex, i);
              if (requiresDecode) {
                  part = URLUtils.decode(encodedPart, charset, decodeSlashFlag,false, decodeBuffer);
              } else {
                  part = encodedPart;
              }
              pathBuilder.append(part);
              part = pathBuilder.toString();
              exchange.setRequestPath(part);
              exchange.setRelativePath(part);
              if(requiresDecode && allowUnescapedCharactersInUrl) {
                  final String uri = URLUtils.decode(encodedPath.substring(0, i), charset, decodeSlashFlag,false, decodeBuffer);
                  exchange.setRequestURI(uri);
              } else {
                  exchange.setRequestURI(encodedPath.substring(0, i));
              }
      
              final String qs = encodedPath.substring(i + 1);
              if(requiresDecode && allowUnescapedCharactersInUrl) {
                  final String decodedQS = URLUtils.decode(qs, charset, decodeSlashFlag,false, decodeBuffer);
                  exchange.setQueryString(decodedQS);
              } else {
                  exchange.setQueryString(qs);
              }
      
              URLUtils.parseQueryString(qs, exchange, charset, decodeQueryString, maxParameters);
              return;
          } else if(c == ';') {
              String part;
              String encodedPart = encodedPath.substring(currentPathPartIndex, i);
              if (requiresDecode) {
                  part = URLUtils.decode(encodedPart, charset, decodeSlashFlag, false, decodeBuffer);
              } else {
                  part = encodedPart;
              }
              pathBuilder.append(part);
              if(requiresDecode && allowUnescapedCharactersInUrl) {
                  final String uri = URLUtils.decode(encodedPath, charset, decodeSlashFlag,false, decodeBuffer);
                  exchange.setRequestURI(uri);
              } else {
                  exchange.setRequestURI(encodedPath);
              }
      
              currentPathPartIndex = i + 1 + URLUtils.parsePathParams(encodedPath.substring(i + 1), exchange, charset, decode, maxParameters);
              i = currentPathPartIndex -1 ;
          } else if(decode && (c == '+' || c == '%' || c > 127)) {
              requiresDecode = decode;
          }
      }

      As you can see in the code block above, requiresDecode is used indiscriminately to define if query string should be decoded. But query string (qs in the code above) is in the interval of the characters that have not been evaluated in the main loop, as only all characters until index i have been evaluated at this point.

              flaviarnn Flavia Rainone
              flaviarnn Flavia Rainone
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved: