Jump to content
billyb

how to extract from tidhttpserver PostStrean

Recommended Posts

I have need to send files to a Delphi service. I am able to send the files, but have not figured out how to extract the multipart items when received.

 

procedure TForm15.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  ARequestInfo.PostStream.Seek(0, soFromBeginning);
  Memo1.Lines.LoadFromStream(ARequestInfo.PostStream);
 end;
 

 

Here is what I get when file is posted with a 2 other values added to the stream. What I need is a way to access each item. 

 

How do I ask for "type" and get back "OPRS"

How do I ask for "ID" and get back "1234"

How do I ask for "filename" and get back "test.pdf"

How do I ask for actual file contents and save to memory stream to then write to disk

 

----------040224182640701
Content-Disposition: form-data; name="type"
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

OPRS
----------040224182640701
Content-Disposition: form-data; name="ID"
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

1234
----------040224182640701
Content-Disposition: form-data; name="file"; filename="test.PDF"
Content-Type: application/pdf
Content-Transfer-Encoding: binary

%PDF-1.6
%âãÏÓ
290 0 obj
<<
/Border [ 0 0 0 ]
/Contents (þÿ

Share this post


Link to post
Posted (edited)

TIdHTTPServer does not currently support extracting values from a "multipart/form-data" request (see https://github.com/IndySockets/Indy/issues/138). You have to parse the raw MIME data in the PostStream yourself. You can use Indy's TIdMessageDecoderMIME class to help you with that.  See https://en.delphipraxis.net/topic/10918-multipartform-data-vs-x-www-form-urlencoded-indy-http-server/ for an example.

Edited by Remy Lebeau

Share this post


Link to post

I added your code and the section where you create the DEST stream appears is not containing the value

If I add

              sl:=tstringlist.Create;
              sl.LoadFromStream(dest);
my stringlist is empty

 

What would be great is a function you can call that returns a value for a name

example

  GetPostStreamValue(aname:string,var avalue:String;,var astream):boolean

 

where aname is the item name (Like "type")

avalue = the value for the name (like "OPRS")

astream = a memory stream you pass in that gets filled with the file contents when Content-Transfer-Encoding: binary

 

 

 

      case Decoder.PartType of
        mcptText, mcptAttachment:
        begin
          Dest := TMemoryStream.Create;
          try
            NewDecoder := Decoder.ReadBody(Dest, MsgEnd);
            try
              // use Dest as needed...
              sl:=tstringlist.Create;
              sl.LoadFromStream(dest);
            finally
              Decoder.Free;
              Decoder := NewDecoder;
            end;
          finally
            Dest.Free;
          end;
        end;

 

Share this post


Link to post

I found the issue with the empty stringlist. I forgot to do a seek(0,0).

This is a lot more complicated then I expected.

It appears I have to manually parse the dest stream to get the name and the contents as it contains both.

Content-Disposition: form-data; name="file"; filename="test.PDF"
Content-Type: application/pdf
Content-Transfer-Encoding: binary

%PDF-1.6
%âãÏÓ

 

 

I saw that Remy posted a enhancement request back in 2017 to add mutlipart parsing. Sad it was not added.

 

Bill B

Share this post


Link to post
Posted (edited)
3 hours ago, billyb said:

What would be great is a function you can call that returns a value for a name

example

  GetPostStreamValue(aname:string,var avalue:String;,var astream):boolean

 

where aname is the item name (Like "type")

avalue = the value for the name (like "OPRS")

astream = a memory stream you pass in that gets filled with the file contents when Content-Transfer-Encoding: binary

That's not going to happen anytime soon, if ever. You will have to write your own function if you want that kind of functionality.

3 hours ago, billyb said:

This is a lot more complicated then I expected.

MIME is complicated.

Quote

It appears I have to manually parse the dest stream to get the name and the contents as it contains both.

No, the Dest stream only contains the body content (that is why the method is called ReadBody()). The Decoder has a Headers property, which is populated by the call to the ReadHeaders() method. The headers are stored as a TStrings in "name=value" format. You can use Indy's ExtractHeaderSubItem() function to get the "name" and "filename" attribute values from the "Content-Disposition" header.

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×