HomePage Delphi Library Shopping

Web Programming in Delphi

by Bryan Valencia

Chapter 1

The Basics

In many ways a web application is much simpler than an average Delphi program. Where a standard Windows application might be required to open, accept inputs, process, update, have provisions for cancelling, and error trapping, the architecture of a web application is very limited. There is one call to open the program, which contains parameters, and the program must return a file stream to be returned to the brower at the other end.

As you have no doubt noticed, the web is a place of hypertext documents. The word hypertext merely means that it can contain an active link to another document. In this way, by following links on web pages, you can journey all over the web.

As intriguing as that is, and considering the ability to embed graphics, sound, and other media into web pages, a standard HTML page is still a rather flat and lifeless place. Unless the webmaster constantly changes the content of the web page, you get exactly the same document every time. Wouldn't it be better if a web site could let the user decide what content he wanted to see? Let them upload their comments, sign guestbooks, answer surveys?

This is what makes for an exciting web site that users will bookmark and return to. It is called active content. While there are several ways to accomplish this, they all use a web mechanism called the Common Gateway Interface, or CGI.

CGI is a set of rules defining how data can be streamed in and out of a webserver. In essence, the rules go like this:

The console device is usually the keyboard and screen for a DOS application. But they can be redirected at will by any program. There used to be a trick for debugging text printers in the DOS days. If you typed COPY CON LPT1:, everything entered at the keyboard was redirected to the printer port. This statement means "Copy the input of the console to the printer port".

So, for the purposes of a CGI application, there is one place to gather input, and one place to send output... except in the web world, input is referred to as a request, and output is called a response.

Requests have a very limited vocabulary, and a very strict format. They must contain the address the request is being sent to, the return address to send the response to, the request itself, and the parameters to be passed in.

Responses can be in any format the client's browser can interpret. If the response is a ZIP file, the client may ask the user to save or open it. If it's a GIF or JPEG graphic, the browser will probably just show it. HTML will be displayed. There is almost no limit to what can be returned to a client via a web response. As long as the client machine has an idea what type of response it is, it will be accepted.

To all rules there must be exceptions, and the first one was that in Visual Basic, the programmer was unable to capture ports. Therefore the standard was expanded to allow for a new type of CGI where the request is first written into a file, and the response is read from another file to be sent back. They called this type of CGI WIN-CGI, but they might as well have named it VB-CGI. Delphi supports it, but as far as I can tell, there is no compelling reason to use it - ever.

A CGI program is executed by the webserver on request from the client's browser, but it is also possible to write a DLL (dynamically linked library) to respond to user requests. If your application takes a long time to boot up, such as when logging in to databases, then an ISAPI/NSAPI DLL may be the better way to go.

I have several apps that are CGI EXE's, and log into Interbase on startup. The response time so far has been acceptable. There will be more on this subject in Chapter 4.

To "execute" HTML, the Client's browser mus attempt to load the document. If you open your browser and enter "www.209software.com" you will be taken to that web site. If you want to create a link to one site from another HTML page, you use the same method. In your <a href> tag, you insert "http://www.209software.com". But how can you tell the browser to execute a Delphi EXE?

There are 2 ways to accomplish this, but it's important to remember the unlike Java, the Delphi EXE program will execute on the Web Server, not the Client's browser. What difference does that make? Well, if you try to include the SYSTEM date or other system variables they will reflect the current state of your web host, not the client. Your clock may be right, but only for 1/24th of the world.

The first way to execute Delphi CGI programs is to call them from a link or type them into the URL window on your browser. Here is an example:

http://www.209software.com/cgi-bin/cgicounter.exe/showgraphs.html?id=wpid


This will call up a page of graphs about the hits on the web version of this book. But if you look at the source of the page, you find that within the page there are embedded calls to the individual graphs.

This brings us to the second way to use Delphi CGI programs. Their output can be embedded into another HTML page or even another CGI program's web page. The image calls look like this:

http://www.209software.com/cgi-bin/cgicounter.exe/days.jpg?ID=wpid&N=30

Of course your CGI programs can do other things too, pretty much like any delphi program, you just can't use the Windows API. Why? Because if you play a movie or a sound, it will play on the server. If you pop up a dialog, it will be on the server. The good news is that you can create and access disk files, the web server's registry, you have full access to the BDE - which means you can access Oracle, Sybase, Informix, Interbase, even Paradox and Dbase tables!

As for playing sounds and such, you can still do these things, but they must be HTML commands sent to the browser, not Delphi commands to the server.

As you learn the tricks of the trade, you'll find that there are few limitations on what you can do via Delphi CGI and the Web. So let's jump right in...

 

Chapter 2

Setting Up for Development

The first thing you need to understand about developing for the web is that the Web Server executes the programs, not the browser. You must have a web server online to develop for the web. Of course you must also have Delphi installed. First, figure out what your development environment will look like. It is foolish to compile your exe's into the live directory on the web or intranet. So you need an off line development server. My live server is co-located offsite, and I use a local webserver for development.

Of course, being Delphi programmers currently limits us to the Windows OS, and only a fool would deploy to the web on any Windows other than NT. There are several webservers available for NT. Here are some you should consider.

Once a server is installed and configured on your machine, there are a few things to take note of. Know where your server is configured to look for CGI-BIN and CGI-WIN programs. You'll need this information to set your Delphi compiler directories up.

To test your webserver, don't go to the HTML documents directory with the Windows Explorer and click on the "index.html" document. This method of loading a page transferrs the file to the browser as a file stream from the drive. See the URL in the browser? It says "file:///...". Instead, enter http://localhost. If that fails to please, then enter 127.0.0.1. This is a special address reserved for the local machine. At this point, you should see either an index of your HTML Document root directory, or a prefab welcome message. Oh, yeah, I almost forgot. If you use Dialup Networking (DUN) then you will have to dial in before you can do this. The IP addressing needs winsock.dll in memory in order to work. If you access the internet via a network, you needn't worry.

There is a text file called hosts.<nothing>, find it. Open it in Notepad. It should already contain a listing for localhost. It should look a lot like this:

<TBODY>

# Copyright (c) 1993-1995 Microsoft Corp.

#

# This is a sample HOSTS file used by Microsoft TCP/IP for Windows NT.

#

# This file contains the mappings of IP addresses to host names. Each

# entry should be kept on an individual line. The IP address should

# be placed in the first column followed by the corresponding host name.

# The IP address and the host name should be separated by at least one

# space.

#

# Additionally, comments (such as these) may be inserted on individual

# lines or following the machine name denoted by a '#' symbol.

#

# For example:

#

# 102.54.94.97 rhino.acme.com # source server

# 38.25.63.10 x.acme.com # x client host

#

127.0.0.1 localhost

</TBODY>

The only line Winsock cares about is the last one. All the others are comments. You can manually add servers to your own computer by editing this file. Here's what I do to my development server. My domain is www.209software.com, so I chose to create a local version called 209software.loc. You can't add multiple lines for the same IP address in Hosts, but you can assign them like this...

<TBODY>

Change

127.0.0.1 localhost

to

127.0.0.1 localhost 209software.loc

you can add more if you like...

127.0.0.1 localhost 209software.loc omnilist.loc takeoursurvey.loc

</TBODY>

This will allow multiple domains on your one local web server. Just don't forget to tell the webserver which name is which.

