4

I have been using the Synapse library to download files from the internet, but I have recently converted my application to use INDY instead and I am missing one of the nicer features in the Synapse library which is the ability to easily get the Mime-Type of a file that I was downloading from a server before saving it to my local machine. Does INDY have this feature and if so how do I go about accessing it?

2 Answers2

9

You can issue an HTTP HEAD request and check the Content-Type header. Before you actually GET the file (download) :

procedure TForm1.Button1Click(Sender: TObject);
var
  Url: string;
  Http: TIdHTTP;
begin
  Url := 'http://yoursite.com/yourfile.png';
  Http := TIdHTTP.Create(nil);
  try
    Http.Head(Url);
    ShowMessage(Http.Response.ContentType); // "image/png"
  finally
    Http.Free;
  end;
end;

The ContentType you receive back depends on the web server implementation and is not guaranteed to be the same on each and every server.


The other option, is to actually GET the file and save it's content to a memory stream such as TMemoryStream (not to a local file). Indy provides an overload:

Http.Get(Url, AStream);

Then you check the Http.Response.ContentType, and Save the stream to file: AStream.SaveToFile.


Not sure about the relevancy here, but note also that Indy can return/guess the mime type of a local file as well (given a file extension). with GetMIMETypeFromFile (uses IdGlobalProtocols). See also here.

Community
  • 1
  • 1
kobik
  • 21,001
  • 4
  • 61
  • 121
  • Thanks for the reply. It seems like a backwards way of doing things compared to the way that Synapse works, but it works in the end that is all that matters. – kathrine jensen Aug 25 '14 at 09:53
  • 2
    "It seems like a backwards way...": I never used Synapse. you could edit your question and post the code you used with Synapse and I might try to guess how it's done there (I also believe source code is available). What I do know, is that any HTTP client (Idny/Synapse/other) either needs to request HEAD - which will not download the server content, or GET - which will download the content first (or stream it to memory). See my edit. – kobik Aug 25 '14 at 10:46
  • Yeah with Synapse you just check for the mimtype of the file as it's getting downloaded and before it's actually saved. I guess your stream code is closer to the way that Synapse does it, but either way it works so I am not complaining, just not what I was used to. – kathrine jensen Aug 25 '14 at 22:30
2

Or you can build your function

function GetMIMEType(sFile: TFileName): string;
var aMIMEMap: TIdMIMETable;
begin
  aMIMEMap:= TIdMIMETable.Create(true);
    try
  result:= aMIMEMap.GetFileMIMEType(sFile);
    finally
      aMIMEMap.Free;
    end;
  end;

And then call

procedure HTTPServerGet(aThr: TIdPeerThread; reqInf: TIdHTTPRequestInfo;
                                             respInf: TIdHTTPResponseInfo);
var localDoc: string;
    ByteSent: Cardinal;
begin
  //RespInfo.ContentType:= 'text/HTML';
  Writeln(Format('Command %s %s at %-10s received from %s:%d',[ReqInf.Command, ReqInf.Document, 
                       DateTimeToStr(Now),aThr.Connection.socket.binding.PeerIP,
                       aThr.Connection.socket.binding.PeerPort]));
  localDoc:= ExpandFilename(Exepath+'/web'+ReqInf.Document);
  RespInf.ContentType:= GetMIMEType(LocalDoc);
  if FileExists(localDoc) then begin
    ByteSent:= HTTPServer.ServeFile(AThr, RespInf, LocalDoc);
    Writeln(Format('Serving file %s (%d bytes/ %d bytes sent) to %s:%d at %s',
          [LocalDoc,ByteSent,FileSizeByName(LocalDoc), aThr.Connection.Socket.Binding.PeerIP,
           aThr.Connection.Socket.Binding.PeerPort, dateTimeToStr(now)]));
  end else begin
    RespInf.ResponseNo:= 404; //Not found RFC
    RespInf.ContentText:=
          '<html><head><title>Sorry WebBox Error</title></head><body><h1>' +
    RespInf.ResponseText + '</h1></body></html>';
  end; 
end;
kobik
  • 21,001
  • 4
  • 61
  • 121
  • I already mentioned Indy's `GetMIMETypeFromFile` (Which I kinda regret I did). Your code is the **server** side implementation of reporting back the content type. OP asks about HTTP **client**. but on the other hand this shows the OP what I wrote in my answer "The ContentType you receive back depends on the web server implementation and is not guaranteed to be the same on each and every server" :) – kobik Aug 25 '14 at 10:59