mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-21 15:17:40 +00:00
fix(developer): URL parameters should be UTF-8
Fixes #7628. Indy components do not treat URLs as UTF-8. Our legacy EncodeURL function (sourced from Indy components) was the same. Discovered we needed to fixup the parsing of URLs as well as the construction of them; there may be other places we need to fix, although I did do a search for the relevant types in TIKE source.
This commit is contained in:
parent
2afde0cc9d
commit
0f2fbd443d
3 changed files with 12 additions and 74 deletions
|
|
@ -27,9 +27,10 @@ unit utilhttp; // I3306 // I3308 // I3309
|
|||
interface
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
System.WideStrUtils;
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
System.WideStrUtils,
|
||||
System.NetEncoding;
|
||||
|
||||
function GetParamsFromURL(URL: WideString; var Params: TStringList): Boolean;
|
||||
function GetParamsFromURLEx(URL: WideString; var Params: TStringList): Boolean;
|
||||
|
|
@ -42,77 +43,14 @@ function ConvertPathToFileURL(s: WideString): WideString;
|
|||
|
||||
implementation
|
||||
|
||||
function CharIsInSet(const AString: string; const ACharPos: Integer; ASet: TSysCharSet): Boolean;
|
||||
begin
|
||||
if ACharPos > Length(AString) then begin
|
||||
Result := False;
|
||||
end else begin
|
||||
{$IFDEF DotNet}
|
||||
Result := AnsiString(AString[ACharPos])[1] in ASet;
|
||||
{$ELSE}
|
||||
Result := CharInSet(AString[ACharPos], ASet);
|
||||
{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
|
||||
function URLEncode(ASrc: string): string;
|
||||
var
|
||||
i: Integer;
|
||||
const
|
||||
UnsafeChars = ['*', '#', '%', '<', '>', ' ','[',']', '{', '}', '?', '&']; {do not localize}
|
||||
begin
|
||||
Result := ''; {Do not Localize}
|
||||
for i := 1 to Length(ASrc) do
|
||||
begin
|
||||
// S.G. 27/11/2002: Changed the parameter encoding: Even in parameters, a space
|
||||
// S.G. 27/11/2002: is much more likely to be meaning "space" than "this is
|
||||
// S.G. 27/11/2002: a new parameter"
|
||||
// S.G. 27/11/2002: ref: Message-ID: <3de30169@newsgroups.borland.com> borland.public.delphi.internet.winsock
|
||||
// S.G. 27/11/2002: Most low-ascii is actually Ok in parameters encoding.
|
||||
if ((CharIsInSet(ASrc, i, UnsafeChars)) or (not (CharIsInSet(ASrc, i, [#33..#128])))) then
|
||||
begin {do not localize}
|
||||
Result := Result + '%' + IntToHex(Ord(ASrc[i]), 2); {do not localize}
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := Result + ASrc[i];
|
||||
end;
|
||||
end;
|
||||
Result := TNetEncoding.URL.Encode(ASrc);
|
||||
end;
|
||||
|
||||
function URLDecode(ASrc: AnsiString): string;
|
||||
var
|
||||
i: integer;
|
||||
s: ansistring;
|
||||
ESC: ansistring;
|
||||
CharCode: integer;
|
||||
begin
|
||||
Result := ''; {Do not Localize}
|
||||
// S.G. 27/11/2002: Spaces is NOT to be encoded as "+".
|
||||
// S.G. 27/11/2002: "+" is a field separator in query parameter, space is...
|
||||
// S.G. 27/11/2002: well, a space
|
||||
// ASrc := StringReplace(ASrc, '+', ' ', [rfReplaceAll]); {do not localize}
|
||||
i := 1;
|
||||
while i <= Length(ASrc) do
|
||||
begin
|
||||
if ASrc[i] <> '%' then
|
||||
begin {do not localize}
|
||||
S := S + ASrc[i]
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(i); // skip the % char
|
||||
ESC := Copy(ASrc, i, 2); // Copy the escape code
|
||||
Inc(i, 1); // Then skip it.
|
||||
try
|
||||
CharCode := StrToInt('$' + string(ESC)); {do not localize}
|
||||
S := S + AnsiChar(CharCode);
|
||||
except
|
||||
end;
|
||||
end;
|
||||
Inc(i);
|
||||
end;
|
||||
Result := UTF8ToString(S);
|
||||
Result := TNetEncoding.URL.Decode(ASrc);
|
||||
end;
|
||||
|
||||
procedure DecodeAndSetParams(const AValue: WideString; Params: TStringList);
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ procedure TAppHttpResponder.RespondProject(doc: string; AContext: TIdContext;
|
|||
Exit;
|
||||
end;
|
||||
|
||||
path := ARequestInfo.Params.Values['path'];
|
||||
path := UTF8ToString(AnsiString(ARequestInfo.Params.Values['path']));
|
||||
|
||||
if (Path <> '') and (not FileExists(path) or not SameText(ExtractFileExt(path), Ext_ProjectSource)) then
|
||||
begin
|
||||
|
|
@ -132,7 +132,7 @@ procedure TAppHttpResponder.RespondProject(doc: string; AContext: TIdContext;
|
|||
Exit;
|
||||
end;
|
||||
|
||||
path := ARequestInfo.Params.Values['path'];
|
||||
path := UTF8ToString(AnsiString(ARequestInfo.Params.Values['path']));
|
||||
|
||||
if not FileExists(path) or (
|
||||
not SameText(ExtractFileExt(path), '.ico') and
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ begin
|
|||
if ARequestInfo.Document = '/app/source/file' then
|
||||
begin
|
||||
// TODO: We should be passing a token to the browser for future POST security
|
||||
Filename := ARequestInfo.Params.Values['Filename'];
|
||||
Filename := UTF8ToString(AnsiString(ARequestInfo.Params.Values['Filename']));
|
||||
|
||||
if ARequestInfo.CommandType = hcGET then
|
||||
begin
|
||||
|
|
@ -112,12 +112,12 @@ begin
|
|||
else if ARequestInfo.Document = '/app/source/toucheditor' then
|
||||
begin
|
||||
// Respond files?
|
||||
Filename := ARequestInfo.Params.Values['Filename'];
|
||||
Filename := UTF8ToString(AnsiString(ARequestInfo.Params.Values['Filename']));
|
||||
RespondTouchEditor(Filename, AContext, ARequestInfo, AResponseInfo);
|
||||
end
|
||||
else if ARequestInfo.Document = '/app/source/toucheditor/state' then
|
||||
begin
|
||||
Filename := ARequestInfo.Params.Values['Filename'];
|
||||
Filename := UTF8ToString(AnsiString(ARequestInfo.Params.Values['Filename']));
|
||||
RespondTouchEditorState(Filename, AContext, ARequestInfo, AResponseInfo);
|
||||
end
|
||||
else if ARequestInfo.Document.StartsWith('/app/source/toucheditor/lib/') then
|
||||
|
|
@ -147,7 +147,7 @@ begin
|
|||
end
|
||||
else if ARequestInfo.CommandType = hcPOST then
|
||||
begin
|
||||
FData := ARequestInfo.Params.Values['State'];
|
||||
FData := UTF8ToString(AnsiString(ARequestInfo.Params.Values['State']));
|
||||
RegisterSource(AFilename + '#state', FData, True);
|
||||
end;
|
||||
end;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue