Pluggable protocol

There is not much difference between the pluggable namespacehandler and a pluggable protocolhandler of the following type:

myhttp://www.euromind.com/iedelphi

Declare the name of your new protocol in RegisterNameSpace:

procedure TForm1.FormCreate(Sender: TObject);
begin
CoGetClassObject(Class_Protocol, CLSCTX_SERVER, nil, IClassFactory, Factory);
CoInternetGetSession(0, InternetSession, 0);
InternetSession.RegisterNameSpace(Factory, Class_Protocol, 'myhttp', 0, nil, 0);
end;

However, in the namespacehandler demo you had the functionality of the default http-protocol to build on. When you register a new protocol, you don't automatically have this, but must build it from scratch and it is not always an easy job.

To make the work easier you can aggregate the default http-protocol. Use TAggregatedObject or just use TComObject (which support aggregating in D4 & D5).  Override function Initialize and create an instance of the original http-protocol:

procedure TProtocol.Initialize;
begin
inherited;
if
FDefaultProtocol = nil then
CoCreateInstance(Class_HttpProtocol, Iunknown(Self), CLSCTX_INPROC_SERVER,
IUnknown, FDefaultProtocol);
end;

Class_HttpProtocol is not included in urlmon.pas, but you can find it in WIN32 SDK:

Class_HttpProtocol: TGUID = '{79eac9e2-baf9-11ce-8c82-00aa004ba90b}';

Use this instance of http-protocol as the inner object and your implementation of IInternetProtocol as the outer object. Now you can deligate most of the work to the original protocol. In each function you can call the http-protocol before or after your modifications, e.g:

function TProtocol.Read(pv: Pointer; cb: ULONG; out cbRead: ULONG): HResult;
begin

//Make your modifications here ///

Result := (FDefaultProtocol as IInternetprotocol).Read(pv, cb, cbread);

//Make your modifications here ///

end;

In this way the new protocol is just a simple wrapper around the default http-protocol.

To create it as a permanent pluggable protocol, put your protocol in a DLL and add a key named "myhttp" (or what you choose as name for your protocol) to the registry under HKEY_CLASSES_ROOT\PROTOCOLS\Handler. Under the new key, HKEY_CLASSSES_ROOT\PROTOCOLS\Handler\myhttp, the string value, CLSID, must be assigned the CLSID of your protocol handler. 

The following demo demonstrates how to aggregate the default http-protocol in a new protocol. Notice the implementation of IInternetProtocolSink and IInternetBindInfo. This is a simple trick, so all calls from the http-protocol to the transaction handler can be captured, by replacing IOProtSink and IOBindInfo with self when function "start" is deligated to the original http-protocol:

Result := (FDefaultProtocol as IInternetprotocol).Start(szUrl, self, self, grfPI, dwReserved);

AppHelper.pas is included to make debugging easier.The demo is only tested in D5 but should work also in D4.

Enjoy!

 

Download Temporary pluggable protocol demo

Temporary pluggable protocol demo (D4 & D5)