1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . C G I . C O O K I E --
9 -- Copyright (C) 2000-2003 Ada Core Technologies, Inc. --
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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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 ------------------------------------------------------------------------------
34 with Ada
.Strings
.Fixed
;
35 with Ada
.Strings
.Maps
;
37 with Ada
.Integer_Text_IO
;
41 package body GNAT
.CGI
.Cookie
is
45 Valid_Environment
: Boolean := False;
46 -- This boolean will be set to True if the initialization was fine.
48 Header_Sent
: Boolean := False;
49 -- Will be set to True when the header will be sent.
51 -- Cookie data that have been added.
53 type String_Access
is access String;
55 type Cookie_Data
is record
57 Value
: String_Access
;
58 Comment
: String_Access
;
59 Domain
: String_Access
;
62 Secure
: Boolean := False;
65 type Key_Value
is record
66 Key
, Value
: String_Access
;
69 package Cookie_Table
is new Table
(Cookie_Data
, Positive, 1, 5, 50);
70 -- This is the table to keep all cookies to be sent back to the server.
72 package Key_Value_Table
is new Table
(Key_Value
, Positive, 1, 1, 50);
73 -- This is the table to keep all cookies received from the server.
75 procedure Check_Environment
;
76 pragma Inline
(Check_Environment
);
77 -- This procedure will raise Data_Error if Valid_Environment is False.
80 -- Initialize CGI package by reading the runtime environment. This
81 -- procedure is called during elaboration. All exceptions raised during
82 -- this procedure are deferred.
84 -----------------------
85 -- Check_Environment --
86 -----------------------
88 procedure Check_Environment
is
90 if not Valid_Environment
then
93 end Check_Environment
;
99 function Count
return Natural is
101 return Key_Value_Table
.Last
;
108 function Exists
(Key
: String) return Boolean is
112 for K
in 1 .. Key_Value_Table
.Last
loop
113 if Key_Value_Table
.Table
(K
).Key
.all = Key
then
121 ----------------------
122 -- For_Every_Cookie --
123 ----------------------
125 procedure For_Every_Cookie
is
131 for K
in 1 .. Key_Value_Table
.Last
loop
134 Action
(Key_Value_Table
.Table
(K
).Key
.all,
135 Key_Value_Table
.Table
(K
).Value
.all,
141 end For_Every_Cookie
;
147 procedure Initialize
is
149 HTTP_COOKIE
: constant String := Metavariable
(CGI
.HTTP_Cookie
);
151 procedure Set_Parameter_Table
(Data
: String);
152 -- Parse Data and insert information in Key_Value_Table.
154 -------------------------
155 -- Set_Parameter_Table --
156 -------------------------
158 procedure Set_Parameter_Table
(Data
: String) is
160 procedure Add_Parameter
(K
: Positive; P
: String);
161 -- Add a single parameter into the table at index K. The parameter
162 -- format is "key=value".
164 Count
: constant Positive
165 := 1 + Strings
.Fixed
.Count
(Data
, Strings
.Maps
.To_Set
(";"));
166 -- Count is the number of parameters in the string. Parameters are
167 -- separated by ampersand character.
169 Index
: Positive := Data
'First;
176 procedure Add_Parameter
(K
: Positive; P
: String) is
177 Equal
: constant Natural := Strings
.Fixed
.Index
(P
, "=");
182 Key_Value_Table
.Table
(K
) :=
183 Key_Value
'(new String'(Decode
(P
(P
'First .. Equal
- 1))),
184 new String'(Decode (P (Equal + 1 .. P'Last))));
189 Key_Value_Table.Set_Last (Count);
191 for K in 1 .. Count - 1 loop
192 Sep := Strings.Fixed.Index (Data (Index .. Data'Last), ";");
194 Add_Parameter (K, Data (Index .. Sep - 1));
199 -- add last parameter
201 Add_Parameter (Count, Data (Index .. Data'Last));
202 end Set_Parameter_Table;
205 if HTTP_COOKIE /= "" then
206 Set_Parameter_Table (HTTP_COOKIE);
209 Valid_Environment := True;
213 Valid_Environment := False;
220 function Key (Position : Positive) return String is
224 if Position <= Key_Value_Table.Last then
225 return Key_Value_Table.Table (Position).Key.all;
227 raise Cookie_Not_Found;
235 function Ok return Boolean is
237 return Valid_Environment;
245 (Header : String := Default_Header;
246 Force : Boolean := False)
249 procedure Output_Cookies;
250 -- Iterate through the list of cookies to be sent to the server
257 procedure Output_Cookies is
259 procedure Output_One_Cookie
267 -- Output one cookie in the CGI header.
269 -----------------------
270 -- Output_One_Cookie --
271 -----------------------
273 procedure Output_One_Cookie
283 Text_IO.Put ("Set-Cookie: ");
284 Text_IO.Put (Key & '=' & Value);
286 if Comment /= "" then
287 Text_IO.Put ("; Comment=" & Comment);
291 Text_IO.Put ("; Domain=" & Domain);
294 if Max_Age /= Natural'Last then
295 Text_IO.Put ("; Max-Age=");
296 Integer_Text_IO.Put (Max_Age, Width => 0);
300 Text_IO.Put ("; Path=" & Path);
304 Text_IO.Put ("; Secure");
308 end Output_One_Cookie;
310 -- Start of processing for Output_Cookies
313 for C in 1 .. Cookie_Table.Last loop
314 Output_One_Cookie (Cookie_Table.Table (C).Key.all,
315 Cookie_Table.Table (C).Value.all,
316 Cookie_Table.Table (C).Comment.all,
317 Cookie_Table.Table (C).Domain.all,
318 Cookie_Table.Table (C).Max_Age,
319 Cookie_Table.Table (C).Path.all,
320 Cookie_Table.Table (C).Secure);
324 -- Start of processing for Put_Header
327 if Header_Sent = False or else Force then
329 Text_IO.Put_Line (Header);
343 Comment : String := "";
344 Domain : String := "";
345 Max_Age : Natural := Natural'Last;
346 Path : String := "/";
347 Secure : Boolean := False) is
349 Cookie_Table.Increment_Last;
351 Cookie_Table.Table (Cookie_Table.Last) :=
352 Cookie_Data'(new String'(Key),
354 new String'(Comment),
367 Required : Boolean := False)
373 for K in 1 .. Key_Value_Table.Last loop
374 if Key_Value_Table.Table (K).Key.all = Key then
375 return Key_Value_Table.Table (K).Value.all;
380 raise Cookie_Not_Found;
386 function Value (Position : Positive) return String is
390 if Position <= Key_Value_Table.Last then
391 return Key_Value_Table.Table (Position).Value.all;
393 raise Cookie_Not_Found;
397 -- Elaboration code for package
400 -- Initialize unit by reading the HTTP_COOKIE metavariable and fill
401 -- Key_Value_Table structure.