When you set up your website, you must place your HTML pages in a directory that can be read by the Web Server. WebSites
209software
htdocs*
data (I typically put my interbase data in here.)
cgi-bin (This is where the Delphi EXE's go )
cgi-win (This dir should remain barren forever )
isapi (Delphi ISAPI DLL's go in here)
netnag
htdocs
data
cgi-bin
cgi-win
isapi
testsite1
htdocs
data
cgi-bin
cgi-win
isapi
testsite2
htdocs
data
cgi-bin
cgi-win
isapi

<TBODY>(* as far as yor webserver is concerned, this is the "ROOT" of this site. Only this directory, and the ones under it can be accessed by a browser. Nothing in here may be executed on the server.) </TBODY>

It is important to note here that the Web Server has to be told to recognize the various directories. Please consult the help for your web server to figure out it's configuration issues.

 

Chapter 3

Choosing between CGI, WIN-CGI, and ISAPI

CGI

CGI programs are standalone executables that accept input from the stdin device, and stream results back on the stdout device. In Delphi terms, these devices are called the console. The good news is that the Delphi components parse all the inputs and store them in a structure called a TWebRequest. Your results are formatted into a TWebResponse structure.

It should be noted that CGI applications execute from scratch every time a user accesses them from a web page. This means that if 5 users hit the page at the same time, 5 copies of the program will be launched. If your program accesses a client/server database via a slow lan, you could see problems with the server 'timing out' before the result is sent.

I have successfully run an Interbase database on the same machine with a webserver without incident. My webserver timeouts are set for 90 seconds, and there is plenty of time to log in, retreive information, and get out before that.

WIN-CGI

WIN-CGI, as mentioned earlier, is a way of working around shortcomings in Visual Basic. VB can't read or write directly to the console, so this type of application accepts input from a temporary file, and exports it's results to a temporary file, which the webserver sends as it's response.

As far as I can see, there is no compelling reason to use Win-CGI, unless you want to stress test your hard drive.

ISAPI DLL

Larger applications take time to load, initialize, log into databases, etc., so more complex apps may be constructed as ISAPI DLL's. The DLL only need load once, and after that, it waits for requests, and processes them. It is most important to use correct scoping for your variables, because globals are available to all instances running at any given time.

I also commonly hear complaints from programmers who are developing ISAPI apps, that it's a pain to get the DLL out of memory to recompile. Some programmers say they have to restart their webservers.

Comparison

<TBODY>Standard CGI

Good for small, fast programs, ok for client/server

Windows CGI

Compatible with VB programs

ISAPI DLL

Good for large, slow programs, ideal for more complex client/server</TBODY>


Web Programming in Delphi

by Bryan Valencia

Chapter 4

Choosing a Database for Web Use

There are many databases available for use on a web site. If you aren't hosting your own site, you may be stuck using whatever the ISP has installed, and that will usually be Access. You will have to get them to install the BDE and ODBC drivers to use any database. This chapter is mostly written for those who have a level of choice over what software to install on the server side.

There are 3 items to consider when choosing a database for a web site. They are: cost, performance, resource usage, reliability, and maintainability. And to make it more difficult, most web sites use only one database system for all web data... which means that even if one app would be best in Paradox Tables, and another really needs Oracle, you will probably have to use one system for both. This also plays into the maintenance of your system, because who wants to hire Oracle, Informix, Paradox, DB2, etc. experts to keep it all running?

Let me make one caution at the outset. Most small development shops choose their database system because they have experience with it, or because they laid out money for it, and damnit, that's what they'll use. Good project analysis, however, calls us to consider all these factors, and make a decision outside of our personal biases (but you already know what database you're going to use, don't you).

So let's explore the differences between databases from a web perspective... For the purpose of this discussion, there are essentially 3 major classes of database system: File based (where each table is a file), Single File (where all the tables are in one file), and client/server (where who cares where the data is, because there is a program running somewhere that will just serve up the results you want.

Database Systems

These are the types of database systems we will consider here:

<TBODY>Text Based

Text files

Text files are just files containing strings of data organized into lines. This HTML file you are reading is just a text file that resides in a directory on a drive in my web server.

Text files are good for storing logs, freeform text, and parameterized data. An example of what I mean here is:
File.txt---
USERNAME="ERICN"
NICKNAME="ELVIS"
LASTLOGIN="07/14/1999"
SUPERUSER=1

Ini files

These are a special class of text file. The advantage here is that Windows 3.1 and above has several built-in routines to understand them, and Delphi has even more routines to create, modify, and read them.

In 32 bit Windows, the ini file has been largely replaced by the registry, but the functionality still remains to create and use this type of file. I still find them extremely useful for storing initialization parameters. This type of file is particularly useful for projects such as web counters.

The Registry

The registry is designed to replace the ini file and like it's predecessor, Windows includes a set of procedures to get and set data in the registry. I have a web counter that stores it's counts in the registry, but I wouldn't use this method for the kind of data that keeps accumulating over time.

Typed files

Typed files are fast, pretty reliable, and even if they fail, they just go right on working. This is where you create a structure that stores a record, and create a file of the same type as the structure.

I have a counter (see the bottom of the contents frame at left. There is a counter there that uses a typed file for it's data. If you click the counter, the data will be displayed as a series of graphs.

The main advantage of typed files is the speed. There is no login, as there would be with a client/server database, and the speed is better because all the records are of a fixed length. So a "seek(file, 30);" takes you there at lightning speed.

Paradox

Even though Paradox requires you to use the BDE, it still stores the data in text files. What you gain using Paradox files is...

  • SQL access, including joins, and bulk updating
  • Record locking (not a big issue for web data)
  • Use of Delphi data-aware components
  • Still no time wasted 'logging in' to database
  • Ability to store images and sounds in DB
  • Ability to use data on multiple servers, even Unix servers

dBase

dBase is so similar to Paradox from a development standpoint, it has almost all the same advantages. There are some minor differences, however, such as that dBase doesn't delete records from the table when you tell it to, it just flags them as deleted, to be used for a future post.

Single File

Access

As I work for various companies, many times they'll hand me an Access file, and ask me to do something useful with it. The most useful thig I have found to do is to convert it to another format. But there are Access ODBC drivers that will allow you to write Delphi Apps that can access Access tables. The problem I always find is that the newest version of Delphi almost never has the drivers for the newest version of Access tables. So I would pick another system if I could.

 

 

Client/Server

Interbase

The most compelling thing about Interbase is that it's thoroughly integrated with the BDE and Delphi*. I have done SELECT * FROM MEMOS WHERE MEMOTEXT LIKE '%SOMESTRING%' in Memo fields using Interbase. Oracle won't do text matches in memo fields, so you have to iterate through the entire DB. Also, with Interbase, it's easy to back up and transmit an Interbase database, data, schema, and all.

It doesn't take excessively long to log in, so CGI apps can be written to access an Interbase DB. It doesn't lose track of indexes, and it's very reliable. There are some other reasons to choose Interbase*, but the one big drawback is this... Most non-Borland developers have never heard of it. Ask a room full of VC++ snobs about Interbase, and they'll shrug at you.

* and it's free (with Delphi C/S)!

Sybase

I played with Sybase quite early on, and I am sure my experience with it is a bit out of date. My general impression was this: It had a very strong set of stored procedure and SQL functions, it was very fast, and it was quite stable. If you have experience using Sybase for a web app, Email me

Oracle

I use Oracle regularly in business apps, but not for the web. Oracle is a great system for business, but it has a few drawbacks from a development standpoint.

It takes forever to log in. I am working on a program right now for a client that takes 45 seconds from the time the user types their password to when the app is ready to come up. In my code, all it does is call a database1.open. Now the LAN traffic has an effect here, but as far as I can tell, this slowness would force me to write all ISAPI DLL's, or write a middle tier.

So for now, I'll use Interbase for Web, and Oracle for business apps.

 

<TBODY>

Subject: my oracle experiecnces

Date: Tue, 27 Jul 1999 17:19:19 -0400

From: [email protected]

My experiences using oracle in a web application are...

1) Oracle is the most reliable 24x7 DBMS

2) Oracle is fastest when you have LOTS of users

3) Of the top ten web sites (most hits), they ALL use Oracle!

