2

I've got an Indy server, and having it send a file when the URL requests a file is trivial and always seems to work right.

But I'm also trying to set up a second case that looks like this:

http://example.com/getFile.html?filename=myImage.png

(This works with dynamically generated content, so asking for a static file wouldn't work.) I'm using a custom Indy client and calling TIdHTTP.Get to retrieve all these files, and in the second use case, it seems to be following this algorithm:

Roll 1D4.  If you rolled 2 or higher, download correctly.
Otherwise, roll 1D6 against this table of Indy exceptions and
raise one of them.
If a random exception is raised, it MUST NOT be caught inside
of Indy code.

So far the common ones seem to be EIdHTTPProtocolException, EIdClosedSocket, and EIdNotConnected, but I've seen a few others as well. Setting up an exception handler to catch these and retry the download works sometimes, and other times it just raises more exceptions, again seemingly at random with no deterministic principle behind it.

The fact that this never happens using the static download use case tells me that there's probably something strange going on under the hood in the second use case that my code isn't accounting for properly.

The code is really quite simple. On the client side:

procedure TdmConnection.GetFile(const URL: string; stream: TStream);

  procedure Retry;
  begin
     sleep(100);
     stream.Size := 0; //clear any aborted partial download
     http.Get(URL, stream);
  end;

begin
   try
      http.Get(URL, stream);
   except
      on EIdClosedSocket do
        Retry;
      on EIdNotConnected do
        Retry;
      on EIdHTTPProtocolException do
        Retry;
   end;
end;

And on the server side, the request runs a script that produces the file (correctly; I've verified that part) and tells the Indy server to return it as the HTTP response. I've tried simply opening a TFileStream and assigning it to Response.ContentStream, and I've tried calling the ServeFile method on the Response object, and I still end up getting the same errors on the client side. The relevant part of the server code looks like this:

  if lServeFile <> '' then begin //variable set by the script
     if lServeFile = '***' then
        response.ResponseNo := 404
     else begin
       response.ResponseNo := 200;
       response.ServeFile(AContext, lServeFile);
     end;
  end;

Any experienced Indy users out there know what I'm doing wrong? Using stock Indy 10 that came with Delphi XE.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • I've used ServeFile, but for some reason, I've ended up using WriteFile, don't recall why, maybe you can try that? –  Jun 30 '12 at 14:07
  • There is no problem with your client code. Please show your server code. – Remy Lebeau Jun 30 '12 at 15:45
  • @Remy: Edited to add the server code. It really is just that simple. – Mason Wheeler Jun 30 '12 at 15:55
  • There is no way the code you have shown so far can be causing the behavior you have described, so it has to be in code you have not shown. How does `lServeFile` get prepared? What does `Roll 1D4` and `Roll 1D6` refer to? – Remy Lebeau Jun 30 '12 at 22:26
  • @Remy: Gamer terminology. 1dX means "one die with X sides". As in, what's happening appears to be completely random. – Mason Wheeler Jun 30 '12 at 23:10
  • 1
    Even if your server code were raising random exceptions, `TIdHTTPServer` would catch and translate them into HTTP `500` responses for you, which would then raise `EIdHTTPProtocolException` exceptions on the client side. The fact that you are seeing other exception types being raised client-side means that something other than just HTTP handling is occuring. I suggest you use the debugger to analyze the call stack when those other exceptions occur and trace what is really happening. – Remy Lebeau Jul 01 '12 at 00:05
  • As for `EIdHTTPProtocolException` specifically, it might tell you what happened server-side. When the server catches an exception, the value of the `Exception.Message` property becomes the value of the `EIdHTTPProtocolException.ErrorMessage` property. – Remy Lebeau Jul 01 '12 at 00:07

1 Answers1

1

Nevermind, the problem wasn't in Indy. Upon further debugging I eventually figured out that there were two threads both using the IdHTTP component, and sometimes they were using it at the same time. Guaranteeing that each thread would have its own IdHTTP fixed the problem.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • Don't be so quick to blame indy, the bug is usually in your own code. but not allways [as I pointed out here](http://stackoverflow.com/a/4414918/407361) – Mike Taylor Sep 26 '12 at 13:12