Re: Http Server

Giganews Newsgroups
Subject: Re: Http Server
Posted by:  Remy Lebeau \(Indy Team\) (no.spam@no.spam.com)
Date: Wed, 26 Aug 2009

"Richard" <rwskinner@ATccwipDOTnet> wrote in message
news:93A2F74A5E8EE340rwskinner@ATccwipDOTnet...

> I do have a problem now that each time I serve a static web html page
> from disk, the client (IE6) always ask to Open or Save the File instead
> of simply displaying the page.

The only way it would do that is if you are not specifying the correct
Content-Type value, or if you are including a Content-Disposition header.

> Also, the IE Dialog that comes up shows a weird filename which
> is part of the IP Address like....

Please show the actual HTTP reply headers that the server is generating.

>      if
> AnsiSameText(Copy(LocalDoc,1,Length(edRoot)),ExtractFilePath(edRoot)) then

You should look at using the VCL's AnsiStartsText() function, or Indy's
TextStartsWith() function, ie:

    if AnsiStartsWith(ExtractFilePath(edRoot), LocalDoc) then

    if TextStartsWith(LocalDoc, ExtractFilePath(edRoot)) then

>        if AnsiSameText(aRequestInfo.Command, 'HEAD') then

Alternatively:

    if aRequestInfo.CommandType = hcHEAD then

>          ResultFile := TFileStream.Create(localDoc,fmOpenRead or
> fmShareDenyWrite);
>          Try
>            AResponseInfo.ResponseNo := 200;
>            AResponseInfo.ContentType := GetMIMEType(LocalDoc);
>            AResponseInfo.ContentLength := ResultFile.Size;
>          Finally
>            ResultFile.Free;
>          End;

Indy has a FileSizeByName() function so you don't have to retreive the Size
manually, ie:

    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentType := GetMIMEType(LocalDoc);
    AResponseInfo.ContentLength := FileSizeByName(LocalDoc);

> AResponseInfo.CustomHeaders.Values['Content-Disposition'] := 'filename=' +
> AnsiQuotedStr(ExtractFileName(LocalDoc), '"');

That Content-Disposition header value is missing key data.  'filename' is an
attribute for that header, not the main value.  You need to include
'attachment' as the main value.  Also, you should not be using the
CustomHeaders property at all for filling in the Content-Disposition header
anyway.  You need to use the TIdHTTPResponseInfo.ContentDisposition property
instead, ie:

    AResponseInfo.ContentDisposition := 'attachment; filename=' +
AnsiQuotedStr(ExtractFileName(LocalDoc), '"');

> AResponseInfo.ServeFile(AContext,LocalDoc);

TIdHTTPResponseInfo.ServeFile() adds its own Content-Type and
Content-Disposition headers if the TIdHTTPResponse.ContentType and
TIdHTTPResponseInfo.ContentDisposition properties are empty
(ContentDisposition is empty in your code).  Since you are calling
ServeFile() for all of your files, including your HTML pages, it makes sense
why your web browser is trying to save your HTML pages rather than display
them - your server is explicitally telling them to save the file by
including a Content-Disposition header!  You need to stop calling
ServeFile() for your HTML pages, and just use the
TIdHTTPResponseInfo.ContentStream property, like you were originally doing.

With all of that said, try this code:

procedure TWebServerForm.HttpServerCommandGet(AContext: TidContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
....
var
  LocalDoc: String;
begin
  // Log the request
  if ((aRequestInfo.AuthUsername <> 'xxxx') or (aRequestInfo.AuthPassword <>
'xxxx')) then
  begin
    AuthFailed;
    Exit;
  end;
  if TextIsSame(aRequestinfo.Document, '/datalogs.html') then
  begin
    ServeDataLogPage(AContext, aRequestInfo, aResponseInfo);
  end
  else if TextIsSame(aRequestinfo.Document, '/mbregs.html') then
  begin
    ServeMBPage(AContext, aRequestInfo, aResponseInfo);
  end else
  begin
    edRoot := MyProgramPath + 'Web\';
    if aRequestInfo.Document = '/' then begin
      LocalDoc := ExpandFileName(edRoot + '/index.html');
    end else begin
      LocalDoc := ExpandFileName(edRoot + aRequestInfo.Document);
    end;
    if not FileExists(LocalDoc) then
    begin
      AResponseInfo.ResponseNo := 404;
      AResponseInfo.ContentText :=
'<html><head><title>Error</title></head><body><h1>' +
AResponseInfo.ResponseText + '</h1></body></html>';
    end
    else if not TextStartsWith(LocalDoc, edRoot) then
    begin
      AccessDenied;
    end else
    begin
      AResponseInfo.ResponseNo := 200;
      if aRequestInfo.CommandType = hcHead then
      begin
        AResponseInfo.ContentType := GetMIMETypeFromFile(LocalDoc);
        AResponseInfo.ContentLength := FileSizeByName(LocalDoc);
      end
      else if TextIsSame(ExtractFileExt(LocalDoc), '.CSV') then
      begin
        AResponseInfo.ContentType := 'application/excel';
        AResponseInfo.ServeFile(LocalDoc);
      end else
      begin
        AResponseInfo.ContentType := GetMIMETypeFromFile(LocalDoc);
        AResponseInfo.ContentStream := TFileStream.Create(LocalDoc,
fmOpenRead or fmShareDenyWrite);
      end;
    end;
  end;
end;

--
Remy Lebeau (TeamB)

Replies

In response to

Http Server posted by Richard on Wed, 26 Aug 2009