I would NOT recommend Oracle for a small or medium requirement.

It must run on Unix for best performance, and it requires a full-time DBA.

Eric Engler

</TBODY>

<TBODY>

Subject: RE: my oracle experiecnces

Date: Mon, 16 Aug 1999 16:08:45 -0400

I have used Oracle with both unix/C with cgi,

and Delphi with ISAPI.

Of course, Oracle is too slow with regular cgi because you

can't keep a session open. It has to re-connect each time

a user hits the page. This is only OK if you won't have many

simoultaneous hits. When I wrote this app, we only had a few

users on our webserver at any specific moment.

By using ISAPI, you can keep a connection to Oracle open

all the time, and this makes it much faster.

We are migrating to AppServer so we can have more

server's running, and to use load balancing. This is the only way

to get real high throughput.

We are designing our own broker, since our needs are

very custom. We are going to have 3 banks of brokers, and each

broker can handle about 5 application servers.

But, "average" companies should not get an aggressive plan like this!

It is far too costly, and we have had a number of stumbling blocks.

We now have a fulltime onsight rep. from Inprise to help us solve

problems. And we have paid lots of $$$ for special folks to help us

on a contract basis. This is in addition to our 9 fulltime Delphi

programmers.

Eric

</TBODY>

If you have Oracle/web experience, Email me

Informix

I used Informix at a contract once, but a problem cropped up almost immediately. It seems that Informix desperately needs a middle tier (4GL) to work properly. Now, I expected that all the functionality I needed would be in the 2 tier version, but it just wasn't. There was no way to convert strings to upper or lower, or implement a case-insensitive query. We called support, but they just said it was all in the middle tier we didn't buy.

It seems to me that they didn't create new, whiz-bang technology for their 3 tier system, they just split the server side into two crippled, useless halves. I have never touched Informix since, so if you are using it for web apps, Email me

MSSQL

I used MSSQL at a job once, just after it was separated from Sybase. Since my experience with it is so outdated, Email me

</TBODY>

cost

Ok, this kind of goes without saying, but you don't purchase a $3,500 Database package to store data for a hit counter. It's just a waste. It will cost you more to maintain than the benefit you get from using it. I worked with a programmer once who was so jazzed about client/server, that if you asked him for a rewrite of the Windows Notepad, he would have found a reason to make it access a client/server database and execute triggers and stored proceedures to work.

Also, this may come as a shock, but the cost of a big client/server database doesn't end with the shelf sticker price. Think about the cost of user support (from the manufacturer), the amount of on-site support required to keep it running, etc.

performance

When you use the web, what do you do when you click on something, and the browser says, "contacting host", "host contacted, waiting for reply"... You wait. I will wait about 90 seconds max before I click onto something else. Many people click away well before that. Most will flag the site in their minds with a "terrible" sticker, and not return. On the web, speed and convenience are everything. So when you set up your database, speed test it. A 45 second response time (from clicking in, to seeing the result) is good, 30 is better, 10 is godlike. If you buy a big client/server package, and when you log in to your database over the LAN, if the login dialog takes 35 seconds or more to go away, you are going to hack the users off.

Actually, what you are doing is committing yourself to write only ISAPI DLLs that login at the beginning of the day, and stay logged in all day. Of course this makes you more vulnerable to network outages, so you'll be writing code to check the connection, and reconnect if it gets dropped.

I am not saying that all client/server databases are too slow, in fact, I use Interbase on the web for my database apps. I am just warning you to check the actual speeds before you commit to a database system.

resource usage

All applications use resources. Resources cost money. Make sure that you use a database system that can coexist with your code, webserver, and OS without eating all the memory and system handles for lunch.

When testing web apps, use the Task Manager to keep an eye on peak usage. If it gets over 90%, you have to either plan to upgrade or trim something down.

reliability

This is pretty much a no-brainer, but this one is the reason I don't download a freeware database server for my web development. I know the systems I use, and I know that they have high reliability and quick error recovery built in.

maintainability

