EldoS | Feel safer!

Software components for data protection, secure storage and transfer

POST parameters order

Also by EldoS: Callback File System
Create virtual file systems and disks, expose and manage remote data as if they were files on the local disk.
#19001
Posted: 02/10/2012 19:44:11
by Leonardo Herrera (Standard support level)
Joined: 02/14/2011
Posts: 66

Hello,

I'm using TElHTTPClient to post to some secure server. The request appears to work properly but apparently the software my counterpart is using somehow cannot read some parameters.

Just to comply with one of their requirements, I want to see if I can change the order of the _file_ sent by putting it at the end of the request. It appears that by using the following code the file is always put at first. Is it possible to change this behavior?

Code
  Data := TElStringList.Create;
  Data.Add('p2=some data');
  Data.Add('p3=some more data');
  xmlStream := TFileStream.Create('c:\file.xml', fmOpenRead);
  client.Post(host, Data, 'p1', '/', xmlStream, 'text/xml');
  xmlStream.Free;


Thanks in advance,
Leonardo Herrera
#19005
Posted: 02/11/2012 02:00:00
by Eugene Mayevski (EldoS Corp.)

The only way to change the order is to modify the source code of the Post method. As you have a license with source code, you can do this yourself quite easily (you just exchange places of two blocks of code which add streams with file and with form data). If this works for you - send us the changes and we will incorporate them to the code.


Sincerely yours
Eugene Mayevski
#19006
Posted: 02/11/2012 12:15:03
by Leonardo Herrera (Standard support level)
Joined: 02/14/2011
Posts: 66

Thank you, Eugene. I just wanted to make sure there wasn't another way - last time I just went ahead modifying code and you guys pointed me to a solution without having to modify sources, so I thought I should ask first.

Effectively, the server code I'm working against seems to be, hm, 'hand-crafted' so parameter order was crucial. This worked for me.
Code
function TElHTTPSClient.Post(const URL: string; Fields: TElStringList;
  const FileField: string {$IFDEF HAS_DEF_PARAMS} = '' {$ENDIF};
  const FileName: string {$IFDEF HAS_DEF_PARAMS} = '' {$ENDIF};
  FileStream: {$IFDEF SB_VCL}TStream {$ELSE}System.IO.Stream {$ENDIF}
    {$IFDEF HAS_DEF_PARAMS} = nil {$ENDIF};
  ContentType: string {$IFDEF HAS_DEF_PARAMS} = '' {$ENDIF};
  CloseStream: boolean {$IFDEF HAS_DEF_PARAMS} = false {$ENDIF}): integer;

  function BufToDataStream(Buf: ByteArray): TElDataStream;
  var
    MS: TMemoryStream;
  begin
    MS := {$IFDEF SB_VCL}TMemoryStream {$ELSE}MemoryStream {$ENDIF}.Create;
{$IFDEF SB_VCL}
    MS.Write(Buf[0], Length(Buf));
{$ELSE}
    MS.Write(Buf, 0, Length(Buf));
{$ENDIF}
    MS.Position := 0;
    result := TElDataStream.Create(MS, true);
  end;

var
  Boundary, ParamName, ParamValue: string;
  Buf: ByteArray;
  MS: {$IFDEF SB_VCL}TMemoryStream {$ELSE}MemoryStream {$ENDIF};
  I: integer;
  ValueExists: TSBBoolean;
  EncVal: string;
begin
  FDataStreams.Clear;
  FRequestParameters.ContentLength := -1;
  if FileStream <> nil then
  begin
    if ContentType = '' then
      ContentType := 'application/octet-stream';

    Boundary := '-----------------------------114782935826962';
    FRequestParameters.ContentType := 'multipart/form-data; boundary=' +
    {$IFDEF SB_VCL}System.Copy(Boundary, 3, Length(Boundary) - 2)
    {$ELSE}Boundary.SubString(2, Length(Boundary) - 2) {$ENDIF};

    // generate fields stream
    if (Fields <> nil) and (Fields.Count > 0) then
    begin
      SetLength(Buf, 0);
      for I := 0 to Fields.Count - 1 do
      begin
        SplitParam(Fields[I], ParamName, ParamValue, ValueExists);
        if not ValueExists then
          ParamValue := '';
        EncVal := EncodeFormData(ParamName, ParamValue, Boundary);
        Buf := SBConcatBuffers(Buf, BytesOfString(EncVal));
      end;
      FDataStreams.Add(BufToDataStream(Buf));
    end;

    // add file
    Buf := BytesOfString(Boundary + CRLFStr +
      'Content-Disposition: form-data; name="' + EncodeFieldValue(FileField) +
      '"; filename="' + EncodeFieldValue(FileName) + '"' + CRLFStr +
      'Content-Type: ' + ContentType + CRLFStr + CRLFStr);

    FDataStreams.Add(BufToDataStream(Buf));
    FDataStreams.Add(TElDataStream.Create(FileStream, CloseStream));

    Buf := BytesOfString(CRLFStr + Boundary + '--' + CRLFStr);
    FDataStreams.Add(BufToDataStream(Buf));
  end
  else
  begin // usual URLEncoded sendings
    if ContentType = '' then
      FRequestParameters.ContentType := 'application/x-www-form-urlencoded'
    else
      FRequestParameters.ContentType := ContentType;
    if Fields <> nil then
    begin
      SetLength(Buf, 0);
      for I := 0 to Fields.Count - 1 do
      begin
        SplitParam(Fields[I], ParamName, ParamValue, ValueExists);

        if ValueExists then
          EncVal := URLEncode(ParamName) + '=' + URLEncode(ParamValue)
        else
          EncVal := URLEncode(ParamName);

        if I = 0 then
          Buf := SBConcatBuffers(Buf, BytesOfString(EncVal))
        else
          Buf := SBConcatBuffers(Buf, BytesOfString('&' + EncVal));
      end;
      FDataStreams.Add(BufToDataStream(Buf));
    end;
  end;
  result := PerformRequest(SB_HTTP_REQUEST_POST, URL);
end;


Kind regards,
Leonardo Herrera
#19007
Posted: 02/11/2012 12:58:39
by Eugene Mayevski (EldoS Corp.)

Great, thank you for posting the code. We will incorporate changes.


Sincerely yours
Eugene Mayevski

Reply

Statistics

Topic viewed 842 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!