ExposureRoom Home
  Log in Sign Up
Shiv's Website
Shiv Kumar
United States
Friends: 77
Focused on : 2
 
       
                                                             

Server Push using ISAPI

Not Rated YetNot Rated YetNot Rated YetNot Rated YetNot Rated Yet0votes
January 09, 2008 12:05 PM  Views:127   Favorited:0 Comments:0
Filed Under:  Programming
Tags:  Delphi, ISAPI
 
Before we start with the explanation of the protocol and the project, lets take a look at the demos.

I found that IE does NOT support the server push protocol as specified by the W3C. These demos and therefore the project work best with NetScape.

Continuous Stream of Text
Continuous Stream of Images

The normal HTTP protocol behavior is to terminate the connection as soon as an HTTP response has been sent.

In server push, an HTTP connection is held open for an indefinite period of time. This is controlled at the server end. The server then has the option to continuously send documents to the client (browser) while it does some background processing simultaneously. The client has the option of stopping the flow of data or terminating the connection on its end. The advantage of this is that the server can do rudimentary synchronization. Any type of document (HTML, plain text, audio, video, images etc.) can be part of such a sequence since the initiative for reloading is always on the server's side.

State-full information can easily be kept inside the server since that one connection is purely maintained for that one client. The server is free to respond to other requests but the current connection with the client is maintained thus maintaining state as well. Server push can also be used for parts of documents. Unfortunately, server push has the disadvantage of possibly many open connections and running processes on the server, which consume much of the server's resources.

The MIME message format is used by HTTP to encapsulate data returned from a server in response to a request. MIME has a standard facility for representing many pieces of data in a single message (or HTTP response). This facility uses a standard MIME type called multipart/mixed.

The Multipart Content-Type

In the case of multiple part messages, in which one or more different sets of data are combined in a single body, a "multipart" Content-Type field must appear in the entity's header. The body must then contain one or more "body parts", each proceeded by an encapsulation boundary, and the last one followed by a closing boundary. Each part starts with an encapsulation boundary, and then contains a body part consisting of header area, a blank line, and a body area. Thus a body part is similar to an RFC 822 message in syntax, but different in meaning.

To begin with, NO header fields are actually required in body parts. A body part that starts with a blank line, therefore, is allowed and is a body part for which all default values are to be assumed. In such a case, the absence of a Content-Type header field implies that the encapsulation is plain US-ASCII text. The only header fields that have defined meaning for body parts are those names that begin with "Content-". All other header fields are generally to be ignored in body parts. Other fields are permitted to appear in body parts but should not be depended on.

As stated previously, each body part is preceded by an encapsulation boundary. The encapsulation boundary MUST NOT appear inside any of the encapsulated parts. That is, it should be unique. Thus, it is crucial that the composing agent be able to choose and specify the unique boundary that will separate the parts.

The primary subtype for multipart - mixed, is intended for use when the body parts are independent and intended to be displayed serially. Any multipart subtypes that an implementation does not recognize should be treated as being of subtype "mixed".

The Content-Type field for multipart entities requires one parameter, "boundary", which is used to specify the encapsulation boundary. The encapsulation boundary is defined as a line consisting entirely of two hyphen characters ("-", decimal code 45) followed by the boundary parameter value from the Content-Type header field.

What does all this mean? Lets take a look at an example with some real data. The MIME header should look like this:

  Content-type: multipart/mixed;boundary="r46ghyST8S2mdSpm0"