A database system that is difficult to maintain is fine as long as it rarely breaks down, right? I twice had to do some work with a Visual Foxpro database, and in both cases it would drop some indexes about once or twice a day. It was simple to fix this problem, but it was a constant nightmare to keep up with it. AND... every time the indexes broke, the USERS were the ones calling me saying the system sucked.

I point this out to say that maintainability is a factor, but only as it relates to reliability. Ideally we want both.


 

Chapter 5

Setting up Responders

I do apologize for taking 5 chapters before getting to any actual Delphi code, but I tend to ramble. So before I wax poetic over some concept, let's do some sample applications.

Simple Text Demo

In this example, we are going to say Hello through the browser. For this, you'll need to have your webserver running.

Ok, Launch Delphi, and do File|New.

File New

For some reason, probably to discourage us from doing web apps, Borland hid the web apps icon so you have to scroll up to see it, so scroll up, and choose the Web Application icon. Then select CGI Standalone Executable from the next dialog. You will create a WebModule, which is a nonvisual form like a data module. It can contain TQueries, TTables, and most other non-visual components, but... do this: Double click the client area. You'll get a dialog called Editing Webmodule1.Actions. This is where you will begin to create responders to web requests. Now hit insert and you will create a web module action object.

Ok, for this demo, click the default property to true, and go to the object inspector's events tab. Then double click the blank in the right column, and a handler will be created.

Modify the handler so it looks like this:

<TBODY>

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;

Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);

begin

response.Content:='Hello'; //the string to return

handled:=true; //tell the system we have dealt with the request.

end;

</TBODY>

Now select Project|Options, and on the Directories/Conditionals tab, set the Output Directory to the cgi-bin directory for your server.

Do not hit F9 or select File RUN. That would launch the application with no input, and cause an error. Remember that web requests are highly structured, and "" doesn't fit the spec.

Instead, hit ctrl-F9 to build the project, saving it as Project1.dpr. If all went well, there is now a project1.exe in your cgi-bin directory. Then click here.

You should get back a pleasant greeting. If not, then click here. If neither of these worked, then there are some things you may want to check out.

Ok, assuming we have it all running, look at the "Hello" page you got back. View the source of the page. Note that you got back exactly what you said to send. There are no headers, no HTML at all. Now view the source for the frame this text is in. It's LOADED with HTML commands. I know. I typed them all in!

Sending proper HTML

The next thing we'll do is create a correctly formatted HTML document to send back. I won't go overboard on this, because there are exactly 23,432 books available to teach you how this is done.


 

Chapter 6

MIME Types

"MIME" stands for Multipurpose Internet Mail Extensions, which is a specification for formatting non-ASCII messages so that they can be sent over the Internet. Almost all e-mail clients support MIME, which enables them to send and receive graphics, audio, and video files via the Internet mail system. In addition, MIME supports messages in character sets other than ASCII.

There are many predefined MIME types, such as GIF's, WAV's, and JPEG's. It is also possible to define your own MIME types.

In addition to e-mail applications, Web browsers also support various MIME types. This enables the browser to display or output files that are not in HTML format.

Here are the MIME settings from my web server...

<TBODY>

".ai"="application/postscript"

".eps"="application/postscript"

".ps"="application/postscript"

".doc"="application/msword"

".rtf"="application/rtf"

".pdf"="application/pdf"

".exe"="application/exe"

".dll"="application/dll"

".zip"="application/zip"

".p7c"="application/pkcs7-mime"

".arj"="application/x-arj"

".gz"="application/x-gzip"

".lzh"="application/x-lzh"

".js"="application/x-javascript"

".tar"="application/x-tar"

".cert"="application/x-x509-ca-cert"

".aif"="audio/aiff"

".aiff"="audio/aiff"

".aifc"="audio/aiff"

".au"="audio/basic"

".snd"="audio/basic"

".mid"="audio/midi"

".rmi"="audio/midi"

".mp3"="audio/mpeg"

".wav"="audio/wav"

".ra"="audio/x-pn-realaudio"

".ram"="audio/x-pn-realaudio"

".gif"="image/gif"

".jpeg"="image/jpeg"

".jpg"="image/jpeg"

".tif"="image/tiff"

".tiff"="image/tiff"

".bmp"="image/bmp"

".xbm"="image/xbm"

".wrl"="model/vrml"

".txt"="text/plain"

".htm"="text/html"

".html"="text/html"

".rtx"="text/richtext"

".shtml"="text/ssi"

".qt"="video/quicktime"

".mov"="video/quicktime"

".avi"="video/avi"

".mpeg"="video/mpeg"

".mpg"="video/mpeg"

".pl"="wwwserver/stdcgi"

".cgi"="wwwserver/stdcgi"

".pli"="wwwserver/isapi"

".asp"="wwwserver/isapi"

".cfm"="wwwserver/isapi"

".wcgi"="wwwserver/wincgi"

".url"="wwwserver/redirection"

".inc"="text/ssi"

</TBODY>

