// This function will encode all "special" characters in typical url // encoding, that is %hh where h is a valid hex digit. It will also fold // any duplicated slashes. bool nsUrlClassifierUtils::SpecialEncode(const nsACString & url, bool foldSlashes, nsACString & _retval) { bool changed = false; const char* curChar = url.BeginReading(); const char* end = url.EndReading(); unsigned char lastChar = '\0'; while (curChar != end) { unsigned char c = static_cast<unsigned char>(*curChar); if (ShouldURLEscape(c)) { _retval.Append('%'); _retval.Append(int_to_hex_digit(c / 16)); _retval.Append(int_to_hex_digit(c % 16)); changed = true; } else if (foldSlashes && (c == '/' && lastChar == '/')) { // skip } else { _retval.Append(*curChar); } lastChar = c; curChar++; } return changed; }
void TestEnc() { // Test empty string TestEncodeHelper("", ""); // Test that all characters we shouldn't encode ([33-36],[38,126]) are not. nsCString noenc; for (PRInt32 i = 33; i < 127; i++) { if (i != 37) { // skip % noenc.Append(static_cast<char>(i)); } } nsUrlClassifierUtils utils; nsCString out; utils.SpecialEncode(noenc, false, out); CheckEquals(noenc, out); // Test that all the chars that we should encode [0,32],37,[127,255] are nsCString yesAsString, yesExpectedString; for (PRInt32 i = 1; i < 256; i++) { if (i < 33 || i == 37 || i > 126) { yesAsString.Append(static_cast<char>(i)); yesExpectedString.Append('%'); yesExpectedString.Append(int_to_hex_digit(i / 16)); yesExpectedString.Append(int_to_hex_digit(i % 16)); } } out.Truncate(); utils.SpecialEncode(yesAsString, false, out); CheckEquals(yesExpectedString, out); TestEncodeHelper("blah//blah", "blah/blah"); }
// Make sure Unescape from nsEncode.h's unescape does what the server does. void TestUnescape() { // test empty string TestUnescapeHelper("\0", "\0"); // Test docoding of all characters. nsCString allCharsEncoded, allCharsEncodedLowercase, allCharsAsString; for (PRInt32 i = 1; i < 256; ++i) { allCharsEncoded.Append('%'); allCharsEncoded.Append(int_to_hex_digit(i / 16)); allCharsEncoded.Append((int_to_hex_digit(i % 16))); allCharsEncodedLowercase.Append('%'); allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i / 16))); allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i % 16))); allCharsAsString.Append(static_cast<char>(i)); } nsUrlClassifierUtils utils; nsCString out; NS_UnescapeURL(allCharsEncoded.get(), allCharsEncoded.Length(), esc_AlwaysCopy, out); CheckEquals(allCharsAsString, out); out.Truncate(); NS_UnescapeURL(allCharsEncodedLowercase.get(), allCharsEncodedLowercase.Length(), esc_AlwaysCopy, out); CheckEquals(allCharsAsString, out); // Test %-related edge cases TestUnescapeHelper("%", "%"); TestUnescapeHelper("%xx", "%xx"); TestUnescapeHelper("%%", "%%"); TestUnescapeHelper("%%%", "%%%"); TestUnescapeHelper("%%%%", "%%%%"); TestUnescapeHelper("%1", "%1"); TestUnescapeHelper("%1z", "%1z"); TestUnescapeHelper("a%1z", "a%1z"); TestUnescapeHelper("abc%d%e%fg%hij%klmno%", "abc%d%e%fg%hij%klmno%"); // A few more tests TestUnescapeHelper("%25", "%"); TestUnescapeHelper("%25%32%35", "%25"); }
size_t url_encode_cstr( char *dest, const char*src, size_t max_size ) { size_t ret = 0; if(!max_size--) return 0; while(true) { const char src_char = *src++; if(src_char==0) break; if(max_size==0) { ret++; break; } if(isurlchar(src_char)) { *dest++ = src_char; ret++; max_size--; #if URL_ENCODE_SPACES_AS_PLUSES } else if(src_char == ' ') { *dest++ = '+'; // Stupid legacy space encoding. ret++; max_size--; #endif } else { if(max_size < 3) { // Dest buffer too small for the next character. ret++; break; } *dest++ = '%'; *dest++ = int_to_hex_digit(src_char >> 4); *dest++ = int_to_hex_digit(src_char & 0xF); ret += 3; max_size -= 3; } } *dest = 0; return ret; }