Hallo Leute,
Ich habe da ein kleines Problem, das mir Kopfschmerzen bereitet. Folgendes Szenario:
Ich habe einen Delphi-Web-Server der auf den
Indy-Komponenten aufbaut. Wenn der Browser einen Get oder Post-Request absetzt, welcher in den Parametern
Unicode-Zeichen (Umlaute, Akzente etc.) enthält, so werden diese vom Browser mit UrlEncode codiert. Also z.B ein Parameter namens MyParam mit dem Wert 'Über':
MyParam=
%C3%9Cber
Das Problem liegt daran, dass
Indy (D2010) zuerst ein Utf8Decode vornimmt und erst danach das UrlDecode macht, was leider ein Problem ist, denn die Zeichen #$C3 und #$9C werden als einzelne Zeichen gesetzt. Konkret wird dann daraus:
MyParam=
Ã'#$009C'ber
oder Hexadezimal:
$4D $00 $79 $00 $50 $00 $61 $00 $72 $00 $61 $00 $6D $00 $3D $00
$C3 $00 $9C $00 $62 $00 $65 $00 $72 $00
Was ich aber gerne hätte ist:
MyParam=
Ü'ber
oder Hexadezimal:
$4D $00 $79 $00 $50 $00 $61 $00 $72 $00 $61 $00 $6D $00 $3D $00
$DC $00 $62 $00 $65 $00 $72 $00
Der fehler liegt klar bei
Indy, weil zuerst das Utf8decode vorgenommen wird und danach das UrlDecode gemacht wird anstatt umgekehrt. Ich weiss nicht ob der Fehler in einer aktuelleren Version behoben worden ist, aber erste Versuche mit einer aktuellen Version sind an anderen Problemen gescheitert (veränderte
API und ein noch ungeklärtes Problem mit der Cookie-Version).
Deshalb suche ich einen Workaround. Und zwar habe ich mir gedacht ich könnte den fehlerhaften String wieder zurückkonvertieren, dass er so aussieht wie der Browser ihn gesendet hat und danach die Korrekte decodierung vornehmen. Aber die Theorie scheitert an der Praxis, es will mir einfach nicht gelingen den ursprünglichen String wiederherzustellen:
Delphi-Quellcode:
uses
IdURI;
function URLEncode(Text:
String):
String;
var
i: Integer;
begin
Result := '
';
i := 1;
while i <= Length(Text)
do
begin
if CharInSet(Text[i], ['
A'..'
Z', '
a'..'
z', '
0'..'
9', '
-', '
_', '
.', '
~' , '
/'])
and not CharInSet(Text[i], ['
!', '
*', '
''
', '
(', '
)', '
;', '
:', '
@', '
&', '
=', '
+', '
$', '
,', '
?', '
#', '
%', '
[', '
]'])
then
begin
Result := Result + Text[i];
Inc(i);
end
else
begin
Result := Result + '
%' + IntToHex(Ord(Text[i]), 2);
inc(i);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Input:
String;
WrongString:
String;
CorrectedString:
String;
RightString:
String;
RBS: RawByteString;
s:
string;
Output:
String;
begin
Input := '
%C3%9Cber';
// Der Ausgangsstting
WrongString := TIdURI.URLDecode(UTF8ToString(Input));
// Das ist das was Indy liefert
RightString := '
Über';
// So müsste das Ergebnis aussehen
{ URLEncode rückgängig machen:
TidURI.URLEncode mag es nicht wenn der übergebene String keine URL
ist - bzw. das Protokoll fehlt. Deswegen wird hier meine eigene Version von URLDecode() verwendet.
}
s := URLEncode(WrongString);
// Utf8Decode rückgängig machen
CorrectedString := UTF8Encode(s);
// und richtig decodieren
s := TIdURI.URLDecode(CorrectedString);
RBS := s;
// !!! Hauptproblem ist hier
{ s : $C3 $00 $9C $00 $62 $00 $65 $00 $72 $00
RBS: $C3 $3F $62 $65 $72
gewünscht wäre: $C3 $9C $62 $65 $72
}
Output := UTF8ToString(RBS);
ShowMessage('
Expected String: ' + RightString + #13 + '
Computed String:' + Output);
end;
Das Hauptproblem scheint die konversion von
UnicodeString zu
RawByteString. Delphi nimmt dort irgendwie eine konversion vor, die gar nicht erwünscht ist.
Ich bin für jede Hilfe dankbar.