Every response sent from your server to a brower contains a MIME description, either explicitly or by reference (from the file extension). This can be set in Delphi web responses like this:

<TBODY>

Response.ContentType := 'image/jpeg';

</TBODY>

This tells the browser that the response is a jpeg image, even if the filename is "FILE.HTML".

Ok, let's write some code. Create a new Standalone CGI application, like we did in chapter 5, or download the project from here.

Save it in it's own directory. I named the project mimedemo.dpr, so it will have an exe called mimedemo.exe. To run it, click here for the HTML version, and here for the Jpeg version.

Of course I presume the virtual path to your cgi-bin directory is /cgi-bin. If yours isn't then you have to locate it yourself.

Here is the full source code for mimedemo.

<TBODY>

program mimedemo;

{$APPTYPE CONSOLE}

uses

HTTPApp,

CGIApp,

uMIME in 'uMIME.pas' {WebModule1: TWebModule};

{$R *.RES}

begin

Application.Initialize;

Application.CreateForm(TWebModule1, WebModule1);

Application.Run;

end.


unit uMIME;

interface

uses

Windows, Messages, SysUtils, Classes, HTTPApp,

Graphics, JPEG; //I added Graphics and JPEG here

type

TWebModule1 = class(TWebModule)

procedure goJpeg(Sender: TObject; Request: TWebRequest;

Response: TWebResponse; var Handled: Boolean);

procedure goHTML(Sender: TObject; Request: TWebRequest;

Response: TWebResponse; var Handled: Boolean);

private

{ Private declarations }

public

{ Public declarations }

end;

var

WebModule1: TWebModule1;

implementation

{$R *.DFM}

procedure TWebModule1.goJpeg(Sender: TObject; Request: TWebRequest;

Response: TWebResponse; var Handled: Boolean);

var

b:tBitmap; //to paint the image on

j:TJPEGImage; //to convert to a Jpeg

ms:TMemoryStream; //to stream to the webserver

s:String;

begin

s:='Hello, as a Jpeg';

//create everything

b:=tbitmap.create;

j:=TJPEGImage.Create;

ms:=TMemoryStream.Create;

try

b.canvas.Font.Name:='Impact';

b.Canvas.Font.Size:=72; //set up the font

b.Width:=b.Canvas.TextWidth(s); //make the bitmap just big enough

b.Height:=b.Canvas.TextHeight(s);

b.Canvas.Brush.Color:=clBlack; //fill the canvas

b.Canvas.FillRect(b.Canvas.ClipRect);

b.Canvas.Font.Color:=clWhite; //paint the text

b.Canvas.TextRect(b.Canvas.ClipRect, 1,1, s);

j.Assign(b); //copy the bitmap

j.CompressionQuality:=90; //do the JPEG compression

j.Compress;

j.SaveToStream(ms); //send it to the stream

ms.Position:=0; //'rewind' the stream

Response.ContentType := 'image/jpeg';

Response.ContentStream:=ms;

Response.SendResponse;

finally

b.free;

j.free;

//no need to free the stream, the webserver does that.

//in fact if we did it, there would be an access violation.

end;

end;

procedure TWebModule1.goHTML(Sender: TObject; Request: TWebRequest;

Response: TWebResponse; var Handled: Boolean);

var

s:string;

resp:tStringList;

begin

s:='Hello, as HTML';

resp:=TStringList.Create; //I like to use tStringLists to

//compose HTML, but it can just

//as easily be accomplished in

//a string.

try

resp.Add('<HTML>'); //create the text of the reply

resp.Add(' <HEAD>');

resp.Add(' </HEAD>');

resp.Add(' <BODY>');

resp.add(' <font face="Impact" size="72">');

resp.Add(s);

resp.add(' </font>');

resp.Add(' </BODY>');

resp.Add('</HTML>');

Response.ContentType := 'text/HTML'; //Set it's MIME type

Response.Content:=resp.Text; //Copy the text into the Response

handled:=true; //tell the program we're done here.

finally

resp.free;

end;

end;

end.


object WebModule1: TWebModule1

OldCreateOrder = False

Actions = <

item

Name = 'GetJpeg'

PathInfo = '/hello.jpg'

OnAction = goJpeg

end

item

Name = 'GetHTML'

PathInfo = '/hello.html'

OnAction = goHTML

end>

Left = 321

Top = 108

Height = 150

Width = 215

end

</TBODY>


Chapter 7

Anatomy of an HTML Page

The HTML page is a very simple thing. It is a text file (or a hypertext file), with sections the browser interprets. It is also a heirarchical arrangement, meaning that certain things can only exist in certain contexts. Kind of like Delphi, where you can't do this:

<TBODY>

procedure DoSomething;

Var

a,b,c:integer;

begin

a:=5; b:=3; c:=2;

var //you can't do this because it's out of context.

d,e,f:real;

end;

</TBODY>

Likewise the HTML anatomy has a certain context that the various browsers expect to see.

