0

I'm using Indy to build both a client and server application using HTTP. On the Client, I'm using TIdHTTP and on the server I'm using TIdHTTPWebBrokerBridge with a web module. I need the Client to be able to post any type of data via a Stream to the Server. This is done through a universal command I have called /set?Key=API_KEY&Name=FILE_NAME where Key is the API Key for authentication and Name is the name of the file being posted.

On the client, I am posting the data like so:

function TInnoCloudClient.SetData(const Name: String; AStream: TStream): Bool;
var
  U: String;
begin
  U:= FServerURL; //Base URL of Server
  if Copy(U, Length(U)-1, 1) <> '/' then
    U:= U + '/';
  U:= U + 'get?Key='+Encode(FAPIKey);
  U:= U + '&Name='+Encode(Name);
  try
    FWeb.Post(U, AStream);
  except
    on e: exception do begin
      //Handle Exception
    end;
  end;
end;

This function is supposed to save the data inside AStream to a file on the server with the filename of Name. On the Server end, however, in the request handler, I see no corresponding TStream property in the Request which I can read this from.

In the Server, how do I acquire the data which I sent as a TStream descendant? I don't need to know how to save it or handle the request, just how do I obtain this Stream from the Request (TWebRequest)?

1 Answer 1

4

Use the TWebRequest.ReadClient() or TWebClient.ReadString() method to read the posted binary data, or the TWebRequest.RawContent property to retreive the posted data as an AnsiString.

Something like this should work:

procedure TWebModule1.GetAllDataAsStream(ARequest: TWebRequest; AStream: TMemoryStream);
var
  BytesRead, ContentLength: Integer;
  Buffer: array[0..1023] of Byte;
begin
  AStream.Clear;
  ContentLength := ARequest.ContentLength;
  while ContentLength > 0 do begin
    BytesRead := ARequest.ReadClient(Buffer[0], Min(ContentLength, SizeOf(Buffer)));
    if BytesRead < 1 then Break;
    AStream.WriteBuffer(Buffer[0], BytesRead);
    Dec(ContentLength, BytesRead);
  end;
  AStream.Position:= 0;
end;
Sign up to request clarification or add additional context in comments.

6 Comments

From what I saw in the Delphi docs and what my own tests seem to prove is that this code results in truncated content - the first 48k(?) will be missing. It's necessary to read content before calling ReadClient, which retrieves only the rest of the buffer after the first 48k of content .
I don't use WebBroker, so I can't say if that is true or not. All I do know is that TIdHTTPWebBrokerBridge uses TIdHTTPServer internally and exposes its functionality to WebBroker. The various TWebRequest.Read...() methods read directly from Indy's TIdHTTPRequestInfo.PostStream object if the client posted data, otherwise it reads from a TStringStream containing data from TIdHTTPRequestInfo.FormParams and TIdHTTPRequestInfo.UnparsedParams. So, if reading in the manner I showed above is missing data, chances are that it was already read prior to this code being run.
WebBroker's Content value reads from the same stream, and in the case of a client-posted stream, Content seeks the PostStream to the beginning, reads the entire stream, and then seeks it back to where it was previously, whereas the Read...() methods read from the current position onward.
@RemyLebeau - chances are that it was already read prior to this code being run - I understand, yet i have code that seems to prove otherwise. A colleague sent me this link also along the same lines: Re: Reading with IDThhp.Post sended data in ISAPI-DLL: data get messed up - Hello Remy, sorry for the inconvenience but your code doesn't work:
I have never used DataSnap/WebBroker, so I can't comment on how it actually works. I can only comment on what I see in the TIdHTTPWebBrokerBridge source code.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.