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 | --
-- Author: Brent Seidel
-- Date: 6-Aug-2024
--
-- This file is part of Simple Ada Web Server.
-- Simple Ada Web Server is free software: you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as published
-- by the Free Software Foundation, either version 3 of the License, or (at
-- your option) any later version.
--
-- Simple Ada Web Server is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-- more details.
--
-- You should have received a copy of the GNU General Public License along
-- with Simple Ada Web Server. If not, see <https://www.gnu.org/licenses/>.--
--
with Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO;
with Ada.Exceptions;
package body BBS.web is
package ASU renames Ada.Strings.Unbounded; -- not the school
--
-- A protected type for maintianing a counter of active request_handler
-- tasks.
--
protected body protected_counter is
procedure increment is
begin
value := value + 1;
end;
--
procedure decrement is
begin
value := value - 1;
end;
--
function read return Integer is
begin
return value;
end;
end protected_counter;
--
-- A protected flag for communicating between tasks
--
protected body protected_flag is
procedure set is
begin
value := True;
end;
procedure clear is
begin
value := False;
end;
function get return Boolean is
begin
return value;
end;
end protected_flag;
--
-- Load the dictionary from a file. No error checking is done on the open
-- since if this doesn't work, there really isn't much point in continuing.
--
-- Each line of the file must contain three entries each separated by a
-- single space. The entries themselves cannot contain spaces.
--
-- The first entry is the reqested item. This is what the client sends to
-- the server. Since the client HTML encodes certain characters, this will
-- have to match the encoded value.
--
-- The second entry is either the local filename or a name to identify an
-- internal routine to generate data.
--
-- The last entry is the MIME type of the file or "internal" if the data is
-- generated internally.
--
-- Comments can be added. A comment is indicated by a '#' character at the
-- start of a line. Everything through the end of that line is ignored.
--
procedure load_directory(name : String; map : out dictionary.Map) is
location : ASU.Unbounded_String;
file : Ada.Text_IO.File_Type;
line : ASU.Unbounded_String;
item : ASU.Unbounded_String;
mime : ASU.Unbounded_String;
space : Natural;
el : element;
begin
map.Clear;
Ada.Text_IO.Open(File => file,
Mode => Ada.Text_IO.In_File,
Name => name);
while not Ada.Text_IO.End_Of_File(file) loop
line := Ada.Text_IO.Unbounded_IO.Get_Line(file);
--
-- Check for comment. First character is '#'.
--
if (ASU.Element(line, 1) /= '#') then
--
-- Parse out the item
--
space := ASU.Index(line, " ");
item := ASU.Head(line, space - 1);
line := ASU.Tail(line, ASU.Length(line) - space);
--
-- Parse out the location and MIME type
--
space := ASU.Index(line, " ");
location := ASU.Head(line, space - 1);
mime := ASU.Tail(line, ASU.Length(line) - space);
el.file := location;
el.mime := mime;
map.Insert(ASU.To_String(item), el);
end if;
end loop;
Ada.Text_IO.Close(file);
exception
when err: others =>
Ada.Text_IO.Put_Line("Exception occured processing directory file.");
Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Information(err));
raise;
end load_directory;
--
-- Convert a hex digit character to a number
--
function hex_digit(c : Character) return Integer is
n : Integer := 0;
begin
case c is
when '0' =>
n := 0;
when '1' =>
n := 1;
when '2' =>
n := 2;
when '3' =>
n := 3;
when '4' =>
n := 4;
when '5' =>
n := 5;
when '6' =>
n := 6;
when '7' =>
n := 7;
when '8' =>
n := 8;
when '9' =>
n := 9;
when 'a' | 'A' =>
n := 10;
when 'b' | 'B' =>
n := 11;
when 'c' | 'C' =>
n := 12;
when 'd' | 'D' =>
n := 13;
when 'e' | 'E' =>
n := 14;
when 'f' | 'F' =>
n := 15;
when others =>
n := 0;
end case;
return n;
end hex_digit;
--
-- URL Decode a string.
--
function url_decode(s : String) return String is
t : ASU.Unbounded_String := ASU.Null_Unbounded_String;
i : Natural := 1;
c : Character;
v : Integer;
begin
while (i <= s'Length) loop
c := s(i);
if (c = '%') then
v := hex_digit(s(i + 1))*16 + hex_digit(s(i + 2));
c := Character'Val(v);
i := i + 2;
null;
elsif (c = '+')
then
c := ' ';
end if;
i := i + 1;
t := t & c;
end loop;
return ASU.To_String(t);
end url_decode;
end BBS.web;
|