<TBODY>

<!doctype html public "-//w3c//dtd html 4.0 transitional//en">


<html>


<head>


<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">


<meta name="GENERATOR" content="Mozilla/4.61 [en] (Win95;I) [Netscape]">


<meta name="Author" content="Bryan Valencia">


<meta name="Description" content="Web Server Applications">


<meta name="KeyWords" content="Delphi,Borland,program,CGI,Web,server,application">


<title>Web Server Apps</title>


</head>


<body


text="#000000"


bgcolor="#FEFEFE"


link="#FF0000"


vlink="#800080"


alink="#0000FF"


background="binderpaper1.gif"


>


</body>


</html>

</TBODY>

Ok, the main sections for this page are laid out like this.
<HTML>
<HEAD>
(all the meta tags go in here)
</HEAD>
<BODY>
(the text of the page goes in here)
</BODY>
</HTML>

This was just a sample. There is a different structure for framesets, and we don't show any tables, data entry forms, embedded images, or graphics. For most uses, however, this is the basic layout of an HTML page.

Next is the basic layout of a frameset page.

<TBODY>

 

<HTML>


<HEAD>


<TITLE>Web Programming in Delphi</TITLE>


<META NAME="description" CONTENT="Create great web content in your own home">


<META NAME="keywords" CONTENT="Pascal, Delphi, Programming, web">


</HEAD>


<FRAMESET COLS="250,*" NORESIZE BORDER="0">


<FRAME SRC="ChapterList.shtml" NAME="Chapters">


<FRAME SRC="Intro.shtml" NAME="MainText">


</FRAMESET>

</HTML>

</TBODY>

Note that instead of a section for the <BODY>, that there is a definition for a <FRAMESET>. Actually, a <BODY> section can be added after the frames, so that browsers that don't support frames will display that HTML text instead.

The default pages that load into the framesets are noted in the <FRAME SRC="..." NAME="..."> sections, where the SRC is the filename of the page to load in, and the NAME is the name used to identify the actual frame in your links.

The NAME= is extremely useful when you create a link, because the default target of a link is _self.
so, <a href="/page1">CLICK</a> is the same as <a href="/Page1" target="_self"> CLICK</a>. The valid targets for a link are:

In the case of the frameset above, our choices for PAGE NAME are "Chapters" and "MainText".

Warning! Don't gloss over this section. One of the most common things you will be called upon to do is create a CGI frameset that can accept Query parameters and auto-load frames. For instance, say the last frameset was called Page.html. It is set up to load Chapterlist.shtml and Intro.shtml into it's frames. But, what if you wanted to create a link in another place, say in a newsgroup message, saying, "the answer to your question is in the HINTS page of my web site... Click Here..." Now you want to create a link to your page called HINTS, but if you just send HINTS, it will be out of the frameset, and if you send the link to the frameset, they will get your front page.

There are 2 really good answers to this problem. Make it so you can call your frameset with a query parameter, like this http://www.209software.com/cgi-bin/index.exe?page=hints. Alternately, there is a Javascript command you can put on your HINTS page that says, "If I am outside my frame, Load the frame set!


 

Chapter 8

The Header Section

The header contains items which are not shown in the body of the text of your HTML document. There are several meta tags that are expected to be found within this section of your web page.

Here are the header sections from some famous pages...

<TBODY>

Yahoo

<head><title>Yahoo!</title><base href=http://www.yahoo.com/></head>


Microsoft

<HEAD>

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso8859-1">

<TITLE>Welcome to Microsoft's Homepage</TITLE>

<META http-equiv="PICS-Label" content='(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" by "[email protected]" for "http://www.microsoft.com/" on "1997.06.30T14:21-0500" r (n 0 s 0 v 0 l 0))'>

<META NAME="KEYWORDS" CONTENT="products; headlines; downloads; news; Web site; what's new; solutions; services; software; contests; corporate news;">

<META NAME="DESCRIPTION" CONTENT="The entry page to Microsoft's Web site. Find software, solutions and answers. Support, and Microsoft news.">

<META NAME="MS.LOCALE" CONTENT="EN-US">

<META NAME="CATEGORY"CONTENT="home page">

<STYLE TYPE="text/css">

<!--

A:link {color:"#003399";}

A:visited {color:"#003399";}

A:hover {color:"red";}

-->

</STYLE>

</HEAD>


Borland

<TITLE>Borland Home Page</TITLE>

<!--CONTAINS JAVASCRIPT-->

<SCRIPT LANGUAGE="JavaScript" SRC="/scripts/topnav/topnavNull.js">

</SCRIPT>

<SCRIPT LANGUAGE="JavaScript">

<!--

window.onerror = null

useridEnd = window.location.search.indexOf("+")

useridName = window.location.search.substring(1,useridEnd)

productStart = useridEnd + 1

productEnd = window.location.search.indexOf("+",productStart)

productName = window.location.search.substring(productStart,productEnd)

