summaryrefslogtreecommitdiff
path: root/misc/pascal/tests/src/804-cgiform.pas
blob: e3043f548b734d75dcf9b8d404df3df705c5d530 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
(********************************************************************************************
** PROGRAM     : cgiform
** VERSION     : 1.0.0
** DESCRIPTION : Demonstrates how to process HTML forms in CGI programs.
** AUTHOR      : Stuart King
** COPYRIGHT   : Copyright (c) Irie Tools, 2002. All Rights Reserved.
** NOTES       :
**    This sample program is distributed with Irie Pascal, and was written to illustrate
** how to process HTML forms. To make best use of this sample you should have a basic
** understanding of Pascal as well as a basic understanding of the Common Gateway Interface
** (CGI).
**
**    HTML forms provide a way for websites to receive input from visitors, and to process
** this input in some way. HTML forms contain different kinds of input elements in order
** to conveniently receive different kinds of visitor input. The most common kinds of
** input elements are:
**   1. One line text entry boxes
**   2. Multi-line text entry boxes
**   3. Checkboxes
**   4. Radio buttons
**   5. Hidden fields
**   6. Selection lists (Drop-down menus and List boxes).
**   7. Reset button
**   8. Submit button
**
**    HTML forms have action attributes that indicate what should happen when the submit
** button is clicked. It is very common for the action attribute to point at the URL of
** a CGI program. In this case when the submit button is pressed the CGI program is executed
** and the form's input is passed to the program for processing. Each input element in the
** form has a name and the form's input is sent to the CGI program in the form of name/value
** pairs, where the values are the input received by the input elements.
**
**    What this program actually does is retrieve any form input passed to it. If it receives
** form input then this program just displays the name/value pairs, along with a link that
** can be used to execute the program again. If the program does not receive any form input
** then it displays a form with a variaty of input elements. The form's action element points
** back to the program, so that the program will receive the input from the form when the
** submit button is pressed.
**********************************************************************************************)
program cgiform;
const
	MAX_BUFFER = 8000;
	MAX_NAME = 20;
	MAX_VALUE = 400;
type
	positive = 0..maxint;
	BufferType = string[MAX_BUFFER];
	NameValuePair = record
		Name : string[MAX_NAME];
		Value : string[MAX_VALUE]
	end;
