Skip to content

Commit 13094d6

Browse files
author
Daniel Collins
committed
initial commit after reorganization
0 parents  commit 13094d6

File tree

7 files changed

+229
-0
lines changed

7 files changed

+229
-0
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*~
2+
*.orig
3+
*.swp
4+
*.out
5+
*.rej
6+
*.ali
7+
*.o
8+
9+
/bin
10+

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
This program (all files herein) is hereby placed in the public domain.
2+
3+
If you live in a country which does not regcognize the above commission,
4+
you may wish to instead use this program under a liberal license, below.
5+
6+
-------
7+
8+
Alternatively, this program is licensed to you under the following terms:
9+
10+
Copyright (C) 2020, Daniel C.
11+
12+
Permission to use, copy, modify, and/or distribute this software for
13+
any purpose with or without fee is hereby granted.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18+
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19+
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20+
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21+
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

build.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
gnatmake test

http-request.adb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
with Ada.Text_IO; use Ada.Text_IO;
2+
3+
package body HTTP.Request is
4+
package body Parse is
5+
procedure Debug (Ctx : in Context; Str : in String) is
6+
function Slice (Idx: in HTTP.Indexes; Str : in String) return String
7+
is (Str (Idx.First .. Idx.Last));
8+
begin
9+
Put_Line ("KIND: " & Slice (Ctx.Split.Line.Kind, Str));
10+
Put_Line ("PATH: " & Slice (Ctx.Split.Line.Path, Str));
11+
Put_Line ("VERS: " & Slice (Ctx.Split.Line.Vers, Str));
12+
for I in Integer range 1 .. Ctx.Split.Cnt-1 loop
13+
Put_Line ("["
14+
& Slice (Ctx.Split.Headers (I).Key, Str) & ": "
15+
& Slice (Ctx.Split.Headers (I).Val, Str)
16+
&
17+
"]");
18+
end loop;
19+
Put_Line ("TERMINAL STATE: " & Parse_State'Image (Ctx.State));
20+
end Debug;
21+
22+
package State is
23+
type Char_Table is array (Character) of Parse_State;
24+
type Step_Table is array (Parse_State) of Char_Table;
25+
26+
subtype Up is Character range 'A' .. 'Z';
27+
subtype Low is Character range 'a' .. 'z';
28+
subtype Num is Character range '0' .. '9';
29+
30+
CR : constant Character := ASCII.CR; LF : constant Character := ASCII.LF;
31+
32+
-- A mealy machine expressed as a lookup table, for request parsing;
33+
Table : Step_Table :=
34+
(
35+
Kind => (Up => Kind, ' ' => Path, others => Err),
36+
Path => (Up | Low |'/' | '.' => Path, ' ' => Pref, others => Err),
37+
Pref => (Up | Num |'/' | '.' => Pref, CR => Line, others => Err),
38+
--------------------------------------------------------------------
39+
-- TODO: ... Perhaps put the transitions for Responses here.
40+
--------------------------------------------------------------------
41+
Line => ( LF => Head, others => Err),
42+
Head => (Up|Low|'-' => Head, ':' => SSep, CR => Term, others => Err),
43+
SSep => ( ' ' => HBod, others => Err ),
44+
HBod => (CR => Line, others => HBod),
45+
Term => (LF => Done, others => Err ),
46+
Done => (others => Overread),
47+
Overread => (others => Overread), -- Maps to itself.
48+
Err => (others => Err )); -- Maps to itself.
49+
50+
function Step (St : Parse_State; Ch : Character) return Parse_State
51+
is (State.Table (St) (Ch));
52+
end State;
53+
54+
procedure Update_Split (Req : in out As_Sliced;
55+
Prv, Nxt : in Parse_State;
56+
Count : in Natural) is
57+
procedure Update (Next_Indxs : in out Indexes;
58+
Transition : in Boolean) is
59+
begin
60+
if Transition then Next_Indxs.First := Count + 1; end if;
61+
Next_Indxs.Last := Count;
62+
end Update;
63+
64+
Trans : Boolean := Prv /= Nxt;
65+
begin -- TODO: Use inheiritance + casting to have a single function.
66+
case Nxt is
67+
when Kind => Update (Req.Line.Kind, False);
68+
when Path => Update (Req.Line.Path, Trans);
69+
when Pref => Update (Req.Line.Vers, Trans);
70+
when Head => Update (Req.Headers (Req.Cnt).Key, Trans);
71+
when HBod => Update (Req.Headers (Req.Cnt).Val, Trans);
72+
when Line => Req.Cnt := Req.Cnt + 1;
73+
when others => null;
74+
end case;
75+
end Update_Split;
76+
77+
procedure One_Char (Ctx : in out Context; Char : in Character) is
78+
Next_State : Parse_State;
79+
begin
80+
Next_State := State.Step(Ctx.State, Char);
81+
Update_Split (Ctx.Split, Ctx.State, Next_State, Ctx.Count);
82+
83+
Ctx. Count := Ctx. Count + 1;
84+
Ctx. State := Next_State;
85+
end One_Char;
86+
87+
procedure Str_Read (Ctx: in out Context; Str: in String; Cnt: out Natural) is
88+
Original : Positive := Ctx.Count;
89+
begin
90+
for I in Str'Range loop
91+
One_Char (Ctx, Str (I));
92+
exit when Ctx. State = Done;
93+
end loop;
94+
95+
Cnt := Ctx. Count - Original;
96+
end Str_Read;
97+
end Parse;
98+
end HTTP.Request;

http-request.ads

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package HTTP.Request with SPARK_Mode => On
2+
is
3+
package Sliced is
4+
type Header is record
5+
Key : Indexes;
6+
Val : Indexes;
7+
end record;
8+
subtype Header_Index is Natural range 1 .. 20;
9+
type Header_List is array (Header_Index) of Header;
10+
11+
type Request_Line is record
12+
Kind : Indexes; -- Get, Post, ect.
13+
Path : Indexes;
14+
Vers : Indexes;
15+
end record;
16+
17+
type Request is record
18+
Line : Request_Line;
19+
Headers : Header_List;
20+
Cnt : Natural := 0;
21+
end record;
22+
end Sliced;
23+
24+
type As_Stored is null record; -- TODO;
25+
type As_Sliced is new Sliced.Request;
26+
type Parse_State is private;
27+
28+
29+
-- Note: Parse is a separate nested pacakge.
30+
package Parse is
31+
type Context is private;
32+
procedure One_Char (Ctx : in out Context; Char: in Character);
33+
procedure Str_Read (Ctx : in out Context; Str : in String; Cnt: out Natural);
34+
procedure Debug (Ctx : in Context; Str : in String);
35+
36+
private
37+
type Context is record
38+
State : Parse_State;
39+
Split : As_Sliced; -- TODO: Better names for ``Count''
40+
Count : Positive := 1; -- Position of incoming char (1st, 2nd, ..)
41+
end record;
42+
end Parse;
43+
44+
-- Note: Parse is a separate nested package.
45+
46+
private
47+
type Parse_State is (
48+
-- Request Header --
49+
Kind, -- Kind: The request method type; Get, Post, ect.
50+
Path,
51+
Pref, -- HTTP version preferred by client.
52+
53+
Line, -- Waiting for the rest of the carriage return sequence.
54+
Head, -- Gathering the name of header (Part preceeded by colon ':').
55+
SSep, -- Remainder of separator, following colon; (a single space).
56+
HBod, -- Body of header. (Following the colon and space);
57+
58+
-- Final CRLF; HTTP Requests terminated by an additional CRLF sequence;
59+
-- These states represent this final evenuality.
60+
Term, -- Remainder of terminal CRLF sequence (the LF ('\n') part);
61+
Done, -- Done reading all the header sections!
62+
Overread, -- A character was fed after all header sections done with!
63+
Err -- Error state; Signals that an error occurred.
64+
) with Default_Value => Kind;
65+
end HTTP.Request;

http.ads

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--
2+
-- Nice little HTTP 1.x request parser. Uses a state machine.
3+
-- Operates by cutting up the incoming request string into sections.
4+
--
5+
6+
package HTTP with SPARK_Mode => On
7+
is
8+
type Version is delta 0.1 range 1.0 .. 9.9;
9+
10+
type Indexes is record
11+
First : Natural := 1;
12+
Last : Natural := 0;
13+
end record;
14+
end HTTP;

test.adb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
with HTTP; use HTTP;
2+
with HTTP.Request; use HTTP.Request;
3+
4+
procedure Test is
5+
CRLF : constant String := ASCII.CR & ASCII.LF;
6+
Test_String : constant String :=
7+
"GET /index.html HTTP/1.1" & CRLF &
8+
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)" & CRLF &
9+
"Host: www.adaisquitecool.com" & CRLF &
10+
"Accept-Language: en-us" & CRLF &
11+
"Accept-Encoding: gzip, deflate" & CRLF &
12+
"Connection: Keep-Alive" & CRLF & CRLF;
13+
HTTP_Parser : Parse.Context;
14+
Read_Length : Natural;
15+
begin
16+
Parse.Str_Read (HTTP_Parser, Test_String, Read_Length);
17+
Parse.Debug (HTTP_Parser, Test_String);
18+
end Test;

0 commit comments

Comments
 (0)