Garbage in headers when POST-ing with Indy 10.5.8

纵然是瞬间 提交于 2019-12-02 00:17:06

The root of the problem is that your custom TStream code is not compatible with D2009+ versions of Delphi. Delphi's String and PChar types are not Ansi anymore, but the code assumes they still are. They are Unicode UTF-16 now. You are not accounting for that correctly, eg:

procedure TMsMultiPartFormDataStream.AddFile(const FieldName, FileName, ContentType: string; FileData: TStream);   
var   
  sFormFieldInfo: AnsiString;
  iSize: Int64;   
begin   
  iSize := FileData.Size;   
  // NOTE: this will only work for ASCII filenames!!!!
  //
  // Non-ASCII filenames will get converted to Ansi, which can cause data loss.
  // To send non-ASCII filenames correctly, you have to encode it to a charset
  // first, such as UTF-8, and then encode the resulting bytes using
  // MIME's RFC2047 encoding so the server can decode the filename properly
  // on its end...
  //
  sFormFieldInfo := Format(CRLF + '--' + Boundary + CRLF + CONTENT_DISPOSITION +   
    FILE_NAME_PLACE_HOLDER + CRLF + CONTENT_LENGTH +   
      CONTENT_TYPE_PLACE_HOLDER, [FieldName, FileName, iSize, ContentType]);   
  {so: boundary + crlf + content-disposition+file-name-place-holder}   

  Write(sFormFieldInfo[1], Length(sFormFieldInfo) * SizeOf(AnsiChar));   

  if iSize > 0 then
  begin
    FileData.Position := 0;   
    CopyFrom(FileData, iSize);   
  end;
end;   

procedure TMsMultiPartFormDataStream.AddFormField(const FieldName, FieldValue: string);   
var   
  sFormFieldInfo: AnsiString;   
begin   
  // NOTE: this will only work for ASCII text!!!!
  //
  // Non-ASCII text will get converted to Ansi, which can cause data loss.
  // To send non-ASCII text correctly, you have to encode it to a charset
  // first, such as UTF-8 and then encode the resulting bytes using
  // MIME's 'quoted-printable' or 'base64' enoding, and then include
  // appropriate 'charset' and Content-Transfer-Encoding' headers so the
  // server can decode the data properly on its end...
  //
  sFormFieldInfo := Format(CRLF + '--' + Boundary + CRLF + CONTENT_DISPOSITION + CRLF + CRLF +   
    FieldValue, [FieldName]);   
  Write(sFormFieldInfo[1], Length(sFormFieldInfo) * AnsiString(AnsiChar));   
end;   

procedure TMsMultiPartFormDataStream.PrepareStreamForDispatch;   
var   
  sFormFieldInfo: AnsiString;   
begin   
  sFormFieldInfo := CRLF + '--' + Boundary + '--' + CRLF;   
  Write(sFormFieldInfo[1], Length(sFormFieldInfo) * SizeOf(AnsiChar));   
  Position := 0;   
end;   

With that said, I strongly suggest you get rid of your custom TMsMultiPartFormDataStream class completely. All it is doing is mimicing an outdated version of Indy's own TIdMultipartFormDataStream class . Just use Indy's native TIdMultipartFormDataStream class as-is instead. It handles D2009+ Unicode for you, eg:

uses
  ..., IdMultipartFormData;

function PostFile(const filename, apikey: string): boolean; 
var 
  ResponseStream: TMemoryStream; 
  MultiPartFormDataStream: TIdMultiPartFormDataStream; 
begin 
  Result := False; 

  //Form5.IdHTTP1.HandleRedirects := true; 
  Form5.idHTTP1.ReadTimeout := 0; 
  //Form5.idHTTP1.IOHandler.LargeStream := True; 

  try
    ResponseStream := TMemoryStream.Create; 
    try
      MultiPartFormDataStream := TIdMultiPartFormDataStream.Create; 
      try 
        MultiPartFormDataStream.AddFormField('apikey', apikey); 
        MultiPartFormDataStream.AddFile('file', filename, 'application/octet-stream');      
        Form5.IdHTTP1.Post('http://www.updserver.tld/api/file/save', MultiPartFormDataStream, ResponseStream); 
        ResponseStream.SaveToFile(ExtractFilePath(Application.ExeName) + 'a.txt'); 
        Result := True; 
      finally 
        MultiPartFormDataStream.Free; 
      end;
    finally
      ResponseStream.Free; 
    end; 
  except 
    on E:Exception do 
    begin 
      Form5.Close; 
      ShowMessage('Upload failed! ' + E.Message); 
      end; 
    end; 
  end; 
end;

Do all of those . characters represent a 00 byte? Because that looks like the result of a ASCII->UTF16 conversion. And the garbage in the Content-Disposition could be related to a conversion like that copying bytes around and getting the end of the buffer wrong, leaving you with a corrupted string.

If you can come up with code to reproduce this consistently, you should probably post a bug report on the Indy forums.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!