code: public static final byte[] decodeUrlLoose(byte[] bytes) 
      {
          if (bytes == null) {
              return null;
          }
          ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
          for (int i = 0; i < bytes.length; i++) {
              int b = bytes[i];
              if (b == '+') {
                  buffer.write(' ');
                  continue;
              }
              if (b == '%') {
                  if(i+2<bytes.length) {
                      int u = Character.digit((char)bytes[i+1], 16);
                      int l = Character.digit((char)bytes[i+2], 16);
                      if (u > -1 && l > -1) {
                          // good encoding
                          int c = ((u << 4) + l);
                          buffer.write((char)c);
                          i += 2;
                          continue;
                      } // else: bad encoding digits, leave '%' in place
                  } // else: insufficient encoding digits, leave '%' in place
              }
              buffer.write(b);
          }
          return buffer.toByteArray(); 
      }
docs: Decodes an array of URL safe 7-bit characters into an array of
  original bytes. Escaped characters are converted back to their
  original representation.
  
  Differs from URLCodec.decodeUrl() in that it throws no
  exceptions; bad or incomplete escape sequences are ignored
  and passed into result undecoded. This matches the behavior
  of browsers, which will use inconsistently-encoded URIs
  in HTTP request-lines.
  
  @param bytes array of URL safe characters
  @return array of original bytes