var
	buffer : BufferType;
	NameValuePairs : list of NameValuePair;
	ScriptName : filename;

	function EscapeCharacters(s : string) : string; forward;

	//PURPOSE: Initializes the program
	//NOTES:
	//   Initializes the list that will be used to store the name/value pairs
	//passed to the program. The program also retrieves it's name so that it can
	//refer to itself in the generated response.
	procedure Initialize;
	begin (* Initialize *)
		new(NameValuePairs);
		ScriptName := getenv('SCRIPT_NAME');
	end; (* Initialize *)

	//PURPOSE: Retrieves the information passed to the CGI applications.
	//GLOBAL(s) - buffer - Used to store the GET or POST information passed to the CGI program
	procedure GetCGIData;
	var
		RequestMethod : string;

		//PURPOSE: Retrieves information sent to by a GET request (i.e. in the QUERY_STRING
		//         environment variable).
		procedure GetRequest;
		begin (* GetRequest *)
			buffer := getenv('QUERY_STRING')
		end; (* GetRequest *)

		//PURPOSE: Retrieves information sent to by a POST request (i.e. through the standard
		//         input stream, with the length of the data in the environment variable
		//         CONTENT_LENGTH).
		procedure PostRequest;
		var
			len, i : positive;
			err : integer;
			ContentLength : string;
			c : char;
		begin (* PostRequest *)
			buffer := '';
			ContentLength := getenv('CONTENT_LENGTH');
			if ContentLength <> '' then
				val(ContentLength, len, err)
			else
				len := 0;
			if len <= MAX_BUFFER then
				for i := 1 to len do
					begin
						read(c);
						buffer := buffer + c
					end
		end; (* PostRequest *)

	begin (* GetCGIData *)
		RequestMethod := getenv('REQUEST_METHOD');
		if RequestMethod = 'GET' then
			GetRequest
		else
			PostRequest
	end; (* GetCGIData *)

	//PURPOSE: Process the data passed to the program.
	//NOTES: This is the main part of the program. After retreiving
	//       the information passed to the program this procedure is
	//       called to perform the required processing.
	procedure ProcessCGIData;
	var
		i, num, p : integer;
		EncodedVariable, DecodedVariable, name, value : string;

		//PURPOSE: Processes the named value pairs sent with the GET or POST request.
		//         Which in this case is the information entered by the user about the
		//         cookie to add or delete.
		//ARGUMENT(s): name - name part of the name/value pair
		//             value - value part of name/value pair
		//NOTES:
		//    The information entered by the user is sent as name/value pairs (i.e. name-value)
		//with the name part being the name of the form element holding the information and
		//the value part being the actual information held by the form element.
		procedure ProcessNameValuePair(var name, value : string);
		var
			pair : NameValuePair;
		begin (* ProcessNameValuePair *)
			pair.name := name;
			pair.value := value;
			insert(pair, NameValuePairs);
		end; (* ProcessNameValuePair *)

	begin (* ProcessCGIData *)
		//Retrieve each name/value pair from the form and processes them.
		num := CountWords(buffer, '&');
		for i := 1 to num do
			begin
				EncodedVariable := CopyWord(buffer, i, '&');
				DecodedVariable := URLDecode(EncodedVariable);
				p := pos('=', DecodedVariable);
				if p > 0 then
					begin
						name := lowercase(trim(copy(DecodedVariable, 1, p-1)));
						value := trim(copy(DecodedVariable, p+1));
						ProcessNameValuePair(name, value);
					end
			end;
	end; (* ProcessCGIData *)

	//PURPOSE: Generates the response to send back to the browser.
	procedure GenerateResponse;

		procedure GenerateHeader;
		begin (* GenerateHeader *)
			//Generate the response headers (including the blank line at the end).
			writeln('content-type: text/html');
			writeln;

			writeln('<html>');
			writeln('<head>');
			writeln('<title>Irie Pascal sample CGI application</title>');
			writeln('<h1>CGIFORM</h1>');
			writeln('<h2>This program displays the data entered into a form.</h2>');
			writeln('</head>');
			writeln('  <hr>');
		end; (* GenerateHeader *)

		procedure GenerateBody;

			procedure WriteForm;
			begin (* WriteForm *)
				writeln('<form method="POST" action="', ScriptName, '">');
				writeln('  <h2>One Line Text Box:</h2>');
				writeln('  <p>OneLine <input type="text" name="OneLine" size="20"></p>');
				writeln('  <hr>');
				writeln('  <h2>Scrolling Text Box:</h2>');
				writeln('  <p>Scrolling <textarea rows="2" name="Scrolling" cols="20"></textarea></p>');
				writeln('  <hr>');
				writeln('  <h2>Check Boxes</h2>');
				writeln('  <p>Box1 <input type="checkbox" name="Box1" value="1">');
				writeln('  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Box2 <input type="checkbox" name="Box2"');
				writeln('  value="1"></p>');
				writeln('  <p>Box3 <input type="checkbox" name="Box3" value="1">');
				writeln('  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Box4 <input type="checkbox" name="Box4"');
				writeln('  value="1"></p>');
				writeln('  <hr>');
				writeln('  <h2>Radio Buttons</h2>');
				writeln('  <p>Radio1 <input type="radio" value="1" checked name="Radio1">');
				writeln('  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Radio2 <input type="radio" name="Radio2"');
				writeln('  value="2"></p>');
				writeln('  <p>Radio3 <input type="radio" name="Radio3" value="3">');
				writeln('  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Radio4 <input type="radio" name="Radio4"');
				writeln('  value="4"></p>');
				writeln('  <hr>');
				writeln('  <h2>Drop-Down Menu</h2>');
				writeln('  <p>DropDown <select name="DropDown" size="1">');
				writeln('    <option value="Choice1">Choice1</option>');
				writeln('    <option value="Choice2">Choice2</option>');
				writeln('    <option value="Choice3">Choice3</option>');
				writeln('    <option value="Choice4">Choice4</option>');
				writeln('    <option value="Choice5">Choice5</option>');
				writeln('    <option value="Choice6">Choice6</option>');
				writeln('  </select></p>');
				writeln('  <hr>');
				writeln('  <p><input type="submit" value="Submit" name="Submit"><input type="reset" value="Reset"');
				writeln('  name="Reset"></p>');
				writeln('</form>');
			end; (* WriteForm *)

			procedure WriteFormData;
			var
				pair : NameValuePair;
				i : positive;
			begin (* WriteFormData *)
				writeln('<h1>Form Data</h1>');
				for i := 1 to length(NameValuePairs) do
					begin
						pair := NameValuePairs[i];
						writeln('<h3>', EscapeCharacters(pair.name), ' = ', EscapeCharacters(pair.value), '</h3>');
					end;
				writeln('<hr>');
				writeln('<p>Click <a href="', ScriptName, '">here</a> to go back to the form.</p>');
			end; (* WriteFormData *)

		begin (* GenerateBody *)
			writeln('<body>');

 			if length(NameValuePairs) = 0 then
 				begin
					//Generate the HTML for the form
					WriteForm;
				end
			else
				begin
					//Generate the HTML that displays the form data
					WriteFormData;
				end;

			writeln('</body>');
		end; (* GenerateBody *)

		procedure GenerateFooter;
		begin (* GenerateFooter *)
			writeln('</html>');
		end; (* GenerateFooter *)

	begin (* GenerateResponse *)
		GenerateHeader;
		GenerateBody;
		GenerateFooter;
	end; (* GenerateResponse *)
              
    procedure Shutdown;
	begin (* Shutdown *)
		dispose(NameValuePairs);
	end; (* Shutdown *)

	//*************************************************************************
	//PURPOSE: This function converts certain characters that have a
	//         special meaning in HTML documents to their HTML representation.
	//ARGUMENT(s): s - The string to be escaped.
	//RETURNS: The string with all special characters escaped.
	//NOTES: The characters converted are < > "
	function EscapeCharacters;
	const
		LessThanChar = '<';
		GreaterThanChar = '>';
		QuoteChar = '"';
		HTMLLessThan = '&lt;';
		HTMLGreaterThan = '&gt;';
		HTMLQuote = '&quot;';
	var
		i : positive;

		procedure ReplaceChar(var strBuffer : string; strReplace : string; i : positive);
		begin (* ReplaceChar *)
			delete(strBuffer, i, 1);
			insert(strReplace, strBuffer, i)
		end; (* ReplaceChar *)

	begin (* EscapeCharacters *)
		repeat
			i := pos(LessThanChar, s, 1);
			if i > 0 then
				ReplaceChar(s, HTMLLessThan, i)
		until i = 0;

		repeat
			i := pos(GreaterThanChar, s, 1);
			if i > 0 then
				ReplaceChar(s, HTMLGreaterThan, i)
		until i = 0;

		repeat
			i := pos(QuoteChar, s, 1);
			if i > 0 then
				ReplaceChar(s, HTMLQuote, i)
		until i = 0;

		EscapeCharacters := s;
	end; (* EscapeCharacters *)

begin
	Initialize;

	GetCGIData;

	ProcessCGIData;

	GenerateResponse;

	Shutdown;
end.