Index: src/OFString+URLEncoding.m ================================================================== --- src/OFString+URLEncoding.m +++ src/OFString+URLEncoding.m @@ -44,12 +44,19 @@ if ((retCString = malloc(([self UTF8StringLength] * 3) + 1)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: ([self UTF8StringLength] * 3) + 1]; for (i = 0; *string != '\0'; string++) { - if (isalnum((int)*string) || *string == '-' || *string == '_' || - *string == '.' || *string == '~') + /* + * '+' is also listed in RFC 1738, however, '+' is sometimes + * interpreted as space in HTTP. Therefore always escape it to + * make sure it's always interpreted correctly. + */ + if (!(*string & 0x80) && (isalnum((int)*string) || + *string == '$' || *string == '-' || *string == '_' || + *string == '.' || *string == '!' || *string == '*' || + *string == '(' || *string == ')' || *string == ',')) retCString[i++] = *string; else { uint8_t high, low; high = *string >> 4; Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -538,11 +538,11 @@ TEST(@"-[SHA1Hash]", [[@"asdfoobar" SHA1Hash] isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"]) TEST(@"-[stringByURLEncoding]", - [[@"foo\"ba'_~$" stringByURLEncoding] isEqual: @"foo%22ba%27_~%24"]) + [[@"foo\"ba'_~$" stringByURLEncoding] isEqual: @"foo%22ba%27_%7E$"]) TEST(@"-[stringByURLDecoding]", [[@"foo%20bar%22+%24" stringByURLDecoding] isEqual: @"foo bar\" $"]) TEST(@"-[insertString:atIndex:]",