boundary here is an arbitrary string that shuld not appear anywhere in the body. The MIME type should be followed by two CRLF pairs producing a blank line and then followed by the boundary that is also preceded by a blank line and two hyphens (such as this:
  Content-type: multipart/mixed;boundary="r46ghyST8S2mdSpm0"
  
  
  -- r46ghyST8S2mdSpm0
The --r46ghyST8S2mdSpm0 is the indicator of the beginning (the boundary) of the actual body that needs to be sent. The connection will remain open until:
  1. The connection is dropped by the client the terminating boundary is sent
The terminating boundary is the same as the boundary with two hyphens appended to the end. So the terminating boundary will look like this:
  r46ghyST8S2mdSpm0--
So if the body of our message was Please wait we need to send data back to the client that looks like this:
  Content-type: multipart/mixed;boundary="r46ghyST8S2mdSpm0"
  CRLF  
  CRLF  
  --r46ghyST8S2mdSpm0
  Content-type: text/html
  Please Wait...
  --r46ghyST8S2mdSpm0
  CRLF
The next body part we want to send to the client should then consist of:
  CRLF
  --r46ghyST8S2mdSpm0
  Content-type: text/html
  Please Wait...
  --r46ghyST8S2mdSpm0
  CRLF
and so on.

Note that the encapsulation boundary must occur at the beginning of a line, i.e., following a CRLF, and that that initial CRLF is considered to be part of the encapsulation boundary rather than part of the preceding part. The boundary must be followed immediately either by another CRLF and the header fields for the next part, or by two CRLFs, in which case there are no header fields for the next part and it is therefore assumed to be of Content-Type text/plain.

NOTE: The CRLF preceding the encapsulation line is considered part of the boundary so that it is possible to have a part that does not end with a CRLF (line break). Body parts that must be considered to end with line breaks, therefore, should have two CRLFs preceding the encapsulation line, the first of which is part of the preceding body part, and the second of which is part of the encapsulation boundary. The requirement that the encapsulation boundary begins with a CRLF implies that the body of a multipart entity must itself begin with a CRLF before the first encapsulation line.

The Project

The project is a simple project that demonstrates this feature of the HTTP protocol. The full source of the project is listed below:
unit uMain;
interface
uses
  Windows, Messages, SysUtils, Classes, HTTPApp;
type
  TWebModule1 = class(TWebModule)
    procedure WebModuleCreate(Sender: TObject);
    procedure WebModule1WebActionItem1Action(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    procedure WebModule1waImageAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    Boundary : string;
    MultipartContentType : string;
    { Private declarations }
  public
    { Public declarations }
  end;
var
  WebModule1: TWebModule1;
implementation
{$R *.DFM}
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
  Boundary := 'erERT45GSqJtasftnd31Afghdrte6';
  MultipartContentType := 'Content-type: multipart/x-mixed-replace';
end;
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Request.WriteString('HTTP/1.1 200'   #13#10);
  Request.WriteString(Format('%s;boundary="%s"'#13#10#13#10, [MultipartContentType, Boundary]));
  repeat
    Request.WriteString(#13#10   '--'   Boundary   #13#10);
    Request.WriteString('Content-type: text/html'   #13#10#13#10);
    Request.WriteString('<title>Server Push Example</title>'   #13#10);
    Request.WriteString('<body>'   #13#10);
    Request.WriteString('<h3>'   FormatDateTime('dddd, dd mmm yyyy hh:nn:ss', Now)   '</h3>'   #13#10);
    Request.WriteString('</body>'   #13#10);
    Request.WriteString('--'   Boundary   #13#10);
    Sleep(1000);
  until (False);
end;
procedure TWebModule1.WebModule1waImageAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  MemStrm : TMemoryStream;
  Images  : array[0..9] of string;
  ImageNo : Integer;
begin
  Images[0] := 'C:\Inetpub\wwwroot\images\thumb_1.jpg';
  Images[1] := 'C:\Inetpub\wwwroot\images\thumb_2.jpg';
  Images[2] := 'C:\Inetpub\wwwroot\images\thumb_3.jpg';
  Images[3] := 'C:\Inetpub\wwwroot\images\thumb_4.jpg';
  Images[4] := 'C:\Inetpub\wwwroot\images\thumb_5.jpg';
  Images[5] := 'C:\Inetpub\wwwroot\images\thumb_6.jpg';
  Images[6] := 'C:\Inetpub\wwwroot\images\thumb_7.jpg';
  Images[7] := 'C:\Inetpub\wwwroot\images\thumb_8.jpg';
  Images[8] := 'C:\Inetpub\wwwroot\images\thumb_9.jpg';
  Images[9] := 'C:\Inetpub\wwwroot\images\thumb_10.jpg';
  ImageNo := 0;
  MemStrm := TMemoryStream.Create;
  try
    Request.WriteString('HTTP/1.1 200'   #13#10);
    Request.WriteString(Format('%s;boundary="%s"'#13#10#13#10, [MultipartContentType, Boundary]));
    repeat
      MemStrm.LoadFromFile(Images[ImageNo]);
      MemStrm.Position := 0;
      Request.WriteString(#13#10   '--'   Boundary   #13#10);
      Request.WriteString('Content-type: image/jpeg'   #13#10#13#10);
      Response.SendStream(MemStrm);
      Request.WriteString('--'   Boundary   #13#10);
      if ImageNo = High(Images) then
        ImageNo := -1;
      Inc(ImageNo);
      Sleep(1000);
    until (False);
  finally
    MemStrm.Free; {The Web server normally takes care of this }
  end;
end;
end.

Sending Text / HTML

The first action waTime continuously streams data in the form of HTML. This aspect is primarily controlled by the line
    Request.WriteString('Content-type: text/html'   #13#10#13#10);
to be continued...

Sending a Stream of Images

to be continued...

Comments have been Disabled for this post





Menus

Theme

Privacy Policy  |  Terms Of Service  |  Contact Us  |  Support  |  Help/FAQs  |  News