1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2005, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
35 with Ada
.Strings
.Fixed
;
36 with Ada
.Characters
.Handling
;
37 with Ada
.Strings
.Maps
;
42 package body GNAT
.CGI
is
46 Valid_Environment
: Boolean := True;
47 -- This boolean will be set to False if the initialization was not
48 -- completed correctly. It must be set to true there because the
49 -- Initialize routine (called during elaboration) will use some of the
50 -- services exported by this unit.
52 Current_Method
: Method_Type
;
53 -- This is the current method used to pass CGI parameters
55 Header_Sent
: Boolean := False;
56 -- Will be set to True when the header will be sent
58 -- Key/Value table declaration
60 type String_Access
is access String;
62 type Key_Value
is record
64 Value
: String_Access
;
67 package Key_Value_Table
is new Table
(Key_Value
, Positive, 1, 1, 50);
69 -----------------------
70 -- Local subprograms --
71 -----------------------
73 procedure Check_Environment
;
74 pragma Inline
(Check_Environment
);
75 -- This procedure will raise Data_Error if Valid_Environment is False
78 -- Initialize CGI package by reading the runtime environment. This
79 -- procedure is called during elaboration. All exceptions raised during
80 -- this procedure are deferred.
86 function Argument_Count
return Natural is
89 return Key_Value_Table
.Last
;
92 -----------------------
93 -- Check_Environment --
94 -----------------------
96 procedure Check_Environment
is
98 if not Valid_Environment
then
101 end Check_Environment
;
107 function Decode
(S
: String) return String is
108 Result
: String (S
'Range);
109 K
: Positive := S
'First;
110 J
: Positive := Result
'First;
113 while K
<= S
'Last loop
116 and then Characters
.Handling
.Is_Hexadecimal_Digit
(S
(K
+ 1))
117 and then Characters
.Handling
.Is_Hexadecimal_Digit
(S
(K
+ 2))
119 -- Here we have '%HH' which is an encoded character where 'HH' is
120 -- the character number in hexadecimal.
122 Result
(J
) := Character'Val
123 (Natural'Value ("16#" & S
(K
+ 1 .. K
+ 2) & '#'));
134 return Result
(Result
'First .. J
- 1);
137 -------------------------
138 -- For_Every_Parameter --
139 -------------------------
141 procedure For_Every_Parameter
is
147 for K
in 1 .. Key_Value_Table
.Last
loop
151 Action
(Key_Value_Table
.Table
(K
).Key
.all,
152 Key_Value_Table
.Table
(K
).Value
.all,
159 end For_Every_Parameter
;
165 procedure Initialize
is
167 Request_Method
: constant String :=
168 Characters
.Handling
.To_Upper
169 (Metavariable
(CGI
.Request_Method
));
171 procedure Initialize_GET
;
172 -- Read CGI parameters for a GET method. In this case the parameters
173 -- are passed into QUERY_STRING environment variable.
175 procedure Initialize_POST
;
176 -- Read CGI parameters for a POST method. In this case the parameters
177 -- are passed with the standard input. The total number of characters
178 -- for the data is passed in CONTENT_LENGTH environment variable.
180 procedure Set_Parameter_Table
(Data
: String);
181 -- Parse the parameter data and set the parameter table
187 procedure Initialize_GET
is
188 Data
: constant String := Metavariable
(Query_String
);
190 Current_Method
:= Get
;
192 Set_Parameter_Table
(Data
);
196 ---------------------
197 -- Initialize_POST --
198 ---------------------
200 procedure Initialize_POST
is
201 Content_Length
: constant Natural :=
202 Natural'Value (Metavariable
(CGI
.Content_Length
));
203 Data
: String (1 .. Content_Length
);
206 Current_Method
:= Post
;
208 if Content_Length
/= 0 then
210 Set_Parameter_Table
(Data
);
214 -------------------------
215 -- Set_Parameter_Table --
216 -------------------------
218 procedure Set_Parameter_Table
(Data
: String) is
220 procedure Add_Parameter
(K
: Positive; P
: String);
221 -- Add a single parameter into the table at index K. The parameter
222 -- format is "key=value".
224 Count
: constant Positive :=
225 1 + Strings
.Fixed
.Count
(Data
, Strings
.Maps
.To_Set
("&"));
226 -- Count is the number of parameters in the string. Parameters are
227 -- separated by ampersand character.
229 Index
: Positive := Data
'First;
236 procedure Add_Parameter
(K
: Positive; P
: String) is
237 Equal
: constant Natural := Strings
.Fixed
.Index
(P
, "=");
244 Key_Value_Table
.Table
(K
) :=
245 Key_Value
'(new String'(Decode
(P
(P
'First .. Equal
- 1))),
246 new String'(Decode (P (Equal + 1 .. P'Last))));
250 -- Start of processing for Set_Parameter_Table
253 Key_Value_Table.Set_Last (Count);
255 for K in 1 .. Count - 1 loop
256 Amp := Strings.Fixed.Index (Data (Index .. Data'Last), "&");
258 Add_Parameter (K, Data (Index .. Amp - 1));
263 -- add last parameter
265 Add_Parameter (Count, Data (Index .. Data'Last));
266 end Set_Parameter_Table;
268 -- Start of processing for Initialize
271 if Request_Method = "GET" then
274 elsif Request_Method = "POST" then
278 Valid_Environment := False;
284 -- If we have an exception during initialization of this unit we
285 -- just declare it invalid.
287 Valid_Environment := False;
294 function Key (Position : Positive) return String is
298 if Position <= Key_Value_Table.Last then
299 return Key_Value_Table.Table (Position).Key.all;
301 raise Parameter_Not_Found;
309 function Key_Exists (Key : String) return Boolean is
313 for K in 1 .. Key_Value_Table.Last loop
314 if Key_Value_Table.Table (K).Key.all = Key then
326 function Metavariable
327 (Name : Metavariable_Name;
328 Required : Boolean := False) return String
330 function Get_Environment (Variable_Name : String) return String;
331 -- Returns the environment variable content
333 ---------------------
334 -- Get_Environment --
335 ---------------------
337 function Get_Environment (Variable_Name : String) return String is
338 Value : OS_Lib.String_Access := OS_Lib.Getenv (Variable_Name);
339 Result : constant String := Value.all;
346 Result : constant String :=
347 Get_Environment (Metavariable_Name'Image (Name));
349 -- Start of processing for Metavariable
354 if Result = "" and then Required then
355 raise Parameter_Not_Found;
361 -------------------------
362 -- Metavariable_Exists --
363 -------------------------
365 function Metavariable_Exists (Name : Metavariable_Name) return Boolean is
369 if Metavariable (Name) = "" then
374 end Metavariable_Exists;
380 function Method return Method_Type is
383 return Current_Method;
390 function Ok return Boolean is
392 return Valid_Environment;
400 (Header : String := Default_Header;
401 Force : Boolean := False)
404 if Header_Sent = False or else Force then
406 Text_IO.Put_Line (Header);
416 function URL return String is
418 function Exists_And_Not_80 (Server_Port : String) return String;
419 -- Returns ':' & Server_Port if Server_Port is not "80" and the empty
420 -- string otherwise (80 is the default sever port).
422 -----------------------
423 -- Exists_And_Not_80 --
424 -----------------------
426 function Exists_And_Not_80 (Server_Port : String) return String is
428 if Server_Port = "80" then
431 return ':' & Server_Port;
433 end Exists_And_Not_80;
435 -- Start of processing for URL
441 & Metavariable (Server_Name)
442 & Exists_And_Not_80 (Metavariable (Server_Port))
443 & Metavariable (Script_Name);
452 Required : Boolean := False)
458 for K in 1 .. Key_Value_Table.Last loop
459 if Key_Value_Table.Table (K).Key.all = Key then
460 return Key_Value_Table.Table (K).Value.all;
465 raise Parameter_Not_Found;
475 function Value (Position : Positive) return String is
479 if Position <= Key_Value_Table.Last then
480 return Key_Value_Table.Table (Position).Value.all;
482 raise Parameter_Not_Found;