if (productName) {

document.cookie = "PRODUCTS=" + productName + "; expires=Friday, 31-Dec-99 23:59:59 GMT; path=/; domain=.borland.com"

}

if (useridName) {

document.cookie = "USERID=" + useridName + "; expires=Friday, 31-Dec-99 23:59:59 GMT; path=/; domain=.borland.com"

}

else {

hasTheCookie = document.cookie.indexOf("USERID=",0) + 1

if (!hasTheCookie) {

today = new Date()

if (Math.random) {

numeric = Math.random() * 8999 + 1000

numeric = parseInt(numeric)

}

else {

numeric = "0000"

}

document.cookie = "USERID=" + today.getTime() + "" + numeric + "; expires=Friday, 31-Dec-99 23:59:59 GMT; path=/; domain=.borland.com"

}

}

// THIS IS THE SCRIPT THAT CONTROLS THE DATE ON THE TOP RIGHT CORNER

function addDate() {

monthNames = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

myDate = new Date();

var year = myDate.getYear();

if (year < 1000) year += 1900;

document.write("<FONT SIZE='3' FACE='Arial, Sans-serif' COLOR='000000'><B>" + monthNames[myDate.getMonth()] + " " + myDate.getDate() + ", " + year + "</B></FONT>");

}

//-->

</SCRIPT>

<!--CONTAINS STYLES-->

<LINK REL="stylesheet" TITLE="Default" HREF="/styles/default.css" TYPE="text/css">

</HEAD>


The CIA for Kids Home Page

<head>

<title>CIA Kids Page </title>

</head>

</TBODY>

Ok, there are a variety of things in the header section of the HTML page. There are meta tags, comments, style sheets, and even Javascript. I have searched the web for additional items that can be included in the <HEAD> section, but there is no definitive list that I can find. So here are some that I know of.

Essentially the header is to communicate to the outside world what your page is about, without showing it to the user. For example, you can...

Comments

Comments in HTML can exist in any section, and they are completely ignored by the browser - almost. a comment begins with a <!-- and ends with -->. There are some server commands that exist as comments, so they'll get ignored by older browsers. If your server has Server Side Includes set, then the command <!--#include virtual="MainMenu.shtml"--> will tell the server to parse (or read) the file, and instead of this comment, it will place the contents of the file "MainMenu.shtml".

Meta Tags

In general, meta tags tell search engines and browsers about the page or frameset. There are also some browser commands that can go in the header section.

Javascript

There are some common things that can happen in Javascript in the header section. One common thing is to preload the alternate button images that appear when the user mouses over them. To prevent the image from having to load when the user touches them, Javascript can preload all the images for quick response time.

Style Sheets

I don't use style sheets, but they can be specified in the header section as well.


Chapter 9

The Body Section

The body section contains the content that is intended for the user to see in his browser. Apart from HTML tags, which usually format the display, most everything in the body section is intended to be displayed. There are tags to display images, animations, play sound, and links to other web pages.

Its the tags that turn a document from text into hypertext. Here is a quick overview of the most common HTML tags. It should be noted that like Delphi Pascal, HTML tags are not case sensitive.

In general HTML tags have a begin and end tag, in the format <tag>...</tag>. The tag is always the beginning, and /tag is always the end. There are some tags that have no ending tag, like the hr or "horizontal rule" (line) tag.

Many HTML tags have optional parameters. These are placed in the begin tag. For instance, a hyperlink tag is <a>...</a>, but it's useless unless until it has an address to link to.

<TBODY>Tag

Description

example

Text Formatting Tags

<b>

Bold

This is <b>Bold</b> text
This is Bold text

<i>

Italic

This is <i>Italic</i> text
This is Italic text

<u>

Underlined

This is <u>underlined</u> text
This is underlined text

<s>

Strikethrough

This is <s>strikethrough</s> text
This is strikethrough text

Link Tags

<a href=...>

http:

Click <a href="http://www.209software.com">here</a>.
Click
here.

<a href=...>

email

<a href="mailto:[email protected]">Send Mail</a>.
Send Mail.

Image Tags

<Img...>

embed image

<img src="/icons/audio.gif">

Table Tags

<TABLE...>

create a table

<table>...</table>

<tr...>

table row

<table>
<tr> </tr>
</table>

<td...>

table data

<table>
<tr>
<td>This text is in a cell</td>
</tr>
</table>

*

table example

<table>
<tr>
<td>Cell 0,0</td>
<td>Cell 1,0</td>
<td>Cell 2,0</td>
</tr>
<tr>
<td>Cell 0,1</td>
<td>Cell 1,1</td>
<td>Cell 2,1</td>
</tr>
<tr>
<td>Cell 0,1</td>
<td>Cell 1,1</td>
<td>Cell 2,1</td>
</tr>
</table>
</TBODY>

This was intended to be an exhaustive list, but there are just way too many HTML tags to note here.

Hosted by www.Geocities.ws

1