Discussion:
[fpc-devel] Avoid exception if FPHTTPClient cannot connect to server?
Werner Pamler
2017-07-31 11:52:40 UTC
Permalink
Here is a little demo program which uses fphttpclient to download some
file from some server.

If the URL exists everything is fine (note on Windows, that the OpenSSL
dlls must be copied to the exe directory for the demo to work). If the
URL does not exist, but the server responds, the program returns the
well-known error 404 (if the 404 has been added to the response codes in
HTTPMethod) - also fine. But if a connection to the server cannot be
established -- maybe because the server URL is wrong -- then the program
creates an exception. Synapse, on the other hand, does not crash on this
occasion, it just returns an error 500. This behavior appears to be much
more consistent than fpc's.

Is this intentional? Or should I report a bug?

// ------------------ snip ----------------------

program project1;

{$mode objfpc}{$H+}

uses
Sysutils, Classes, fphttpclient;

function DownloadURL(URL: String; AStream: TStream; out AErrMsg:
String): Boolean;
begin
AErrMsg := '';
with TFPHTTPClient.Create(nil) do
try
AllowRedirect := true;
HTTPMethod('GET', URL, AStream, [200, 404{, 500}]);
Result := (ResponseStatusCode = 200);
if not Result then
AErrMsg := 'Error code ' + IntToStr(ResponseStatusCode) + ': '
+ ResponseStatusText;
finally
Free;
end;
end;

const
// existing URL --> ok
//URL =
'https://sourceforge.net/projects/freepascal/files/Documentation/3.0.2/doc-txt.zip/download';

// Existing server, but not existing URL --> error 404
//URL =
'https://sourceforge.net/projects/freepascal/files/Documentation/3.0.2/doc-txt.zip/download-1';

// Non-existing server
URL =
'https://sourceforge-1.net/projects/freepascal/files/Documentation/3.0.2/doc-txt.zip/download-1';

var
stream: TStream;
errmsg: String;

begin
stream := TFileStream.Create('test.zip', fmCreate);
try
if DownloadURL(URL, stream, errmsg) then
WriteLn('Download of ' + URL + ' completed.')
else
WriteLn(errmsg);
finally
stream.Free;
end;

{$IFDEF WINDOWS}
WriteLn('Press ENTER to quit.');
ReadLn;
{$ENDIF}
end.

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/c
Karoly Balogh (Charlie/SGR)
2017-07-31 12:04:59 UTC
Permalink
Hi,
Post by Werner Pamler
If the URL exists everything is fine (note on Windows, that the OpenSSL
dlls must be copied to the exe directory for the demo to work). If the
URL does not exist, but the server responds, the program returns the
well-known error 404 (if the 404 has been added to the response codes in
HTTPMethod) - also fine. But if a connection to the server cannot be
established -- maybe because the server URL is wrong -- then the program
creates an exception. Synapse, on the other hand, does not crash on this
occasion, it just returns an error 500. This behavior appears to be much
more consistent than fpc's.
I disagree. I think generating any HTTP error code locally, which should
always come from the server is anything but a good idea. It could mask
true server issues from network connectivity issues, which distinction
could be still relevant and the client application might want to employ
different error mitigation techniques to solve one or the other case.
Post by Werner Pamler
Is this intentional? Or should I report a bug?
The code in FPHTTPClient has an explicit Raise line when the connection is
unsuccessful. So I'd say this is not a bug, but by design. Maybe this
behavior should be better documented or the Exception itself could be more
descriptive tho', but I haven't tried this.

(Note that I generally dislike APIs which are designed to throw
exceptions, but anyway, in this case it looks like it's by design and it's
still better than just generating a random HTTP code locally.)

Charlie
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc
Werner Pamler
2017-07-31 13:10:26 UTC
Permalink
Agreed. This is the same situation as with string-to-number conversion:
StrToFloat fires an exception if the string is not a valid float, but
there's also a "TryStrToFloat" which by-passes the exception and just
returns a false in case of an error. Why not having something like a
"TryGet" which returns true only if the file is successfully downloaded
and false in all other cases (HTTP error, or no connection)?

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/list
Michael Van Canneyt
2017-07-31 13:27:41 UTC
Permalink
Post by Werner Pamler
StrToFloat fires an exception if the string is not a valid float, but
there's also a "TryStrToFloat" which by-passes the exception and just
returns a false in case of an error. Why not having something like a
"TryGet" which returns true only if the file is successfully downloaded
and false in all other cases (HTTP error, or no connection)?
Because that would require to completely change the interface and possibly
implementation of underlying/intermediate methods, which rely now on an
exception being thrown.

It's of course possibly to make a TryGet which calls get and catches the exception,
but you can make such a function yourself, I really don't see the value:
in my experience, you usually want to know why the call failed, and then the
exception is useful. A boolean value of 'false' is not very descriptive.

Michael.
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.

Michael Van Canneyt
2017-07-31 12:37:57 UTC
Permalink
Post by Werner Pamler
Here is a little demo program which uses fphttpclient to download some
file from some server.
If the URL exists everything is fine (note on Windows, that the OpenSSL
dlls must be copied to the exe directory for the demo to work). If the
URL does not exist, but the server responds, the program returns the
well-known error 404 (if the 404 has been added to the response codes in
HTTPMethod) - also fine. But if a connection to the server cannot be
established -- maybe because the server URL is wrong -- then the program
creates an exception. Synapse, on the other hand, does not crash on this
occasion, it just returns an error 500. This behavior appears to be much
more consistent than fpc's.
Is this intentional? Or should I report a bug?
This is very intentional.

Returning a 500 on connection error is plain wrong.
Status 500 indicates an internal error on the server.
This is an 'agreement' governed by a RFC.

But if the connection cannot be made, there was no server,
and there cannot be a server status either.

Michael.
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin
Loading...