-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.pl
114 lines (90 loc) · 3.79 KB
/
server.pl
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
:-use_module(library(sockets)).
:-use_module(library(lists)).
:-use_module(library(codesio)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Server %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% To run, enter 'server.' on sicstus command line after consulting this file.
% You can test requests to this server by going to http://localhost:8081/<request>.
% Go to http://localhost:8081/quit to close server.
% Made by Luis Reis (ei12085@fe.up.pt) for LAIG course at FEUP.
port(8082).
% Server Entry Point
server :-
port(Port),
write('Opened Server'),nl,nl,
socket_server_open(Port, Socket),
server_loop(Socket),
socket_server_close(Socket),
write('Closed Server'),nl.
% Server Loop
% Uncomment writes for more information on incomming connections
server_loop(Socket) :-
repeat,
write('Em socket_server_accept\n'),
socket_server_accept(Socket, _Client, Stream, [type(text)]),
write('Accepted connection'), nl,
% Parse Request
catch((
read_request(Stream, Request),
read_header(Stream)
),_Exception,(
write('Error parsing request.'),nl,
close_stream(Stream),
fail
)),
% Generate Response
handle_request(Request, MyReply, Status),
format('Request: ~q~n',[Request]),
format('Reply: ~q~n', [MyReply]),
% Output Response
format(Stream, 'HTTP/1.0 ~p~n', [Status]),
format(Stream, 'Access-Control-Allow-Origin: *~n', []),
format(Stream, 'Content-Type: text/plain~n~n', []),
format(Stream, '~p', [MyReply]),
write('Finnished Connection'),nl,nl,
close_stream(Stream),
(Request = quit), !.
close_stream(Stream) :- flush_output(Stream), close(Stream).
% Handles parsed HTTP requests
% Returns 200 OK on successful aplication of parse_input on request
% Returns 400 Bad Request on syntax error (received from parser) or on failure of parse_input
handle_request(Request, MyReply, '200 OK') :- catch(parse_input(Request, MyReply),error(_,_),fail), !.
handle_request(syntax_error, 'Syntax Error', '400 Bad Request') :- !.
handle_request(_, 'Bad Request', '400 Bad Request').
% Reads first Line of HTTP Header and parses request
% Returns term parsed from Request-URI
% Returns syntax_error in case of failure in parsing
read_request(Stream, Request) :-
write('Em read_line\n'),
read_line(Stream, LineCodes),
print_header_line(LineCodes),
% Parse Request
atom_codes('GET /',Get),
append(Get,RL,LineCodes),
read_request_aux(RL,RL2),
catch(read_from_codes(RL2, Request), error(syntax_error(_),_), fail), !.
read_request(_,syntax_error).
read_request_aux([32|_],[46]) :- !.
read_request_aux([C|Cs],[C|RCs]) :- read_request_aux(Cs, RCs).
% Reads and Ignores the rest of the lines of the HTTP Header
read_header(Stream) :-
repeat,
read_line(Stream, Line),
print_header_line(Line),
(Line = []; Line = end_of_file),!.
check_end_of_header([]) :- !, fail.
check_end_of_header(end_of_file) :- !,fail.
check_end_of_header(_).
% Function to Output Request Lines (uncomment the line bellow to see more information on received HTTP Requests)
% print_header_line(LineCodes) :- catch((atom_codes(Line,LineCodes),write(Line),nl),_,fail), !.
print_header_line(_).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Commands %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Require your Prolog Files here
parse_input(handshake, handshake).
parse_input(test(C,N), Res) :- test(C,Res,N).
parse_input(quit, goodbye).
test(_,[],N) :- N =< 0.
test(A,[A|Bs],N) :- N1 is N-1, test(A,Bs,N1).