Commit 0f0689d5ee2c708265bd7e70107318ac787dee4d

Authored by Julien Verneuil
1 parent 8645a410

add CXM_jq_radio, replace url (String) argument of all jq_confirm_button to use …

…a JQuery_Actioner instead and update subsequent code thorough the project, some whitespaces may have been added to some files...
web/CXM_jquery.anubis
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 * User: Jeremy 3 * User: Jeremy
4 * Date: 21/08/2012 4 * Date: 21/08/2012
5 * Time: 16:52 5 * Time: 16:52
6 - * 6 + *
7 */ 7 */
8 8
9 read calexium_lib/web/CXM_making_a_web_site.anubis 9 read calexium_lib/web/CXM_making_a_web_site.anubis
@@ -26,6 +26,69 @@ public type JQuerySelector: @@ -26,6 +26,69 @@ public type JQuerySelector:
26 element_class(String name), 26 element_class(String name),
27 childs(HtmlId id). 27 childs(HtmlId id).
28 28
  29 +define String
  30 + jquery_button_get_onclick_action_window_options
  31 + (
  32 + List(Other_Window_Option) options,
  33 + String formated_options
  34 + )
  35 + =
  36 + //if there is already formated_options add a comma + space between the options
  37 + with comma = if formated_options="" then "" else ", ",
  38 +
  39 + if options is
  40 + {
  41 + [ ] then formated_options,
  42 + [ h . t ] then
  43 + if h is
  44 + {
  45 + resizable then jquery_button_get_onclick_action_window_options(
  46 + t, formated_options+ comma+ "resizable=yes" ),
  47 +
  48 + scrollbars then jquery_button_get_onclick_action_window_options(
  49 + t, formated_options+ comma + "scrollbars=yes"),
  50 +
  51 + width(w) then jquery_button_get_onclick_action_window_options(
  52 + t, formated_options+ comma + "width="+w),
  53 +
  54 + height(h) then jquery_button_get_onclick_action_window_options(
  55 + t, formated_options+ comma + "height="+h)
  56 + }
  57 + }
  58 + .
  59 +
  60 +public define String
  61 + jquery_button_get_onclick_action
  62 + (
  63 + JQuery_Actioner actioner
  64 + )
  65 + =
  66 + if actioner is jQuery_actioner(target, act_type, str) then
  67 + if target is
  68 + {
  69 + same then
  70 + if act_type is
  71 + {
  72 + jqform then "$('#"+str+"').submit();",
  73 + jqlink then "document.location='/?a="+str+"';",
  74 + jqscript then str
  75 + },
  76 + same(label) then
  77 + if act_type is
  78 + {
  79 + jqform then "$('#"+str+"').submit();",
  80 + jqlink then "document.location='/?a="+str+"';",
  81 + jqscript then str
  82 + },
  83 + other(window_name, window_options) then
  84 + if act_type is
  85 + {
  86 + jqform then "$('#"+str+"').submit();", //il s'agit d'une soumision d'un formulaire => cela se fait uniquement dans la même fenêtre !
  87 + jqlink then "window.open('"+str+"', '"+window_name+"', '"+jquery_button_get_onclick_action_window_options(window_options, "")+"');",
  88 + jqscript then str
  89 + }
  90 + }.
  91 +
29 public define String 92 public define String
30 format_jquery_selector 93 format_jquery_selector
31 ( 94 (
@@ -35,10 +98,10 @@ public define String @@ -35,10 +98,10 @@ public define String
35 { 98 {
36 element(html_id) then 99 element(html_id) then
37 if html_id is htmlId(id) then "'#" + id + "'", 100 if html_id is htmlId(id) then "'#" + id + "'",
38 - 101 +
39 element_class(name) then 102 element_class(name) then
40 "'." + name + "'", 103 "'." + name + "'",
41 - 104 +
42 childs(html_id) then 105 childs(html_id) then
43 if html_id is htmlId(id) then "'#" + id + " > *'" 106 if html_id is htmlId(id) then "'#" + id + " > *'"
44 }. 107 }.
@@ -50,14 +113,14 @@ public define Script @@ -50,14 +113,14 @@ public define Script
50 String code //javascript code to execute when the document is ready 113 String code //javascript code to execute when the document is ready
51 )= 114 )=
52 script("text/javascript","$(document).ready(function(){"+code+"});"). 115 script("text/javascript","$(document).ready(function(){"+code+"});").
53 - 116 +
54 public define String 117 public define String
55 jquery_ready 118 jquery_ready
56 ( 119 (
57 String code //javascript code to execute when the document is ready 120 String code //javascript code to execute when the document is ready
58 )= 121 )=
59 "$(document).ready(function(){"+code+"});". 122 "$(document).ready(function(){"+code+"});".
60 - 123 +
61 /* jQuery default js files */ 124 /* jQuery default js files */
62 define List(HTML_Head_Tag) 125 define List(HTML_Head_Tag)
63 jquery_defaults 126 jquery_defaults
@@ -66,7 +129,7 @@ define List(HTML_Head_Tag) @@ -66,7 +129,7 @@ define List(HTML_Head_Tag)
66 js(js_file("/js/jquery/jquery-1.11.3.js")), 129 js(js_file("/js/jquery/jquery-1.11.3.js")),
67 js(js_file("/js/jquery/jquery-ui-1.11.4/jquery-ui.min.js")), 130 js(js_file("/js/jquery/jquery-ui-1.11.4/jquery-ui.min.js")),
68 ]. 131 ].
69 - 132 +
70 /* Initialize jQuery in compatiblity mode with jQueryUI */ 133 /* Initialize jQuery in compatiblity mode with jQueryUI */
71 public define List(HTML_Head_Tag) 134 public define List(HTML_Head_Tag)
72 jquery_init 135 jquery_init
web/CXM_json.anubis
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 * User: ricard 3 * User: ricard
4 * Date: 18/08/2008 4 * Date: 18/08/2008
5 * Time: 08:12 5 * Time: 08:12
6 - * 6 + *
7 * To change this template use Tools | Options | Coding | Edit Standard Headers. 7 * To change this template use Tools | Options | Coding | Edit Standard Headers.
8 */ 8 */
9 9
@@ -38,7 +38,7 @@ public define JsonMember @@ -38,7 +38,7 @@ public define JsonMember
38 List(JsonMember) value, 38 List(JsonMember) value,
39 ) = 39 ) =
40 json_member(name, json_object(value)). 40 json_member(name, json_object(value)).
41 - 41 +
42 42
43 public define JsonMember 43 public define JsonMember
44 json_member 44 json_member
@@ -72,7 +72,7 @@ public define JsonMember @@ -72,7 +72,7 @@ public define JsonMember
72 String value, 72 String value,
73 ) = 73 ) =
74 json_member(name, json_string(value)). 74 json_member(name, json_string(value)).
75 - 75 +
76 public define JsonMember 76 public define JsonMember
77 json_member 77 json_member
78 ( 78 (
@@ -123,7 +123,7 @@ public define Printable_tree @@ -123,7 +123,7 @@ public define Printable_tree
123 ( 123 (
124 JsonValue json 124 JsonValue json
125 ). 125 ).
126 - 126 +
127 public define Printable_tree 127 public define Printable_tree
128 to_javascript 128 to_javascript
129 ( 129 (
@@ -137,7 +137,7 @@ public define Printable_tree @@ -137,7 +137,7 @@ public define Printable_tree
137 ) = 137 ) =
138 if member is json_member(name, value) then 138 if member is json_member(name, value) then
139 [ "\"", name, "\":" . format_json(value) ]. 139 [ "\"", name, "\":" . format_json(value) ].
140 - 140 +
141 public define Printable_tree 141 public define Printable_tree
142 json_member_to_js 142 json_member_to_js
143 ( 143 (
@@ -151,18 +151,18 @@ define Printable_tree @@ -151,18 +151,18 @@ define Printable_tree
151 ( 151 (
152 List(JsonMember) members 152 List(JsonMember) members
153 ) = 153 ) =
154 - if members is 154 + if members is
155 { 155 {
156 [] then [], 156 [] then [],
157 [h . t] then [ format_json_member(h), (if t is [] then "" else ",") . format_json_object(t) ] 157 [h . t] then [ format_json_member(h), (if t is [] then "" else ",") . format_json_object(t) ]
158 }. 158 }.
159 - 159 +
160 define Printable_tree 160 define Printable_tree
161 json_object_to_js 161 json_object_to_js
162 ( 162 (
163 List(JsonMember) members 163 List(JsonMember) members
164 ) = 164 ) =
165 - if members is 165 + if members is
166 { 166 {
167 [] then [], 167 [] then [],
168 [h . t] then [ json_member_to_js(h), (if t is [] then "" else ",") . json_object_to_js(t) ] 168 [h . t] then [ json_member_to_js(h), (if t is [] then "" else ",") . json_object_to_js(t) ]
@@ -173,18 +173,18 @@ define Printable_tree @@ -173,18 +173,18 @@ define Printable_tree
173 ( 173 (
174 List(JsonValue) values 174 List(JsonValue) values
175 ) = 175 ) =
176 - if values is 176 + if values is
177 { 177 {
178 [] then [], 178 [] then [],
179 [h . t] then [ format_json(h), (if t is [] then "" else ",") . format_json_array(t) ] 179 [h . t] then [ format_json(h), (if t is [] then "" else ",") . format_json_array(t) ]
180 }. 180 }.
181 - 181 +
182 define Printable_tree 182 define Printable_tree
183 json_array_to_js 183 json_array_to_js
184 ( 184 (
185 List(JsonValue) values 185 List(JsonValue) values
186 ) = 186 ) =
187 - if values is 187 + if values is
188 { 188 {
189 [] then [], 189 [] then [],
190 [h . t] then [ to_javascript(h), (if t is [] then "" else ",") . format_json_array(t) ] 190 [h . t] then [ to_javascript(h), (if t is [] then "" else ",") . format_json_array(t) ]
@@ -205,7 +205,7 @@ public define Printable_tree @@ -205,7 +205,7 @@ public define Printable_tree
205 json_bool(b) then str_pt(if b then "true" else "false", []), 205 json_bool(b) then str_pt(if b then "true" else "false", []),
206 json_null then str_pt("null", []) 206 json_null then str_pt("null", [])
207 }. 207 }.
208 - 208 +
209 public define Printable_tree 209 public define Printable_tree
210 to_javascript 210 to_javascript
211 ( 211 (
@@ -221,26 +221,25 @@ public define Printable_tree @@ -221,26 +221,25 @@ public define Printable_tree
221 json_bool(b) then str_pt(if b then "true" else "false", []), 221 json_bool(b) then str_pt(if b then "true" else "false", []),
222 json_null then str_pt("null", []) 222 json_null then str_pt("null", [])
223 }. 223 }.
224 - 224 +
225 public define String 225 public define String
226 format_json 226 format_json
227 ( 227 (
228 JsonValue json 228 JsonValue json
229 ) = 229 ) =
230 to_String(format_json(json)). 230 to_String(format_json(json)).
231 - 231 +
232 public define String 232 public define String
233 to_javascript 233 to_javascript
234 ( 234 (
235 JsonValue json 235 JsonValue json
236 ) = 236 ) =
237 to_String(to_javascript(json)). 237 to_String(to_javascript(json)).
238 -  
239 -public define WriteFileResult 238 +
  239 +public define WriteFileResult
240 write_to_file 240 write_to_file
241 ( 241 (
242 String filename, //filename where the JSON will be dump 242 String filename, //filename where the JSON will be dump
243 JsonValue json //JSON to dump 243 JsonValue json //JSON to dump
244 )= 244 )=
245 write_to_file(filename, format_json(json)). 245 write_to_file(filename, format_json(json)).
246 -  
web/CXM_multihost_http_server.anubis
1  1 
2 *Project* The Anubis Project 2 *Project* The Anubis Project
3 - 3 +
4 *Title* A Multi Host HTTP/HTTPS Server 4 *Title* A Multi Host HTTP/HTTPS Server
5 -  
6 - *Copyright* Copyright (c) Anubis Team 2003-2007. 5 +
  6 + *Copyright* Copyright (c) Anubis Team 2003-2007.
7 7
8 8
9 *Authors* Alain Prouté 9 *Authors* Alain Prouté
10 David René 10 David René
11 Cédric Ricard 11 Cédric Ricard
12 -  
13 12
14 - *Revised* 13 +
  14 + *Revised*
15 June 2015 : Optimization of the file upload 15 June 2015 : Optimization of the file upload
16 July 2007 : Initial version in calexium_lib 16 July 2007 : Initial version in calexium_lib
17 -  
18 -  
19 - *Overviews* 17 +
  18 +
  19 + *Overviews*
20 In this file a HTTP/HTTPS server is defined, which is able to handle multiple hosts 20 In this file a HTTP/HTTPS server is defined, which is able to handle multiple hosts
21 (virtual hosts). It answers HTTP/HTTPS requests, sends files (images or any other kind 21 (virtual hosts). It answers HTTP/HTTPS requests, sends files (images or any other kind
22 of file), constructs HTML pages on the fly using informations received from the client 22 of file), constructs HTML pages on the fly using informations received from the client
@@ -30,46 +30,46 @@ @@ -30,46 +30,46 @@
30 ----------------------------------- Table of Contents --------------------------------- 30 ----------------------------------- Table of Contents ---------------------------------
31 31
32 *** (1) Multihosting and redirections. 32 *** (1) Multihosting and redirections.
33 - *** (2) The incompatibility between SSL and virtual hosts. 33 + *** (2) The incompatibility between SSL and virtual hosts.
34 *** (3) HTTP headers and web arguments. 34 *** (3) HTTP headers and web arguments.
35 - *** (4) Site descriptions.  
36 - *** (5) Protection against denial of service attacks.  
37 - *** (6) Starting your HTTP and HTTPS servers.  
38 - *** (7) Private download.  
39 - *** (8) About web argument names.  
40 - *** (9) A web dispatcher. 35 + *** (4) Site descriptions.
  36 + *** (5) Protection against denial of service attacks.
  37 + *** (6) Starting your HTTP and HTTPS servers.
  38 + *** (7) Private download.
  39 + *** (8) About web argument names.
  40 + *** (9) A web dispatcher.
41 *** (10) HTTP Errors 41 *** (10) HTTP Errors
42 - 42 +
43 --------------------------------------------------------------------------------------- 43 ---------------------------------------------------------------------------------------
44 -  
45 44
46 -  
47 - 45 +
  46 +
  47 +
48 *** (1) Multihosting and redirections. 48 *** (1) Multihosting and redirections.
49 - 49 +
50 This HTTP/HTTPS server can handle several host (also called 'virtual hosts'), in other 50 This HTTP/HTTPS server can handle several host (also called 'virtual hosts'), in other
51 words, you may have several sites on the same server, with the same IP address and same 51 words, you may have several sites on the same server, with the same IP address and same
52 port numbers, but distinct 'host names'. 52 port numbers, but distinct 'host names'.
53 - 53 +
54 A HTTP request sent by a browser contains the following informations: 54 A HTTP request sent by a browser contains the following informations:
55 -  
56 - - a 'host name', 55 +
  56 + - a 'host name',
57 - an URI (Uniform Resource Identifier), 57 - an URI (Uniform Resource Identifier),
58 - - HTTP headers,  
59 - - web arguments (in the form 'name=value').  
60 - 58 + - HTTP headers,
  59 + - web arguments (in the form 'name=value').
  60 +
61 Actually, the host name is just the value of the HTTP header whose name is 'Host'. The 61 Actually, the host name is just the value of the HTTP header whose name is 'Host'. The
62 host name indicates which site is requested. Hence, it is the primary information for 62 host name indicates which site is requested. Hence, it is the primary information for
63 branching to the right site. If there is no 'Host' HTTP header in the request, the 63 branching to the right site. If there is no 'Host' HTTP header in the request, the
64 request is denied. 64 request is denied.
65 - 65 +
66 From now on, we may assume that the host is determined, and consequently that we are 66 From now on, we may assume that the host is determined, and consequently that we are
67 concerned by only one site. Each site has his own directories on the server's 67 concerned by only one site. Each site has his own directories on the server's
68 - disk.  
69 - 68 + disk.
  69 +
70 Each site also has a list of 'redirections'. A redirection is a triplet, like this one: 70 Each site also has a list of 'redirections'. A redirection is a triplet, like this one:
71 -  
72 - redirect("/", "www.our-business.com", "/homepage.awp") 71 +
  72 + redirect("/", "www.our-business.com", "/homepage.awp")
73 73
74 meaning that if the host is "www.our-business.com", and if the requested URI is "/", 74 meaning that if the host is "www.our-business.com", and if the requested URI is "/",
75 then the URI to be served is "/homepage.awp". 'redirect' is a constructor of the type 75 then the URI to be served is "/homepage.awp". 'redirect' is a constructor of the type
@@ -81,12 +81,12 @@ @@ -81,12 +81,12 @@
81 like ".jpg", ".png", ".txt", etc... and represents a file path relative to the 81 like ".jpg", ".png", ".txt", etc... and represents a file path relative to the
82 'public' directory of the site. If these conditions are satisfied, the file is sent to 82 'public' directory of the site. If these conditions are satisfied, the file is sent to
83 the client. Known extensions are recorded in 'web/mime.anubis'. 83 the client. Known extensions are recorded in 'web/mime.anubis'.
84 -  
85 -  
86 84
87 -  
88 - *** (2) The incompatibility between SSL and virtual hosts.  
89 - 85 +
  86 +
  87 +
  88 + *** (2) The incompatibility between SSL and virtual hosts.
  89 +
90 Handling virtual hosts makes a problem under SSL (i.e. when using HTTPS), which is due 90 Handling virtual hosts makes a problem under SSL (i.e. when using HTTPS), which is due
91 to the fact that the guys at Netscape who designed SSL probably did not have the 91 to the fact that the guys at Netscape who designed SSL probably did not have the
92 question of virtual hosts in mind. Indeed, the SSL handshake is completed before the 92 question of virtual hosts in mind. Indeed, the SSL handshake is completed before the
@@ -96,7 +96,7 @@ @@ -96,7 +96,7 @@
96 of the requested host. The user will have to accept the certificate manually, which is 96 of the requested host. The user will have to accept the certificate manually, which is
97 not good for the security image of the site. This problem has at least two solutions 97 not good for the security image of the site. This problem has at least two solutions
98 (as far as Anubis is concerned). 98 (as far as Anubis is concerned).
99 - 99 +
100 Solution 1. Arrange so that the network interface on which the server is listening 100 Solution 1. Arrange so that the network interface on which the server is listening
101 has at least as many different IP addresses as you have virtual hosts. Such 101 has at least as many different IP addresses as you have virtual hosts. Such
102 supplementary IP addresses are called 'IP Aliases'. In this case, start one HTTPS 102 supplementary IP addresses are called 'IP Aliases'. In this case, start one HTTPS
@@ -105,7 +105,7 @@ @@ -105,7 +105,7 @@
105 'anbexec' as you have virtual hosts, because each instance of 'anbexec' can handle only 105 'anbexec' as you have virtual hosts, because each instance of 'anbexec' can handle only
106 one server certificate. Of course, getting IP aliases is another problem to be solved 106 one server certificate. Of course, getting IP aliases is another problem to be solved
107 with your Internet provider. 107 with your Internet provider.
108 - 108 +
109 Solution 2. We propose a simple solution, using only one server certificate (hence 109 Solution 2. We propose a simple solution, using only one server certificate (hence
110 only one instance of 'anbexec'). Since, we have only one server certificate, we must 110 only one instance of 'anbexec'). Since, we have only one server certificate, we must
111 introduce a notion of 'main host', i.e. a host containing all other 'virtual 111 introduce a notion of 'main host', i.e. a host containing all other 'virtual
@@ -114,48 +114,48 @@ @@ -114,48 +114,48 @@
114 that the main host redirects him to the right virtual host. Actually, the process will 114 that the main host redirects him to the right virtual host. Actually, the process will
115 be transparent to the client, except that the client will see the name of the main host 115 be transparent to the client, except that the client will see the name of the main host
116 instead of the name of the virtual host in the 'location' field of the browser. 116 instead of the name of the virtual host in the 'location' field of the browser.
117 - 117 +
118 So, assume that the name of main host is 'www.securedhost.com', and that the names of 118 So, assume that the name of main host is 'www.securedhost.com', and that the names of
119 the virtual hosts are: 119 the virtual hosts are:
120 - 120 +
121 actual name simplified name 121 actual name simplified name
122 ----------------------------------------------------- 122 -----------------------------------------------------
123 www.virtual1.com virtual1 123 www.virtual1.com virtual1
124 www.virtual2.com virtual2 124 www.virtual2.com virtual2
125 www.virtual3.com virtual3 125 www.virtual3.com virtual3
126 - 126 +
127 Then the (confidential) document '/doc/my_document.pdf' on 'www.virtual2.com' will have 127 Then the (confidential) document '/doc/my_document.pdf' on 'www.virtual2.com' will have
128 the URL: 128 the URL:
129 - 129 +
130 https://www.securedhost.com/virtual2/doc/my_document.pdf 130 https://www.securedhost.com/virtual2/doc/my_document.pdf
131 - 131 +
132 In order to work transparently, this solution must combine HTTP and HTTPS. Indeed, the 132 In order to work transparently, this solution must combine HTTP and HTTPS. Indeed, the
133 vitual host must have a first page reachable under HTTP, through the URL: 133 vitual host must have a first page reachable under HTTP, through the URL:
134 - 134 +
135 http://www.virtual2.com/ 135 http://www.virtual2.com/
136 - 136 +
137 The HTTP server will redirect this URL to the awp handler of virtual host 'virtual2'. 137 The HTTP server will redirect this URL to the awp handler of virtual host 'virtual2'.
138 The handler of this virtual host is able to generate a first page containing the 138 The handler of this virtual host is able to generate a first page containing the
139 following HTML meta: 139 following HTML meta:
140 - 140 +
141 <meta http-equiv="Refresh" content="0;URL=https://www.securedhost.com/virtual2/">, 141 <meta http-equiv="Refresh" content="0;URL=https://www.securedhost.com/virtual2/">,
142 - 142 +
143 so that the client is immediately redirected to the main host under HTTPS (hence 143 so that the client is immediately redirected to the main host under HTTPS (hence
144 accepting tranparently the server certificate). The awp handler of 'virtual2' then 144 accepting tranparently the server certificate). The awp handler of 'virtual2' then
145 redirects this URL to the home page (maybe a login page) of 'virtual2'. 145 redirects this URL to the home page (maybe a login page) of 'virtual2'.
146 -  
147 - See 'web/making_a_web_site.anubis' for the sequel of this story.  
148 -  
149 -  
150 -  
151 -  
152 - 146 +
  147 + See 'web/making_a_web_site.anubis' for the sequel of this story.
  148 +
  149 +
  150 +
  151 +
  152 +
153 *** (3) HTTP headers and web arguments. 153 *** (3) HTTP headers and web arguments.
154 - 154 +
155 Each HTTP request which arrives on the server contains a request line followed by a 155 Each HTTP request which arrives on the server contains a request line followed by a
156 series of HTTP headers. Each HTTP header is a pair '(name,value)' assigning a value to 156 series of HTTP headers. Each HTTP header is a pair '(name,value)' assigning a value to
157 - a name. The type 'HTTP_header' is defined in 'web/common.anubis'.  
158 - 157 + a name. The type 'HTTP_header' is defined in 'web/common.anubis'.
  158 +
159 The request may also have a 'body'. The body contains either 'web arguments' or 159 The request may also have a 'body'. The body contains either 'web arguments' or
160 uploaded files (or both). The request line itself may also contain web arguments (in a 160 uploaded files (or both). The request line itself may also contain web arguments (in a
161 so-called 'query string'). Like HTTP headers, 'web arguments' are pairs 161 so-called 'query string'). Like HTTP headers, 'web arguments' are pairs
@@ -163,26 +163,26 @@ @@ -163,26 +163,26 @@
163 which the client clicks, while HTTP headers are generated by the browser itself. The 163 which the client clicks, while HTTP headers are generated by the browser itself. The
164 type 'Web_arg' is defined in 'web/common.anubis'. It has two alternatives, one for 164 type 'Web_arg' is defined in 'web/common.anubis'. It has two alternatives, one for
165 ordinary web arguments (pairs) and one for uploaded files. 165 ordinary web arguments (pairs) and one for uploaded files.
166 -  
167 -read CXM_common.anubis 166 +
  167 +read CXM_common.anubis
168 read tools/basis.anubis 168 read tools/basis.anubis
169 read tools/printable_tree.anubis 169 read tools/printable_tree.anubis
170 read system/string.anubis 170 read system/string.anubis
171 read system/files.anubis 171 read system/files.anubis
172 read system/lists.anubis 172 read system/lists.anubis
173 read system/data_io.anubis 173 read system/data_io.anubis
174 -read web/mime.anubis  
175 -  
176 -  
177 -  
178 - *** (4) Site descriptions. 174 +read web/mime.anubis
  175 +
  176 +
  177 +
  178 + *** (4) Site descriptions.
179 179
180 The type HTTP_Info gathers informations comming along with the client's request. These 180 The type HTTP_Info gathers informations comming along with the client's request. These
181 informations are rarely used for composing HTML pages. Nevertheless, they are at your 181 informations are rarely used for composing HTML pages. Nevertheless, they are at your
182 disposal. 182 disposal.
183 - 183 +
184 public type HTTP_Info: 184 public type HTTP_Info:
185 - http_info 185 + http_info
186 ( 186 (
187 Word32 ip_address, // IP address of the client 187 Word32 ip_address, // IP address of the client
188 String hostname, // hostname requested by the client 188 String hostname, // hostname requested by the client
@@ -191,25 +191,25 @@ public type HTTP_Info: @@ -191,25 +191,25 @@ public type HTTP_Info:
191 Bool is_https 191 Bool is_https
192 //One -> String generate_trust_ticket // may be used against denial of 192 //One -> String generate_trust_ticket // may be used against denial of
193 // service attacks 193 // service attacks
194 - ). 194 + ).
  195 +
  196 +
195 197
196 -  
197 -  
198 Each site is described by a 'web site description', which is a datum of type 198 Each site is described by a 'web site description', which is a datum of type
199 'Web_Site_Description'. 199 'Web_Site_Description'.
200 - 200 +
201 public type Web_Site_Description: 201 public type Web_Site_Description:
202 web_site_description( 202 web_site_description(
203 - List(String) common_names,  
204 - String site_directory,  
205 - Redirections redirections,  
206 - String charset,  
207 - List(String) journal_extensions,  
208 - List(String) journal_headers,  
209 - String authorization_secret,  
210 - List(MIME) known_mime_types,  
211 - (String host_name,  
212 - HTTP_Info http_info, 203 + List(String) common_names,
  204 + String site_directory,
  205 + Redirections redirections,
  206 + String charset,
  207 + List(String) journal_extensions,
  208 + List(String) journal_headers,
  209 + String authorization_secret,
  210 + List(MIME) known_mime_types,
  211 + (String host_name,
  212 + HTTP_Info http_info,
213 List(Web_arg) lwa, 213 List(Web_arg) lwa,
214 Bool is_https) -> (//List(HTTP_header), 214 Bool is_https) -> (//List(HTTP_header),
215 Printable_tree) awp_handler, 215 Printable_tree) awp_handler,
@@ -222,36 +222,36 @@ public type Web_Site_Description: @@ -222,36 +222,36 @@ public type Web_Site_Description:
222 "www.our-business.com". The reason why we have a list of common names instead of a 222 "www.our-business.com". The reason why we have a list of common names instead of a
223 single common name, is that it may be useful to have a common name like "192.168.0.1" 223 single common name, is that it may be useful to have a common name like "192.168.0.1"
224 for testing. 224 for testing.
225 - 225 +
226 'charset' is a string which will determine the character encoding to be used by the 226 'charset' is a string which will determine the character encoding to be used by the
227 browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252", 227 browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",
228 etc... 228 etc...
229 - 229 +
230 'journal_extensions' is the list of URI extensions for which you want a log in the 230 'journal_extensions' is the list of URI extensions for which you want a log in the
231 journal (and on the console). When a request arrives, and if the extension is a member 231 journal (and on the console). When a request arrives, and if the extension is a member
232 of this list, a message is printed into the journal of the site including the date, the 232 of this list, a message is printed into the journal of the site including the date, the
233 IP address of the client, the complete HTTP request line. The HTTP headers whose name 233 IP address of the client, the complete HTTP request line. The HTTP headers whose name
234 is a member of 'journal_headers' are also printed in the journal. A reasonable minimum 234 is a member of 'journal_headers' are also printed in the journal. A reasonable minimum
235 for these two components is: 235 for these two components is:
236 - 236 +
237 [".awp"] for journal_extensions 237 [".awp"] for journal_extensions
238 ["user-agent"] for journal_headers 238 ["user-agent"] for journal_headers
239 - 239 +
240 'authorization_secret' is a string which should just be unguessable. You may choose 240 'authorization_secret' is a string which should just be unguessable. You may choose
241 something like (but don't choose this one !): 241 something like (but don't choose this one !):
242 - 242 +
243 "Hg8kJe42gCML9jNH-74" 243 "Hg8kJe42gCML9jNH-74"
244 - 244 +
245 i.e. a sequence of characters typed at random, long enough to be unguessable. This is 245 i.e. a sequence of characters typed at random, long enough to be unguessable. This is
246 - used by the 'private download' mecanism, which is discussed later in this file.  
247 - 246 + used by the 'private download' mecanism, which is discussed later in this file.
  247 +
248 The component 'awp_handler' is a function of type: 248 The component 'awp_handler' is a function of type:
249 -  
250 - (String host_name,  
251 - HTTP_Info http_info, 249 +
  250 + (String host_name,
  251 + HTTP_Info http_info,
252 List(Web_arg) web_args, 252 List(Web_arg) web_args,
253 Bool is_https) -> Printable_tree 253 Bool is_https) -> Printable_tree
254 - 254 +
255 ('Printable_tree' is a substitute for 'String' and is defined in 255 ('Printable_tree' is a substitute for 'String' and is defined in
256 'tools/basis.anubis'). This function is the 'awp handler' for the site. When the URI 256 'tools/basis.anubis'). This function is the 'awp handler' for the site. When the URI
257 ends by ".awp", this function is called, and the result (an HTML page) is sent to the 257 ends by ".awp", this function is called, and the result (an HTML page) is sent to the
@@ -259,173 +259,173 @@ public type Web_Site_Description: @@ -259,173 +259,173 @@ public type Web_Site_Description:
259 'true' when the requests arrives through the HTTPS channel, and 'false' when it arrives 259 'true' when the requests arrives through the HTTPS channel, and 'false' when it arrives
260 through the HTTP channel. 260 through the HTTP channel.
261 261
262 -  
263 -  
264 -  
265 -  
266 -  
267 -  
268 - *** (5) Protection against denial of service attacks.  
269 - 262 +
  263 +
  264 +
  265 +
  266 +
  267 +
  268 + *** (5) Protection against denial of service attacks.
  269 +
270 We need to protect our servers against 'denial of service' attacks. The attack may be 270 We need to protect our servers against 'denial of service' attacks. The attack may be
271 send automatically from machines which are infested by viruses. In that case, our 271 send automatically from machines which are infested by viruses. In that case, our
272 server is saturated of connections (all virtual machines at work), but nothing is 272 server is saturated of connections (all virtual machines at work), but nothing is
273 comming on the connections. In order to avoid this problem, we propose the following: 273 comming on the connections. In order to avoid this problem, we propose the following:
274 - 274 +
275 (1) Limit the number of simultaneous connections (say to 100). 275 (1) Limit the number of simultaneous connections (say to 100).
276 (2) Close a connection if the request is not complete after say 10 seconds. 276 (2) Close a connection if the request is not complete after say 10 seconds.
277 (3) Close the connection if the request is bigger than a given size (normal requests 277 (3) Close the connection if the request is bigger than a given size (normal requests
278 - are small except when there are uploaded files. 278 + are small except when there are uploaded files.
279 (4) Close the connection during the sending of the answer if the client is waiting 279 (4) Close the connection during the sending of the answer if the client is waiting
280 too much. 280 too much.
281 (5) Record all IP addresses with which we have encountered one of the problems above. 281 (5) Record all IP addresses with which we have encountered one of the problems above.
282 (6) Immediately close the connections if the IP address is in our list. 282 (6) Immediately close the connections if the IP address is in our list.
283 (7) Remove an address from the list only after 5 minutes of inactivity of this 283 (7) Remove an address from the list only after 5 minutes of inactivity of this
284 address. 284 address.
285 - (8) Maintain a list of reliable IP addresses. 285 + (8) Maintain a list of reliable IP addresses.
286 286
287 Of course, all the above are approximative solutions which may in some circumstances 287 Of course, all the above are approximative solutions which may in some circumstances
288 become either cumbersome or also partially block the system. So, it is needed to have a 288 become either cumbersome or also partially block the system. So, it is needed to have a
289 set of dynamically modifiable parameters in order to master the behavior of this 289 set of dynamically modifiable parameters in order to master the behavior of this
290 mecanism. 290 mecanism.
291 -  
292 - 291 +
  292 +
293 Each dubious IP address is recorded together with its last activity time. 293 Each dubious IP address is recorded together with its last activity time.
294 - 294 +
295 public type DubiousIP: 295 public type DubiousIP:
296 dubious_ip (Word32 address, 296 dubious_ip (Word32 address,
297 - Int last_activity).  
298 -  
299 - 297 + Int last_activity).
  298 +
  299 +
300 public type DenialOfService: 300 public type DenialOfService:
301 - denial_of_service(Var(Int) max_connections, 301 + denial_of_service(Var(Int) max_connections,
302 Var(Int) request_line_delay, // seconds 302 Var(Int) request_line_delay, // seconds
303 - Var(Int) headers_delay,  
304 - Var(Int) answer_delay, 303 + Var(Int) headers_delay,
  304 + Var(Int) answer_delay,
305 Var(List(DubiousIP)) list_of_dubious, 305 Var(List(DubiousIP)) list_of_dubious,
306 - Var(List(Word32)) reliable_addresses).  
307 - 306 + Var(List(Word32)) reliable_addresses).
  307 +
308 The informations in this set of variables are stored serialized into the file 308 The informations in this set of variables are stored serialized into the file
309 'my_anubis/web_sites/dos_info'. If this file does not exist a set if variables with 309 'my_anubis/web_sites/dos_info'. If this file does not exist a set if variables with
310 default values is created. The values are saved on the disk each time they are 310 default values is created. The values are saved on the disk each time they are
311 modified. 311 modified.
312 -  
313 -public define DenialOfService load_denial_of_service_info.  
314 -  
315 -  
316 -  
317 - *** (6) Starting your HTTP and HTTPS servers.  
318 - 312 +
  313 +public define DenialOfService load_denial_of_service_info.
  314 +
  315 +
  316 +
  317 + *** (6) Starting your HTTP and HTTPS servers.
  318 +
319 When your web site descriptions are ready, you can start a pair of servers (a HTTP 319 When your web site descriptions are ready, you can start a pair of servers (a HTTP
320 server and a HTTPS server) for serving your web sites. Notice that there are always 320 server and a HTTPS server) for serving your web sites. Notice that there are always
321 two servers, regardless of the number of web sites, and that each web sites normally 321 two servers, regardless of the number of web sites, and that each web sites normally
322 uses the two servers. 322 uses the two servers.
323 -  
324 - 323 +
  324 +
325 public define StartServerResult 325 public define StartServerResult
326 start_http_server 326 start_http_server
327 ( 327 (
328 - Word32 ip_address,  
329 - Word32 http_port, 328 + Word32 ip_address,
  329 + Word32 http_port,
330 List(Web_Site_Description) web_sites, 330 List(Web_Site_Description) web_sites,
331 DenialOfService dos 331 DenialOfService dos
332 - ).  
333 - 332 + ).
  333 +
334 public define StartServerResult 334 public define StartServerResult
335 start_https_server 335 start_https_server
336 ( 336 (
337 - Word32 ip_address, 337 + Word32 ip_address,
338 Word32 https_port, 338 Word32 https_port,
339 - String certificate_common_name, 339 + String certificate_common_name,
340 List(Web_Site_Description) web_sites, 340 List(Web_Site_Description) web_sites,
341 DenialOfService dos 341 DenialOfService dos
342 - ).  
343 - 342 + ).
  343 +
344 The first argument 'ip_address' is the IP address on which the servers listen. If you 344 The first argument 'ip_address' is the IP address on which the servers listen. If you
345 put 0, the servers listen on all adresses of the machine (which is useful if the 345 put 0, the servers listen on all adresses of the machine (which is useful if the
346 machine has several network interfaces). Otherwise, use the function 'ip_address' 346 machine has several network interfaces). Otherwise, use the function 'ip_address'
347 - defined in 'tools/basis.anubis' for composing a particular IP address.  
348 - 347 + defined in 'tools/basis.anubis' for composing a particular IP address.
  348 +
349 The next arguments are the port numbers for HTTP and HTTPS. The usual values are 80 and 349 The next arguments are the port numbers for HTTP and HTTPS. The usual values are 80 and
350 - 443, but you may have reasons to choose other values.  
351 - 350 + 443, but you may have reasons to choose other values.
  351 +
352 The next argument is the list of your web site descriptions. All the sites described in 352 The next argument is the list of your web site descriptions. All the sites described in
353 this list will be accessible on the server. 353 this list will be accessible on the server.
354 - 354 +
355 The argument 'dos' is a set of dynamic variables containing the informations for 355 The argument 'dos' is a set of dynamic variables containing the informations for
356 protecting the servers against denial of service attacks. 356 protecting the servers against denial of service attacks.
357 -  
358 -  
359 -  
360 -  
361 -  
362 -  
363 - *** (7) Private download.  
364 - 357 +
  358 +
  359 +
  360 +
  361 +
  362 +
  363 + *** (7) Private download.
  364 +
365 It may happen that you want to propose private files for download. This means that such 365 It may happen that you want to propose private files for download. This means that such
366 a file could be downloaded only by the authorized person, and should not be seen by any 366 a file could be downloaded only by the authorized person, and should not be seen by any
367 other one. This feature can be used only under HTTPS, not under HTTP. 367 other one. This feature can be used only under HTTPS, not under HTTP.
368 368
369 The file may be located anywhere on the server. Hence, the file has a complete absolute 369 The file may be located anywhere on the server. Hence, the file has a complete absolute
370 path, like for example: 370 path, like for example:
371 - 371 +
372 /home/georges/my_documents/my_text.pdf 372 /home/georges/my_documents/my_text.pdf
373 - 373 +
374 which has nothing to do with the directories of the web server. Now, you may also want 374 which has nothing to do with the directories of the web server. Now, you may also want
375 to show another path or simply just a name to the client, not the actual absolute path 375 to show another path or simply just a name to the client, not the actual absolute path
376 above, which may need to remain secret. So for example, the same file may appear to the 376 above, which may need to remain secret. So for example, the same file may appear to the
377 client as: 377 client as:
378 - 378 +
379 informations.pdf 379 informations.pdf
380 - 380 +
381 The page must provide a link with an authorization. The authorization is just a web 381 The page must provide a link with an authorization. The authorization is just a web
382 argument, whose name is "zauth". The value of this web argument is computed by hashing 382 argument, whose name is "zauth". The value of this web argument is computed by hashing
383 some secret string (known only from the programmer of the web site) with the absolute 383 some secret string (known only from the programmer of the web site) with the absolute
384 path of the file. The HTTPS request will have the form: 384 path of the file. The HTTPS request will have the form:
385 - 385 +
386 GET /informations.pdf?zauth=d38161f5b4e87e2d46e06ff8b3e233be563794d1 386 GET /informations.pdf?zauth=d38161f5b4e87e2d46e06ff8b3e233be563794d1
387 -  
388 - The server will search for a file named  
389 - 387 +
  388 + The server will search for a file named
  389 +
390 zd38161f5b4e87e2d46e06ff8b3e233be563794d1 390 zd38161f5b4e87e2d46e06ff8b3e233be563794d1
391 - 391 +
392 (i.e. "z" concatenated with the value of the authorization) in the subdirectory 392 (i.e. "z" concatenated with the value of the authorization) in the subdirectory
393 'private_download' of the site directory. This file contains the absolute path of the 393 'private_download' of the site directory. This file contains the absolute path of the
394 file, i.e: 394 file, i.e:
395 - 395 +
396 /home/georges/my_documents/my_text.pdf 396 /home/georges/my_documents/my_text.pdf
397 - 397 +
398 At that point, the server may hash the secret string and the absolute path together, to 398 At that point, the server may hash the secret string and the absolute path together, to
399 check if the client is authorized to download the file. If it is the case, it sends the 399 check if the client is authorized to download the file. If it is the case, it sends the
400 file (the MIME type is declared as 'application/octet-stream' if it is not recognized). 400 file (the MIME type is declared as 'application/octet-stream' if it is not recognized).
401 The file is sent under the visible name. 401 The file is sent under the visible name.
402 - 402 +
403 The server creates automatically the subdirectory 'private_download/' within the 'site 403 The server creates automatically the subdirectory 'private_download/' within the 'site
404 directory' (for each web site) if it does not already exist. Files in this directory 404 directory' (for each web site) if it does not already exist. Files in this directory
405 are deleted when they become too old (for example, after 3 days of life). 405 are deleted when they become too old (for example, after 3 days of life).
406 - 406 +
407 Here is the function for computing the value of the authorization, and for making the 407 Here is the function for computing the value of the authorization, and for making the
408 authorization file in 'private_download'. 408 authorization file in 'private_download'.
409 -  
410 -public define String 409 +
  410 +public define String
411 make_authorization 411 make_authorization
412 ( 412 (
413 - String site_directory, 413 + String site_directory,
414 String authorization_secret, // known only by the programmer of the web site 414 String authorization_secret, // known only by the programmer of the web site
415 String absolute_path // on server 415 String absolute_path // on server
416 - ).  
417 -  
418 - See 'web/making_a_web_site.anubis' for the construction of the link for downloading.  
419 -  
420 -  
421 -  
422 -  
423 -  
424 -  
425 -  
426 -  
427 - *** (8) About web argument names.  
428 - 416 + ).
  417 +
  418 + See 'web/making_a_web_site.anubis' for the construction of the link for downloading.
  419 +
  420 +
  421 +
  422 +
  423 +
  424 +
  425 +
  426 +
  427 + *** (8) About web argument names.
  428 +
429 The server reserves the name "zauth" for the authorization in the private download 429 The server reserves the name "zauth" for the authorization in the private download
430 mecanism. Also, if the name of a web arguments begins by "p" (like 'password'), it does 430 mecanism. Also, if the name of a web arguments begins by "p" (like 'password'), it does
431 not print the value of the web argument neither on the console or in the journal. A 431 not print the value of the web argument neither on the console or in the journal. A
@@ -433,18 +433,18 @@ public define String @@ -433,18 +433,18 @@ public define String
433 method is used in 'web/making_a_web_site.anubis'. This will avoid clashes of names. 433 method is used in 'web/making_a_web_site.anubis'. This will avoid clashes of names.
434 434
435 435
436 -  
437 -  
438 -  
439 -  
440 - *** (9) A web dispatcher.  
441 - 436 +
  437 +
  438 +
  439 +
  440 + *** (9) A web dispatcher.
  441 +
442 For hosting several sites you may prefer another method which we now describe. We start 442 For hosting several sites you may prefer another method which we now describe. We start
443 a HTTP server on port 80 (or on another port). This server is called the 443 a HTTP server on port 80 (or on another port). This server is called the
444 ``dispatcher''. When a requests arrives, the dispatcher examines the ``host'' HTTP 444 ``dispatcher''. When a requests arrives, the dispatcher examines the ``host'' HTTP
445 header, so that it gets the name of the requested host. Then it sends to the client a 445 header, so that it gets the name of the requested host. Then it sends to the client a
446 page like this one: 446 page like this one:
447 - 447 +
448 <html> 448 <html>
449 <head> 449 <head>
450 <meta http-equiv="Refresh" content="0;URL=..."> 450 <meta http-equiv="Refresh" content="0;URL=...">
@@ -452,53 +452,53 @@ public define String @@ -452,53 +452,53 @@ public define String
452 <body> 452 <body>
453 </body> 453 </body>
454 </html> 454 </html>
455 - 455 +
456 where the URL represented by '...' is the URL of the requested site. This URL may have 456 where the URL represented by '...' is the URL of the requested site. This URL may have
457 the same IP address as the dispatcher, except that the port number is different. It may 457 the same IP address as the dispatcher, except that the port number is different. It may
458 also have a different IP address. 458 also have a different IP address.
459 - 459 +
460 The dispatcher uses the file 'my_anubis/web_sites/dispatcher.info'. This file contains 460 The dispatcher uses the file 'my_anubis/web_sites/dispatcher.info'. This file contains
461 - a serialized datum of type 'List(DispatcherInfo)'.  
462 - 461 + a serialized datum of type 'List(DispatcherInfo)'.
  462 +
463 public type DispatcherInfo: 463 public type DispatcherInfo:
464 - site(String common_name,  
465 - Word32 http_port).  
466 - 464 + site(String common_name,
  465 + Word32 http_port).
  466 +
467 The dispatcher does not write into this file. It reads it when it starts, and rereads 467 The dispatcher does not write into this file. It reads it when it starts, and rereads
468 it each time the date of last modification of the file changes, so that the dispatcher 468 it each time the date of last modification of the file changes, so that the dispatcher
469 always has up to date data. The file may be managed (written and updated) by another 469 always has up to date data. The file may be managed (written and updated) by another
470 program. 470 program.
471 - 471 +
472 So, for each site, the dispatcher knows the common name (needed to recognize the 'host' 472 So, for each site, the dispatcher knows the common name (needed to recognize the 'host'
473 HTTP header), and the pair (ip_address,port) used by the actual site for HTTP. The 473 HTTP header), and the pair (ip_address,port) used by the actual site for HTTP. The
474 - dispatcher does not worry about HTTPS. HTTPS must be managed by the actual site.  
475 -  
476 - The dispatcher is started by:  
477 - 474 + dispatcher does not worry about HTTPS. HTTPS must be managed by the actual site.
  475 +
  476 + The dispatcher is started by:
  477 +
478 public define One 478 public define One
479 start_web_dispatcher 479 start_web_dispatcher
480 ( 480 (
481 Word32 ip_address, // address for listening (typically 0) 481 Word32 ip_address, // address for listening (typically 0)
482 Word32 port, // typically 80 482 Word32 port, // typically 80
483 DenialOfService dos 483 DenialOfService dos
484 - ).  
485 - 484 + ).
  485 +
486 A command line tool for managing the file 'my_anubis/web_sites/dispatcher.info' is also 486 A command line tool for managing the file 'my_anubis/web_sites/dispatcher.info' is also
487 provided: 487 provided:
488 - 488 +
489 global define One 489 global define One
490 manage_web_dispatcher 490 manage_web_dispatcher
491 ( 491 (
492 List(String) args 492 List(String) args
493 - ).  
494 -  
495 - 493 + ).
  494 +
  495 +
496 *** (10) HTTP Errors 496 *** (10) HTTP Errors
497 - 497 +
498 public type HTTP_Status: 498 public type HTTP_Status:
499 http_continue, // 100 499 http_continue, // 100
500 http_switching_protocol, // 101 500 http_switching_protocol, // 101
501 - 501 +
502 http_ok, // 200 502 http_ok, // 200
503 http_created, // 201 503 http_created, // 201
504 http_accepted, // 202 504 http_accepted, // 202
@@ -506,7 +506,7 @@ public type HTTP_Status: @@ -506,7 +506,7 @@ public type HTTP_Status:
506 http_no_content, // 204 506 http_no_content, // 204
507 http_reset_content, // 205 507 http_reset_content, // 205
508 http_partial_content, // 206 508 http_partial_content, // 206
509 - 509 +
510 http_multiple_choices, 510 http_multiple_choices,
511 http_moved_permanently(String location), // 301 511 http_moved_permanently(String location), // 301
512 http_moved_temporarily(String location), // 302 512 http_moved_temporarily(String location), // 302
@@ -514,7 +514,7 @@ public type HTTP_Status: @@ -514,7 +514,7 @@ public type HTTP_Status:
514 http_not_modified, // 304 514 http_not_modified, // 304
515 http_use_proxy(String location), // 305 515 http_use_proxy(String location), // 305
516 http_temporary_redirect(String location), // 307 516 http_temporary_redirect(String location), // 307
517 - 517 +
518 http_bad_request, // 400 518 http_bad_request, // 400
519 http_unauthorized, // 401 519 http_unauthorized, // 401
520 http_payment_required, // 402 520 http_payment_required, // 402
@@ -533,14 +533,14 @@ public type HTTP_Status: @@ -533,14 +533,14 @@ public type HTTP_Status:
533 http_unsupported_media_type, // 415 533 http_unsupported_media_type, // 415
534 http_request_range_unsatisfiable, // 416 534 http_request_range_unsatisfiable, // 416
535 http_expectation_failed, // 417 535 http_expectation_failed, // 417
536 - 536 +
537 http_internal_server_error, // 500 537 http_internal_server_error, // 500
538 http_not_implemented, // 501 538 http_not_implemented, // 501
539 http_bad_gateway, // 502 539 http_bad_gateway, // 502
540 http_service_unavailable, // 503 540 http_service_unavailable, // 503
541 http_gateway_timeout, // 504 541 http_gateway_timeout, // 504
542 http_version_not_supported, // 505 542 http_version_not_supported, // 505
543 - 543 +
544 http_error(Int /*code*/, String /*message*/). 544 http_error(Int /*code*/, String /*message*/).
545 545
546 public define (String, List(HTTP_header)) 546 public define (String, List(HTTP_header))
@@ -548,23 +548,23 @@ public define (String, List(HTTP_header)) @@ -548,23 +548,23 @@ public define (String, List(HTTP_header))
548 ( 548 (
549 HTTP_Status status 549 HTTP_Status status
550 ). 550 ).
551 -  
552 -  
553 -  
554 -  
555 - 551 +
  552 +
  553 +
  554 +
  555 +
556 --- That's all for the public part ! -------------------------------------------------- 556 --- That's all for the public part ! --------------------------------------------------
557 - 557 +
558 define Maybe(String) get_host_header_value(List(HTTP_header) headers). 558 define Maybe(String) get_host_header_value(List(HTTP_header) headers).
559 - 559 +
560 define String 560 define String
561 __utime_to_string 561 __utime_to_string
562 ( 562 (
563 UTime t 563 UTime t
564 ) = 564 ) =
565 to_decimal(t.seconds) + "." + zero_pad_n(6, t.microseconds ) + "s". 565 to_decimal(t.seconds) + "." + zero_pad_n(6, t.microseconds ) + "s".
566 -  
567 - 566 +
  567 +
568 variable UTime t0 = utime(0,0). 568 variable UTime t0 = utime(0,0).
569 variable UTime t1 = utime(0,0). 569 variable UTime t1 = utime(0,0).
570 570
@@ -572,18 +572,18 @@ define String @@ -572,18 +572,18 @@ define String
572 accumulate_t1 572 accumulate_t1
573 ( 573 (
574 UTime start 574 UTime start
575 - ) = 575 + ) =
576 with delta = (UTime)unow - start, 576 with delta = (UTime)unow - start,
577 t1 <- delta + *t1; 577 t1 <- delta + *t1;
578 unique. 578 unique.
579 - 579 +
580 variable UTime t2 = utime(0,0). 580 variable UTime t2 = utime(0,0).
581 581
582 define One 582 define One
583 accumulate_t2 583 accumulate_t2
584 ( 584 (
585 UTime start 585 UTime start
586 - ) = 586 + ) =
587 with delta = (UTime)unow - start, 587 with delta = (UTime)unow - start,
588 t2 <- delta + *t2; 588 t2 <- delta + *t2;
589 unique. 589 unique.
@@ -593,208 +593,208 @@ define String @@ -593,208 +593,208 @@ define String
593 print_delta 593 print_delta
594 ( 594 (
595 String txt 595 String txt
596 - ) = 596 + ) =
597 println(__utime_to_string((UTime)unow - *t0) + " : " + txt). 597 println(__utime_to_string((UTime)unow - *t0) + " : " + txt).
598 -  
599 - 598 +
  599 +
600 ----------------------------------- Table of Contents --------------------------------- 600 ----------------------------------- Table of Contents ---------------------------------
601 -  
602 - *** [1] Types which are private to this file.  
603 -  
604 - *** [2] Tools.  
605 - *** [2.1] Formating an error message.  
606 - *** [2.2] Converting IP addresses.  
607 - *** [2.3] Reading and unputting characters.  
608 - *** [2.4] Reading and discarding characters.  
609 - *** [2.5] Reading a character string.  
610 - *** [2.6] Padding integers with zeros.  
611 - *** [2.7] Converting web arguments to ASCII.  
612 - *** [2.8] Server description.  
613 -  
614 - *** [3] Managing the journal.  
615 - *** [3.1] Naming journal files.  
616 - *** [3.2] Formating HTTP headers.  
617 - *** [3.3] Formating web arguments.  
618 - *** [3.4] Formating the whole request.  
619 - *** [3.5] Putting it in the journal file (and on the console).  
620 -  
621 - *** [4] Reading the HTTP request.  
622 - *** [4.1] Skipping leading blanks.  
623 - *** [4.2] Reading a new line.  
624 - *** [4.3] Reading a 'word'.  
625 - *** [4.4] Separating the URI from the query string.  
626 - *** [4.5] Reading the web arguments.  
627 - *** [4.7] Reading the request line.  
628 - *** [4.8] Reading the HTTP headers.  
629 - *** [4.9] Getting the size of the request's body. 601 +
  602 + *** [1] Types which are private to this file.
  603 +
  604 + *** [2] Tools.
  605 + *** [2.1] Formating an error message.
  606 + *** [2.2] Converting IP addresses.
  607 + *** [2.3] Reading and unputting characters.
  608 + *** [2.4] Reading and discarding characters.
  609 + *** [2.5] Reading a character string.
  610 + *** [2.6] Padding integers with zeros.
  611 + *** [2.7] Converting web arguments to ASCII.
  612 + *** [2.8] Server description.
  613 +
  614 + *** [3] Managing the journal.
  615 + *** [3.1] Naming journal files.
  616 + *** [3.2] Formating HTTP headers.
  617 + *** [3.3] Formating web arguments.
  618 + *** [3.4] Formating the whole request.
  619 + *** [3.5] Putting it in the journal file (and on the console).
  620 +
  621 + *** [4] Reading the HTTP request.
  622 + *** [4.1] Skipping leading blanks.
  623 + *** [4.2] Reading a new line.
  624 + *** [4.3] Reading a 'word'.
  625 + *** [4.4] Separating the URI from the query string.
  626 + *** [4.5] Reading the web arguments.
  627 + *** [4.7] Reading the request line.
  628 + *** [4.8] Reading the HTTP headers.
  629 + *** [4.9] Getting the size of the request's body.
630 *** [4.10] Reading the body of the request. 630 *** [4.10] Reading the body of the request.
631 -  
632 - *** [5] Making the HTTP answer.  
633 - *** [5.1] Avoiding illegal URIs.  
634 - *** [5.2] Managing authorizations for downloading private files.  
635 - *** [5.3] Recognizing MIME types.  
636 - *** [5.4] Formating HTTP headers.  
637 - *** [5.5] Sending a file.  
638 - *** [5.6] Answering a www-url encoded request.  
639 - *** [5.7] Answering a multipart/form-data encoded request. 631 +
  632 + *** [5] Making the HTTP answer.
  633 + *** [5.1] Avoiding illegal URIs.
  634 + *** [5.2] Managing authorizations for downloading private files.
  635 + *** [5.3] Recognizing MIME types.
  636 + *** [5.4] Formating HTTP headers.
  637 + *** [5.5] Sending a file.
  638 + *** [5.6] Answering a www-url encoded request.
  639 + *** [5.7] Answering a multipart/form-data encoded request.
640 *** [5.7.1] Finding the boundary. 640 *** [5.7.1] Finding the boundary.
641 - *** [5.7.2] Reading attributes from a multipart entity.  
642 - *** [5.7.3] Creating a temporary filename for an uploaded file.  
643 - *** [5.7.4] Saving an uploaded file under a temporary filename.  
644 - *** [5.7.5] Removing the path from a file name.  
645 - *** [5.7.6] Reading a multipart entity.  
646 - *** [5.8] Handling redirections.  
647 - *** [5.9] Answering both sorts of requests.  
648 -  
649 - *** [6] The HTTP/HTTPS servers.  
650 - *** [6.1] The HTTP request handler.  
651 - *** [6.2] Server's tasks.  
652 - *** [6.3] Starting the HTTP/HTTPS servers.  
653 -  
654 - *** [7] The web dispatcher.  
655 - *** [7.1] The dispatcher server.  
656 - *** [7.2] The dispatcher web site.  
657 - *** [7.3] Managing the info file.  
658 - 641 + *** [5.7.2] Reading attributes from a multipart entity.
  642 + *** [5.7.3] Creating a temporary filename for an uploaded file.
  643 + *** [5.7.4] Saving an uploaded file under a temporary filename.
  644 + *** [5.7.5] Removing the path from a file name.
  645 + *** [5.7.6] Reading a multipart entity.
  646 + *** [5.8] Handling redirections.
  647 + *** [5.9] Answering both sorts of requests.
  648 +
  649 + *** [6] The HTTP/HTTPS servers.
  650 + *** [6.1] The HTTP request handler.
  651 + *** [6.2] Server's tasks.
  652 + *** [6.3] Starting the HTTP/HTTPS servers.
  653 +
  654 + *** [7] The web dispatcher.
  655 + *** [7.1] The dispatcher server.
  656 + *** [7.2] The dispatcher web site.
  657 + *** [7.3] Managing the info file.
  658 +
659 --------------------------------------------------------------------------------------- 659 ---------------------------------------------------------------------------------------
660 -  
661 -  
662 -  
663 -  
664 -read tools/basis.anubis  
665 -read tools/findstring.anubis  
666 -read tools/connections.anubis  
667 -  
668 -  
669 -  
670 -  
671 -  
672 - *** [1] Types which are private to this file.  
673 -  
674 - We use the following self-explanatory types.  
675 - 660 +
  661 +
  662 +
  663 +
  664 +read tools/basis.anubis
  665 +read tools/findstring.anubis
  666 +read tools/connections.anubis
  667 +
  668 +
  669 +
  670 +
  671 +
  672 + *** [1] Types which are private to this file.
  673 +
  674 + We use the following self-explanatory types.
  675 +
676 type Error: 676 type Error:
677 cannot_read_from_connection, 677 cannot_read_from_connection,
678 not_get_or_post_request(String), 678 not_get_or_post_request(String),
679 end_of_line_expected, 679 end_of_line_expected,
680 incorrect_content_length_value, 680 incorrect_content_length_value,
681 colon_expected, 681 colon_expected,
682 - timeout(Int).  
683 - 682 + timeout(Int).
  683 +
684 type HTTP_RequestType: 684 type HTTP_RequestType:
685 get, 685 get,
686 - post.  
687 - 686 + post.
  687 +
688 type HTTP_RequestLine: 688 type HTTP_RequestLine:
689 - request_line (HTTP_RequestType type, 689 + request_line (HTTP_RequestType type,
690 String uri, 690 String uri,
691 - List(Web_arg) query_string).  
692 - 691 + List(Web_arg) query_string).
  692 +
693 type EncodingType: 693 type EncodingType:
694 www_url, 694 www_url,
695 - multipart_form_data.  
696 - 695 + multipart_form_data.
  696 +
697 type BufferedConnection: 697 type BufferedConnection:
698 buffered_connection(Connection conn, 698 buffered_connection(Connection conn,
699 Var(ByteArray) buffer, 699 Var(ByteArray) buffer,
700 Var(Int) read_pos). 700 Var(Int) read_pos).
701 -  
702 -  
703 -  
704 - *** [2] Tools.  
705 -  
706 - *** [2.1] Formating an error message.  
707 -  
708 - The next function formats an error message.  
709 - 701 +
  702 +
  703 +
  704 + *** [2] Tools.
  705 +
  706 + *** [2.1] Formating an error message.
  707 +
  708 + The next function formats an error message.
  709 +
710 define String 710 define String
711 format 711 format
712 ( 712 (
713 Error msg 713 Error msg
714 ) = 714 ) =
715 - if msg is 715 + if msg is
716 { 716 {
717 - cannot_read_from_connection then 717 + cannot_read_from_connection then
718 "Cannot read from connection.\n", 718 "Cannot read from connection.\n",
719 - not_get_or_post_request(s) then 719 + not_get_or_post_request(s) then
720 "The request did not begin by 'GET' or 'POST': "+s+".\n", 720 "The request did not begin by 'GET' or 'POST': "+s+".\n",
721 - end_of_line_expected then 721 + end_of_line_expected then
722 "End of line expected.\n", 722 "End of line expected.\n",
723 - incorrect_content_length_value then 723 + incorrect_content_length_value then
724 "Incorrect value for HTTP header 'Content-Length'.\n", 724 "Incorrect value for HTTP header 'Content-Length'.\n",
725 colon_expected then 725 colon_expected then
726 - "':' was expected.\n",  
727 - timeout(n) then 726 + "':' was expected.\n",
  727 + timeout(n) then
728 //"time out: "+n+"\n" 728 //"time out: "+n+"\n"
729 //"time out.\n" 729 //"time out.\n"
730 "" 730 ""
731 }. 731 }.
732 -  
733 -  
734 -  
735 -  
736 -  
737 -  
738 - *** [2.2] Converting IP addresses.  
739 - 732 +
  733 +
  734 +
  735 +
  736 +
  737 +
  738 + *** [2.2] Converting IP addresses.
  739 +
740 We need two conversion functions for IP addresses: 740 We need two conversion functions for IP addresses:
741 - 741 +
742 (Word8,Word8,Word8,Word8) --> Word32 ip_address 742 (Word8,Word8,Word8,Word8) --> Word32 ip_address
743 Word32 --> String ip_addr_to_string 743 Word32 --> String ip_addr_to_string
744 -  
745 - These conversions are defined in 'tools/basis.anubis'.  
746 -  
747 -  
748 -  
749 - *** [2.3] A set of state variables for the server.  
750 - 744 +
  745 + These conversions are defined in 'tools/basis.anubis'.
  746 +
  747 +
  748 +
  749 + *** [2.3] A set of state variables for the server.
  750 +
751 public type SState: 751 public type SState:
752 sstate 752 sstate
753 ( 753 (
754 Var(List(Word8)) unput_chars, // for reading requests 754 Var(List(Word8)) unput_chars, // for reading requests
755 Var(Int) sttm, // 'start time' 755 Var(Int) sttm, // 'start time'
756 - Var(Int) uploaded_file_count  
757 - ).  
758 -  
759 -  
760 - *** [2.4] Reading and unputting characters.  
761 - 756 + Var(Int) uploaded_file_count
  757 + ).
  758 +
  759 +
  760 + *** [2.4] Reading and unputting characters.
  761 +
762 We need a mecanism for unputting several characters (actually at least 3). This is 762 We need a mecanism for unputting several characters (actually at least 3). This is
763 because when reading the client connection, we must sometimes go ahead several 763 because when reading the client connection, we must sometimes go ahead several
764 characters, and virtually put them back into the connection, so that they can be 764 characters, and virtually put them back into the connection, so that they can be
765 reread. Of course, we do not send them back to the client. We store them in a list 765 reread. Of course, we do not send them back to the client. We store them in a list
766 (hold by the variable 'unput_chars'), and we manage this list, so that characters may 766 (hold by the variable 'unput_chars'), and we manage this list, so that characters may
767 be virtually put back in the connection (this is called 'unputting'). 767 be virtually put back in the connection (this is called 'unputting').
768 -  
769 - variable List(Word8) unput_chars = [].  
770 - 768 +
  769 + variable List(Word8) unput_chars = [].
  770 +
771 The most recently read one is the head of list. Fortunately, this variable is private 771 The most recently read one is the head of list. Fortunately, this variable is private
772 to this virtual machine (hence to this client). 772 to this virtual machine (hence to this client).
773 -  
774 - 773 +
  774 +
775 define One 775 define One
776 - unput // unputting a character (add it in front of the list) 776 + unput // unputting a character (add it in front of the list)
777 ( 777 (
778 Word8 character, 778 Word8 character,
779 SState s 779 SState s
780 ) = 780 ) =
781 - s.unput_chars <- (List(Word8))[character . *(s.unput_chars)].  
782 -  
783 -  
784 -  
785 -define One record_dubious_IP(Word32 addr,DenialOfService dos).  
786 -  
787 - variable Int sttm = 0. // contains the start time for this connection.  
788 - 781 + s.unput_chars <- (List(Word8))[character . *(s.unput_chars)].
  782 +
  783 +
  784 +
  785 +define One record_dubious_IP(Word32 addr,DenialOfService dos).
  786 +
  787 + variable Int sttm = 0. // contains the start time for this connection.
  788 +
789 define Result(Error,Word8) 789 define Result(Error,Word8)
790 record_dubious_connection 790 record_dubious_connection
791 ( 791 (
792 - Connection conn, 792 + Connection conn,
793 Int dead_line, 793 Int dead_line,
794 DenialOfService dos, 794 DenialOfService dos,
795 SState s 795 SState s
796 ) = 796 ) =
797 - if remote_IP_address_and_port(conn) is (addr,port) then 797 + if remote_IP_address_and_port(conn) is (addr,port) then
798 record_dubious_IP(addr,dos); 798 record_dubious_IP(addr,dos);
799 print("Recording IP address "+ip_addr_to_string(addr)+ 799 print("Recording IP address "+ip_addr_to_string(addr)+
800 " as dubious after "+(dead_line-*(s.sttm))+" seconds. Total: "+ 800 " as dubious after "+(dead_line-*(s.sttm))+" seconds. Total: "+
@@ -818,9 +818,9 @@ define One @@ -818,9 +818,9 @@ define One
818 if nth(i,source) is 818 if nth(i,source) is
819 { 819 {
820 failure then unique, 820 failure then unique,
821 - success(b) then if put(dest,position,b) is 821 + success(b) then if put(dest,position,b) is
822 { 822 {
823 - failure then unique, 823 + failure then unique,
824 success(_) then put(source,dest,position+1,i+1) 824 success(_) then put(source,dest,position+1,i+1)
825 } 825 }
826 }. 826 }.
@@ -832,9 +832,9 @@ define ReadResult @@ -832,9 +832,9 @@ define ReadResult
832 Int size, 832 Int size,
833 Int time_out, 833 Int time_out,
834 ByteArray result_buffer, 834 ByteArray result_buffer,
835 - Int position 835 + Int position
836 ) = 836 ) =
837 - //println(pid + "read_from_connexion(" + size + ")"); 837 + //println(pid + "read_from_connexion(" + size + ")");
838 838
839 if *connection.read_pos < length(*connection.buffer) then 839 if *connection.read_pos < length(*connection.buffer) then
840 //println(pid + " reading from buffer (size = " + length(*connection.buffer) + ", pos = " + *connection.read_pos); 840 //println(pid + " reading from buffer (size = " + length(*connection.buffer) + ", pos = " + *connection.read_pos);
@@ -852,7 +852,7 @@ define ReadResult @@ -852,7 +852,7 @@ define ReadResult
852 // timeout then ok(result), 852 // timeout then ok(result),
853 // ok(ba) then ok(result + ba) 853 // ok(ba) then ok(result + ba)
854 // } 854 // }
855 - else 855 + else
856 ok(result_buffer) 856 ok(result_buffer)
857 else 857 else
858 with t0 = (UTime) unow, 858 with t0 = (UTime) unow,
@@ -861,24 +861,24 @@ define ReadResult @@ -861,24 +861,24 @@ define ReadResult
861 { 861 {
862 error then println(pid + "read failed ["+to_string(result_buffer)+"]"); error, 862 error then println(pid + "read failed ["+to_string(result_buffer)+"]"); error,
863 timeout then timeout, 863 timeout then timeout,
864 - ok(ba) then 864 + ok(ba) then
865 with size_read = length(ba), 865 with size_read = length(ba),
866 - //the needed read is higher than the 866 + //the needed read is higher than the
867 if size > size_read then 867 if size > size_read then
868 put(ba, result_buffer, position, 0); 868 put(ba, result_buffer, position, 0);
869 - read_from_connexion(connection, size - size_read, time_out, result_buffer, position+size_read) 869 + read_from_connexion(connection, size - size_read, time_out, result_buffer, position+size_read)
870 else 870 else
871 - //println(pid + "ba = " + length(ba) + " duration: " + __utime_to_string((UTime) unow - t0)); 871 + //println(pid + "ba = " + length(ba) + " duration: " + __utime_to_string((UTime) unow - t0));
872 connection.buffer <- ba; 872 connection.buffer <- ba;
873 connection.read_pos <- 0; 873 connection.read_pos <- 0;
874 - //println(pid + "rb = " + length(*read_buffer));  
875 - 874 + //println(pid + "rb = " + length(*read_buffer));
  875 +
876 terminal read_from_connexion(connection, size, time_out, result_buffer, position) 876 terminal read_from_connexion(connection, size, time_out, result_buffer, position)
877 }. 877 }.
878 878
879 define Result(Error,Word8) 879 define Result(Error,Word8)
880 next_char // reading a character (check the list first, and read on the connection 880 next_char // reading a character (check the list first, and read on the connection
881 - // only when the list is empty). 881 + // only when the list is empty).
882 ( 882 (
883 BufferedConnection connection, 883 BufferedConnection connection,
884 Int dead_line, 884 Int dead_line,
@@ -886,11 +886,11 @@ define Result(Error,Word8) @@ -886,11 +886,11 @@ define Result(Error,Word8)
886 SState s 886 SState s
887 ) = 887 ) =
888 //with t2_tmp = (UTime) now, 888 //with t2_tmp = (UTime) now,
889 - if *(s.unput_chars) is 889 + if *(s.unput_chars) is
890 { 890 {
891 - [ ] then 891 + [ ] then
892 // /////////////////// 892 // ///////////////////
893 - // Buffered reading 893 + // Buffered reading
894 //if unow > dead_line then record_dubious_connection(connection,dead_line,dos) else 894 //if unow > dead_line then record_dubious_connection(connection,dead_line,dos) else
895 if nth(*connection.read_pos, *connection.buffer) is 895 if nth(*connection.read_pos, *connection.buffer) is
896 { 896 {
@@ -899,48 +899,48 @@ define Result(Error,Word8) @@ -899,48 +899,48 @@ define Result(Error,Word8)
899 { 899 {
900 error then /*accumulate_t2(t2_tmp);*/ error(cannot_read_from_connection), 900 error then /*accumulate_t2(t2_tmp);*/ error(cannot_read_from_connection),
901 timeout then /*accumulate_t2(t2_tmp);*/ error(timeout(600)), 901 timeout then /*accumulate_t2(t2_tmp);*/ error(timeout(600)),
902 - //record_dubious_connection(connection,dead_line,dos),  
903 - ok(ba) then if nth(0,ba) is 902 + //record_dubious_connection(connection,dead_line,dos),
  903 + ok(ba) then if nth(0,ba) is
904 { 904 {
905 failure then /*accumulate_t2(t2_tmp);*/ error(cannot_read_from_connection), 905 failure then /*accumulate_t2(t2_tmp);*/ error(cannot_read_from_connection),
906 - success(c) then 906 + success(c) then
907 //println("-" + pid + "read [" + implode([c]) + "]\t"); 907 //println("-" + pid + "read [" + implode([c]) + "]\t");
908 - //accumulate_t2(t2_tmp); 908 + //accumulate_t2(t2_tmp);
909 ok(c) 909 ok(c)
910 } 910 }
911 }, 911 },
912 - success(c) then 912 + success(c) then
913 connection.read_pos <- *connection.read_pos + 1; 913 connection.read_pos <- *connection.read_pos + 1;
914 - //accumulate_t2(t2_tmp); 914 + //accumulate_t2(t2_tmp);
915 ok(c) 915 ok(c)
916 }, 916 },
917 - 917 +
918 // /////////////////// 918 // ///////////////////
919 // standard reading 919 // standard reading
920 // if read(connection.conn, 1, 600) is // the connection is closed after 10 minutes of inactivity 920 // if read(connection.conn, 1, 600) is // the connection is closed after 10 minutes of inactivity
921 // { 921 // {
922 // error then accumulate_t2(t2_tmp); println(pid + "read failed)"); error(cannot_read_from_connection), 922 // error then accumulate_t2(t2_tmp); println(pid + "read failed)"); error(cannot_read_from_connection),
923 // timeout then accumulate_t2(t2_tmp); error(timeout(600)), 923 // timeout then accumulate_t2(t2_tmp); error(timeout(600)),
924 -// ok(ba) then if nth(0,ba) is 924 +// ok(ba) then if nth(0,ba) is
925 // { 925 // {
926 // failure then accumulate_t2(t2_tmp); error(cannot_read_from_connection), 926 // failure then accumulate_t2(t2_tmp); error(cannot_read_from_connection),
927 -// success(c) then accumulate_t2(t2_tmp); 927 +// success(c) then accumulate_t2(t2_tmp);
928 // ok(c) 928 // ok(c)
929 // } 929 // }
930 // }, 930 // },
931 -  
932 - [h . t] then  
933 - s.unput_chars <- t; //accumulate_t2(t2_tmp); 931 +
  932 + [h . t] then
  933 + s.unput_chars <- t; //accumulate_t2(t2_tmp);
934 ok(h) 934 ok(h)
935 - }.  
936 - 935 + }.
  936 +
937 define ByteArray 937 define ByteArray
938 get_and_erase_buffer 938 get_and_erase_buffer
939 ( 939 (
940 BufferedConnection connection, 940 BufferedConnection connection,
941 SState s 941 SState s
942 )= 942 )=
943 - with head = to_byte_array(implode(*s.unput_chars)), 943 + with head = to_byte_array(implode(*s.unput_chars)),
944 tail = extract(*connection.buffer, *connection.read_pos, length(*connection.buffer)), 944 tail = extract(*connection.buffer, *connection.read_pos, length(*connection.buffer)),
945 // println("--- get_and_erase_buffer ----"); 945 // println("--- get_and_erase_buffer ----");
946 // println("unput char length : "+length(to_string(head))); 946 // println("unput char length : "+length(to_string(head)));
@@ -949,105 +949,105 @@ define ByteArray @@ -949,105 +949,105 @@ define ByteArray
949 // println(" tail length : "+length(tail)); 949 // println(" tail length : "+length(tail));
950 // println(" -- unputchar content "); 950 // println(" -- unputchar content ");
951 // println("["+to_string(head)+"]"); 951 // println("["+to_string(head)+"]");
952 -// println(" -- buffer content "); 952 +// println(" -- buffer content ");
953 // println("["+to_string(*connection.buffer)+"]"); 953 // println("["+to_string(*connection.buffer)+"]");
954 -// println(" -- tail content "); 954 +// println(" -- tail content ");
955 // println("["+to_string(tail)+"]"); 955 // println("["+to_string(tail)+"]");
956 s.unput_chars <- []; 956 s.unput_chars <- [];
957 connection.buffer <- constant_byte_array(0,0); 957 connection.buffer <- constant_byte_array(0,0);
958 connection.read_pos <- 0; 958 connection.read_pos <- 0;
959 head + tail 959 head + tail
960 . 960 .
961 -  
962 -  
963 -  
964 -  
965 -  
966 - *** [2.4] Reading and discarding characters.  
967 - 961 +
  962 +
  963 +
  964 +
  965 +
  966 + *** [2.4] Reading and discarding characters.
  967 +
968 The next function reads the specified number of bytes (this is the same as 968 The next function reads the specified number of bytes (this is the same as
969 'characters') from the connection and discards them. This is used for discarding CR LF 969 'characters') from the connection and discards them. This is used for discarding CR LF
970 just before the body of a request. 970 just before the body of a request.
971 - 971 +
972 define Result(Error,One) 972 define Result(Error,One)
973 read_and_ignore 973 read_and_ignore
974 ( 974 (
975 BufferedConnection connection, // to client 975 BufferedConnection connection, // to client
976 - Int dead_line, 976 + Int dead_line,
977 Int number_of_characters, // number of characters to read and ignore 977 Int number_of_characters, // number of characters to read and ignore
978 DenialOfService dos, 978 DenialOfService dos,
979 - SState s 979 + SState s
980 ) = 980 ) =
981 if number_of_characters =< 0 then ok(unique) else 981 if number_of_characters =< 0 then ok(unique) else
982 - if next_char(connection, dead_line, dos, s) is 982 + if next_char(connection, dead_line, dos, s) is
983 { 983 {
984 error(msg) then error(msg), 984 error(msg) then error(msg),
985 ok(c) then read_and_ignore(connection,dead_line,number_of_characters-1,dos, s) 985 ok(c) then read_and_ignore(connection,dead_line,number_of_characters-1,dos, s)
986 }. 986 }.
987 -  
988 -  
989 -  
990 -  
991 -  
992 -  
993 -  
994 - *** [2.5] Reading a character string.  
995 - 987 +
  988 +
  989 +
  990 +
  991 +
  992 +
  993 +
  994 + *** [2.5] Reading a character string.
  995 +
996 Sometimes values of HTTP attributes or web args are presented in the form of double 996 Sometimes values of HTTP attributes or web args are presented in the form of double
997 quoted strings. The next function handles the reading of such things. The leading 997 quoted strings. The next function handles the reading of such things. The leading
998 double quote is already read in. We must read subsequent characters until the next non 998 double quote is already read in. We must read subsequent characters until the next non
999 backslashed double quote. 999 backslashed double quote.
1000 -  
1001 -define Result(Error,String) 1000 +
  1001 +define Result(Error,String)
1002 read_string 1002 read_string
1003 ( 1003 (
1004 BufferedConnection connection, // connection with the client 1004 BufferedConnection connection, // connection with the client
1005 - Int dead_line, 1005 + Int dead_line,
1006 List(Word8) so_far, // characters read so far (in reverse order) 1006 List(Word8) so_far, // characters read so far (in reverse order)
1007 DenialOfService dos, 1007 DenialOfService dos,
1008 - SState s 1008 + SState s
1009 ) = 1009 ) =
1010 - if next_char(connection, dead_line,dos, s) is 1010 + if next_char(connection, dead_line,dos, s) is
1011 { 1011 {
1012 error(msg) then error(msg), 1012 error(msg) then error(msg),
1013 - ok(c) then 1013 + ok(c) then
1014 if c = '\\' 1014 if c = '\\'
1015 - then if next_char(connection,dead_line,dos, s) is 1015 + then if next_char(connection,dead_line,dos, s) is
1016 { 1016 {
1017 - error(msg) then error(msg),  
1018 - ok(d) then 1017 + error(msg) then error(msg),
  1018 + ok(d) then
1019 if d = '\"' 1019 if d = '\"'
1020 - then read_string(connection,dead_line,['\"' . so_far],dos, s) 1020 + then read_string(connection,dead_line,['\"' . so_far],dos, s)
1021 else read_string(connection,dead_line,[d, c . so_far],dos, s) 1021 else read_string(connection,dead_line,[d, c . so_far],dos, s)
1022 } 1022 }
1023 else if c = '\"' 1023 else if c = '\"'
1024 then ok(implode(reverse(so_far))) 1024 then ok(implode(reverse(so_far)))
1025 else read_string(connection,dead_line,[c . so_far],dos, s) 1025 else read_string(connection,dead_line,[c . so_far],dos, s)
1026 }. 1026 }.
1027 -  
1028 -  
1029 -  
1030 -  
1031 -  
1032 -  
1033 -  
1034 -  
1035 -  
1036 -  
1037 -  
1038 -  
1039 - *** [2.7] Converting web arguments to ASCII. 1027 +
  1028 +
  1029 +
  1030 +
  1031 +
  1032 +
  1033 +
  1034 +
  1035 +
  1036 +
  1037 +
  1038 +
  1039 + *** [2.7] Converting web arguments to ASCII.
1040 1040
1041 The function 'web_to_ascii' gets a character string and replaces web encoding by normal 1041 The function 'web_to_ascii' gets a character string and replaces web encoding by normal
1042 ASCII encoding. This amounts to replacing: 1042 ASCII encoding. This amounts to replacing:
1043 - 1043 +
1044 + by blank 1044 + by blank
1045 %xx by the character whose ASCII code is xx in hexadecimal 1045 %xx by the character whose ASCII code is xx in hexadecimal
1046 -  
1047 - Note: We assume that '9' < 'A' (which is the case for ASCII code).  
1048 1046
1049 -  
1050 - 1047 + Note: We assume that '9' < 'A' (which is the case for ASCII code).
  1048 +
  1049 +
  1050 +
1051 define Word8 1051 define Word8
1052 web_decode 1052 web_decode
1053 ( 1053 (
@@ -1056,10 +1056,10 @@ define Word8 @@ -1056,10 +1056,10 @@ define Word8
1056 ) = 1056 ) =
1057 with n1 = if x1 +=< '9' then (x1 - '0') else if x1 +=< 'F' then (x1 - 'A' + 10) else (x1 - 'a' + 10), 1057 with n1 = if x1 +=< '9' then (x1 - '0') else if x1 +=< 'F' then (x1 - 'A' + 10) else (x1 - 'a' + 10),
1058 n2 = if x2 +=< '9' then (x2 - '0') else if x2 +=< 'F' then (x2 - 'A' + 10) else (x2 - 'a' + 10), 1058 n2 = if x2 +=< '9' then (x2 - '0') else if x2 +=< 'F' then (x2 - 'A' + 10) else (x2 - 'a' + 10),
1059 - (n1 << 4) + n2.  
1060 - 1059 + (n1 << 4) + n2.
  1060 +
  1061 +
1061 1062
1062 -  
1063 define String 1063 define String
1064 web_to_ascii 1064 web_to_ascii
1065 ( 1065 (
@@ -1067,93 +1067,93 @@ define String @@ -1067,93 +1067,93 @@ define String
1067 Int n, // current position in web_string 1067 Int n, // current position in web_string
1068 List(Word8) so_far 1068 List(Word8) so_far
1069 ) = 1069 ) =
1070 - if nth(n,web_string) is 1070 + if nth(n,web_string) is
1071 { 1071 {
1072 - failure then implode(reverse(so_far)),  
1073 - success(c) then 1072 + failure then implode(reverse(so_far)),
  1073 + success(c) then
1074 if c = '+' 1074 if c = '+'
1075 then web_to_ascii(web_string,n+1,[' ' . so_far]) 1075 then web_to_ascii(web_string,n+1,[' ' . so_far])
1076 else if c = '%' 1076 else if c = '%'
1077 then if nth(n+1,web_string) is 1077 then if nth(n+1,web_string) is
1078 { 1078 {
1079 failure then implode(reverse(so_far)), 1079 failure then implode(reverse(so_far)),
1080 - success(x1) then if nth(n+2,web_string) is 1080 + success(x1) then if nth(n+2,web_string) is
1081 { 1081 {
1082 - failure then implode(reverse(so_far)), 1082 + failure then implode(reverse(so_far)),
1083 success(x2) then web_to_ascii(web_string,n+3,[web_decode(x1,x2) . so_far]) 1083 success(x2) then web_to_ascii(web_string,n+3,[web_decode(x1,x2) . so_far])
1084 } 1084 }
1085 } 1085 }
1086 else web_to_ascii(web_string,n+1,[c . so_far]) 1086 else web_to_ascii(web_string,n+1,[c . so_far])
1087 }. 1087 }.
1088 -  
1089 -  
1090 -  
1091 -  
1092 -  
1093 -  
1094 -  
1095 -  
1096 - *** [3] Managing the journal.  
1097 - 1088 +
  1089 +
  1090 +
  1091 +
  1092 +
  1093 +
  1094 +
  1095 +
  1096 + *** [3] Managing the journal.
  1097 +
1098 Concurrently working machines should not try to access the same file at the same 1098 Concurrently working machines should not try to access the same file at the same
1099 - time. This problem may be solved by using the 'protect' mecanism.  
1100 -  
1101 -  
1102 -  
1103 - *** [3.1] Naming journal files.  
1104 - 1099 + time. This problem may be solved by using the 'protect' mecanism.
  1100 +
  1101 +
  1102 +
  1103 + *** [3.1] Naming journal files.
  1104 +
1105 Since journal messages are rather prolific, we should have at least one file per 1105 Since journal messages are rather prolific, we should have at least one file per
1106 hour. Hence, the name of a journal file must be constructed from the current year, 1106 hour. Hence, the name of a journal file must be constructed from the current year,
1107 month, day and hour. For example, it may be: 1107 month, day and hour. For example, it may be:
1108 - 1108 +
1109 2003_03_12_19 1109 2003_03_12_19
1110 -  
1111 - (this is for the journal of 7 PM to 8 PM, 2003/mar/12).  
1112 -  
1113 -define String 1110 +
  1111 + (this is for the journal of 7 PM to 8 PM, 2003/mar/12).
  1112 +
  1113 +define String
1114 make_current_journal_file_name 1114 make_current_journal_file_name
1115 = 1115 =
1116 - if convert_time(now) is date_and_time(y,m,d,h,_,_,_,_,_) then 1116 + if convert_time(now) is date_and_time(y,m,d,h,_,_,_,_,_) then
1117 to_decimal(y)+"_"+ 1117 to_decimal(y)+"_"+
1118 zero_pad_n(2,m)+"_"+ 1118 zero_pad_n(2,m)+"_"+
1119 zero_pad_n(2,d)+"_"+ 1119 zero_pad_n(2,d)+"_"+
1120 - zero_pad_n(2,h).  
1121 -  
1122 -  
1123 -  
1124 -  
1125 -  
1126 -  
1127 -  
1128 - *** [3.2] Formating HTTP headers.  
1129 - 1120 + zero_pad_n(2,h).
  1121 +
  1122 +
  1123 +
  1124 +
  1125 +
  1126 +
  1127 +
  1128 + *** [3.2] Formating HTTP headers.
  1129 +
1130 HTTP headers may be shown on the console or written in the journal. The function below 1130 HTTP headers may be shown on the console or written in the journal. The function below
1131 - formats a list of HTTP headers.  
1132 -  
1133 -define String 1131 + formats a list of HTTP headers.
  1132 +
  1133 +define String
1134 show_format 1134 show_format
1135 ( 1135 (
1136 - Web_Site_Description desc, 1136 + Web_Site_Description desc,
1137 List(HTTP_header) headers, 1137 List(HTTP_header) headers,
1138 ) = 1138 ) =
1139 - if headers is 1139 + if headers is
1140 { 1140 {
1141 [ ] then "", 1141 [ ] then "",
1142 - [h . t] then if h is http_header(name,value) then 1142 + [h . t] then if h is http_header(name,value) then
1143 if member(journal_headers(desc),name) 1143 if member(journal_headers(desc),name)
1144 then " | "+name+": "+value+"\n"+show_format(desc,t) 1144 then " | "+name+": "+value+"\n"+show_format(desc,t)
1145 else show_format(desc,t) 1145 else show_format(desc,t)
1146 }. 1146 }.
1147 -  
1148 -  
1149 -  
1150 -  
1151 -  
1152 -  
1153 - *** [3.3] Formating web arguments.  
1154 -  
1155 - The same thing for web arguments.  
1156 - 1147 +
  1148 +
  1149 +
  1150 +
  1151 +
  1152 +
  1153 + *** [3.3] Formating web arguments.
  1154 +
  1155 + The same thing for web arguments.
  1156 +
1157 define String 1157 define String
1158 show_format 1158 show_format
1159 ( 1159 (
@@ -1162,25 +1162,25 @@ define String @@ -1162,25 +1162,25 @@ define String
1162 if lwa is 1162 if lwa is
1163 { 1163 {
1164 [ ] then "", 1164 [ ] then "",
1165 - [h . t] then if h is 1165 + [h . t] then if h is
1166 { 1166 {
1167 - web_arg(n,v) then 1167 + web_arg(n,v) then
1168 " | "+n+"="+(if nth(0,n) = success('p') then "<not shown>" else v)+"\n"+show_format(t), 1168 " | "+n+"="+(if nth(0,n) = success('p') then "<not shown>" else v)+"\n"+show_format(t),
1169 upload(n,fn,tfn) then 1169 upload(n,fn,tfn) then
1170 " | "+n+"="+fn+" (uploaded as '"+tfn+"')\n"+show_format(t) 1170 " | "+n+"="+fn+" (uploaded as '"+tfn+"')\n"+show_format(t)
1171 } 1171 }
1172 }. 1172 }.
1173 -  
1174 -  
1175 -  
1176 -  
1177 -  
1178 -  
1179 - *** [3.4] Formating the whole request. 1173 +
  1174 +
  1175 +
  1176 +
  1177 +
  1178 +
  1179 + *** [3.4] Formating the whole request.
1180 1180
1181 It is cheap to transform month numbers into abbreviated month names. This enhances the 1181 It is cheap to transform month numbers into abbreviated month names. This enhances the
1182 readability of the journal. 1182 readability of the journal.
1183 - 1183 +
1184 define String 1184 define String
1185 format_month 1185 format_month
1186 ( 1186 (
@@ -1198,86 +1198,86 @@ define String @@ -1198,86 +1198,86 @@ define String
1198 if m = 10 then "oct" else 1198 if m = 10 then "oct" else
1199 if m = 11 then "nov" else 1199 if m = 11 then "nov" else
1200 if m = 12 then "dec" else 1200 if m = 12 then "dec" else
1201 - "???".  
1202 -  
1203 - 1201 + "???".
  1202 +
  1203 +
1204 Below we format a whole HTTP request. This may give this (actually, it depends on how 1204 Below we format a whole HTTP request. This may give this (actually, it depends on how
1205 you defined the values of 'journal_headers' and 'journal_extensions'): 1205 you defined the values of 'journal_headers' and 'journal_extensions'):
1206 - 1206 +
1207 [3] 2003/mar/10 10:06:57 from 123.456.123.456: /homepage.awp 1207 [3] 2003/mar/10 10:06:57 from 123.456.123.456: /homepage.awp
1208 | host: www.the-best-one.com 1208 | host: www.the-best-one.com
1209 | user-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 1209 | user-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0
1210 1210
1211 The leading number between brackets is the number of the virtual machine which served 1211 The leading number between brackets is the number of the virtual machine which served
1212 the URI. 1212 the URI.
1213 - 1213 +
1214 define String 1214 define String
1215 format_request 1215 format_request
1216 ( 1216 (
1217 - Web_Site_Description desc,  
1218 - Connection client_connection,  
1219 - HTTP_RequestLine request_line,  
1220 - List(HTTP_header) headers, 1217 + Web_Site_Description desc,
  1218 + Connection client_connection,
  1219 + HTTP_RequestLine request_line,
  1220 + List(HTTP_header) headers,
1221 List(Web_arg) web_args 1221 List(Web_arg) web_args
1222 ) = 1222 ) =
1223 with dt = convert_time(now), 1223 with dt = convert_time(now),
1224 - if remote_IP_address_and_port(client_connection) is (addr,port) then 1224 + if remote_IP_address_and_port(client_connection) is (addr,port) then
1225 to_decimal(year(dt))+"/"+format_month(month(dt))+"/"+zero_pad_n(2,day(dt))+" "+ 1225 to_decimal(year(dt))+"/"+format_month(month(dt))+"/"+zero_pad_n(2,day(dt))+" "+
1226 zero_pad_n(2,hour(dt))+":"+zero_pad_n(2,minute(dt))+":"+zero_pad_n(2,second(dt))+ 1226 zero_pad_n(2,hour(dt))+":"+zero_pad_n(2,minute(dt))+":"+zero_pad_n(2,second(dt))+
1227 " from "+ip_addr_to_string(addr)+ 1227 " from "+ip_addr_to_string(addr)+
1228 ": "+uri(request_line)+"\n"+ 1228 ": "+uri(request_line)+"\n"+
1229 show_format(desc,headers)+ 1229 show_format(desc,headers)+
1230 - show_format(web_args). 1230 + show_format(web_args).
  1231 +
  1232 +
  1233 +
  1234 +
1231 1235
1232 1236
1233 -  
1234 -  
1235 -  
1236 -  
1237 -  
1238 - *** [3.5] Putting it in the journal file (and on the console). 1237 +
  1238 + *** [3.5] Putting it in the journal file (and on the console).
1239 1239
1240 We must not forget to 'protect' this operation, so that the messages of two machines 1240 We must not forget to 'protect' this operation, so that the messages of two machines
1241 (working for the same site) will not be mixed together. 1241 (working for the same site) will not be mixed together.
1242 -  
1243 -define One 1242 +
  1243 +define One
1244 log_journal_msg 1244 log_journal_msg
1245 ( 1245 (
1246 - Web_Site_Description desc, 1246 + Web_Site_Description desc,
1247 String msg, 1247 String msg,
1248 ) = 1248 ) =
1249 - with ba_msg = to_byte_array("["+virtual_machine_id+"] "+msg+"\n"), 1249 + with ba_msg = to_byte_array("["+virtual_machine_id+"] "+msg+"\n"),
1250 protect 1250 protect
1251 ( 1251 (
1252 if file(site_directory(desc)+"/journal/"+make_current_journal_file_name,append) is 1252 if file(site_directory(desc)+"/journal/"+make_current_journal_file_name,append) is
1253 { 1253 {
1254 failure then unique, 1254 failure then unique,
1255 - success(journal_file) then 1255 + success(journal_file) then
1256 forget(reliable_write(file(journal_file),ba_msg)) 1256 forget(reliable_write(file(journal_file),ba_msg))
1257 }; 1257 };
1258 forget(reliable_write(file(stdout),ba_msg)) 1258 forget(reliable_write(file(stdout),ba_msg))
1259 ). 1259 ).
1260 -  
1261 -  
1262 -  
1263 -  
1264 -  
1265 -  
1266 -  
1267 - *** [4] Reading the HTTP request.  
1268 -  
1269 -  
1270 - *** [4.1] Skipping leading blanks.  
1271 - 1260 +
  1261 +
  1262 +
  1263 +
  1264 +
  1265 +
  1266 +
  1267 + *** [4] Reading the HTTP request.
  1268 +
  1269 +
  1270 + *** [4.1] Skipping leading blanks.
  1271 +
1272 One of the peculiarities of HTTP is that the characters 13 (carriage return) and 10 1272 One of the peculiarities of HTTP is that the characters 13 (carriage return) and 10
1273 (line feed) followed by either a space (32) or a tab (9), is considered as a blank not 1273 (line feed) followed by either a space (32) or a tab (9), is considered as a blank not
1274 containing any new line. 'skip_http_blanks' must skip all blanks characters until the 1274 containing any new line. 'skip_http_blanks' must skip all blanks characters until the
1275 first non blank character, which should not be read in. Obviously, because of the above 1275 first non blank character, which should not be read in. Obviously, because of the above
1276 peculiarity, we need at least 3 characters of lookahead to do this. In other words, we 1276 peculiarity, we need at least 3 characters of lookahead to do this. In other words, we
1277 must be able to unput at least 3 characters (hopefully we are). 1277 must be able to unput at least 3 characters (hopefully we are).
1278 -  
1279 - Strictly blanks characters are 'space' and 'tab'.  
1280 - 1278 +
  1279 + Strictly blanks characters are 'space' and 'tab'.
  1280 +
1281 define Bool 1281 define Bool
1282 is_strict_blank 1282 is_strict_blank
1283 ( 1283 (
@@ -1285,46 +1285,46 @@ define Bool @@ -1285,46 +1285,46 @@ define Bool
1285 ) = 1285 ) =
1286 if c = ' ' then true else c = '\t'. 1286 if c = ' ' then true else c = '\t'.
1287 1287
1288 - 1288 +
1289 On the contrary, blanks include 13 and 10. 1289 On the contrary, blanks include 13 and 10.
1290 - 1290 +
1291 define Bool 1291 define Bool
1292 is_blank 1292 is_blank
1293 ( 1293 (
1294 Word8 c 1294 Word8 c
1295 ) = 1295 ) =
1296 - if c = ' ' then true else 1296 + if c = ' ' then true else
1297 if c = '\t' then true else 1297 if c = '\t' then true else
1298 if c = 13 then true else 1298 if c = 13 then true else
1299 - c = 10. 1299 + c = 10.
  1300 +
  1301 +
  1302 + Skipping HTTP blanks.
1300 1303
1301 -  
1302 - Skipping HTTP blanks.  
1303 -  
1304 define Result(Error,One) 1304 define Result(Error,One)
1305 skip_http_blanks 1305 skip_http_blanks
1306 ( 1306 (
1307 BufferedConnection connection, 1307 BufferedConnection connection,
1308 Int dead_line, 1308 Int dead_line,
1309 DenialOfService dos, 1309 DenialOfService dos,
1310 - SState s  
1311 - ) =  
1312 - if next_char(connection, dead_line, dos, s) is 1310 + SState s
  1311 + ) =
  1312 + if next_char(connection, dead_line, dos, s) is
1313 { 1313 {
1314 - error(msg) then error(msg),  
1315 - ok(c) then 1314 + error(msg) then error(msg),
  1315 + ok(c) then
1316 if is_strict_blank(c) 1316 if is_strict_blank(c)
1317 then skip_http_blanks(connection, dead_line, dos, s) 1317 then skip_http_blanks(connection, dead_line, dos, s)
1318 else if c = 13 1318 else if c = 13
1319 then if next_char(connection, dead_line, dos, s) is 1319 then if next_char(connection, dead_line, dos, s) is
1320 { 1320 {
1321 error(msg) then error(msg), // (unput(c); ok(unique)), 1321 error(msg) then error(msg), // (unput(c); ok(unique)),
1322 - ok(d) then 1322 + ok(d) then
1323 if d = 10 1323 if d = 10
1324 - then if next_char(connection, dead_line, dos, s) is 1324 + then if next_char(connection, dead_line, dos, s) is
1325 { 1325 {
1326 error(msg) then error(msg), // (unput(d); unput(c); ok(unique)), 1326 error(msg) then error(msg), // (unput(d); unput(c); ok(unique)),
1327 - ok(e) then 1327 + ok(e) then
1328 if is_strict_blank(e) 1328 if is_strict_blank(e)
1329 then skip_http_blanks(connection, dead_line, dos, s) 1329 then skip_http_blanks(connection, dead_line, dos, s)
1330 else (unput(e, s); unput(d, s); unput(c, s); ok(unique)) 1330 else (unput(e, s); unput(d, s); unput(c, s); ok(unique))
@@ -1333,16 +1333,16 @@ define Result(Error,One) @@ -1333,16 +1333,16 @@ define Result(Error,One)
1333 } 1333 }
1334 else (unput(c, s); ok(unique)) 1334 else (unput(c, s); ok(unique))
1335 }. 1335 }.
1336 -  
1337 -  
1338 -  
1339 -  
1340 -  
1341 -  
1342 -  
1343 -  
1344 - *** [4.2] Reading a new line.  
1345 - 1336 +
  1337 +
  1338 +
  1339 +
  1340 +
  1341 +
  1342 +
  1343 +
  1344 + *** [4.2] Reading a new line.
  1345 +
1346 Normally in HTTP a new line is the sequence 13 10 (carriage return line feed), not 1346 Normally in HTTP a new line is the sequence 13 10 (carriage return line feed), not
1347 followed by a space or tabulator. If it is followed by a space or tabulator, the three 1347 followed by a space or tabulator. If it is followed by a space or tabulator, the three
1348 characters are considered blanks, and no new line has been read. Before trying to read 1348 characters are considered blanks, and no new line has been read. Before trying to read
@@ -1350,54 +1350,54 @@ define Result(Error,One) @@ -1350,54 +1350,54 @@ define Result(Error,One)
1350 we read another character. if this character is space or tab, we consider we have read 1350 we read another character. if this character is space or tab, we consider we have read
1351 only blanks and we continue reading in order to find our new line. Otherwise, we unput 1351 only blanks and we continue reading in order to find our new line. Otherwise, we unput
1352 this character (which may be for example the first character of the name of the next 1352 this character (which may be for example the first character of the name of the next
1353 - header), and answer that we have seen a new line.  
1354 - 1353 + header), and answer that we have seen a new line.
  1354 +
1355 Warning: we must not use this function for reading the last pair (13,10) before the 1355 Warning: we must not use this function for reading the last pair (13,10) before the
1356 beginning of the body, because if the body is empty, there is no character to read 1356 beginning of the body, because if the body is empty, there is no character to read
1357 after this pair, so that the server could wait for a character which will never 1357 after this pair, so that the server could wait for a character which will never
1358 come. This is the reason for 'read_and_ignore' above, which is used precisely for 1358 come. This is the reason for 'read_and_ignore' above, which is used precisely for
1359 reading that last (13,10) pair. 1359 reading that last (13,10) pair.
1360 - 1360 +
1361 define Result(Error,One) 1361 define Result(Error,One)
1362 read_new_line 1362 read_new_line
1363 ( 1363 (
1364 BufferedConnection connection, 1364 BufferedConnection connection,
1365 Int dead_line, 1365 Int dead_line,
1366 DenialOfService dos, 1366 DenialOfService dos,
1367 - SState s 1367 + SState s
1368 ) = 1368 ) =
1369 - if skip_http_blanks(connection, dead_line, dos, s) is 1369 + if skip_http_blanks(connection, dead_line, dos, s) is
1370 { 1370 {
1371 error(msg) then error(msg), 1371 error(msg) then error(msg),
1372 - ok(_) then  
1373 - if next_char(connection, dead_line, dos, s) is 1372 + ok(_) then
  1373 + if next_char(connection, dead_line, dos, s) is
1374 { 1374 {
1375 - error(msg) then error(msg), 1375 + error(msg) then error(msg),
1376 ok(c) then 1376 ok(c) then
1377 if c = 13 1377 if c = 13
1378 - then if next_char(connection, dead_line, dos, s) is 1378 + then if next_char(connection, dead_line, dos, s) is
1379 { 1379 {
1380 error(msg) then error(msg), 1380 error(msg) then error(msg),
1381 - ok(d) then 1381 + ok(d) then
1382 if d = 10 1382 if d = 10
1383 then ok(unique) 1383 then ok(unique)
1384 - else (unput(d, s);  
1385 - unput(c, s); 1384 + else (unput(d, s);
  1385 + unput(c, s);
1386 error(end_of_line_expected)) 1386 error(end_of_line_expected))
1387 } 1387 }
1388 - else (unput(c, s); 1388 + else (unput(c, s);
1389 error(end_of_line_expected)) 1389 error(end_of_line_expected))
1390 }}. 1390 }}.
1391 -  
1392 -  
1393 -  
1394 -  
1395 -  
1396 -  
1397 -  
1398 -  
1399 - *** [4.3] Reading a 'word'.  
1400 - 1391 +
  1392 +
  1393 +
  1394 +
  1395 +
  1396 +
  1397 +
  1398 +
  1399 + *** [4.3] Reading a 'word'.
  1400 +
1401 A 'word' is a sequence of characters which begins either by a double quote or not by a 1401 A 'word' is a sequence of characters which begins either by a double quote or not by a
1402 double quote. (However, any leading blanks are read in and ignored. This is 1402 double quote. (However, any leading blanks are read in and ignored. This is
1403 accomplished by 'skip_http_blanks'.) If it begins by a double quote, it is read like a 1403 accomplished by 'skip_http_blanks'.) If it begins by a double quote, it is read like a
@@ -1407,26 +1407,26 @@ define Result(Error,One) @@ -1407,26 +1407,26 @@ define Result(Error,One)
1407 double quoted, the right delimiting blank character is not read in (it is 'unput' back 1407 double quoted, the right delimiting blank character is not read in (it is 'unput' back
1408 into the connection), and may be read in again. This is needed because carriage return 1408 into the connection), and may be read in again. This is needed because carriage return
1409 or line feed which are 'blank', also have a meaning in HTTP. 1409 or line feed which are 'blank', also have a meaning in HTTP.
1410 - 1410 +
1411 define Result(Error,String) 1411 define Result(Error,String)
1412 read_word_aux 1412 read_word_aux
1413 ( 1413 (
1414 - BufferedConnection connection,  
1415 - Int dead_line, 1414 + BufferedConnection connection,
  1415 + Int dead_line,
1416 List(Word8) so_far, 1416 List(Word8) so_far,
1417 DenialOfService dos, 1417 DenialOfService dos,
1418 - SState s 1418 + SState s
1419 ) = 1419 ) =
1420 - if next_char(connection,dead_line,dos, s) is 1420 + if next_char(connection,dead_line,dos, s) is
1421 { 1421 {
1422 error(msg) then error(msg), 1422 error(msg) then error(msg),
1423 - ok(c) then 1423 + ok(c) then
1424 if is_blank(c) 1424 if is_blank(c)
1425 - then (unput(c, s); 1425 + then (unput(c, s);
1426 ok(implode(reverse(so_far)))) 1426 ok(implode(reverse(so_far))))
1427 else read_word_aux(connection,dead_line,[c . so_far],dos, s) 1427 else read_word_aux(connection,dead_line,[c . so_far],dos, s)
1428 }. 1428 }.
1429 - 1429 +
1430 define Result(Error,String) 1430 define Result(Error,String)
1431 read_word 1431 read_word
1432 ( 1432 (
@@ -1435,117 +1435,117 @@ define Result(Error,String) @@ -1435,117 +1435,117 @@ define Result(Error,String)
1435 DenialOfService dos, 1435 DenialOfService dos,
1436 SState s 1436 SState s
1437 ) = 1437 ) =
1438 - if skip_http_blanks(connection,dead_line,dos, s) is 1438 + if skip_http_blanks(connection,dead_line,dos, s) is
1439 { 1439 {
1440 - error(msg) then error(msg),  
1441 - ok(_) then  
1442 - if next_char(connection, dead_line, dos, s) is 1440 + error(msg) then error(msg),
  1441 + ok(_) then
  1442 + if next_char(connection, dead_line, dos, s) is
1443 { 1443 {
1444 - error(msg) then error(msg),  
1445 - ok(c) then 1444 + error(msg) then error(msg),
  1445 + ok(c) then
1446 if c = '\"' 1446 if c = '\"'
1447 then read_string(connection,dead_line,[],dos, s) 1447 then read_string(connection,dead_line,[],dos, s)
1448 else read_word_aux(connection,dead_line,[c],dos, s) 1448 else read_word_aux(connection,dead_line,[c],dos, s)
1449 } 1449 }
1450 - }.  
1451 -  
1452 -  
1453 -  
1454 -  
1455 -  
1456 -  
1457 -  
1458 -  
1459 - *** [4.4] Separating the URI from the query string.  
1460 - 1450 + }.
  1451 +
  1452 +
  1453 +
  1454 +
  1455 +
  1456 +
  1457 +
  1458 +
  1459 + *** [4.4] Separating the URI from the query string.
  1460 +
1461 A 'query string' may be postfixed to the URI, just after a question mark. For example, 1461 A 'query string' may be postfixed to the URI, just after a question mark. For example,
1462 the client may send the following request: 1462 the client may send the following request:
1463 - 1463 +
1464 GET /catalog.awp?item=3&color=blue 1464 GET /catalog.awp?item=3&color=blue
1465 - 1465 +
1466 We separate this into an URI: "/catalog.awp" and the string: "item=3&color=blue" which 1466 We separate this into an URI: "/catalog.awp" and the string: "item=3&color=blue" which
1467 will be later transformed into the list: 1467 will be later transformed into the list:
1468 - 1468 +
1469 [web_arg("item","3"),web_arg("color","blue")] 1469 [web_arg("item","3"),web_arg("color","blue")]
1470 -  
1471 - 1470 +
  1471 +
1472 define (String,String) 1472 define (String,String)
1473 separate_uri_from_query_string 1473 separate_uri_from_query_string
1474 ( 1474 (
1475 String uri_and_query_string, 1475 String uri_and_query_string,
1476 Int n 1476 Int n
1477 ) = 1477 ) =
1478 - if nth(n,uri_and_query_string) is 1478 + if nth(n,uri_and_query_string) is
1479 { 1479 {
1480 failure then (uri_and_query_string,""), 1480 failure then (uri_and_query_string,""),
1481 - success(c) then 1481 + success(c) then
1482 if c = '?' 1482 if c = '?'
1483 then (substr(uri_and_query_string,0,n), 1483 then (substr(uri_and_query_string,0,n),
1484 substr(uri_and_query_string,n+1,length(uri_and_query_string)-(n+1))) 1484 substr(uri_and_query_string,n+1,length(uri_and_query_string)-(n+1)))
1485 else separate_uri_from_query_string(uri_and_query_string,n+1) 1485 else separate_uri_from_query_string(uri_and_query_string,n+1)
1486 }. 1486 }.
1487 -  
1488 -  
1489 -  
1490 -  
1491 -  
1492 -  
1493 -  
1494 -  
1495 -  
1496 - *** [4.5] Reading the web arguments.  
1497 -  
1498 - HTTP/HTTPS requests are sent in one of two formats:  
1499 - 1487 +
  1488 +
  1489 +
  1490 +
  1491 +
  1492 +
  1493 +
  1494 +
  1495 +
  1496 + *** [4.5] Reading the web arguments.
  1497 +
  1498 + HTTP/HTTPS requests are sent in one of two formats:
  1499 +
1500 (1) www-url encoded 1500 (1) www-url encoded
1501 (2) multipart/form-data encoded 1501 (2) multipart/form-data encoded
1502 - 1502 +
1503 The first one is the normal (historical) way of encoding. The second one is required 1503 The first one is the normal (historical) way of encoding. The second one is required
1504 for uploading files. A server which is supposed to accept upload of files must handle 1504 for uploading files. A server which is supposed to accept upload of files must handle
1505 both formats. The first thing to do is to decide the format of the request. This is 1505 both formats. The first thing to do is to decide the format of the request. This is
1506 easily done by examining the HTTP headers. If we find the header: 1506 easily done by examining the HTTP headers. If we find the header:
1507 - 1507 +
1508 Content-Type: multipart/form-data 1508 Content-Type: multipart/form-data
1509 - 1509 +
1510 the request is multipart/form-data encoded. Otherwise, it is 'www-url' encoded. We 1510 the request is multipart/form-data encoded. Otherwise, it is 'www-url' encoded. We
1511 first consider 'www-url' encoded requests. 1511 first consider 'www-url' encoded requests.
1512 - 1512 +
1513 For a 'www-url' encoded request, the web argument are either in the query string or in 1513 For a 'www-url' encoded request, the web argument are either in the query string or in
1514 the body of the request, or both. The format is the same for both: 1514 the body of the request, or both. The format is the same for both:
1515 - 1515 +
1516 name=value&name=value&... 1516 name=value&name=value&...
1517 - 1517 +
1518 However, we may also have 1518 However, we may also have
1519 - 1519 +
1520 name 1520 name
1521 name= 1521 name=
1522 name=&... 1522 name=&...
1523 name&... 1523 name&...
1524 -  
1525 - i.e. some parts may be missing. Hence, we must be careful.  
1526 - 1524 +
  1525 + i.e. some parts may be missing. Hence, we must be careful.
  1526 +
1527 Furthermore, web arguments must be translated from web to ASCII when www-url encoded. 1527 Furthermore, web arguments must be translated from web to ASCII when www-url encoded.
1528 - 1528 +
1529 define Bool 1529 define Bool
1530 is_ampersand_or_equal 1530 is_ampersand_or_equal
1531 ( 1531 (
1532 Word8 c 1532 Word8 c
1533 ) = 1533 ) =
1534 - if c = '&' then true else c = '='.  
1535 -  
1536 -  
1537 - 1534 + if c = '&' then true else c = '='.
  1535 +
  1536 +
  1537 +
1538 The function 'read_name_or_value' reads the string 's' starting at position 'n' until 1538 The function 'read_name_or_value' reads the string 's' starting at position 'n' until
1539 - either the end of the string or the first '&' or '='.  
1540 -  
1541 -define String 1539 + either the end of the string or the first '&' or '='.
  1540 +
  1541 +define String
1542 read_name_or_value 1542 read_name_or_value
1543 ( 1543 (
1544 String s, 1544 String s,
1545 - Int start, 1545 + Int start,
1546 Int i 1546 Int i
1547 ) = 1547 ) =
1548 - if nth(i,s) is 1548 + if nth(i,s) is
1549 { 1549 {
1550 failure then substr(s,start,i - start), 1550 failure then substr(s,start,i - start),
1551 success(c) then 1551 success(c) then
@@ -1553,101 +1553,101 @@ define String @@ -1553,101 +1553,101 @@ define String
1553 then substr(s,start,i-start) // the separator is not included 1553 then substr(s,start,i-start) // the separator is not included
1554 else read_name_or_value(s,start,i+1) 1554 else read_name_or_value(s,start,i+1)
1555 }. 1555 }.
1556 -  
1557 - 1556 +
  1557 +
1558 define List(Web_arg) 1558 define List(Web_arg)
1559 read_www_url_encoded_web_args 1559 read_www_url_encoded_web_args
1560 ( 1560 (
1561 String s, 1561 String s,
1562 - Int start, 1562 + Int start,
1563 ) = 1563 ) =
1564 - with first = read_name_or_value(s,start,start), 1564 + with first = read_name_or_value(s,start,start),
1565 if first = "" 1565 if first = ""
1566 - then []  
1567 - else with i = start+length(first),  
1568 - if nth(i,s) is 1566 + then []
  1567 + else with i = start+length(first),
  1568 + if nth(i,s) is
1569 { 1569 {
1570 failure then [web_arg(first,"")], 1570 failure then [web_arg(first,"")],
1571 success(c) then 1571 success(c) then
1572 if c = '&' 1572 if c = '&'
1573 then [web_arg(first,"") . read_www_url_encoded_web_args(s,i+1)] 1573 then [web_arg(first,"") . read_www_url_encoded_web_args(s,i+1)]
1574 - else if c = '=' 1574 + else if c = '='
1575 then with second1 = read_name_or_value(s,i+1,i+1), 1575 then with second1 = read_name_or_value(s,i+1,i+1),
1576 - // print("\""+second1+"\"\n"); 1576 + // print("\""+second1+"\"\n");
1577 with second = web_to_ascii(second1,0,[]), 1577 with second = web_to_ascii(second1,0,[]),
1578 [web_arg(first,second) . read_www_url_encoded_web_args(s,i+length(second1)+2)] 1578 [web_arg(first,second) . read_www_url_encoded_web_args(s,i+length(second1)+2)]
1579 else print("**** ALERT **** badly formatted argument [" + s + "]!!!\n"); 1579 else print("**** ALERT **** badly formatted argument [" + s + "]!!!\n");
1580 [] 1580 []
1581 }. 1581 }.
1582 -  
1583 -  
1584 -  
1585 -  
1586 -  
1587 - *** [4.7] Reading the request line.  
1588 - 1582 +
  1583 +
  1584 +
  1585 +
  1586 +
  1587 + *** [4.7] Reading the request line.
  1588 +
1589 'read_request_line' reads three words and a new line from the connection. It tries to 1589 'read_request_line' reads three words and a new line from the connection. It tries to
1590 recognize "get" or "post" in the first word, separates the URI from the query string in 1590 recognize "get" or "post" in the first word, separates the URI from the query string in
1591 the second word, transforms the query string into a list of 'Web_arg', and finally 1591 the second word, transforms the query string into a list of 'Web_arg', and finally
1592 returns a datum of type 'HTTP_RequestLine' if no error arose. 1592 returns a datum of type 'HTTP_RequestLine' if no error arose.
1593 -  
1594 - 1593 +
  1594 +
1595 define Result(Error,HTTP_RequestType) 1595 define Result(Error,HTTP_RequestType)
1596 identify_get_or_post 1596 identify_get_or_post
1597 ( 1597 (
1598 String s 1598 String s
1599 - ) = 1599 + ) =
1600 with ls = to_lower(s), 1600 with ls = to_lower(s),
1601 if ls = "get" then ok(get) else 1601 if ls = "get" then ok(get) else
1602 if ls = "post" then ok(post) else 1602 if ls = "post" then ok(post) else
1603 - error(not_get_or_post_request(ls)).  
1604 -  
1605 -define Result(Error,HTTP_RequestLine) 1603 + error(not_get_or_post_request(ls)).
  1604 +
  1605 +define Result(Error,HTTP_RequestLine)
1606 read_request_line 1606 read_request_line
1607 ( 1607 (
1608 BufferedConnection connection, 1608 BufferedConnection connection,
1609 Int dead_line, 1609 Int dead_line,
1610 DenialOfService dos, 1610 DenialOfService dos,
1611 - SState s 1611 + SState s
1612 ) = 1612 ) =
1613 - if read_word(connection, dead_line, dos, s) is 1613 + if read_word(connection, dead_line, dos, s) is
1614 { 1614 {
1615 - error(msg) then error(msg),  
1616 - ok(get_or_post) then if read_word(connection, dead_line, dos, s) is 1615 + error(msg) then error(msg),
  1616 + ok(get_or_post) then if read_word(connection, dead_line, dos, s) is
1617 { 1617 {
1618 - error(msg) then error(msg),  
1619 - ok(uri_and_query_string) then if read_word(connection, dead_line, dos, s) is 1618 + error(msg) then error(msg),
  1619 + ok(uri_and_query_string) then if read_word(connection, dead_line, dos, s) is
1620 { 1620 {
1621 - error(msg) then error(msg),  
1622 - ok(http_version) then if read_new_line(connection, dead_line, dos, s) is 1621 + error(msg) then error(msg),
  1622 + ok(http_version) then if read_new_line(connection, dead_line, dos, s) is
1623 { 1623 {
1624 error(msg) then error(msg), 1624 error(msg) then error(msg),
1625 - ok(_) then if separate_uri_from_query_string(uri_and_query_string,0) is  
1626 - (uri,query_string) then if identify_get_or_post(get_or_post) is 1625 + ok(_) then if separate_uri_from_query_string(uri_and_query_string,0) is
  1626 + (uri,query_string) then if identify_get_or_post(get_or_post) is
1627 { 1627 {
1628 error(msg) then error(msg), 1628 error(msg) then error(msg),
1629 - ok(request_type) then 1629 + ok(request_type) then
1630 ok(request_line(request_type, web_to_ascii(uri, 0, []), read_www_url_encoded_web_args(query_string,0))) 1630 ok(request_line(request_type, web_to_ascii(uri, 0, []), read_www_url_encoded_web_args(query_string,0)))
1631 } 1631 }
1632 - } 1632 + }
1633 } 1633 }
1634 } 1634 }
1635 }. 1635 }.
1636 -  
1637 -  
1638 -  
1639 -  
1640 -  
1641 -  
1642 -  
1643 - *** [4.8] Reading the HTTP headers.  
1644 - 1636 +
  1637 +
  1638 +
  1639 +
  1640 +
  1641 +
  1642 +
  1643 + *** [4.8] Reading the HTTP headers.
  1644 +
1645 Each header is made of a name (containing only letters, the underscore, digits and the 1645 Each header is made of a name (containing only letters, the underscore, digits and the
1646 minus sign), a colon, a value, and a new line. The first empty line ends the headers. 1646 minus sign), a colon, a value, and a new line. The first empty line ends the headers.
1647 -  
1648 1647
1649 - The next function tests characters acceptable in a header name.  
1650 - 1648 +
  1649 + The next function tests characters acceptable in a header name.
  1650 +
1651 define Bool 1651 define Bool
1652 is_header_name_char 1652 is_header_name_char
1653 ( 1653 (
@@ -1657,26 +1657,26 @@ define Bool @@ -1657,26 +1657,26 @@ define Bool
1657 if ('A' +=< c & c +=< 'Z') then true else 1657 if ('A' +=< c & c +=< 'Z') then true else
1658 if ('0' +=< c & c +=< '9') then true else 1658 if ('0' +=< c & c +=< '9') then true else
1659 if c = '-' then true else 1659 if c = '-' then true else
1660 - c = '_'.  
1661 - 1660 + c = '_'.
  1661 +
1662 define Result(Error,String) 1662 define Result(Error,String)
1663 read_header_name 1663 read_header_name
1664 ( 1664 (
1665 BufferedConnection connection, 1665 BufferedConnection connection,
1666 - Int dead_line, 1666 + Int dead_line,
1667 List(Word8) so_far, 1667 List(Word8) so_far,
1668 DenialOfService dos, 1668 DenialOfService dos,
1669 - SState s 1669 + SState s
1670 ) = 1670 ) =
1671 - if next_char(connection, dead_line, dos, s) is 1671 + if next_char(connection, dead_line, dos, s) is
1672 { 1672 {
1673 error(msg) then error(msg), 1673 error(msg) then error(msg),
1674 - ok(c) then 1674 + ok(c) then
1675 if is_header_name_char(c) 1675 if is_header_name_char(c)
1676 then read_header_name(connection, dead_line, [to_lower(c) . so_far], dos, s) 1676 then read_header_name(connection, dead_line, [to_lower(c) . so_far], dos, s)
1677 else unput(c, s); ok(implode(reverse(so_far))) 1677 else unput(c, s); ok(implode(reverse(so_far)))
1678 - }.  
1679 - 1678 + }.
  1679 +
1680 define Result(Error,One) 1680 define Result(Error,One)
1681 skip_colon 1681 skip_colon
1682 ( 1682 (
@@ -1686,43 +1686,43 @@ define Result(Error,One) @@ -1686,43 +1686,43 @@ define Result(Error,One)
1686 SState s 1686 SState s
1687 ) = 1687 ) =
1688 //Skip the blank char until ':' 1688 //Skip the blank char until ':'
1689 - if skip_http_blanks(connection, dead_line, dos, s) is 1689 + if skip_http_blanks(connection, dead_line, dos, s) is
1690 { 1690 {
1691 - error(msg) then error(msg),  
1692 - ok(_) then 1691 + error(msg) then error(msg),
  1692 + ok(_) then
1693 if next_char(connection, dead_line, dos, s) is 1693 if next_char(connection, dead_line, dos, s) is
1694 { 1694 {
1695 - error(msg) then error(msg),  
1696 - ok(c) then 1695 + error(msg) then error(msg),
  1696 + ok(c) then
1697 if c = ':' 1697 if c = ':'
1698 then ok(unique) 1698 then ok(unique)
1699 else error(colon_expected) 1699 else error(colon_expected)
1700 }}. 1700 }}.
1701 -  
1702 - 1701 +
  1702 +
1703 define Result(Error,String) 1703 define Result(Error,String)
1704 read_header_value 1704 read_header_value
1705 ( 1705 (
1706 BufferedConnection connection, 1706 BufferedConnection connection,
1707 - Int dead_line, 1707 + Int dead_line,
1708 List(Word8) so_far, 1708 List(Word8) so_far,
1709 DenialOfService dos, 1709 DenialOfService dos,
1710 SState s 1710 SState s
1711 ) = 1711 ) =
1712 - if next_char(connection, dead_line, dos, s) is 1712 + if next_char(connection, dead_line, dos, s) is
1713 { 1713 {
1714 error(msg) then error(msg), 1714 error(msg) then error(msg),
1715 - ok(c) then 1715 + ok(c) then
1716 if c = 13 1716 if c = 13
1717 - then if next_char(connection, dead_line, dos, s) is 1717 + then if next_char(connection, dead_line, dos, s) is
1718 { 1718 {
1719 error(msg) then error(msg), 1719 error(msg) then error(msg),
1720 ok(d) then 1720 ok(d) then
1721 if d = 10 1721 if d = 10
1722 - then if next_char(connection, dead_line, dos, s) is 1722 + then if next_char(connection, dead_line, dos, s) is
1723 { 1723 {
1724 - error(msg) then error(msg),  
1725 - ok(e) then 1724 + error(msg) then error(msg),
  1725 + ok(e) then
1726 if is_strict_blank(e) 1726 if is_strict_blank(e)
1727 then read_header_value(connection,dead_line, [e . so_far], dos, s) 1727 then read_header_value(connection,dead_line, [e . so_far], dos, s)
1728 else (unput(e, s); ok(implode(reverse(so_far)))) 1728 else (unput(e, s); ok(implode(reverse(so_far))))
@@ -1731,106 +1731,106 @@ define Result(Error,String) @@ -1731,106 +1731,106 @@ define Result(Error,String)
1731 } 1731 }
1732 else read_header_value(connection,dead_line,[c . so_far],dos, s) 1732 else read_header_value(connection,dead_line,[c . so_far],dos, s)
1733 }. 1733 }.
1734 -  
1735 - 1734 +
  1735 +
1736 Reading a single header. 1736 Reading a single header.
1737 - 1737 +
1738 define Result(Error,Maybe(HTTP_header)) 1738 define Result(Error,Maybe(HTTP_header))
1739 read_header 1739 read_header
1740 ( 1740 (
1741 BufferedConnection connection, 1741 BufferedConnection connection,
1742 Int dead_line, 1742 Int dead_line,
1743 DenialOfService dos, 1743 DenialOfService dos,
1744 - SState s 1744 + SState s
1745 ) = 1745 ) =
1746 //Find the name 1746 //Find the name
1747 - if read_header_name(connection, dead_line, [], dos, s) is 1747 + if read_header_name(connection, dead_line, [], dos, s) is
1748 { 1748 {
1749 - error(msg) then error(msg),  
1750 - ok(name) then  
1751 - if name = "" then 1749 + error(msg) then error(msg),
  1750 + ok(name) then
  1751 + if name = "" then
1752 if read_and_ignore(connection, dead_line, 2, dos, s) /* 13 and 10 */ is 1752 if read_and_ignore(connection, dead_line, 2, dos, s) /* 13 and 10 */ is
1753 { 1753 {
1754 - error(msg) then error(msg), 1754 + error(msg) then error(msg),
1755 ok(_) then // this is the blank line 1755 ok(_) then // this is the blank line
1756 ok(failure) // end of headers 1756 ok(failure) // end of headers
1757 } 1757 }
1758 //skip the ':' and blank before and after it 1758 //skip the ':' and blank before and after it
1759 - else if skip_colon(connection, dead_line, dos, s) is 1759 + else if skip_colon(connection, dead_line, dos, s) is
1760 { 1760 {
1761 - error(msg) then error(msg),  
1762 - ok(_) then 1761 + error(msg) then error(msg),
  1762 + ok(_) then
1763 //skip the blank char after the ':' 1763 //skip the blank char after the ':'
1764 if skip_http_blanks(connection, dead_line, dos, s) is 1764 if skip_http_blanks(connection, dead_line, dos, s) is
1765 { 1765 {
1766 error(msg) then error(msg), 1766 error(msg) then error(msg),
1767 - ok(_) then 1767 + ok(_) then
1768 //Now read the value 1768 //Now read the value
1769 if read_header_value(connection, dead_line, [], dos, s) is 1769 if read_header_value(connection, dead_line, [], dos, s) is
1770 { 1770 {
1771 - error(msg) then error(msg), 1771 + error(msg) then error(msg),
1772 ok(value) then ok(success(http_header(name,value))) 1772 ok(value) then ok(success(http_header(name,value)))
1773 } 1773 }
1774 } 1774 }
1775 } 1775 }
1776 }. 1776 }.
1777 1777
1778 -  
1779 -  
1780 - Reading all the headers.  
1781 - 1778 +
  1779 +
  1780 + Reading all the headers.
  1781 +
1782 define Result(Error,List(HTTP_header)) 1782 define Result(Error,List(HTTP_header))
1783 read_http_headers 1783 read_http_headers
1784 ( 1784 (
1785 - BufferedConnection connection, 1785 + BufferedConnection connection,
1786 Int dead_line, 1786 Int dead_line,
1787 DenialOfService dos, 1787 DenialOfService dos,
1788 - SState s 1788 + SState s
1789 ) = 1789 ) =
1790 - if read_header(connection, dead_line, dos, s) is 1790 + if read_header(connection, dead_line, dos, s) is
1791 { 1791 {
1792 - error(msg) then error(msg), 1792 + error(msg) then error(msg),
1793 ok(mbh) then if mbh is 1793 ok(mbh) then if mbh is
1794 { 1794 {
1795 - failure then ok([ ]),  
1796 - success(header) then  
1797 - if read_http_headers(connection, dead_line, dos, s) is 1795 + failure then ok([ ]),
  1796 + success(header) then
  1797 + if read_http_headers(connection, dead_line, dos, s) is
1798 { 1798 {
1799 error(msg) then error(msg), 1799 error(msg) then error(msg),
1800 ok(others) then ok([header . others]) 1800 ok(others) then ok([header . others])
1801 } 1801 }
1802 } 1802 }
1803 }. 1803 }.
1804 -  
1805 -  
1806 -  
1807 -  
1808 -  
1809 -  
1810 -  
1811 - *** [4.9] Getting the size of the request's body. 1804 +
  1805 +
  1806 +
  1807 +
  1808 +
  1809 +
  1810 +
  1811 + *** [4.9] Getting the size of the request's body.
1812 1812
1813 The size of the body of the request is given under the 'Content-Length' header. If this 1813 The size of the body of the request is given under the 'Content-Length' header. If this
1814 - header is not present, the size is assumed to be zero.  
1815 -  
1816 -define Result(Error,Int) 1814 + header is not present, the size is assumed to be zero.
  1815 +
  1816 +define Result(Error,Int)
1817 get_body_size 1817 get_body_size
1818 ( 1818 (
1819 List(HTTP_header) headers 1819 List(HTTP_header) headers
1820 - ) =  
1821 - if headers is 1820 + ) =
  1821 + if headers is
1822 { 1822 {
1823 - [ ] then ok(0),  
1824 - [h . t] then if h is http_header(name,value) then 1823 + [ ] then ok(0),
  1824 + [h . t] then if h is http_header(name,value) then
1825 if name = "content-length" then 1825 if name = "content-length" then
1826 if decimal_scan(value) is 1826 if decimal_scan(value) is
1827 { 1827 {
1828 - failure then error(incorrect_content_length_value), 1828 + failure then error(incorrect_content_length_value),
1829 success(n) then ok(n) 1829 success(n) then ok(n)
1830 } 1830 }
1831 else get_body_size(t) 1831 else get_body_size(t)
1832 }. 1832 }.
1833 - 1833 +
1834 1834
1835 *** [4.10] Reading the body of the request. 1835 *** [4.10] Reading the body of the request.
1836 1836
@@ -1842,11 +1842,11 @@ define Result(Error,Int) @@ -1842,11 +1842,11 @@ define Result(Error,Int)
1842 required number of bytes. However, if the number of bytes read is zero, the connection 1842 required number of bytes. However, if the number of bytes read is zero, the connection
1843 may be broken. In that case, we must not try to read indefinitely. On the contrary, we 1843 may be broken. In that case, we must not try to read indefinitely. On the contrary, we
1844 make at most 10 retries, with a small sleeping time between any two of them. 1844 make at most 10 retries, with a small sleeping time between any two of them.
1845 - 1845 +
1846 define Result(Error, ByteArray) 1846 define Result(Error, ByteArray)
1847 read_http_body 1847 read_http_body
1848 ( 1848 (
1849 - BufferedConnection connection, 1849 + BufferedConnection connection,
1850 Int body_size, 1850 Int body_size,
1851 ByteArray so_far, // when calling this function, 'so_far' is the empty byte array 1851 ByteArray so_far, // when calling this function, 'so_far' is the empty byte array
1852 Int retries // this function is called with retries = 10 1852 Int retries // this function is called with retries = 10
@@ -1854,7 +1854,7 @@ define Result(Error, ByteArray) @@ -1854,7 +1854,7 @@ define Result(Error, ByteArray)
1854 if body_size = 0 then ok(constant_byte_array(0,0)) else 1854 if body_size = 0 then ok(constant_byte_array(0,0)) else
1855 if retries =< 0 then error(cannot_read_from_connection) else 1855 if retries =< 0 then error(cannot_read_from_connection) else
1856 1856
1857 - if read_from_connexion(connection,body_size,60,constant_byte_array(body_size,0),0) is 1857 + if read_from_connexion(connection,body_size,60,constant_byte_array(body_size,0),0) is
1858 { 1858 {
1859 error then error(cannot_read_from_connection), 1859 error then error(cannot_read_from_connection),
1860 timeout then error(timeout(60)), 1860 timeout then error(timeout(60)),
@@ -1864,54 +1864,54 @@ define Result(Error, ByteArray) @@ -1864,54 +1864,54 @@ define Result(Error, ByteArray)
1864 nn = length(new_bytes), // number of bytes just read 1864 nn = length(new_bytes), // number of bytes just read
1865 if nr < body_size // must read more bytes 1865 if nr < body_size // must read more bytes
1866 then if nn > 0 // if connection seems to work 1866 then if nn > 0 // if connection seems to work
1867 -  
1868 - then 1867 +
  1868 + then
1869 println("http body ("+body_size+") read "+nn+" bytes current size "+nr+" Bytes"); 1869 println("http body ("+body_size+") read "+nn+" bytes current size "+nr+" Bytes");
1870 read_http_body(connection,body_size,ba,1000) // continue reading 1870 read_http_body(connection,body_size,ba,1000) // continue reading
1871 else sleep(100); // otherwise, sleep 1/10 of second 1871 else sleep(100); // otherwise, sleep 1/10 of second
1872 read_http_body(connection,body_size,ba, // and retry reading 1872 read_http_body(connection,body_size,ba, // and retry reading
1873 retries-1) // but no more than 10 times 1873 retries-1) // but no more than 10 times
1874 - else ok(ba) // required number of bytes has been read  
1875 - }.  
1876 -  
1877 - 1874 + else ok(ba) // required number of bytes has been read
  1875 + }.
  1876 +
  1877 +
1878 Note: During sleeping, 'anbexec' runs other machines. Actually, calling 'sleep', even 1878 Note: During sleeping, 'anbexec' runs other machines. Actually, calling 'sleep', even
1879 for one millisecond, is some way of giving up explicitly, so that other virtual 1879 for one millisecond, is some way of giving up explicitly, so that other virtual
1880 machines may work. 1880 machines may work.
1881 -  
1882 -  
1883 -  
1884 -  
1885 -  
1886 -  
1887 -  
1888 -  
1889 -  
1890 -  
1891 -  
1892 -  
1893 - *** [5] Making the HTTP answer.  
1894 - 1881 +
  1882 +
  1883 +
  1884 +
  1885 +
  1886 +
  1887 +
  1888 +
  1889 +
  1890 +
  1891 +
  1892 +
  1893 + *** [5] Making the HTTP answer.
  1894 +
1895 At that point we have read the request line, the headers and the body of the 1895 At that point we have read the request line, the headers and the body of the
1896 request, and we must decide what to do. 1896 request, and we must decide what to do.
1897 - 1897 +
1898 Actually, we can do one of the following: 1898 Actually, we can do one of the following:
1899 - 1899 +
1900 - send a file, 1900 - send a file,
1901 - - execute 'tickets_and_web_page' in case of an ".awp" URI.  
1902 - 1901 + - execute 'tickets_and_web_page' in case of an ".awp" URI.
  1902 +
1903 The uploaded file (which are in the body of the request) are saved into temporary files 1903 The uploaded file (which are in the body of the request) are saved into temporary files
1904 below. 1904 below.
1905 1905
1906 -  
1907 -  
1908 -  
1909 -  
1910 - *** [5.1] Avoiding illegal URIs.  
1911 - 1906 +
  1907 +
  1908 +
  1909 +
  1910 + *** [5.1] Avoiding illegal URIs.
  1911 +
1912 For security reasons, we must avoid illegal URIs, for example those which may climb up 1912 For security reasons, we must avoid illegal URIs, for example those which may climb up
1913 in the file hierarchy. First we accept only few characters in URIs. 1913 in the file hierarchy. First we accept only few characters in URIs.
1914 - 1914 +
1915 define Bool 1915 define Bool
1916 is_legal_uri_char 1916 is_legal_uri_char
1917 ( 1917 (
@@ -1921,28 +1921,28 @@ define Bool @@ -1921,28 +1921,28 @@ define Bool
1921 if ('A' +=< c & c +=< 'Z') then true else // accept 'A' to 'Z' 1921 if ('A' +=< c & c +=< 'Z') then true else // accept 'A' to 'Z'
1922 if ('0' +=< c & c +=< '9') then true else // accept '0' to '9' 1922 if ('0' +=< c & c +=< '9') then true else // accept '0' to '9'
1923 if c = '.' then true else // accept '.' '-' '/' and '_' 1923 if c = '.' then true else // accept '.' '-' '/' and '_'
1924 - if c = '-' then true else 1924 + if c = '-' then true else
1925 if c = '/' then true else 1925 if c = '/' then true else
1926 - c = '_'.  
1927 - 1926 + c = '_'.
  1927 +
1928 We do not accept ~ which is some way of climbing. Of course, we cannot disallow single 1928 We do not accept ~ which is some way of climbing. Of course, we cannot disallow single
1929 dots, which are most often present in legal URIs, but we must avoid double dots .. 1929 dots, which are most often present in legal URIs, but we must avoid double dots ..
1930 which mean 'climb up'. 1930 which mean 'climb up'.
1931 - 1931 +
1932 define Bool 1932 define Bool
1933 is_illegal_uri 1933 is_illegal_uri
1934 ( 1934 (
1935 String uri, 1935 String uri,
1936 Int n 1936 Int n
1937 ) = 1937 ) =
1938 - if nth(n,uri) is 1938 + if nth(n,uri) is
1939 { 1939 {
1940 - failure then false, 1940 + failure then false,
1941 success(c) then 1941 success(c) then
1942 if c = '.' // first dot 1942 if c = '.' // first dot
1943 - then if nth(n+1,uri) is 1943 + then if nth(n+1,uri) is
1944 { 1944 {
1945 - failure then false, 1945 + failure then false,
1946 success(d) then 1946 success(d) then
1947 if d = '.' // second dot 1947 if d = '.' // second dot
1948 then true 1948 then true
@@ -1950,79 +1950,79 @@ define Bool @@ -1950,79 +1950,79 @@ define Bool
1950 } 1950 }
1951 else is_illegal_uri(uri,n+1) 1951 else is_illegal_uri(uri,n+1)
1952 }. 1952 }.
1953 -  
1954 -  
1955 -  
1956 -  
1957 -  
1958 -  
1959 - *** [5.2] Managing authorizations for downloading private files. 1953 +
  1954 +
  1955 +
  1956 +
  1957 +
  1958 +
  1959 + *** [5.2] Managing authorizations for downloading private files.
1960 1960
1961 Computing the authorization and making the authorization file (containing the absolute 1961 Computing the authorization and making the authorization file (containing the absolute
1962 path of the file on the server). 1962 path of the file on the server).
1963 -  
1964 -  
1965 -define String  
1966 - compute_authorization 1963 +
  1964 +
  1965 +define String
  1966 + compute_authorization
1967 ( 1967 (
1968 - String authorization_secret, 1968 + String authorization_secret,
1969 String absolute_path 1969 String absolute_path
1970 ) = 1970 ) =
1971 to_ascii(sha1((authorization_secret, 1971 to_ascii(sha1((authorization_secret,
1972 - absolute_path))).  
1973 -  
1974 -  
1975 -public define String 1972 + absolute_path))).
  1973 +
  1974 +
  1975 +public define String
1976 make_authorization 1976 make_authorization
1977 ( 1977 (
1978 String site_directory, 1978 String site_directory,
1979 - String authorization_secret, 1979 + String authorization_secret,
1980 String absolute_path 1980 String absolute_path
1981 ) = 1981 ) =
1982 - with private_download_dir = site_directory+"/private_download", 1982 + with private_download_dir = site_directory+"/private_download",
1983 auth = compute_authorization(authorization_secret, 1983 auth = compute_authorization(authorization_secret,
1984 - absolute_path), 1984 + absolute_path),
1985 forget(save(absolute_path, 1985 forget(save(absolute_path,
1986 - private_download_dir+"/z"+auth));  
1987 - auth.  
1988 -  
1989 -  
1990 - The function 'send_file' defined below handles the recognition of authorizations.  
1991 -  
1992 -  
1993 -  
1994 -  
1995 -  
1996 - *** [5.3] Recognizing MIME types.  
1997 - 1986 + private_download_dir+"/z"+auth));
  1987 + auth.
  1988 +
  1989 +
  1990 + The function 'send_file' defined below handles the recognition of authorizations.
  1991 +
  1992 +
  1993 +
  1994 +
  1995 +
  1996 + *** [5.3] Recognizing MIME types.
  1997 +
1998 The extension of the (redirected) URI must be either ".awp" or recognized as associated 1998 The extension of the (redirected) URI must be either ".awp" or recognized as associated
1999 to a MIME type. Otherwise, the server will not send the file. This is for security, but 1999 to a MIME type. Otherwise, the server will not send the file. This is for security, but
2000 also because, we must generate a 'Content-Type' header in the answer, with the right 2000 also because, we must generate a 'Content-Type' header in the answer, with the right
2001 MIME type. 2001 MIME type.
2002 - 2002 +
2003 define String 2003 define String
2004 get_uri_extension_aux 2004 get_uri_extension_aux
2005 ( 2005 (
2006 String uri, 2006 String uri,
2007 Int n // used for searching backwards 2007 Int n // used for searching backwards
2008 ) = 2008 ) =
2009 - if nth(n,uri) is 2009 + if nth(n,uri) is
2010 { 2010 {
2011 - failure then "",  
2012 - success(c) then 2011 + failure then "",
  2012 + success(c) then
2013 if c = '.' then substr(uri,n,length(uri)-n) 2013 if c = '.' then substr(uri,n,length(uri)-n)
2014 else if c = '/' then "" 2014 else if c = '/' then ""
2015 else get_uri_extension_aux(uri,n-1) 2015 else get_uri_extension_aux(uri,n-1)
2016 }. 2016 }.
2017 - 2017 +
2018 public define String 2018 public define String
2019 get_uri_extension 2019 get_uri_extension
2020 ( 2020 (
2021 String uri 2021 String uri
2022 ) = 2022 ) =
2023 get_uri_extension_aux(uri, 2023 get_uri_extension_aux(uri,
2024 - length(uri)-1). // search starts at the right end  
2025 - 2024 + length(uri)-1). // search starts at the right end
  2025 +
2026 public define Bool 2026 public define Bool
2027 contains_no_case 2027 contains_no_case
2028 ( 2028 (
@@ -2032,42 +2032,42 @@ public define Bool @@ -2032,42 +2032,42 @@ public define Bool
2032 if l is 2032 if l is
2033 { 2033 {
2034 [] then false, 2034 [] then false,
2035 - [h . t] then 2035 + [h . t] then
2036 if insensitive_equal(h, val) then true 2036 if insensitive_equal(h, val) then true
2037 else contains_no_case(t, val) 2037 else contains_no_case(t, val)
2038 }. 2038 }.
2039 2039
2040 -  
2041 -define Maybe(MIME) 2040 +
  2041 +define Maybe(MIME)
2042 recognize_mime_type_from_ext 2042 recognize_mime_type_from_ext
2043 ( 2043 (
2044 String ext, 2044 String ext,
2045 List(MIME) l 2045 List(MIME) l
2046 ) = 2046 ) =
2047 - if l is 2047 + if l is
2048 { 2048 {
2049 - [ ] then success(mime("application", "octet-stream", [])), // failure, 2049 + [ ] then success(mime("application", "octet-stream", [])), // failure,
2050 [h . t] then if h is mime(type, subtype, extensions) then 2050 [h . t] then if h is mime(type, subtype, extensions) then
2051 if contains_no_case(extensions, ext) 2051 if contains_no_case(extensions, ext)
2052 then success(h) 2052 then success(h)
2053 else recognize_mime_type_from_ext(ext,t) 2053 else recognize_mime_type_from_ext(ext,t)
2054 }. 2054 }.
2055 - 2055 +
2056 define Maybe(MIME) 2056 define Maybe(MIME)
2057 recognize_mime_type_from_uri 2057 recognize_mime_type_from_uri
2058 ( 2058 (
2059 - Web_Site_Description desc, 2059 + Web_Site_Description desc,
2060 String uri 2060 String uri
2061 ) = 2061 ) =
2062 recognize_mime_type_from_ext(get_uri_extension(uri),known_mime_types(desc)). 2062 recognize_mime_type_from_ext(get_uri_extension(uri),known_mime_types(desc)).
2063 -  
2064 2063
2065 -  
2066 - *** [5.4] Formating HTTP headers.  
2067 - 2064 +
  2065 +
  2066 + *** [5.4] Formating HTTP headers.
  2067 +
2068 This is the formating for sending to the client (hence, it has nothing to do with the 2068 This is the formating for sending to the client (hence, it has nothing to do with the
2069 component 'journal_headers' in the web site description). 2069 component 'journal_headers' in the web site description).
2070 - 2070 +
2071 public define Printable_tree 2071 public define Printable_tree
2072 format_headers 2072 format_headers
2073 ( 2073 (
@@ -2079,8 +2079,8 @@ public define Printable_tree @@ -2079,8 +2079,8 @@ public define Printable_tree
2079 [h . t] then if h is http_header(name,value) then 2079 [h . t] then if h is http_header(name,value) then
2080 [name,": ",value,crlf . format_headers(t)] 2080 [name,": ",value,crlf . format_headers(t)]
2081 }. 2081 }.
2082 -  
2083 - 2082 +
  2083 +
2084 2084
2085 define String 2085 define String
2086 month_abrv 2086 month_abrv
@@ -2099,7 +2099,7 @@ define String @@ -2099,7 +2099,7 @@ define String
2099 else if d.month = 10 then "Oct" 2099 else if d.month = 10 then "Oct"
2100 else if d.month = 11 then "Nov" 2100 else if d.month = 11 then "Nov"
2101 else if d.month = 12 then "Dec" 2101 else if d.month = 12 then "Dec"
2102 - else 2102 + else
2103 println("Bad month value [" + d.month + "] on Date_and_Time"); 2103 println("Bad month value [" + d.month + "] on Date_and_Time");
2104 "XXX". 2104 "XXX".
2105 2105
@@ -2115,10 +2115,10 @@ define String @@ -2115,10 +2115,10 @@ define String
2115 else if d.week_day = 4 then "Thu" 2115 else if d.week_day = 4 then "Thu"
2116 else if d.week_day = 5 then "Fri" 2116 else if d.week_day = 5 then "Fri"
2117 else if d.week_day = 6 then "Sat" 2117 else if d.week_day = 6 then "Sat"
2118 - else 2118 + else
2119 println("Bad weekday value [" + d.week_day + "] on Date_and_Time"); 2119 println("Bad weekday value [" + d.week_day + "] on Date_and_Time");
2120 "XXX". 2120 "XXX".
2121 - 2121 +
2122 /** 2122 /**
2123 * Format a date with the followin format : "Mon, 23 Jul 2007 11:33:43 GMT" 2123 * Format a date with the followin format : "Mon, 23 Jul 2007 11:33:43 GMT"
2124 * Currently, this function can't output a GMT time, but only local time. 2124 * Currently, this function can't output a GMT time, but only local time.
@@ -2129,7 +2129,7 @@ public define String @@ -2129,7 +2129,7 @@ public define String
2129 ( 2129 (
2130 Date_and_Time d 2130 Date_and_Time d
2131 ) = 2131 ) =
2132 - weekday_abrv(d) + ", " + zero_pad_n(2,day(d)) + " " + month_abrv(d) + " " + year(d) 2132 + weekday_abrv(d) + ", " + zero_pad_n(2,day(d)) + " " + month_abrv(d) + " " + year(d)
2133 + " " + zero_pad_n(2,hour(d)) + ":" + zero_pad_n(2,minute(d)) + ":" + zero_pad_n(2,second(d)) + " GMT". 2133 + " " + zero_pad_n(2,hour(d)) + ":" + zero_pad_n(2,minute(d)) + ":" + zero_pad_n(2,second(d)) + " GMT".
2134 2134
2135 /** 2135 /**
@@ -2141,12 +2141,12 @@ public define String @@ -2141,12 +2141,12 @@ public define String
2141 Int date 2141 Int date
2142 ) = 2142 ) =
2143 format_http_date(convert_time(date)). 2143 format_http_date(convert_time(date)).
2144 -  
2145 2144
2146 - *** [5.5] Sending a file.  
2147 2145
2148 - We send 2 headers 'Content-Type' and 'Content-Length'.  
2149 - 2146 + *** [5.5] Sending a file.
  2147 +
  2148 + We send 2 headers 'Content-Type' and 'Content-Length'.
  2149 +
2150 define List(HTTP_header) 2150 define List(HTTP_header)
2151 headers_for_send_file 2151 headers_for_send_file
2152 ( 2152 (
@@ -2167,15 +2167,15 @@ define List(HTTP_header) @@ -2167,15 +2167,15 @@ define List(HTTP_header)
2167 success(ftimes) then [http_header("Last-Modified", format_http_date(to_Int(ftimes.last_modified))) . headers] 2167 success(ftimes) then [http_header("Last-Modified", format_http_date(to_Int(ftimes.last_modified))) . headers]
2168 } 2168 }
2169 . 2169 .
2170 -  
2171 -  
2172 -  
2173 - Sending the body of the answer (i.e. the file itself).  
2174 - 2170 +
  2171 +
  2172 +
  2173 + Sending the body of the answer (i.e. the file itself).
  2174 +
2175 define One 2175 define One
2176 send_file_body 2176 send_file_body
2177 ( 2177 (
2178 - Web_Site_Description desc, 2178 + Web_Site_Description desc,
2179 Connection connection, // connection with the client 2179 Connection connection, // connection with the client
2180 Connection file, // file to be sent already opened 2180 Connection file, // file to be sent already opened
2181 Int size, // size of file 2181 Int size, // size of file
@@ -2183,21 +2183,21 @@ define One @@ -2183,21 +2183,21 @@ define One
2183 String filename // name of file 2183 String filename // name of file
2184 ) = 2184 ) =
2185 if sent >= size then unique else 2185 if sent >= size then unique else
2186 - if read(file,min(16384,size-sent),60) is 2186 + if read(file,min(16384,size-sent),60) is
2187 { 2187 {
2188 error then log_journal_msg(desc,"Cannot read from file '"+filename+"'.\n"), 2188 error then log_journal_msg(desc,"Cannot read from file '"+filename+"'.\n"),
2189 timeout then log_journal_msg(desc,"Cannot read from file timeoput'"+filename+"'.\n"), 2189 timeout then log_journal_msg(desc,"Cannot read from file timeoput'"+filename+"'.\n"),
2190 - ok(ba) then 2190 + ok(ba) then
2191 with nr = length(ba), // get the number of bytes read 2191 with nr = length(ba), // get the number of bytes read
2192 - if reliable_write(connection, ba) is 2192 + if reliable_write(connection, ba) is
2193 { 2193 {
2194 - failure then log_journal_msg(desc,"Cannot write into connection delirering '"+filename+"' (sent="+sent+"; size="+size+"; current="+nr+").\n"),  
2195 - success(nw) then  
2196 - send_file_body(desc,connection,file,size,sent+nw,filename) 2194 + failure then log_journal_msg(desc,"Cannot write into connection delirering '"+filename+"' (sent="+sent+"; size="+size+"; current="+nr+").\n"),
  2195 + success(nw) then
  2196 + send_file_body(desc,connection,file,size,sent+nw,filename)
2197 } 2197 }
2198 - }. 2198 + }.
  2199 +
2199 2200
2200 -  
2201 define String 2201 define String
2202 compute_etag 2202 compute_etag
2203 ( 2203 (
@@ -2205,7 +2205,7 @@ define String @@ -2205,7 +2205,7 @@ define String
2205 Maybe(FileTimes) mb_ftimes, 2205 Maybe(FileTimes) mb_ftimes,
2206 Int size, 2206 Int size,
2207 ) = 2207 ) =
2208 - if mb_ftimes is 2208 + if mb_ftimes is
2209 { 2209 {
2210 failure then println("Warning: no file times for '" + filename + "', etag won't be very accurate."); to_ascii(sha1((filename, size))), 2210 failure then println("Warning: no file times for '" + filename + "', etag won't be very accurate."); to_ascii(sha1((filename, size))),
2211 success(ftimes) then to_ascii(md5((filename, ftimes, size))) 2211 success(ftimes) then to_ascii(md5((filename, ftimes, size)))
@@ -2222,13 +2222,13 @@ define Bool @@ -2222,13 +2222,13 @@ define Bool
2222 failure then false, 2222 failure then false,
2223 success(etag) then trim_token(etag, '\"') = current_etag //remove triming " because this is quoted string 2223 success(etag) then trim_token(etag, '\"') = current_etag //remove triming " because this is quoted string
2224 }. 2224 }.
2225 -  
2226 - Sending the answer line, the headers and the body.  
2227 2225
2228 -define One 2226 + Sending the answer line, the headers and the body.
  2227 +
  2228 +define One
2229 send_file 2229 send_file
2230 ( 2230 (
2231 - Web_Site_Description desc, 2231 + Web_Site_Description desc,
2232 Connection connection, 2232 Connection connection,
2233 List(HTTP_header) input_headers, 2233 List(HTTP_header) input_headers,
2234 List(HTTP_header) headers, 2234 List(HTTP_header) headers,
@@ -2239,79 +2239,79 @@ define One @@ -2239,79 +2239,79 @@ define One
2239 MIME mime_type, 2239 MIME mime_type,
2240 One -> One action_before_send_file 2240 One -> One action_before_send_file
2241 ) = 2241 ) =
2242 - action_before_send_file(unique);  
2243 - with input_etag = http_header_value(input_headers, "If-None-Match"), 2242 + action_before_send_file(unique);
  2243 + with input_etag = http_header_value(input_headers, "If-None-Match"),
2244 mb_ftimes = get_file_times(full_path), 2244 mb_ftimes = get_file_times(full_path),
2245 current_etag = compute_etag(full_path, mb_ftimes, size), 2245 current_etag = compute_etag(full_path, mb_ftimes, size),
2246 if are_same_etag(input_etag, current_etag) is 2246 if are_same_etag(input_etag, current_etag) is
2247 { 2247 {
2248 - false then  
2249 - forget(reliable_write(connection,to_byte_array("HTTP/1.1 200 OK"+crlf))); 2248 + false then
  2249 + forget(reliable_write(connection,to_byte_array("HTTP/1.1 200 OK"+crlf)));
2250 forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, current_etag, mb_ftimes)) , crlf])); 2250 forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, current_etag, mb_ftimes)) , crlf]));
2251 //forget(copy_file_to_Connection(file, connection, size)), 2251 //forget(copy_file_to_Connection(file, connection, size)),
2252 send_file_body(desc,connection,file,size,0,filename), 2252 send_file_body(desc,connection,file,size,0,filename),
2253 true then 2253 true then
2254 - forget(reliable_write(connection,to_byte_array("HTTP/1.1 304 Not Modified"+crlf))); 2254 + forget(reliable_write(connection,to_byte_array("HTTP/1.1 304 Not Modified"+crlf)));
2255 forget(reliable_write(connection,[format_headers([http_header("Content-length","0") . [http_header("Etag", "\""+current_etag+"\"") . headers]]) , crlf])) 2255 forget(reliable_write(connection,[format_headers([http_header("Content-length","0") . [http_header("Etag", "\""+current_etag+"\"") . headers]]) , crlf]))
2256 //send_file_body(desc,connection,file,size,0,filename) 2256 //send_file_body(desc,connection,file,size,0,filename)
2257 - }.  
2258 - 2257 + }.
  2258 +
2259 2259
2260 2260
2261 - Checking if a connection is under SSL.  
2262 - 2261 + Checking if a connection is under SSL.
  2262 +
2263 define Bool 2263 define Bool
2264 is_SSL 2264 is_SSL
2265 ( 2265 (
2266 Connection c 2266 Connection c
2267 ) = 2267 ) =
2268 - if c is 2268 + if c is
2269 { 2269 {
2270 - file_r(_) then false,  
2271 - file_w(_) then false,  
2272 - file_rw(_) then false,  
2273 - tcp(_) then false, 2270 + file_r(_) then false,
  2271 + file_w(_) then false,
  2272 + file_rw(_) then false,
  2273 + tcp(_) then false,
2274 ssl(_) then true 2274 ssl(_) then true
2275 - }. 2275 + }.
  2276 +
  2277 +
2276 2278
2277 -  
2278 -  
2279 Before opening and sending a file, we check the MIME type. It must be recognized, 2279 Before opening and sending a file, we check the MIME type. It must be recognized,
2280 except if there is a valid authorization for private download. 2280 except if there is a valid authorization for private download.
2281 2281
2282 define One 2282 define One
2283 send_file 2283 send_file
2284 ( 2284 (
2285 - Web_Site_Description desc,  
2286 - Connection connection,  
2287 - String uri, 2285 + Web_Site_Description desc,
  2286 + Connection connection,
  2287 + String uri,
2288 List(HTTP_header) input_headers, 2288 List(HTTP_header) input_headers,
2289 List(HTTP_header) output_headers, 2289 List(HTTP_header) output_headers,
2290 Maybe(String) mbauthorization, 2290 Maybe(String) mbauthorization,
2291 One -> One action_before_send_file 2291 One -> One action_before_send_file
2292 ) = 2292 ) =
2293 - if mbauthorization is 2293 + if mbauthorization is
2294 { 2294 {
2295 //--- file without authorization: take it from public --- 2295 //--- file without authorization: take it from public ---
2296 - failure then if recognize_mime_type_from_uri(desc,uri) is 2296 + failure then if recognize_mime_type_from_uri(desc,uri) is
2297 { 2297 {
2298 failure then log_journal_msg(desc,"No MIME type found for '"+uri+"'.\n"), 2298 failure then log_journal_msg(desc,"No MIME type found for '"+uri+"'.\n"),
2299 - success(mime_type) then 2299 + success(mime_type) then
2300 with path = site_directory(desc)+"/public"+uri, 2300 with path = site_directory(desc)+"/public"+uri,
2301 - if (Maybe(RStream))file(path, read) is 2301 + if (Maybe(RStream))file(path, read) is
2302 { 2302 {
2303 - failure then 2303 + failure then
2304 println("HTTP/1.1 404 Not Found"+path); 2304 println("HTTP/1.1 404 Not Found"+path);
2305 forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+ 2305 forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+
2306 "Content-Length: 0"+crlf+crlf 2306 "Content-Length: 0"+crlf+crlf
2307 /*+"Connection: close"+crlf+crlf*/))); 2307 /*+"Connection: close"+crlf+crlf*/)));
2308 log_journal_msg(desc,"Cannot find file '"+path+"'.\n"), 2308 log_journal_msg(desc,"Cannot find file '"+path+"'.\n"),
2309 - success(f) then with size = file_size(f), 2309 + success(f) then with size = file_size(f),
2310 send_file(desc, 2310 send_file(desc,
2311 connection, 2311 connection,
2312 input_headers, 2312 input_headers,
2313 output_headers, 2313 output_headers,
2314 - size, 2314 + size,
2315 file(f), 2315 file(f),
2316 uri, 2316 uri,
2317 path, 2317 path,
@@ -2319,60 +2319,60 @@ define One @@ -2319,60 +2319,60 @@ define One
2319 action_before_send_file) 2319 action_before_send_file)
2320 } 2320 }
2321 }, 2321 },
2322 - 2322 +
2323 //--- file with authorization: apply 'private download' mecanism --- 2323 //--- file with authorization: apply 'private download' mecanism ---
2324 - success(authorization) then  
2325 - with private_download_dir = site_directory(desc)+"/private_download",  
2326 - if (RetrieveResult(String))retrieve(private_download_dir+"/z"+authorization)  
2327 - is ok(absolute_path) 2324 + success(authorization) then
  2325 + with private_download_dir = site_directory(desc)+"/private_download",
  2326 + if (RetrieveResult(String))retrieve(private_download_dir+"/z"+authorization)
  2327 + is ok(absolute_path)
2328 then ( 2328 then (
2329 with new_hash = compute_authorization(authorization_secret(desc), 2329 with new_hash = compute_authorization(authorization_secret(desc),
2330 - absolute_path),  
2331 - if (Maybe(RStream))file(absolute_path, read) is 2330 + absolute_path),
  2331 + if (Maybe(RStream))file(absolute_path, read) is
2332 { 2332 {
2333 - failure then 2333 + failure then
2334 println("HTTP/1.1 404 Not Found"+absolute_path); 2334 println("HTTP/1.1 404 Not Found"+absolute_path);
2335 forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+ 2335 forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+
2336 "Content-Length: 0"+crlf+crlf 2336 "Content-Length: 0"+crlf+crlf
2337 /*+"Connection: close"+crlf+crlf*/))); 2337 /*+"Connection: close"+crlf+crlf*/)));
2338 log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"), 2338 log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"),
2339 - success(f) then with size = file_size(f),  
2340 - mime_type = if recognize_mime_type_from_uri(desc,uri) is 2339 + success(f) then with size = file_size(f),
  2340 + mime_type = if recognize_mime_type_from_uri(desc,uri) is
2341 { 2341 {
2342 failure then mime("application", "octet-stream", []), 2342 failure then mime("application", "octet-stream", []),
2343 success(mime_type) then mime_type 2343 success(mime_type) then mime_type
2344 }, 2344 },
2345 send_file(desc, 2345 send_file(desc,
2346 - connection, 2346 + connection,
2347 input_headers, 2347 input_headers,
2348 output_headers, 2348 output_headers,
2349 - size,  
2350 - file(f), 2349 + size,
  2350 + file(f),
2351 uri, 2351 uri,
2352 absolute_path, 2352 absolute_path,
2353 mime_type, 2353 mime_type,
2354 action_before_send_file) 2354 action_before_send_file)
2355 } 2355 }
2356 ) 2356 )
2357 - else log_journal_msg(desc,"Cannot find or read authorization file.\n") 2357 + else log_journal_msg(desc,"Cannot find or read authorization file.\n")
2358 }. 2358 }.
2359 -  
2360 -  
2361 -  
2362 -  
2363 -  
2364 -  
2365 -  
2366 -  
2367 - *** [5.6] Answering a www-url encoded request.  
2368 -  
2369 - Standard headers are for answering ".awp" requests.  
2370 - 2359 +
  2360 +
  2361 +
  2362 +
  2363 +
  2364 +
  2365 +
  2366 +
  2367 + *** [5.6] Answering a www-url encoded request.
  2368 +
  2369 + Standard headers are for answering ".awp" requests.
  2370 +
2371 public define List(HTTP_header) 2371 public define List(HTTP_header)
2372 standard_headers 2372 standard_headers
2373 = 2373 =
2374 [ 2374 [
2375 - http_header("Date", format_http_date(now)), 2375 + http_header("Date", format_http_date(now)),
2376 http_header("Server", "Anubis Embedded Server v" + major_version_number + "." + minor_version_number), 2376 http_header("Server", "Anubis Embedded Server v" + major_version_number + "." + minor_version_number),
2377 /*http_header("Connection", "close"), */ 2377 /*http_header("Connection", "close"), */
2378 ]. 2378 ].
@@ -2385,10 +2385,10 @@ public define List(HTTP_header) @@ -2385,10 +2385,10 @@ public define List(HTTP_header)
2385 Maybe(String) mb_charset, 2385 Maybe(String) mb_charset,
2386 ) = 2386 ) =
2387 [ 2387 [
2388 - http_header("Content-Type", mime_type + if mb_charset is success(charset) then "; charset="+charset else ""), 2388 + http_header("Content-Type", mime_type + if mb_charset is success(charset) then "; charset="+charset else ""),
2389 http_header("Content-length", to_decimal(answer_body_size)) 2389 http_header("Content-length", to_decimal(answer_body_size))
2390 ]. 2390 ].
2391 - 2391 +
2392 public define List(HTTP_header) 2392 public define List(HTTP_header)
2393 file_attached_header 2393 file_attached_header
2394 ( 2394 (
@@ -2396,34 +2396,34 @@ public define List(HTTP_header) @@ -2396,34 +2396,34 @@ public define List(HTTP_header)
2396 ) = 2396 ) =
2397 [ 2397 [
2398 http_header("Content-Disposition", "attachment; filename=\"" + filename +"\"") 2398 http_header("Content-Disposition", "attachment; filename=\"" + filename +"\"")
2399 - ].  
2400 - 2399 + ].
  2400 +
2401 2401
2402 define One 2402 define One
2403 www_url_answer 2403 www_url_answer
2404 ( 2404 (
2405 - String host_name,  
2406 - Web_Site_Description desc, 2405 + String host_name,
  2406 + Web_Site_Description desc,
2407 Connection connection, // with the client 2407 Connection connection, // with the client
2408 Word32 ip_addr, // of the client 2408 Word32 ip_addr, // of the client
2409 HTTP_RequestLine request_line, 2409 HTTP_RequestLine request_line,
2410 - List(HTTP_header) headers, 2410 + List(HTTP_header) headers,
2411 ByteArray body, 2411 ByteArray body,
2412 One -> String generate_tt // trust ticket generation 2412 One -> String generate_tt // trust ticket generation
2413 - ) =  
2414 - with all_web_args = query_string(request_line) + 2413 + ) =
  2414 + with all_web_args = query_string(request_line) +
2415 read_www_url_encoded_web_args(to_string(body),0), 2415 read_www_url_encoded_web_args(to_string(body),0),
2416 uri = uri(request_line), 2416 uri = uri(request_line),
2417 - ext = get_uri_extension(uri), 2417 + ext = get_uri_extension(uri),
2418 http_inf = http_info(ip_addr, host_name, uri, headers, is_SSL(connection)), 2418 http_inf = http_info(ip_addr, host_name, uri, headers, is_SSL(connection)),
2419 (if member(journal_extensions(desc),ext) 2419 (if member(journal_extensions(desc),ext)
2420 then log_journal_msg(desc, 2420 then log_journal_msg(desc,
2421 format_request(desc,connection,request_line,headers,all_web_args)) 2421 format_request(desc,connection,request_line,headers,all_web_args))
2422 - else unique);  
2423 - if is_illegal_uri(uri,0)  
2424 - then log_journal_msg(desc,"Received illegal URI: "+uri+"\n") 2422 + else unique);
  2423 + if is_illegal_uri(uri,0)
  2424 + then log_journal_msg(desc,"Received illegal URI: "+uri+"\n")
2425 else (if (ext = ".awp" | ext = "") 2425 else (if (ext = ".awp" | ext = "")
2426 - then (with answer_headers_body = awp_handler(desc)(host_name, 2426 + then (with answer_headers_body = awp_handler(desc)(host_name,
2427 http_inf, 2427 http_inf,
2428 all_web_args, 2428 all_web_args,
2429 is_SSL(connection)), 2429 is_SSL(connection)),
@@ -2436,7 +2436,7 @@ define One @@ -2436,7 +2436,7 @@ define One
2436 uri, 2436 uri,
2437 headers, 2437 headers,
2438 standard_headers, 2438 standard_headers,
2439 - if web_arg_value(all_web_args,"zauth") is 2439 + if web_arg_value(all_web_args,"zauth") is
2440 { 2440 {
2441 not_found then failure, 2441 not_found then failure,
2442 found(v) then success(v) 2442 found(v) then success(v)
@@ -2444,30 +2444,30 @@ define One @@ -2444,30 +2444,30 @@ define One
2444 (One u) |-> before_send_file(desc)(http_inf, all_web_args)) 2444 (One u) |-> before_send_file(desc)(http_inf, all_web_args))
2445 //print_delta("After sending file") 2445 //print_delta("After sending file")
2446 )). 2446 )).
2447 -  
2448 -  
2449 -  
2450 -  
2451 -  
2452 -  
2453 -  
2454 - *** [5.7] Answering a multipart/form-data encoded request.  
2455 - 2447 +
  2448 +
  2449 +
  2450 +
  2451 +
  2452 +
  2453 +
  2454 + *** [5.7] Answering a multipart/form-data encoded request.
  2455 +
2456 In order to support upload of files, we must be able to read web arguments which are 2456 In order to support upload of files, we must be able to read web arguments which are
2457 encoded in a multipart/form-data body. The first thing to do is to find the 2457 encoded in a multipart/form-data body. The first thing to do is to find the
2458 boundary. The boundary is a special string which delimits the various parts of the 2458 boundary. The boundary is a special string which delimits the various parts of the
2459 'multipart' body. It is found within the value of the 'Content-Type' HTTP header, as 2459 'multipart' body. It is found within the value of the 'Content-Type' HTTP header, as
2460 the value of the 'boundary' attribute. 2460 the value of the 'boundary' attribute.
2461 -  
2462 -  
2463 -  
2464 -  
2465 - 2461 +
  2462 +
  2463 +
  2464 +
  2465 +
2466 *** [5.7.1] Finding the boundary. 2466 *** [5.7.1] Finding the boundary.
2467 - 2467 +
2468 Hence, we just have to find the string 'boundary=' within the value of the 2468 Hence, we just have to find the string 'boundary=' within the value of the
2469 'Content-Type' header, and read the value of the boundary from there. 2469 'Content-Type' header, and read the value of the boundary from there.
2470 - 2470 +
2471 define Bool 2471 define Bool
2472 delimits_boundary 2472 delimits_boundary
2473 ( 2473 (
@@ -2478,101 +2478,101 @@ define Bool @@ -2478,101 +2478,101 @@ define Bool
2478 if c = 10 then true else 2478 if c = 10 then true else
2479 if c = 0 then true else 2479 if c = 0 then true else
2480 if c = ',' then true else 2480 if c = ',' then true else
2481 - c = ';'.  
2482 -  
2483 - 2481 + c = ';'.
  2482 +
  2483 +
2484 define Maybe(String) 2484 define Maybe(String)
2485 get_boundary_value_3 2485 get_boundary_value_3
2486 ( 2486 (
2487 - String s,  
2488 - Int i, 2487 + String s,
  2488 + Int i,
2489 List(Word8) so_far 2489 List(Word8) so_far
2490 ) = 2490 ) =
2491 - if nth(i,s) is 2491 + if nth(i,s) is
2492 { 2492 {
2493 failure then success(implode(reverse(so_far))), 2493 failure then success(implode(reverse(so_far))),
2494 - success(c) then 2494 + success(c) then
2495 if delimits_boundary(c) 2495 if delimits_boundary(c)
2496 - then success(implode(reverse(so_far))) 2496 + then success(implode(reverse(so_far)))
2497 else get_boundary_value_3(s,i+1,[c . so_far]) 2497 else get_boundary_value_3(s,i+1,[c . so_far])
2498 - }.  
2499 -  
2500 -  
2501 - 2498 + }.
  2499 +
  2500 +
  2501 +
2502 define Maybe(String) 2502 define Maybe(String)
2503 get_boundary_value_2 2503 get_boundary_value_2
2504 ( 2504 (
2505 String s, 2505 String s,
2506 Int i, 2506 Int i,
2507 ) = 2507 ) =
2508 - if nth(i,s) is 2508 + if nth(i,s) is
2509 { 2509 {
2510 - failure then failure, 2510 + failure then failure,
2511 success(c) then 2511 success(c) then
2512 - if is_blank(c) 2512 + if is_blank(c)
2513 then get_boundary_value_2(s,i+1) 2513 then get_boundary_value_2(s,i+1)
2514 else get_boundary_value_3(s,i+1,[c]) 2514 else get_boundary_value_3(s,i+1,[c])
2515 - }.  
2516 - 2515 + }.
  2516 +
2517 define Maybe(String) 2517 define Maybe(String)
2518 get_boundary_value_1 2518 get_boundary_value_1
2519 ( 2519 (
2520 String s, // string into which we must find '= ...' 2520 String s, // string into which we must find '= ...'
2521 Int i // position of start of search 2521 Int i // position of start of search
2522 - ) =  
2523 - if nth(i,s) is 2522 + ) =
  2523 + if nth(i,s) is
2524 { 2524 {
2525 - failure then failure, 2525 + failure then failure,
2526 success(c) then 2526 success(c) then
2527 - if is_blank(c) 2527 + if is_blank(c)
2528 then get_boundary_value_1(s,i+1) 2528 then get_boundary_value_1(s,i+1)
2529 else if c = '=' 2529 else if c = '='
2530 then get_boundary_value_2(s,i+1) 2530 then get_boundary_value_2(s,i+1)
2531 else failure 2531 else failure
2532 }. 2532 }.
2533 -  
2534 - 2533 +
  2534 +
2535 define Maybe(String) 2535 define Maybe(String)
2536 get_boundary 2536 get_boundary
2537 ( 2537 (
2538 String content_type_header_value 2538 String content_type_header_value
2539 ) = 2539 ) =
2540 - if find("boundary",content_type_header_value,0) is 2540 + if find("boundary",content_type_header_value,0) is
2541 { 2541 {
2542 - failure then failure,  
2543 - success(n) then // 'boundary' has been found at position n 2542 + failure then failure,
  2543 + success(n) then // 'boundary' has been found at position n
2544 get_boundary_value_1(content_type_header_value,n+8) 2544 get_boundary_value_1(content_type_header_value,n+8)
2545 - }.  
2546 - 2545 + }.
  2546 +
2547 define Maybe(String) 2547 define Maybe(String)
2548 get_boundary 2548 get_boundary
2549 ( 2549 (
2550 List(HTTP_header) headers 2550 List(HTTP_header) headers
2551 )= 2551 )=
2552 - if headers is 2552 + if headers is
2553 { 2553 {
2554 - [ ] then failure,  
2555 - [h . t] then if h is http_header(name,value) then 2554 + [ ] then failure,
  2555 + [h . t] then if h is http_header(name,value) then
2556 if name = "content-type" 2556 if name = "content-type"
2557 then get_boundary(value) 2557 then get_boundary(value)
2558 else get_boundary(t) 2558 else get_boundary(t)
2559 - }.  
2560 -  
2561 -  
2562 -  
2563 -  
2564 -  
2565 -  
2566 -  
2567 -  
2568 - *** [5.7.2] Reading attributes from a multipart entity.  
2569 - 2559 + }.
  2560 +
  2561 +
  2562 +
  2563 +
  2564 +
  2565 +
  2566 +
  2567 +
  2568 + *** [5.7.2] Reading attributes from a multipart entity.
  2569 +
2570 Entities in a multipart/form-data body are separated by instances of the string: 2570 Entities in a multipart/form-data body are separated by instances of the string:
2571 - 2571 +
2572 --bbbbb 2572 --bbbbb
2573 - 2573 +
2574 where bbbbb is the boundary computed above. Actually, the body has the form: 2574 where bbbbb is the boundary computed above. Actually, the body has the form:
2575 - 2575 +
2576 --bbbbb 2576 --bbbbb
2577 <entity 1> 2577 <entity 1>
2578 --bbbbb 2578 --bbbbb
@@ -2582,273 +2582,273 @@ define Maybe(String) @@ -2582,273 +2582,273 @@ define Maybe(String)
2582 --bbbbb 2582 --bbbbb
2583 <last entity> 2583 <last entity>
2584 --bbbbb 2584 --bbbbb
2585 -  
2586 - 2585 +
  2586 +
2587 We have to extract an entity which is in the body between offsets 'start' and 'end' 2587 We have to extract an entity which is in the body between offsets 'start' and 'end'
2588 (computed when boundaries have been localized). The entity itself is made of two parts: 2588 (computed when boundaries have been localized). The entity itself is made of two parts:
2589 headers and body. The body is separated from the headers by a blank line. This blank 2589 headers and body. The body is separated from the headers by a blank line. This blank
2590 line (a double crlf) marks the beginning of the body of the entity. Within the headers 2590 line (a double crlf) marks the beginning of the body of the entity. Within the headers
2591 of the entity, we look for a 'Content-Disposition' header, which should look like this: 2591 of the entity, we look for a 'Content-Disposition' header, which should look like this:
2592 - 2592 +
2593 Content-Disposition: form-data; name="..."; filename="..." crlf 2593 Content-Disposition: form-data; name="..."; filename="..." crlf
2594 - 2594 +
2595 We are just interested in the name and the file name. Hence we first search 2595 We are just interested in the name and the file name. Hence we first search
2596 'Content-Disposition', then we search 'name' and read the value, and we do the same for 2596 'Content-Disposition', then we search 'name' and read the value, and we do the same for
2597 'filename'. 2597 'filename'.
2598 - 2598 +
2599 If the 'filename' attribute is not present, the web arg is an ordinary one, otherwise, 2599 If the 'filename' attribute is not present, the web arg is an ordinary one, otherwise,
2600 - it is an uploaded file.  
2601 - 2600 + it is an uploaded file.
  2601 +
2602 2602
2603 Below is a variant of 'find' (see 'tools/findstring.anubis'), with an extra 'end' 2603 Below is a variant of 'find' (see 'tools/findstring.anubis'), with an extra 'end'
2604 argument. 2604 argument.
2605 -  
2606 -define Maybe(Int) 2605 +
  2606 +define Maybe(Int)
2607 find 2607 find
2608 ( 2608 (
2609 - String what,  
2610 - ByteArray where, 2609 + String what,
  2610 + ByteArray where,
2611 Int start, 2611 Int start,
2612 Int end 2612 Int end
2613 ) = 2613 ) =
2614 - if find(to_byte_array(what),where,start) is 2614 + if find(to_byte_array(what),where,start) is
2615 { 2615 {
2616 - failure then failure,  
2617 - success(n) then  
2618 - if n+length(what) >= end 2616 + failure then failure,
  2617 + success(n) then
  2618 + if n+length(what) >= end
2619 then failure 2619 then failure
2620 else success(n) 2620 else success(n)
2621 }. 2621 }.
2622 2622
2623 -define Maybe(Int) 2623 +define Maybe(Int)
2624 find 2624 find
2625 ( 2625 (
2626 - String what,  
2627 - String where, 2626 + String what,
  2627 + String where,
2628 Int start, 2628 Int start,
2629 Int end 2629 Int end
2630 ) = 2630 ) =
2631 - if find_string(where,what,start) is 2631 + if find_string(where,what,start) is
2632 { 2632 {
2633 - failure then failure,  
2634 - success(n) then  
2635 - if n+length(what) >= end 2633 + failure then failure,
  2634 + success(n) then
  2635 + if n+length(what) >= end
2636 then failure 2636 then failure
2637 else success(n) 2637 else success(n)
2638 - }.  
2639 - 2638 + }.
  2639 +
2640 define String 2640 define String
2641 read_attribute_value 2641 read_attribute_value
2642 ( 2642 (
2643 - ByteArray where, 2643 + ByteArray where,
2644 Int start, 2644 Int start,
2645 Int end, 2645 Int end,
2646 List(Word8) so_far 2646 List(Word8) so_far
2647 ) = 2647 ) =
2648 if start >= end then implode(reverse(so_far)) else 2648 if start >= end then implode(reverse(so_far)) else
2649 - if nth(start,where) is 2649 + if nth(start,where) is
2650 { 2650 {
2651 failure then implode(reverse(so_far)), 2651 failure then implode(reverse(so_far)),
2652 - success(c) then 2652 + success(c) then
2653 if c = '\"' 2653 if c = '\"'
2654 then implode(reverse(so_far)) 2654 then implode(reverse(so_far))
2655 else read_attribute_value(where,start+1,end,[c . so_far]) 2655 else read_attribute_value(where,start+1,end,[c . so_far])
2656 }. 2656 }.
2657 -  
2658 -define Maybe(String) 2657 +
  2658 +define Maybe(String)
2659 find_attribute 2659 find_attribute
2660 ( 2660 (
2661 - String name,  
2662 - ByteArray where,  
2663 - Int start, 2661 + String name,
  2662 + ByteArray where,
  2663 + Int start,
2664 Int end 2664 Int end
2665 ) = 2665 ) =
2666 with prefix = name+"=\"", 2666 with prefix = name+"=\"",
2667 if find(to_byte_array(prefix),where,start) is 2667 if find(to_byte_array(prefix),where,start) is
2668 { 2668 {
2669 failure then failure, 2669 failure then failure,
2670 - success(n) then 2670 + success(n) then
2671 if n+length(prefix) >= end 2671 if n+length(prefix) >= end
2672 then failure 2672 then failure
2673 else success(read_attribute_value(where,n+length(prefix),end,[])) 2673 else success(read_attribute_value(where,n+length(prefix),end,[]))
2674 }. 2674 }.
2675 -  
2676 -  
2677 - 2675 +
  2676 +
  2677 +
2678 define Maybe((String,Maybe(String))) 2678 define Maybe((String,Maybe(String)))
2679 find_name_and_filename 2679 find_name_and_filename
2680 ( 2680 (
2681 - ByteArray body,  
2682 - Int start, 2681 + ByteArray body,
  2682 + Int start,
2683 Int end 2683 Int end
2684 ) = 2684 ) =
2685 - if find(to_byte_array("Content-Disposition"),body,start) is 2685 + if find(to_byte_array("Content-Disposition"),body,start) is
2686 { 2686 {
2687 - failure then failure,  
2688 - success(n) then  
2689 - if find_attribute("name",body,n+19,end) is 2687 + failure then failure,
  2688 + success(n) then
  2689 + if find_attribute("name",body,n+19,end) is
2690 { 2690 {
2691 failure then failure, 2691 failure then failure,
2692 - success(name_value) then if find_attribute("filename",body,n+19,end) is 2692 + success(name_value) then if find_attribute("filename",body,n+19,end) is
2693 { 2693 {
2694 failure then success((name_value,failure)), 2694 failure then success((name_value,failure)),
2695 success(filename_value) then success((name_value,success(filename_value))) 2695 success(filename_value) then success((name_value,success(filename_value)))
2696 } 2696 }
2697 } 2697 }
2698 }. 2698 }.
2699 -  
2700 -  
2701 -  
2702 -  
2703 -  
2704 -  
2705 -  
2706 -  
2707 -  
2708 -  
2709 - *** [5.7.3] Creating a temporary filename for an uploaded file.  
2710 -  
2711 - variable Int uploaded_file_count = 0.  
2712 - 2699 +
  2700 +
  2701 +
  2702 +
  2703 +
  2704 +
  2705 +
  2706 +
  2707 +
  2708 +
  2709 + *** [5.7.3] Creating a temporary filename for an uploaded file.
  2710 +
  2711 + variable Int uploaded_file_count = 0.
  2712 +
2713 This variable is local to the virtual machine. Hence, its value is 0 each time a new 2713 This variable is local to the virtual machine. Hence, its value is 0 each time a new
2714 requests arrives. Temporary uploaded files are stored in the directory represented by 2714 requests arrives. Temporary uploaded files are stored in the directory represented by
2715 'upload_temporary_directory'. The filenames have the form: 2715 'upload_temporary_directory'. The filenames have the form:
2716 - 2716 +
2717 _m_n 2717 _m_n
2718 - 2718 +
2719 where 'm' is the number of the virtual machine, and 'n' a number obtained by 2719 where 'm' is the number of the virtual machine, and 'n' a number obtained by
2720 incrementing 'uploaded_file_count'. Notice that the program must do something with this 2720 incrementing 'uploaded_file_count'. Notice that the program must do something with this
2721 file (move it to some directory/name), otherwise, it will probably be overwritten the 2721 file (move it to some directory/name), otherwise, it will probably be overwritten the
2722 next time the same machine works. 2722 next time the same machine works.
2723 -  
2724 -  
2725 -  
2726 -  
2727 -  
2728 -  
2729 - *** [5.7.4] Saving an uploaded file under a temporary filename.  
2730 - 2723 +
  2724 +
  2725 +
  2726 +
  2727 +
  2728 +
  2729 + *** [5.7.4] Saving an uploaded file under a temporary filename.
  2730 +
2731 define Maybe(String) // returns the temporary file name 2731 define Maybe(String) // returns the temporary file name
2732 save_uploaded_file 2732 save_uploaded_file
2733 ( 2733 (
2734 String web_site_dir, 2734 String web_site_dir,
2735 -// Web_Site_Description desc,  
2736 - 2735 +// Web_Site_Description desc,
  2736 +
2737 RStream body_fd, 2737 RStream body_fd,
2738 -// ByteArray body, 2738 +// ByteArray body,
2739 Int start, 2739 Int start,
2740 Int end, 2740 Int end,
2741 - SState s 2741 + SState s
2742 ) = 2742 ) =
2743 - s.uploaded_file_count <- 1 + *(s.uploaded_file_count); 2743 + s.uploaded_file_count <- 1 + *(s.uploaded_file_count);
2744 with tfn = "_"+to_decimal(virtual_machine_id)+"_"+to_decimal(*(s.uploaded_file_count)), 2744 with tfn = "_"+to_decimal(virtual_machine_id)+"_"+to_decimal(*(s.uploaded_file_count)),
2745 // println("save_uploaded_file to :"+site_directory(desc)+"/upload_temporary/"+tfn); 2745 // println("save_uploaded_file to :"+site_directory(desc)+"/upload_temporary/"+tfn);
2746 // println("start offset = "+start+" end offset = "+end); 2746 // println("start offset = "+start+" end offset = "+end);
2747 //make data_io which is the size of the file to extract 2747 //make data_io which is the size of the file to extract
2748 - if copy_Data_IO_to_file(make_data_io(body_fd, start, end - start), web_site_dir+"/upload_temporary/"+tfn) is copy_ok(_) 2748 + if copy_Data_IO_to_file(make_data_io(body_fd, start, end - start), web_site_dir+"/upload_temporary/"+tfn) is copy_ok(_)
2749 then success(tfn) 2749 then success(tfn)
2750 else failure 2750 else failure
2751 . 2751 .
2752 -  
2753 -  
2754 -  
2755 -// if (Maybe(RWStream))file(site_directory(desc)+"/upload_temporary/"+tfn, new) is 2752 +
  2753 +
  2754 +
  2755 +// if (Maybe(RWStream))file(site_directory(desc)+"/upload_temporary/"+tfn, new) is
2756 // { 2756 // {
2757 -// failure then failure,  
2758 -// success(f) then  
2759 -// if reliable_write(file(f),extract(body,start,end)) is 2757 +// failure then failure,
  2758 +// success(f) then
  2759 +// if reliable_write(file(f),extract(body,start,end)) is
2760 // { 2760 // {
2761 -// failure then failure, 2761 +// failure then failure,
2762 // success(nw) then 2762 // success(nw) then
2763 // if nw = end - start 2763 // if nw = end - start
2764 // then success(tfn) 2764 // then success(tfn)
2765 // else failure 2765 // else failure
2766 // } 2766 // }
2767 -// }.  
2768 -  
2769 -  
2770 -  
2771 -  
2772 -  
2773 -  
2774 -  
2775 -  
2776 - *** [5.7.5] Removing the path from a file name. 2767 +// }.
  2768 +
  2769 +
  2770 +
  2771 +
  2772 +
  2773 +
  2774 +
  2775 +
  2776 + *** [5.7.5] Removing the path from a file name.
2777 2777
2778 When a file is uploaded, the browser sends the complete path of the file on the client 2778 When a file is uploaded, the browser sends the complete path of the file on the client
2779 machine as the file name. Actually, this is not quite normal. Nevertheless, we need to 2779 machine as the file name. Actually, this is not quite normal. Nevertheless, we need to
2780 - remove the path, and keep only the file name. This is achieved by 'remove_path' below.  
2781 - 2780 + remove the path, and keep only the file name. This is achieved by 'remove_path' below.
  2781 +
2782 define Int 2782 define Int
2783 file_name_begin 2783 file_name_begin
2784 ( 2784 (
2785 String full_name, 2785 String full_name,
2786 Int i 2786 Int i
2787 ) = 2787 ) =
2788 - if nth(i,full_name) is 2788 + if nth(i,full_name) is
2789 { 2789 {
2790 - failure then 0,  
2791 - success(c) then 2790 + failure then 0,
  2791 + success(c) then
2792 if c = '/' then i+1 else 2792 if c = '/' then i+1 else
2793 if c = '\\' then i+1 else 2793 if c = '\\' then i+1 else
2794 file_name_begin(full_name,i-1) 2794 file_name_begin(full_name,i-1)
2795 - }.  
2796 - 2795 + }.
  2796 +
2797 define String 2797 define String
2798 remove_path 2798 remove_path
2799 ( 2799 (
2800 String full_name 2800 String full_name
2801 ) = 2801 ) =
2802 - with l = length(full_name), 2802 + with l = length(full_name),
2803 b = file_name_begin(full_name,l-1), 2803 b = file_name_begin(full_name,l-1),
2804 - substr(full_name,b,l-b).  
2805 -  
2806 -  
2807 -  
2808 -  
2809 -  
2810 - *** [5.7.6] Reading a multipart entity.  
2811 - 2804 + substr(full_name,b,l-b).
  2805 +
  2806 +
  2807 +
  2808 +
  2809 +
  2810 + *** [5.7.6] Reading a multipart entity.
  2811 +
2812 define Maybe(Web_arg) 2812 define Maybe(Web_arg)
2813 get_multipart_entity 2813 get_multipart_entity
2814 ( 2814 (
2815 - //Web_Site_Description desc, 2815 + //Web_Site_Description desc,
2816 String web_site_dir, 2816 String web_site_dir,
2817 - String body_temp_file, 2817 + String body_temp_file,
2818 Int start_offset, //real offset in source file of the part 2818 Int start_offset, //real offset in source file of the part
2819 Int end_offset, //real offset in source file of the part 2819 Int end_offset, //real offset in source file of the part
2820 - SState s 2820 + SState s
2821 )= 2821 )=
2822 - //Get header of the part  
2823 - if find_the_first(body_temp_file, crlf+crlf, start_offset, end_offset) is 2822 + //Get header of the part
  2823 + if find_the_first(body_temp_file, crlf+crlf, start_offset, end_offset) is
2824 { 2824 {
2825 - failure then failure,  
2826 - success(k) then 2825 + failure then failure,
  2826 + success(k) then
2827 if (Maybe(RStream))file(body_temp_file, read) is 2827 if (Maybe(RStream))file(body_temp_file, read) is
2828 { 2828 {
2829 failure then failure, 2829 failure then failure,
2830 success(body_fd) then 2830 success(body_fd) then
2831 if read_bytes(make_data_io(body_fd, start_offset, k), k) is success(header_part) then 2831 if read_bytes(make_data_io(body_fd, start_offset, k), k) is success(header_part) then
2832 - 2832 +
2833 if find_name_and_filename(header_part, 0, k) is 2833 if find_name_and_filename(header_part, 0, k) is
2834 { 2834 {
2835 - failure then failure,  
2836 - success(n_mbfn) then if n_mbfn is (name, mbfn) then  
2837 - if mbfn is 2835 + failure then failure,
  2836 + success(n_mbfn) then if n_mbfn is (name, mbfn) then
  2837 + if mbfn is
2838 { 2838 {
2839 - failure then 2839 + failure then
2840 if read_bytes(make_data_io(body_fd, start_offset+k+4, (end_offset-2)-(start_offset+k+4)), (end_offset-2)-(start_offset+k+4)) is success(attachement) then 2840 if read_bytes(make_data_io(body_fd, start_offset+k+4, (end_offset-2)-(start_offset+k+4)), (end_offset-2)-(start_offset+k+4)) is success(attachement) then
2841 success(web_arg(name,to_string(attachement))) 2841 success(web_arg(name,to_string(attachement)))
2842 // we must substract 2 to end because of crlf just before the boundary 2842 // we must substract 2 to end because of crlf just before the boundary
2843 else 2843 else
2844 failure, 2844 failure,
2845 -  
2846 - success(fn) then  
2847 - if save_uploaded_file(web_site_dir, body_fd, start_offset+k+4, end_offset-2, s) is 2845 +
  2846 + success(fn) then
  2847 + if save_uploaded_file(web_site_dir, body_fd, start_offset+k+4, end_offset-2, s) is
2848 { 2848 {
2849 - failure then failure, 2849 + failure then failure,
2850 success(tfn) then success(upload(name, remove_path(fn), web_site_dir+"/upload_temporary/"+tfn)) 2850 success(tfn) then success(upload(name, remove_path(fn), web_site_dir+"/upload_temporary/"+tfn))
2851 - 2851 +
2852 } 2852 }
2853 } 2853 }
2854 } 2854 }
@@ -2857,17 +2857,17 @@ define Maybe(Web_arg) @@ -2857,17 +2857,17 @@ define Maybe(Web_arg)
2857 } 2857 }
2858 }. 2858 }.
2859 2859
2860 -  
2861 - 2860 +
  2861 +
2862 public define List(Web_arg) 2862 public define List(Web_arg)
2863 read_multipart_form_data_encoded_web_args 2863 read_multipart_form_data_encoded_web_args
2864 ( 2864 (
2865 String web_site_dir, 2865 String web_site_dir,
2866 - //Web_Site_Description desc, 2866 + //Web_Site_Description desc,
2867 String body_temp_file, 2867 String body_temp_file,
2868 - String __boundary, 2868 + String __boundary,
2869 Int file_offset, 2869 Int file_offset,
2870 - SState s 2870 + SState s
2871 ) = 2871 ) =
2872 with boundary_length = length(__boundary), 2872 with boundary_length = length(__boundary),
2873 println( 2873 println(
@@ -2876,90 +2876,90 @@ public define List(Web_arg) @@ -2876,90 +2876,90 @@ public define List(Web_arg)
2876 body_temp_file : "+body_temp_file+" 2876 body_temp_file : "+body_temp_file+"
2877 file_offset : "+file_offset); 2877 file_offset : "+file_offset);
2878 //get the first boundary position 2878 //get the first boundary position
2879 - if find_the_first(body_temp_file, __boundary, file_offset) is 2879 + if find_the_first(body_temp_file, __boundary, file_offset) is
2880 { 2880 {
2881 - failure then println("first boundary NOT found");[ ],  
2882 - success(first) then  
2883 - with first = first + file_offset, //adjust the offset to real offset in file 2881 + failure then println("first boundary NOT found");[ ],
  2882 + success(first) then
  2883 + with first = first + file_offset, //adjust the offset to real offset in file
2884 //get the second boundary position 2884 //get the second boundary position
2885 - if find_the_first(body_temp_file, __boundary, first + boundary_length) is 2885 + if find_the_first(body_temp_file, __boundary, first + boundary_length) is
2886 { 2886 {
2887 - failure then println("last boundary NOT found");[ ],  
2888 - success(last) then  
2889 - with last = last + first + boundary_length, //adjust the offset to real offset in file 2887 + failure then println("last boundary NOT found");[ ],
  2888 + success(last) then
  2889 + with last = last + first + boundary_length, //adjust the offset to real offset in file
2890 //Extract the file content here 2890 //Extract the file content here
2891 - if get_multipart_entity(web_site_dir, body_temp_file, first+boundary_length, last, s) is 2891 + if get_multipart_entity(web_site_dir, body_temp_file, first+boundary_length, last, s) is
2892 { 2892 {
2893 failure then [ ], 2893 failure then [ ],
2894 - success(wa) then  
2895 - [wa . read_multipart_form_data_encoded_web_args(web_site_dir, body_temp_file, __boundary, last, s)] 2894 + success(wa) then
  2895 + [wa . read_multipart_form_data_encoded_web_args(web_site_dir, body_temp_file, __boundary, last, s)]
2896 } 2896 }
2897 } 2897 }
2898 }. 2898 }.
2899 -  
2900 -  
2901 - 2899 +
  2900 +
  2901 +
2902 define One 2902 define One
2903 multipart_form_data_answer 2903 multipart_form_data_answer
2904 ( 2904 (
2905 String host_name, 2905 String host_name,
2906 - Web_Site_Description desc,  
2907 - Connection connection,  
2908 - Word32 ip_addr,  
2909 - HTTP_RequestLine request_line,  
2910 - List(HTTP_header) headers, 2906 + Web_Site_Description desc,
  2907 + Connection connection,
  2908 + Word32 ip_addr,
  2909 + HTTP_RequestLine request_line,
  2910 + List(HTTP_header) headers,
2911 String body_temp_file, 2911 String body_temp_file,
2912 One -> String generate_tt, 2912 One -> String generate_tt,
2913 - SState s  
2914 - ) =  
2915 - if get_boundary(headers) is 2913 + SState s
  2914 + ) =
  2915 + if get_boundary(headers) is
2916 { 2916 {
2917 - failure then unique,  
2918 - success(boundary) then  
2919 - with all_web_args = query_string(request_line) + 2917 + failure then unique,
  2918 + success(boundary) then
  2919 + with all_web_args = query_string(request_line) +
2920 read_multipart_form_data_encoded_web_args(desc.site_directory, 2920 read_multipart_form_data_encoded_web_args(desc.site_directory,
2921 body_temp_file, 2921 body_temp_file,
2922 "--"+boundary, 2922 "--"+boundary,
2923 0, 2923 0,
2924 s), 2924 s),
2925 - uri = uri(request_line),  
2926 - ext = get_uri_extension(uri), 2925 + uri = uri(request_line),
  2926 + ext = get_uri_extension(uri),
2927 log_journal_msg(desc, 2927 log_journal_msg(desc,
2928 - format_request(desc,connection,request_line,headers,all_web_args));  
2929 - if is_illegal_uri(uri,0)  
2930 - then log_journal_msg(desc,"Received illegal URI: "+uri+"\n") 2928 + format_request(desc,connection,request_line,headers,all_web_args));
  2929 + if is_illegal_uri(uri,0)
  2930 + then log_journal_msg(desc,"Received illegal URI: "+uri+"\n")
2931 else 2931 else
2932 - if (ext = ".awp" | ext = "") then  
2933 - (with answer_headers_body = awp_handler(desc)(host_name, 2932 + if (ext = ".awp" | ext = "") then
  2933 + (with answer_headers_body = awp_handler(desc)(host_name,
2934 http_info(ip_addr, host_name, uri, headers, is_SSL(connection)), 2934 http_info(ip_addr, host_name, uri, headers, is_SSL(connection)),
2935 all_web_args, 2935 all_web_args,
2936 is_SSL(connection)), 2936 is_SSL(connection)),
2937 forget(reliable_write(connection, answer_headers_body))) 2937 forget(reliable_write(connection, answer_headers_body)))
2938 else unique 2938 else unique
2939 - }.  
2940 -  
2941 -  
2942 -  
2943 -  
2944 -  
2945 -  
2946 -  
2947 -  
2948 - *** [5.8] Handling redirections.  
2949 - 2939 + }.
  2940 +
  2941 +
  2942 +
  2943 +
  2944 +
  2945 +
  2946 +
  2947 +
  2948 + *** [5.8] Handling redirections.
  2949 +
2950 'redirections' (of type 'List(Redirection)') contains redirection directives. Each one 2950 'redirections' (of type 'List(Redirection)') contains redirection directives. Each one
2951 has the form: 2951 has the form:
2952 -  
2953 - redirect(required_uri,required_host,corresponding_uri).  
2954 - 2952 +
  2953 + redirect(required_uri,required_host,corresponding_uri).
  2954 +
2955 The host required by the client may be found in the 'Host' HTTP header. The URI 2955 The host required by the client may be found in the 'Host' HTTP header. The URI
2956 required by the client is given below as 'uri'. We just have to find the required host 2956 required by the client is given below as 'uri'. We just have to find the required host
2957 in the headers, and to find the corresponding redirection directive. 2957 in the headers, and to find the corresponding redirection directive.
2958 -  
2959 - 2958 +
  2959 +
2960 In the next fonction, the required host and URI are known. We just have to search in 2960 In the next fonction, the required host and URI are known. We just have to search in
2961 the 'redirections' list. 2961 the 'redirections' list.
2962 - 2962 +
2963 define String 2963 define String
2964 handle_redirection 2964 handle_redirection
2965 ( 2965 (
@@ -2967,50 +2967,50 @@ define String @@ -2967,50 +2967,50 @@ define String
2967 String required_host, 2967 String required_host,
2968 List(Redirection) redirections 2968 List(Redirection) redirections
2969 ) = 2969 ) =
2970 - if redirections is 2970 + if redirections is
2971 { 2971 {
2972 [ ] then required_uri, 2972 [ ] then required_uri,
2973 - [h . t] then if h is redirect(uri,host,target) then 2973 + [h . t] then if h is redirect(uri,host,target) then
2974 if host = required_host 2974 if host = required_host
2975 then if uri = required_uri 2975 then if uri = required_uri
2976 then target 2976 then target
2977 else handle_redirection(required_uri,required_host,t) 2977 else handle_redirection(required_uri,required_host,t)
2978 else handle_redirection(required_uri,required_host,t) 2978 else handle_redirection(required_uri,required_host,t)
2979 - }.  
2980 -  
2981 -  
2982 - 2979 + }.
  2980 +
  2981 +
  2982 +
2983 The host name may be encumbered by a port number, like 2983 The host name may be encumbered by a port number, like
2984 - 2984 +
2985 www.our-business.com:1607 2985 www.our-business.com:1607
2986 -  
2987 - We must remove this port number, otherwise the host name may not be recognized.  
2988 -  
2989 -define String 2986 +
  2987 + We must remove this port number, otherwise the host name may not be recognized.
  2988 +
  2989 +define String
2990 strip_port 2990 strip_port
2991 ( 2991 (
2992 String name, 2992 String name,
2993 Int i 2993 Int i
2994 ) = 2994 ) =
2995 - if nth(i,name) is 2995 + if nth(i,name) is
2996 { 2996 {
2997 failure then name, 2997 failure then name,
2998 - success(c) then 2998 + success(c) then
2999 if c = ':' 2999 if c = ':'
3000 then substr(name,0,i) 3000 then substr(name,0,i)
3001 else strip_port(name,i+1) 3001 else strip_port(name,i+1)
3002 - }.  
3003 -  
3004 -  
3005 -  
3006 -  
3007 -  
3008 - Finding the 'Host' header. No redirection is performed if this header is not found.  
3009 -  
3010 -define String 3002 + }.
  3003 +
  3004 +
  3005 +
  3006 +
  3007 +
  3008 + Finding the 'Host' header. No redirection is performed if this header is not found.
  3009 +
  3010 +define String
3011 handle_redirection // returns the redirected URI 3011 handle_redirection // returns the redirected URI
3012 ( 3012 (
3013 - Redirections redirections, 3013 + Redirections redirections,
3014 String uri, // original URI 3014 String uri, // original URI
3015 List(HTTP_header) headers 3015 List(HTTP_header) headers
3016 )= 3016 )=
@@ -3022,125 +3022,125 @@ define String @@ -3022,125 +3022,125 @@ define String
3022 { 3022 {
3023 redirection_list(l) then handle_redirection(uri, host, l) 3023 redirection_list(l) then handle_redirection(uri, host, l)
3024 redirection_fn(f) then f(uri, host) 3024 redirection_fn(f) then f(uri, host)
3025 - } 3025 + }
3026 }. 3026 }.
3027 -  
3028 -  
3029 -  
3030 -  
3031 -  
3032 -  
3033 - *** [5.9] Answering both sorts of requests.  
3034 - 3027 +
  3028 +
  3029 +
  3030 +
  3031 +
  3032 +
  3033 + *** [5.9] Answering both sorts of requests.
  3034 +
3035 We must decide if the request is www-url encoded or multipart/form-data encoded. This 3035 We must decide if the request is www-url encoded or multipart/form-data encoded. This
3036 is achieved through the header 'Content-Type'. 3036 is achieved through the header 'Content-Type'.
3037 - 3037 +
3038 define EncodingType 3038 define EncodingType
3039 get_encoding_type 3039 get_encoding_type
3040 ( 3040 (
3041 List(HTTP_header) headers 3041 List(HTTP_header) headers
3042 ) = 3042 ) =
3043 - if headers is 3043 + if headers is
3044 { 3044 {
3045 - [ ] then www_url, // this is the default  
3046 - [h . t] then if h is http_header(name, value) then 3045 + [ ] then www_url, // this is the default
  3046 + [h . t] then if h is http_header(name, value) then
3047 if name = "content-type" 3047 if name = "content-type"
3048 - then if find("multipart/form-data",value,0) is 3048 + then if find("multipart/form-data",value,0) is
3049 { 3049 {
3050 failure then www_url, 3050 failure then www_url,
3051 success(_) then multipart_form_data 3051 success(_) then multipart_form_data
3052 } 3052 }
3053 - else 3053 + else
3054 get_encoding_type(t) //content-type not found, check the next header line 3054 get_encoding_type(t) //content-type not found, check the next header line
3055 }. 3055 }.
3056 -  
3057 -  
3058 - 3056 +
  3057 +
  3058 +
3059 define One 3059 define One
3060 send_answer 3060 send_answer
3061 ( 3061 (
3062 - String host_name,  
3063 - Web_Site_Description desc,  
3064 - Connection connection,  
3065 - HTTP_RequestLine rqline,  
3066 - List(HTTP_header) headers, 3062 + String host_name,
  3063 + Web_Site_Description desc,
  3064 + Connection connection,
  3065 + HTTP_RequestLine rqline,
  3066 + List(HTTP_header) headers,
3067 ByteArray body, 3067 ByteArray body,
3068 One -> String generate_tt, 3068 One -> String generate_tt,
3069 - SState s  
3070 - )=  
3071 - if rqline is request_line(type, uri, qstring) then  
3072 - with rqline2 = request_line(type, handle_redirection(redirections(desc), uri, headers), qstring), 3069 + SState s
  3070 + )=
  3071 + if rqline is request_line(type, uri, qstring) then
  3072 + with rqline2 = request_line(type, handle_redirection(redirections(desc), uri, headers), qstring),
3073 if remote_IP_address_and_port(connection) is (ip_addr,_) then 3073 if remote_IP_address_and_port(connection) is (ip_addr,_) then
3074 - if get_encoding_type(headers) is 3074 + if get_encoding_type(headers) is
3075 { 3075 {
3076 www_url then www_url_answer(host_name, desc, connection, ip_addr, rqline2, headers, body, generate_tt), 3076 www_url then www_url_answer(host_name, desc, connection, ip_addr, rqline2, headers, body, generate_tt),
3077 multipart_form_data then multipart_form_data_answer(host_name, desc, connection, ip_addr, rqline2, headers, body, generate_tt, s) 3077 multipart_form_data then multipart_form_data_answer(host_name, desc, connection, ip_addr, rqline2, headers, body, generate_tt, s)
3078 }. 3078 }.
3079 -  
3080 -  
3081 -  
3082 -  
3083 -  
3084 -  
3085 -  
3086 - *** [6] The HTTP/HTTPS server. 3079 +
  3080 +
  3081 +
  3082 +
  3083 +
  3084 +
  3085 +
  3086 + *** [6] The HTTP/HTTPS server.
3087 3087
3088 The command 'start_server' (declared in 'predefined.anubis') starts a virtual machine 3088 The command 'start_server' (declared in 'predefined.anubis') starts a virtual machine
3089 which opens a server TCP/IP connection, and which continuously listens to this 3089 which opens a server TCP/IP connection, and which continuously listens to this
3090 connection. When a request arrives, this machine delegates the work of deciphering and 3090 connection. When a request arrives, this machine delegates the work of deciphering and
3091 answering the request to another virtual machine, and continues to listen. The job of 3091 answering the request to another virtual machine, and continues to listen. The job of
3092 - the delegated machine is defined by the HTTP request handler below.  
3093 - 3092 + the delegated machine is defined by the HTTP request handler below.
  3093 +
3094 3094
3095 3095
3096 3096
3097 -  
3098 - *** [6.1] Determining the requested host.  
3099 - 3097 +
  3098 + *** [6.1] Determining the requested host.
  3099 +
3100 When a request arrives to one of our two servers, we must decide which site (host) is 3100 When a request arrives to one of our two servers, we must decide which site (host) is
3101 requested. 3101 requested.
3102 -  
3103 -define Maybe(String) 3102 +
  3103 +define Maybe(String)
3104 get_host_header_value 3104 get_host_header_value
3105 ( 3105 (
3106 List(HTTP_header) headers 3106 List(HTTP_header) headers
3107 ) = 3107 ) =
3108 - if headers is 3108 + if headers is
3109 { 3109 {
3110 - [ ] then failure,  
3111 - [h . t] then if h is http_header(name,value) then 3110 + [ ] then failure,
  3111 + [h . t] then if h is http_header(name,value) then
3112 if name = "host" 3112 if name = "host"
3113 then success(strip_port(value,0)) 3113 then success(strip_port(value,0))
3114 else get_host_header_value(t) 3114 else get_host_header_value(t)
3115 - }.  
3116 - 3115 + }.
  3116 +
3117 define Maybe((String,Web_Site_Description)) 3117 define Maybe((String,Web_Site_Description))
3118 get_site 3118 get_site
3119 ( 3119 (
3120 - String requested_host, 3120 + String requested_host,
3121 List(Web_Site_Description) sites 3121 List(Web_Site_Description) sites
3122 ) = 3122 ) =
3123 - if sites is 3123 + if sites is
3124 { 3124 {
3125 - [ ] then print("Requested host '"+requested_host+"' does not exist.\n"); failure,  
3126 - [site1 . others] then  
3127 - if site1 is web_site_description(common_names,_,_,_,_,_,_,_,_,_) then 3125 + [ ] then print("Requested host '"+requested_host+"' does not exist.\n"); failure,
  3126 + [site1 . others] then
  3127 + if site1 is web_site_description(common_names,_,_,_,_,_,_,_,_,_) then
3128 if member(common_names,requested_host) 3128 if member(common_names,requested_host)
3129 then success((requested_host,site1)) 3129 then success((requested_host,site1))
3130 else get_site(requested_host,others) 3130 else get_site(requested_host,others)
3131 }. 3131 }.
3132 -  
3133 - 3132 +
  3133 +
3134 define Maybe((String,Web_Site_Description)) 3134 define Maybe((String,Web_Site_Description))
3135 get_site 3135 get_site
3136 ( 3136 (
3137 - List(HTTP_header) headers, 3137 + List(HTTP_header) headers,
3138 List(Web_Site_Description) sites 3138 List(Web_Site_Description) sites
3139 ) = 3139 ) =
3140 - if get_host_header_value(headers) is 3140 + if get_host_header_value(headers) is
3141 { 3141 {
3142 - failure then print("No 'Host' HTTP header.\n"); failure,  
3143 - success(requested_host) then 3142 + failure then print("No 'Host' HTTP header.\n"); failure,
  3143 + success(requested_host) then
3144 //here we treat the case with only one site. hence we accept any host request 3144 //here we treat the case with only one site. hence we accept any host request
3145 //print("*** there is " +length(sites) + " sites \n"); 3145 //print("*** there is " +length(sites) + " sites \n");
3146 if length(sites) = 1 then 3146 if length(sites) = 1 then
@@ -3152,90 +3152,90 @@ define Maybe((String,Web_Site_Description)) @@ -3152,90 +3152,90 @@ define Maybe((String,Web_Site_Description))
3152 } 3152 }
3153 else 3153 else
3154 get_site(requested_host,sites) 3154 get_site(requested_host,sites)
3155 - }.  
3156 -  
3157 -  
3158 -  
3159 -  
3160 -  
3161 - *** [6.2] The HTTP request handler.  
3162 - 3155 + }.
  3156 +
  3157 +
  3158 +
  3159 +
  3160 +
  3161 + *** [6.2] The HTTP request handler.
  3162 +
3163 Here is the HTTP/HTTPS handler. It is called at each new request in a separate virtual 3163 Here is the HTTP/HTTPS handler. It is called at each new request in a separate virtual
3164 machine. It reads the headers of the HTTP request, determines the host, determines body 3164 machine. It reads the headers of the HTTP request, determines the host, determines body
3165 size, reads the body of the HTTP request, and answers the request. 3165 size, reads the body of the HTTP request, and answers the request.
3166 -  
3167 -  
3168 -  
3169 -define One -> String make_generate_trust_ticket(DenialOfService dos).  
3170 - 3166 +
  3167 +
  3168 +
  3169 +define One -> String make_generate_trust_ticket(DenialOfService dos).
  3170 +
3171 define One 3171 define One
3172 http_https_handler 3172 http_https_handler
3173 ( 3173 (
3174 List(Web_Site_Description) sites, 3174 List(Web_Site_Description) sites,
3175 - BufferedConnection connection, 3175 + BufferedConnection connection,
3176 Bool is_https, 3176 Bool is_https,
3177 DenialOfService dos, 3177 DenialOfService dos,
3178 SState s 3178 SState s
3179 ) = 3179 ) =
3180 //t0 <- (UTime)unow; 3180 //t0 <- (UTime)unow;
3181 - with start_time = (Int)now,  
3182 - s.sttm <- start_time; 3181 + with start_time = (Int)now,
  3182 + s.sttm <- start_time;
3183 //println("Request time: " + format_http_date(start_time)); 3183 //println("Request time: " + format_http_date(start_time));
3184 - if dos is denial_of_service(mc_v,rld_v,hd_v,ad_v,ld_v,ra_v) then  
3185 - if remote_IP_address_and_port(connection.conn) is (ip_addr,port) then  
3186 - if read_request_line(connection, start_time+*rld_v, dos, s) is 3184 + if dos is denial_of_service(mc_v,rld_v,hd_v,ad_v,ld_v,ra_v) then
  3185 + if remote_IP_address_and_port(connection.conn) is (ip_addr,port) then
  3186 + if read_request_line(connection, start_time+*rld_v, dos, s) is
3187 { 3187 {
3188 error(msg) then print(format(msg)), 3188 error(msg) then print(format(msg)),
3189 ok(rqline) then //request line 3189 ok(rqline) then //request line
3190 //print_delta("read_request_line"); 3190 //print_delta("read_request_line");
3191 - if read_http_headers(connection, start_time+*hd_v, dos, s) is 3191 + if read_http_headers(connection, start_time+*hd_v, dos, s) is
3192 { 3192 {
3193 - error(msg) then print(format(msg)),  
3194 - ok(headers) then //print_delta("read_http_headers"); 3193 + error(msg) then print(format(msg)),
  3194 + ok(headers) then //print_delta("read_http_headers");
3195 if get_site(headers,sites) is 3195 if get_site(headers,sites) is
3196 { 3196 {
3197 failure then unique, 3197 failure then unique,
3198 - success(p) then if p is (host_name, desc) then 3198 + success(p) then if p is (host_name, desc) then
3199 //Body Size 3199 //Body Size
3200 - if get_body_size(headers) is 3200 + if get_body_size(headers) is
3201 { 3201 {
3202 error(msg) then log_journal_msg(desc,format(msg)), 3202 error(msg) then log_journal_msg(desc,format(msg)),
3203 - ok(body_size) then  
3204 - if rqline is request_line(type, uri, qstring) then  
3205 - with rqline2 = request_line(type, handle_redirection(redirections(desc), uri, headers), qstring), 3203 + ok(body_size) then
  3204 + if rqline is request_line(type, uri, qstring) then
  3205 + with rqline2 = request_line(type, handle_redirection(redirections(desc), uri, headers), qstring),
3206 3206
3207 //Get the type of encoding which decide if we read the content in ByteArray for www_url or in 3207 //Get the type of encoding which decide if we read the content in ByteArray for www_url or in
3208 //temporary file for multipart. 3208 //temporary file for multipart.
3209 with generate_tt = make_generate_trust_ticket(dos), 3209 with generate_tt = make_generate_trust_ticket(dos),
3210 - if get_encoding_type(headers) is 3210 + if get_encoding_type(headers) is
3211 { 3211 {
3212 //WWW_URL 3212 //WWW_URL
3213 - www_url then  
3214 - if read_http_body(connection, body_size, constant_byte_array(0,0), 1000) is 3213 + www_url then
  3214 + if read_http_body(connection, body_size, constant_byte_array(0,0), 1000) is
3215 { 3215 {
3216 - error(msg) then log_journal_msg(desc,format(msg)),  
3217 - ok(body) then 3216 + error(msg) then log_journal_msg(desc,format(msg)),
  3217 + ok(body) then
3218 www_url_answer(host_name, desc, connection.conn, ip_addr, rqline2, headers, body, generate_tt); 3218 www_url_answer(host_name, desc, connection.conn, ip_addr, rqline2, headers, body, generate_tt);
3219 //it's HTTP 1.1 keep-alive is default 3219 //it's HTTP 1.1 keep-alive is default
3220 http_https_handler(sites, connection, is_https, dos, s) 3220 http_https_handler(sites, connection, is_https, dos, s)
3221 } 3221 }
3222 - //MULTIPART_FORM_DATA  
3223 - multipart_form_data then 3222 + //MULTIPART_FORM_DATA
  3223 + multipart_form_data then
3224 3224
3225 - if body_size > 0 then 3225 + if body_size > 0 then
3226 with t0 = (UTime)unow, 3226 with t0 = (UTime)unow,
3227 - 3227 +
3228 if get_socket_from_connection(conn(connection)) is 3228 if get_socket_from_connection(conn(connection)) is
3229 { 3229 {
3230 failure then println("can't get socket"), 3230 failure then println("can't get socket"),
3231 success(source) then 3231 success(source) then
3232 - 3232 +
3233 with tmp_body_file = "/temp/" + virtual_machine_id + "-" + now, 3233 with tmp_body_file = "/temp/" + virtual_machine_id + "-" + now,
3234 if (Maybe(RWStream))file(desc.site_directory + tmp_body_file, new) is 3234 if (Maybe(RWStream))file(desc.site_directory + tmp_body_file, new) is
3235 { 3235 {
3236 failure then println("can't create target file "+desc.site_directory + tmp_body_file),//nothing to write 3236 failure then println("can't create target file "+desc.site_directory + tmp_body_file),//nothing to write
3237 - success(target) then  
3238 - 3237 + success(target) then
  3238 +
3239 //get the content of the current buffer and unput char list 3239 //get the content of the current buffer and unput char list
3240 with buffer = get_and_erase_buffer(connection, s), 3240 with buffer = get_and_erase_buffer(connection, s),
3241 buffer_size = length(buffer), 3241 buffer_size = length(buffer),
@@ -3244,24 +3244,24 @@ define One @@ -3244,24 +3244,24 @@ define One
3244 if flush(buffer, weaken(target)) is 3244 if flush(buffer, weaken(target)) is
3245 { 3245 {
3246 failure then println("Can't flush the buffer"), 3246 failure then println("Can't flush the buffer"),
3247 - success(_) then  
3248 - if copy_file(weaken(source), weaken(target), body_size - buffer_size) is copy_ok(read_size) then  
3249 - 3247 + success(_) then
  3248 + if copy_file(weaken(source), weaken(target), body_size - buffer_size) is copy_ok(read_size) then
  3249 +
3250 with duration = (UTime) unow - t0, 3250 with duration = (UTime) unow - t0,
3251 println("Read body "+read_size+" duration: " + __utime_to_string(duration)); 3251 println("Read body "+read_size+" duration: " + __utime_to_string(duration));
3252 - 3252 +
3253 multipart_form_data_answer(host_name, desc, connection.conn, ip_addr, rqline2, headers, desc.site_directory + tmp_body_file, generate_tt, s); 3253 multipart_form_data_answer(host_name, desc, connection.conn, ip_addr, rqline2, headers, desc.site_directory + tmp_body_file, generate_tt, s);
3254 - 3254 +
3255 //it's HTTP 1.1 keep-alive is default 3255 //it's HTTP 1.1 keep-alive is default
3256 - http_https_handler(sites, connection, is_https, dos, s)  
3257 - 3256 + http_https_handler(sites, connection, is_https, dos, s)
  3257 +
3258 else 3258 else
3259 println("Can't copy data from stream to temporary file ") 3259 println("Can't copy data from stream to temporary file ")
3260 }}} 3260 }}}
3261 else 3261 else
3262 println("body_size = 0 !") 3262 println("body_size = 0 !")
3263 } 3263 }
3264 - 3264 +
3265 //print_delta("before send_answer"); 3265 //print_delta("before send_answer");
3266 // with body = constant_byte_array(0,0), 3266 // with body = constant_byte_array(0,0),
3267 // send_answer(host_name, desc,connection.conn, request_line, headers, body, 3267 // send_answer(host_name, desc,connection.conn, request_line, headers, body,
@@ -3272,29 +3272,29 @@ define One @@ -3272,29 +3272,29 @@ define One
3272 //println("Request duration: " + __utime_to_string(duration)) 3272 //println("Request duration: " + __utime_to_string(duration))
3273 //println("BufferRead duration: " + __utime_to_string(*t1)); 3273 //println("BufferRead duration: " + __utime_to_string(*t1));
3274 //println("next_char duration: " + __utime_to_string(*t2)) 3274 //println("next_char duration: " + __utime_to_string(*t2))
3275 - 3275 +
3276 } 3276 }
3277 } 3277 }
3278 } 3278 }
3279 }. 3279 }.
3280 -  
3281 - 3280 +
  3281 +
3282 Below are the two tools for constructing the handlers required by 'start_server' and 3282 Below are the two tools for constructing the handlers required by 'start_server' and
3283 'start_ssl_server' (see 'predefined.anubis'). 3283 'start_ssl_server' (see 'predefined.anubis').
3284 -  
3285 -define Bool is_dubious_IP(Word32 ip, DenialOfService dos).  
3286 - 3284 +
  3285 +define Bool is_dubious_IP(Word32 ip, DenialOfService dos).
  3286 +
3287 define Server -> ((RWStream) -> One) 3287 define Server -> ((RWStream) -> One)
3288 make_http_handler 3288 make_http_handler
3289 ( 3289 (
3290 - List(Web_Site_Description) sites,  
3291 - DenialOfService dos 3290 + List(Web_Site_Description) sites,
  3291 + DenialOfService dos
3292 ) = 3292 ) =
3293 - (Server server) |-> (RWStream conn) |->  
3294 - if remote_IP_address_and_port(conn) is (addr,_) then 3293 + (Server server) |-> (RWStream conn) |->
  3294 + if remote_IP_address_and_port(conn) is (addr,_) then
3295 if is_dubious_IP(addr,dos) 3295 if is_dubious_IP(addr,dos)
3296 then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n") 3296 then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n")
3297 - else 3297 + else
3298 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), 3298 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
3299 http_https_handler(sites, connection, false, dos, sstate(var([]),var(0),var(0))). 3299 http_https_handler(sites, connection, false, dos, sstate(var([]),var(0),var(0))).
3300 public define One 3300 public define One
@@ -3304,51 +3304,51 @@ public define One @@ -3304,51 +3304,51 @@ public define One
3304 RWStream conn, 3304 RWStream conn,
3305 DenialOfService dos 3305 DenialOfService dos
3306 ) = 3306 ) =
3307 - if remote_IP_address_and_port(conn) is (addr,_) then 3307 + if remote_IP_address_and_port(conn) is (addr,_) then
3308 if is_dubious_IP(addr,dos) 3308 if is_dubious_IP(addr,dos)
3309 then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n") 3309 then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n")
3310 - else 3310 + else
3311 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), 3311 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
3312 http_https_handler(sites, connection, false, dos, sstate(var([]),var(0),var(0))). 3312 http_https_handler(sites, connection, false, dos, sstate(var([]),var(0),var(0))).
3313 3313
3314 - 3314 +
3315 define Server -> (SSL_Connection -> One) 3315 define Server -> (SSL_Connection -> One)
3316 make_https_handler 3316 make_https_handler
3317 ( 3317 (
3318 - List(Web_Site_Description) sites, 3318 + List(Web_Site_Description) sites,
3319 DenialOfService dos 3319 DenialOfService dos
3320 ) = 3320 ) =
3321 - (Server server) |-> (SSL_Connection conn) |-> 3321 + (Server server) |-> (SSL_Connection conn) |->
3322 with connection = buffered_connection(ssl(conn), var(constant_byte_array(0, 0)), var(0)), 3322 with connection = buffered_connection(ssl(conn), var(constant_byte_array(0, 0)), var(0)),
3323 - http_https_handler(sites, connection, true, dos, sstate(var([]),var(0),var(0))).  
3324 -  
3325 -  
3326 -  
3327 -  
3328 - *** [6.3] Server's tasks.  
3329 - 3323 + http_https_handler(sites, connection, true, dos, sstate(var([]),var(0),var(0))).
  3324 +
  3325 +
  3326 +
  3327 +
  3328 + *** [6.3] Server's tasks.
  3329 +
3330 Some tasks must be executed periodically, for example for cleaning up directories from 3330 Some tasks must be executed periodically, for example for cleaning up directories from
3331 short life time files. 3331 short life time files.
3332 3332
3333 The next function removes from the given directory (and recursively from its 3333 The next function removes from the given directory (and recursively from its
3334 subdirectories) all the files which are more than 10 minutes old. 3334 subdirectories) all the files which are more than 10 minutes old.
3335 -  
3336 -define One 3335 +
  3336 +define One
3337 cleanup_directory_10mn 3337 cleanup_directory_10mn
3338 ( 3338 (
3339 String dir // path of private download directory (or subdirectory) with trailing slash 3339 String dir // path of private download directory (or subdirectory) with trailing slash
3340 ) = 3340 ) =
3341 - forget(map((FileDescription fd) |-> if fd is 3341 + forget(map((FileDescription fd) |-> if fd is
3342 { 3342 {
3343 - no_info(name) then forget(remove(dir+name)), 3343 + no_info(name) then forget(remove(dir+name)),
3344 file(name,_,_,d) then if to_Int(d)+600 < now then forget(remove(dir+name)) else unique, 3344 file(name,_,_,d) then if to_Int(d)+600 < now then forget(remove(dir+name)) else unique,
3345 link(name,_,_,d) then if to_Int(d)+600 < now then forget(remove(dir+name)) else unique, 3345 link(name,_,_,d) then if to_Int(d)+600 < now then forget(remove(dir+name)) else unique,
3346 - directory(name,_,_) then cleanup_directory_10mn(dir+name+"/"), 3346 + directory(name,_,_) then cleanup_directory_10mn(dir+name+"/"),
3347 }, 3347 },
3348 - directory_full_list(dir,"*","*","*"))).  
3349 -  
3350 -  
3351 -define One 3348 + directory_full_list(dir,"*","*","*"))).
  3349 +
  3350 +
  3351 +define One
3352 http_servers_tasks 3352 http_servers_tasks
3353 ( 3353 (
3354 List(Web_Site_Description) sites, 3354 List(Web_Site_Description) sites,
@@ -3359,22 +3359,22 @@ define One @@ -3359,22 +3359,22 @@ define One
3359 if mapand(is_down,servers) 3359 if mapand(is_down,servers)
3360 then unique 3360 then unique
3361 else if now > next_time 3361 else if now > next_time
3362 - then 3362 + then
3363 ( 3363 (
3364 /* 3364 /*
3365 - forget(map((Web_Site_Description wsd) |-> 3365 + forget(map((Web_Site_Description wsd) |->
3366 cleanup_directory_10mn(site_directory(wsd)+"/private_download/"), 3366 cleanup_directory_10mn(site_directory(wsd)+"/private_download/"),
3367 - sites));  
3368 - */ 3367 + sites));
  3368 + */
3369 http_servers_tasks(sites,servers,period,next_time+period) 3369 http_servers_tasks(sites,servers,period,next_time+period)
3370 ) 3370 )
3371 else 3371 else
3372 ( 3372 (
3373 - sleep(1000); 3373 + sleep(1000);
3374 http_servers_tasks(sites,servers,period,next_time) 3374 http_servers_tasks(sites,servers,period,next_time)
3375 ). 3375 ).
3376 -  
3377 - 3376 +
  3377 +
3378 public define One 3378 public define One
3379 start_http_servers_tasks 3379 start_http_servers_tasks
3380 ( 3380 (
@@ -3382,91 +3382,91 @@ public define One @@ -3382,91 +3382,91 @@ public define One
3382 List(Server) servers, 3382 List(Server) servers,
3383 Int period 3383 Int period
3384 ) = 3384 ) =
3385 - delegate http_servers_tasks(sites,servers,period,now),  
3386 - unique.  
3387 -  
3388 -  
3389 -  
3390 -  
3391 - *** [6.4] Protection against 'denial of service' attacks.  
3392 -  
3393 -  
3394 - *** [6.4.1] Counting connections.  
3395 - 3385 + delegate http_servers_tasks(sites,servers,period,now),
  3386 + unique.
  3387 +
  3388 +
  3389 +
  3390 +
  3391 + *** [6.4] Protection against 'denial of service' attacks.
  3392 +
  3393 +
  3394 + *** [6.4.1] Counting connections.
  3395 +
3396 define Bool // returns false if the counter cannot be incremented (too many connections) 3396 define Bool // returns false if the counter cannot be incremented (too many connections)
3397 increment_connections_counter 3397 increment_connections_counter
3398 ( 3398 (
3399 Var(Int) counter 3399 Var(Int) counter
3400 ) = 3400 ) =
3401 - protect with n = *counter, 3401 + protect with n = *counter,
3402 if n >= 100 3402 if n >= 100
3403 then false 3403 then false
3404 - else (counter <- (*counter)+1); true.  
3405 - 3404 + else (counter <- (*counter)+1); true.
  3405 +
3406 define One 3406 define One
3407 decrement_connections_counter 3407 decrement_connections_counter
3408 ( 3408 (
3409 Var(Int) counter 3409 Var(Int) counter
3410 ) = 3410 ) =
3411 - protect counter <- (*counter)-1.  
3412 -  
3413 -  
3414 -  
3415 -  
3416 - 3411 + protect counter <- (*counter)-1.
  3412 +
  3413 +
  3414 +
  3415 +
  3416 +
3417 *** [6.4.2] Recording dubious IP addresses. 3417 *** [6.4.2] Recording dubious IP addresses.
3418 -  
3419 - 3418 +
  3419 +
3420 define List(DubiousIP) 3420 define List(DubiousIP)
3421 record_dubious_IP 3421 record_dubious_IP
3422 ( 3422 (
3423 Word32 ip, 3423 Word32 ip,
3424 List(DubiousIP) l 3424 List(DubiousIP) l
3425 ) = 3425 ) =
3426 - if l is 3426 + if l is
3427 { 3427 {
3428 [ ] then [dubious_ip(ip,now)], 3428 [ ] then [dubious_ip(ip,now)],
3429 - [h . t] then if h is dubious_ip(addr,time) then 3429 + [h . t] then if h is dubious_ip(addr,time) then
3430 if addr = ip 3430 if addr = ip
3431 then [dubious_ip(addr,now) . t] 3431 then [dubious_ip(addr,now) . t]
3432 else [h . record_dubious_IP(ip,t)] 3432 else [h . record_dubious_IP(ip,t)]
3433 }. 3433 }.
3434 -  
3435 - 3434 +
  3435 +
3436 define One 3436 define One
3437 record_dubious_IP 3437 record_dubious_IP
3438 ( 3438 (
3439 Word32 dubious_IP, 3439 Word32 dubious_IP,
3440 Var(List(DubiousIP)) v 3440 Var(List(DubiousIP)) v
3441 ) = 3441 ) =
3442 - protect v <- record_dubious_IP(dubious_IP,*v).  
3443 -  
3444 - 3442 + protect v <- record_dubious_IP(dubious_IP,*v).
  3443 +
  3444 +
3445 define One 3445 define One
3446 record_dubious_IP 3446 record_dubious_IP
3447 ( 3447 (
3448 - Word32 addr, 3448 + Word32 addr,
3449 DenialOfService dos 3449 DenialOfService dos
3450 ) = 3450 ) =
3451 - record_dubious_IP(addr,list_of_dubious(dos)).  
3452 -  
3453 -  
3454 -public define DenialOfService 3451 + record_dubious_IP(addr,list_of_dubious(dos)).
  3452 +
  3453 +
  3454 +public define DenialOfService
3455 load_denial_of_service_info 3455 load_denial_of_service_info
3456 = 3456 =
3457 - if (RetrieveResult(DenialOfService))retrieve(my_anubis_directory+"/web_sites/dos_info") is 3457 + if (RetrieveResult(DenialOfService))retrieve(my_anubis_directory+"/web_sites/dos_info") is
3458 ok(dos) then dos else denial_of_service( 3458 ok(dos) then dos else denial_of_service(
3459 var(100), 3459 var(100),
3460 var(1000), 3460 var(1000),
3461 - var(1500),  
3462 - var(2000), 3461 + var(1500),
  3462 + var(2000),
3463 var([]), 3463 var([]),
3464 - var([])).  
3465 -  
3466 -  
3467 -  
3468 -  
3469 - *** [6.4.3] Testing if an address is dubious. 3464 + var([])).
  3465 +
  3466 +
  3467 +
  3468 +
  3469 + *** [6.4.3] Testing if an address is dubious.
3470 3470
3471 define Bool 3471 define Bool
3472 is_dubious_IP 3472 is_dubious_IP
@@ -3474,41 +3474,41 @@ define Bool @@ -3474,41 +3474,41 @@ define Bool
3474 Word32 ip, 3474 Word32 ip,
3475 List(DubiousIP) l 3475 List(DubiousIP) l
3476 ) = 3476 ) =
3477 - if l is 3477 + if l is
3478 { 3478 {
3479 - [ ] then false,  
3480 - [h . t] then if h is dubious_ip(addr,time) then 3479 + [ ] then false,
  3480 + [h . t] then if h is dubious_ip(addr,time) then
3481 if ip = addr 3481 if ip = addr
3482 then true 3482 then true
3483 else is_dubious_IP(ip,t) 3483 else is_dubious_IP(ip,t)
3484 }. 3484 }.
3485 -  
3486 - 3485 +
  3486 +
3487 define Bool 3487 define Bool
3488 is_dubious_IP 3488 is_dubious_IP
3489 ( 3489 (
3490 Word32 ip, 3490 Word32 ip,
3491 DenialOfService dos 3491 DenialOfService dos
3492 ) = 3492 ) =
3493 - if dos is 3493 + if dos is
3494 { 3494 {
3495 - denial_of_service(mc_v,rld_v,hd_v,ad_v,ld_v,ra_v) then 3495 + denial_of_service(mc_v,rld_v,hd_v,ad_v,ld_v,ra_v) then
3496 if member(*ra_v,ip) then false else 3496 if member(*ra_v,ip) then false else
3497 is_dubious_IP(ip,*ld_v) 3497 is_dubious_IP(ip,*ld_v)
3498 - }.  
3499 -  
3500 -  
3501 -  
3502 -  
3503 - *** [6.4.4] Removing inactive dubious IP addresses.  
3504 - 3498 + }.
  3499 +
  3500 +
  3501 +
  3502 +
  3503 + *** [6.4.4] Removing inactive dubious IP addresses.
  3504 +
3505 define List(DubiousIP) 3505 define List(DubiousIP)
3506 remove_inactive_dubious_IP 3506 remove_inactive_dubious_IP
3507 ( 3507 (
3508 List(DubiousIP) l, 3508 List(DubiousIP) l,
3509 Int ref_time, 3509 Int ref_time,
3510 ) = 3510 ) =
3511 - if l is 3511 + if l is
3512 { 3512 {
3513 [ ] then [ ], 3513 [ ] then [ ],
3514 [h . t] then if h is dubious_ip(addr,time) then 3514 [h . t] then if h is dubious_ip(addr,time) then
@@ -3516,8 +3516,8 @@ define List(DubiousIP) @@ -3516,8 +3516,8 @@ define List(DubiousIP)
3516 then (print(ip_addr_to_string(addr)+" removed from dubious addresses list.\n"); 3516 then (print(ip_addr_to_string(addr)+" removed from dubious addresses list.\n");
3517 remove_inactive_dubious_IP(t,ref_time)) 3517 remove_inactive_dubious_IP(t,ref_time))
3518 else [h . remove_inactive_dubious_IP(t,ref_time)] 3518 else [h . remove_inactive_dubious_IP(t,ref_time)]
3519 - }.  
3520 - 3519 + }.
  3520 +
3521 define One 3521 define One
3522 remove_inactive_dubious_IP 3522 remove_inactive_dubious_IP
3523 ( 3523 (
@@ -3525,62 +3525,62 @@ define One @@ -3525,62 +3525,62 @@ define One
3525 ) = 3525 ) =
3526 protect 3526 protect
3527 with ref_time = (Int)now - 600, // 10 minutes 3527 with ref_time = (Int)now - 600, // 10 minutes
3528 - v <- remove_inactive_dubious_IP(*v,ref_time).  
3529 -  
3530 -  
3531 - The above function will be executed periodically by the servers's tasks machine.  
3532 -  
3533 -  
3534 -  
3535 - *** [6.4.5] Making the function for generating trust tickets.  
3536 -  
3537 -define One -> String 3528 + v <- remove_inactive_dubious_IP(*v,ref_time).
  3529 +
  3530 +
  3531 + The above function will be executed periodically by the servers's tasks machine.
  3532 +
  3533 +
  3534 +
  3535 + *** [6.4.5] Making the function for generating trust tickets.
  3536 +
  3537 +define One -> String
3538 make_generate_trust_ticket 3538 make_generate_trust_ticket
3539 ( 3539 (
3540 DenialOfService dos 3540 DenialOfService dos
3541 ) = 3541 ) =
3542 - (One _) |-> "".  
3543 -  
3544 -  
3545 -  
3546 -  
3547 -  
3548 -  
3549 -  
3550 - *** [6.5] Starting the HTTP/HTTPS server.  
3551 -  
3552 - 3542 + (One _) |-> "".
  3543 +
  3544 +
  3545 +
  3546 +
  3547 +
  3548 +
  3549 +
  3550 + *** [6.5] Starting the HTTP/HTTPS server.
  3551 +
  3552 +
3553 The next function creates the directories for all sites (if they don't already exist). 3553 The next function creates the directories for all sites (if they don't already exist).
3554 - 3554 +
3555 define One 3555 define One
3556 create_directories 3556 create_directories
3557 ( 3557 (
3558 List(Web_Site_Description) sites 3558 List(Web_Site_Description) sites
3559 ) = 3559 ) =
3560 - if sites is 3560 + if sites is
3561 { 3561 {
3562 - [ ] then unique,  
3563 - [s1 . others] then  
3564 - with site_dir = site_directory(s1), 3562 + [ ] then unique,
  3563 + [s1 . others] then
  3564 + with site_dir = site_directory(s1),
3565 forget(make_directory(site_dir+"/public",default_directory_mode)); 3565 forget(make_directory(site_dir+"/public",default_directory_mode));
3566 forget(make_directory(site_dir+"/upload_temporary",default_directory_mode)); 3566 forget(make_directory(site_dir+"/upload_temporary",default_directory_mode));
3567 forget(make_directory(site_dir+"/private_download",default_directory_mode)); 3567 forget(make_directory(site_dir+"/private_download",default_directory_mode));
3568 forget(make_directory(site_dir+"/journal",default_directory_mode)); 3568 forget(make_directory(site_dir+"/journal",default_directory_mode));
3569 create_directories(others) 3569 create_directories(others)
3570 - }.  
3571 -  
3572 -  
3573 -  
3574 -  
3575 -  
3576 - Below are the commands for starting an HTTP server and an HTTPS server.  
3577 -  
3578 - 3570 + }.
  3571 +
  3572 +
  3573 +
  3574 +
  3575 +
  3576 + Below are the commands for starting an HTTP server and an HTTPS server.
  3577 +
  3578 +
3579 define StartServerResult 3579 define StartServerResult
3580 start_http_server 3580 start_http_server
3581 ( 3581 (
3582 Word32 ip_address, 3582 Word32 ip_address,
3583 - Word32 port, 3583 + Word32 port,
3584 Server -> ((RWStream) -> One) handler, 3584 Server -> ((RWStream) -> One) handler,
3585 Int retries, 3585 Int retries,
3586 DenialOfService dos 3586 DenialOfService dos
@@ -3588,160 +3588,160 @@ define StartServerResult @@ -3588,160 +3588,160 @@ define StartServerResult
3588 if start_server(ip_address, 3588 if start_server(ip_address,
3589 port, 3589 port,
3590 handler, 3590 handler,
3591 - identity) is ok(server)  
3592 - then print(" \r"); 3591 + identity) is ok(server)
  3592 + then print(" \r");
3593 ok(server) 3593 ok(server)
3594 - else print("Port "+port+": retry number "+retries+"\r");  
3595 - sleep(1000);  
3596 - start_http_server(ip_address,port,handler,retries+1,dos).  
3597 - 3594 + else print("Port "+port+": retry number "+retries+"\r");
  3595 + sleep(1000);
  3596 + start_http_server(ip_address,port,handler,retries+1,dos).
  3597 +
3598 public define StartServerResult 3598 public define StartServerResult
3599 start_http_server 3599 start_http_server
3600 ( 3600 (
3601 Word32 ip_address, 3601 Word32 ip_address,
3602 - Word32 port, 3602 + Word32 port,
3603 List(Web_Site_Description) sites, 3603 List(Web_Site_Description) sites,
3604 - DenialOfService dos 3604 + DenialOfService dos
3605 ) = 3605 ) =
3606 create_directories(sites); 3606 create_directories(sites);
3607 start_http_server(ip_address,port, 3607 start_http_server(ip_address,port,
3608 make_http_handler(sites, dos), 3608 make_http_handler(sites, dos),
3609 0, 3609 0,
3610 - dos).  
3611 -  
3612 - 3610 + dos).
  3611 +
  3612 +
3613 For the HTTPS server, we have a problem which is due to the fact that 'anbexec' is not 3613 For the HTTPS server, we have a problem which is due to the fact that 'anbexec' is not
3614 yet able to manipulate several SSL server certificates. 'anbexec' and 3614 yet able to manipulate several SSL server certificates. 'anbexec' and
3615 'predefined.anubis' must be changed. Sorry ! This will be done as soon as possible. The 3615 'predefined.anubis' must be changed. Sorry ! This will be done as soon as possible. The
3616 'solution' for the time being is to provide the common name of the unique SSL server 3616 'solution' for the time being is to provide the common name of the unique SSL server
3617 certificate. 3617 certificate.
3618 -  
3619 - 3618 +
  3619 +
3620 define StartServerResult 3620 define StartServerResult
3621 start_https_server 3621 start_https_server
3622 ( 3622 (
3623 Word32 ip_address, 3623 Word32 ip_address,
3624 - Word32 port, 3624 + Word32 port,
3625 String certificate_common_name, 3625 String certificate_common_name,
3626 Server -> (SSL_Connection -> One) handler, 3626 Server -> (SSL_Connection -> One) handler,
3627 Int retries, 3627 Int retries,
3628 DenialOfService dos 3628 DenialOfService dos
3629 - ) = 3629 + ) =
3630 if start_ssl_server(ip_address, 3630 if start_ssl_server(ip_address,
3631 port, 3631 port,
3632 - certificate_common_name, 3632 + certificate_common_name,
3633 handler, 3633 handler,
3634 - identity) is ok(server)  
3635 - then print(" \r"); 3634 + identity) is ok(server)
  3635 + then print(" \r");
3636 ok(server) 3636 ok(server)
3637 - else print("Port "+port+": retry number "+retries+"\r");  
3638 - sleep(1000); 3637 + else print("Port "+port+": retry number "+retries+"\r");
  3638 + sleep(1000);
3639 start_https_server(ip_address,port, 3639 start_https_server(ip_address,port,
3640 certificate_common_name, 3640 certificate_common_name,
3641 handler,retries+1, 3641 handler,retries+1,
3642 - dos). 3642 + dos).
  3643 +
3643 3644
3644 -  
3645 public define StartServerResult 3645 public define StartServerResult
3646 start_https_server 3646 start_https_server
3647 ( 3647 (
3648 Word32 ip_address, 3648 Word32 ip_address,
3649 - Word32 port, 3649 + Word32 port,
3650 String certificate_common_name, // of SSL server certificate 3650 String certificate_common_name, // of SSL server certificate
3651 List(Web_Site_Description) sites, 3651 List(Web_Site_Description) sites,
3652 - DenialOfService dos 3652 + DenialOfService dos
3653 ) = 3653 ) =
3654 create_directories(sites); 3654 create_directories(sites);
3655 start_https_server(ip_address,port,certificate_common_name, 3655 start_https_server(ip_address,port,certificate_common_name,
3656 make_https_handler(sites, dos), 3656 make_https_handler(sites, dos),
3657 - 0,dos).  
3658 -  
3659 -  
3660 -  
3661 -  
3662 -  
3663 -  
3664 -  
3665 -  
3666 -  
3667 - *** [7] The web dispatcher.  
3668 -  
3669 -  
3670 - *** [7.1] The dispatcher server.  
3671 - 3657 + 0,dos).
  3658 +
  3659 +
  3660 +
  3661 +
  3662 +
  3663 +
  3664 +
  3665 +
  3666 +
  3667 + *** [7] The web dispatcher.
  3668 +
  3669 +
  3670 + *** [7.1] The dispatcher server.
  3671 +
3672 define One 3672 define One
3673 send_dispatching_page 3673 send_dispatching_page
3674 ( 3674 (
3675 - RWStream conn,  
3676 - String common_name, 3675 + RWStream conn,
  3676 + String common_name,
3677 Word32 port 3677 Word32 port
3678 ) = 3678 ) =
3679 - print("Dispatching '"+common_name+"' to port "+port+"\n"); 3679 + print("Dispatching '"+common_name+"' to port "+port+"\n");
3680 forget(reliable_write(conn,to_byte_array( 3680 forget(reliable_write(conn,to_byte_array(
3681 "<html><head><meta http-equiv=\"Refresh\" content=\"0;URL="+ 3681 "<html><head><meta http-equiv=\"Refresh\" content=\"0;URL="+
3682 "http://"+common_name+":"+port+"/"+ 3682 "http://"+common_name+":"+port+"/"+
3683 "\"></head><body></body></html>" 3683 "\"></head><body></body></html>"
3684 ))). 3684 ))).
3685 -  
3686 -  
3687 -  
3688 -define Maybe(DispatcherInfo) 3685 +
  3686 +
  3687 +
  3688 +define Maybe(DispatcherInfo)
3689 find_host 3689 find_host
3690 ( 3690 (
3691 List(DispatcherInfo) l, 3691 List(DispatcherInfo) l,
3692 String host 3692 String host
3693 ) = 3693 ) =
3694 - if l is 3694 + if l is
3695 { 3695 {
3696 - [ ] then failure,  
3697 - [h . t] then if h is site(name,port) then 3696 + [ ] then failure,
  3697 + [h . t] then if h is site(name,port) then
3698 if name = host 3698 if name = host
3699 then success(h) 3699 then success(h)
3700 else find_host(t,host) 3700 else find_host(t,host)
3701 }. 3701 }.
3702 -  
3703 -  
3704 - 3702 +
  3703 +
  3704 +
3705 define Server -> ((RWStream) -> One) 3705 define Server -> ((RWStream) -> One)
3706 make_dispatcher_handler 3706 make_dispatcher_handler
3707 ( 3707 (
3708 Var(List(DispatcherInfo)) info_v, 3708 Var(List(DispatcherInfo)) info_v,
3709 DenialOfService dos, 3709 DenialOfService dos,
3710 - SState ss 3710 + SState ss
3711 ) = 3711 ) =
3712 - (Server server) |-> (RWStream conn) |-> 3712 + (Server server) |-> (RWStream conn) |->
3713 with start_time = (Int)now, 3713 with start_time = (Int)now,
3714 connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), 3714 connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
3715 - if read_request_line(connection, start_time+*request_line_delay(dos), dos, ss) is 3715 + if read_request_line(connection, start_time+*request_line_delay(dos), dos, ss) is
3716 { 3716 {
3717 - error(msg) then print(format(msg)),  
3718 - ok(request_line) then  
3719 - if read_http_headers(connection, start_time+*headers_delay(dos), dos, ss) is 3717 + error(msg) then print(format(msg)),
  3718 + ok(request_line) then
  3719 + if read_http_headers(connection, start_time+*headers_delay(dos), dos, ss) is
3720 { 3720 {
3721 error(msg) then print(format(msg)), 3721 error(msg) then print(format(msg)),
3722 - ok(headers) then if get_host_header_value(headers) is 3722 + ok(headers) then if get_host_header_value(headers) is
3723 { 3723 {
3724 failure then print("No 'HOST' HTTP header.\n"), 3724 failure then print("No 'HOST' HTTP header.\n"),
3725 - success(host) then  
3726 - if find_host(*info_v,host) is 3725 + success(host) then
  3726 + if find_host(*info_v,host) is
3727 { 3727 {
3728 failure then print("Host: '"+host+"' not registered.\n"), 3728 failure then print("Host: '"+host+"' not registered.\n"),
3729 - success(s) then if s is site(common_name,ip_port) then 3729 + success(s) then if s is site(common_name,ip_port) then
3730 send_dispatching_page(conn,common_name,ip_port) 3730 send_dispatching_page(conn,common_name,ip_port)
3731 } 3731 }
3732 } 3732 }
3733 } 3733 }
3734 }. 3734 }.
3735 -  
3736 - 3735 +
  3736 +
3737 define One 3737 define One
3738 dispatcher_update_error 3738 dispatcher_update_error
3739 ( 3739 (
3740 String file_path 3740 String file_path
3741 ) = 3741 ) =
3742 - print("web_dispatcher: unable to reread file: '"+file_path+"'.\n").  
3743 -  
3744 - 3742 + print("web_dispatcher: unable to reread file: '"+file_path+"'.\n").
  3743 +
  3744 +
3745 define Bool 3745 define Bool
3746 dispatcher_update_data 3746 dispatcher_update_data
3747 ( 3747 (
@@ -3751,104 +3751,104 @@ define Bool @@ -3751,104 +3751,104 @@ define Bool
3751 ) = 3751 ) =
3752 if directory_full_list(my_anubis_directory+"/web_sites","dispatcher.info","","") is 3752 if directory_full_list(my_anubis_directory+"/web_sites","dispatcher.info","","") is
3753 { 3753 {
3754 - [ ] then false,  
3755 - [h . t] then if h is 3754 + [ ] then false,
  3755 + [h . t] then if h is
3756 { 3756 {
3757 - no_info(n) then false, 3757 + no_info(n) then false,
3758 file(n,_,_,d) then if n = "dispatcher.info" 3758 file(n,_,_,d) then if n = "dispatcher.info"
3759 - then (info_date_v <- to_Int(d); 3759 + then (info_date_v <- to_Int(d);
3760 if (RetrieveResult(List(DispatcherInfo)))retrieve(info_file_path) is 3760 if (RetrieveResult(List(DispatcherInfo)))retrieve(info_file_path) is
3761 { 3761 {
3762 - cannot_find_file then false,  
3763 - read_error then false,  
3764 - type_error then false, 3762 + cannot_find_file then false,
  3763 + read_error then false,
  3764 + type_error then false,
3765 ok(info) then info_v <- info; true 3765 ok(info) then info_v <- info; true
3766 }) 3766 })
3767 - else false,  
3768 - link(_,_,_,_) then false, 3767 + else false,
  3768 + link(_,_,_,_) then false,
3769 directory(_,_,_) then false 3769 directory(_,_,_) then false
3770 - } 3770 + }
3771 }. 3771 }.
3772 -  
3773 -  
3774 - 3772 +
  3773 +
  3774 +
3775 The loop within which the dispatcher updates its data every 3 seconds: 3775 The loop within which the dispatcher updates its data every 3 seconds:
3776 - 3776 +
3777 define One 3777 define One
3778 dispatcher_update_task 3778 dispatcher_update_task
3779 ( 3779 (
3780 String info_file_path, 3780 String info_file_path,
3781 Var(List(DispatcherInfo)) info_v, 3781 Var(List(DispatcherInfo)) info_v,
3782 - Var(Int) info_date_v 3782 + Var(Int) info_date_v
3783 ) = 3783 ) =
3784 - sleep(3000); 3784 + sleep(3000);
3785 (if dispatcher_update_data(info_file_path,info_v,info_date_v) 3785 (if dispatcher_update_data(info_file_path,info_v,info_date_v)
3786 then unique 3786 then unique
3787 else dispatcher_update_error(info_file_path)); 3787 else dispatcher_update_error(info_file_path));
3788 - dispatcher_update_task(info_file_path,info_v,info_date_v).  
3789 -  
3790 - 3788 + dispatcher_update_task(info_file_path,info_v,info_date_v).
  3789 +
  3790 +
3791 public define One 3791 public define One
3792 start_web_dispatcher 3792 start_web_dispatcher
3793 ( 3793 (
3794 Word32 ip_address, // address for listening (typically 0: listen on all interfaces) 3794 Word32 ip_address, // address for listening (typically 0: listen on all interfaces)
3795 Word32 http_port, // typically 80 3795 Word32 http_port, // typically 80
3796 DenialOfService dos, 3796 DenialOfService dos,
3797 - SState s 3797 + SState s
3798 ) = 3798 ) =
3799 - with info_file_path = my_anubis_directory+"/web_sites/dispatcher.info",  
3800 - info_v = var((List(DispatcherInfo))[]), 3799 + with info_file_path = my_anubis_directory+"/web_sites/dispatcher.info",
  3800 + info_v = var((List(DispatcherInfo))[]),
3801 info_date_v = var((Int)0), 3801 info_date_v = var((Int)0),
3802 if dispatcher_update_data(info_file_path,info_v,info_date_v) 3802 if dispatcher_update_data(info_file_path,info_v,info_date_v)
3803 then if start_server(ip_address, 3803 then if start_server(ip_address,
3804 http_port, 3804 http_port,
3805 make_dispatcher_handler(info_v, dos, s), 3805 make_dispatcher_handler(info_v, dos, s),
3806 - (One u)|->u) is 3806 + (One u)|->u) is
3807 { 3807 {
3808 - cannot_create_the_socket then 3808 + cannot_create_the_socket then
3809 print("Cannot create the socket for HTTP server.\n"), 3809 print("Cannot create the socket for HTTP server.\n"),
3810 - cannot_bind_to_port then 3810 + cannot_bind_to_port then
3811 print("Cannot bind HTTP server to port "+http_port+".\n"), 3811 print("Cannot bind HTTP server to port "+http_port+".\n"),
3812 - cannot_listen_on_port then 3812 + cannot_listen_on_port then
3813 print("HTTP server cannot listen on port "+http_port+".\n"), 3813 print("HTTP server cannot listen on port "+http_port+".\n"),
3814 - ok(http_server) then 3814 + ok(http_server) then
3815 dispatcher_update_task(info_file_path,info_v,info_date_v) 3815 dispatcher_update_task(info_file_path,info_v,info_date_v)
3816 } 3816 }
3817 else dispatcher_update_error(info_file_path). 3817 else dispatcher_update_error(info_file_path).
3818 -  
3819 -  
3820 -  
3821 - *** [7.2] The dispatcher web site.  
3822 -  
3823 - global define One 3818 +
  3819 +
  3820 +
  3821 + *** [7.2] The dispatcher web site.
  3822 +
  3823 + global define One
3824 web_dispatcher 3824 web_dispatcher
3825 ( 3825 (
3826 List(String) args 3826 List(String) args
3827 ) = 3827 ) =
3828 - start_web_dispatcher(0,80,load_denial_of_service_info).  
3829 -  
3830 -  
3831 -  
3832 -  
3833 -  
3834 -  
3835 - *** [7.3] Managing the info file.  
3836 - 3828 + start_web_dispatcher(0,80,load_denial_of_service_info).
  3829 +
  3830 +
  3831 +
  3832 +
  3833 +
  3834 +
  3835 + *** [7.3] Managing the info file.
  3836 +
3837 define Word32 3837 define Word32
3838 register_ip_address 3838 register_ip_address
3839 = 3839 =
3840 - if ip_address(prompt(" numerical IP address (for HTTP): ")) is 3840 + if ip_address(prompt(" numerical IP address (for HTTP): ")) is
3841 { 3841 {
3842 failure then print(" *** Error: incorrect IP address.\n"); 3842 failure then print(" *** Error: incorrect IP address.\n");
3843 register_ip_address, 3843 register_ip_address,
3844 success(n) then n 3844 success(n) then n
3845 }. 3845 }.
3846 -  
3847 - 3846 +
  3847 +
3848 define Word32 3848 define Word32
3849 register_ip_port 3849 register_ip_port
3850 = 3850 =
3851 - if decimal_scan(prompt(" IP port (for HTTP): ")) is 3851 + if decimal_scan(prompt(" IP port (for HTTP): ")) is
3852 { 3852 {
3853 failure then print(" *** Error: incorrect IP port.\n"); 3853 failure then print(" *** Error: incorrect IP port.\n");
3854 register_ip_port, 3854 register_ip_port,
@@ -3857,109 +3857,109 @@ define Word32 @@ -3857,109 +3857,109 @@ define Word32
3857 else print(" *** Error: IP port out of bounds.\n"); 3857 else print(" *** Error: IP port out of bounds.\n");
3858 register_ip_port 3858 register_ip_port
3859 }. 3859 }.
3860 -  
3861 - 3860 +
  3861 +
3862 define One 3862 define One
3863 register_new_site 3863 register_new_site
3864 ( 3864 (
3865 Var(List(DispatcherInfo)) info_v 3865 Var(List(DispatcherInfo)) info_v
3866 ) = 3866 ) =
3867 - print("\n"); 3867 + print("\n");
3868 print(" Registering a new site:\n"); 3868 print(" Registering a new site:\n");
3869 - with name = prompt(" Site name: "), 3869 + with name = prompt(" Site name: "),
3870 with addr = register_ip_address, 3870 with addr = register_ip_address,
3871 with port = register_ip_port, 3871 with port = register_ip_port,
3872 (protect info_v <- [site(name,port) . *info_v]); 3872 (protect info_v <- [site(name,port) . *info_v]);
3873 print(" Site "+name+" at "+ip_addr_to_string(addr)+":"+port+" added\n (but not saved to disk).\n"). 3873 print(" Site "+name+" at "+ip_addr_to_string(addr)+":"+port+" added\n (but not saved to disk).\n").
3874 -  
3875 -  
3876 -define List(DispatcherInfo) 3874 +
  3875 +
  3876 +define List(DispatcherInfo)
3877 find_sites 3877 find_sites
3878 ( 3878 (
3879 List(DispatcherInfo) l, 3879 List(DispatcherInfo) l,
3880 String name 3880 String name
3881 ) = 3881 ) =
3882 - if l is 3882 + if l is
3883 { 3883 {
3884 - [ ] then [ ],  
3885 - [h . t] then if h is site(n,_) then  
3886 - if find(name,n,0) is 3884 + [ ] then [ ],
  3885 + [h . t] then if h is site(n,_) then
  3886 + if find(name,n,0) is
3887 { 3887 {
3888 failure then find_sites(t,name), 3888 failure then find_sites(t,name),
3889 success(_) then [h . find_sites(t,name)] 3889 success(_) then [h . find_sites(t,name)]
3890 } 3890 }
3891 - }.  
3892 - 3891 + }.
  3892 +
3893 3893
3894 define String 3894 define String
3895 pad 3895 pad
3896 ( 3896 (
3897 - String s, 3897 + String s,
3898 Int l 3898 Int l
3899 ) = 3899 ) =
3900 if length(s) >= l 3900 if length(s) >= l
3901 then s 3901 then s
3902 - else s+constant_string(l-length(s),' ').  
3903 -  
3904 -  
3905 - 3902 + else s+constant_string(l-length(s),' ').
  3903 +
  3904 +
  3905 +
3906 define One 3906 define One
3907 show_sites_1 3907 show_sites_1
3908 ( 3908 (
3909 - List(DispatcherInfo) l, 3909 + List(DispatcherInfo) l,
3910 Int i 3910 Int i
3911 ) = 3911 ) =
3912 - if l is 3912 + if l is
3913 { 3913 {
3914 - [ ] then unique,  
3915 - [h . t] then if h is site(name,port) then 3914 + [ ] then unique,
  3915 + [h . t] then if h is site(name,port) then
3916 print(" ["+i+"] "+pad(name,40)+" "+" "+port+"\n"); 3916 print(" ["+i+"] "+pad(name,40)+" "+" "+port+"\n");
3917 show_sites_1(t,i+1) 3917 show_sites_1(t,i+1)
3918 }. 3918 }.
3919 -  
3920 - 3919 +
  3920 +
3921 define One 3921 define One
3922 show_sites 3922 show_sites
3923 ( 3923 (
3924 - List(DispatcherInfo) l, 3924 + List(DispatcherInfo) l,
3925 Int i 3925 Int i
3926 ) = 3926 ) =
3927 print(" Name Port\n"); 3927 print(" Name Port\n");
3928 print(" --------------------------------------------------------\n"); 3928 print(" --------------------------------------------------------\n");
3929 - show_sites_1(l,i).  
3930 - 3929 + show_sites_1(l,i).
  3930 +
3931 define List(DispatcherInfo) 3931 define List(DispatcherInfo)
3932 replace_info 3932 replace_info
3933 ( 3933 (
3934 - List(DispatcherInfo) l, 3934 + List(DispatcherInfo) l,
3935 String site_name, 3935 String site_name,
3936 Word32 new_port 3936 Word32 new_port
3937 - ) =  
3938 - if l is 3937 + ) =
  3938 + if l is
3939 { 3939 {
3940 - [ ] then print("ALERT: Empty list into replace_info() [" + __FILE__ + "]\n"); [],  
3941 - [h . t] then if h is site(n,_) then 3940 + [ ] then print("ALERT: Empty list into replace_info() [" + __FILE__ + "]\n"); [],
  3941 + [h . t] then if h is site(n,_) then
3942 if n = site_name 3942 if n = site_name
3943 - then [site(n,new_port) . t] 3943 + then [site(n,new_port) . t]
3944 else [h . replace_info(t,site_name,new_port)] 3944 else [h . replace_info(t,site_name,new_port)]
3945 }. 3945 }.
3946 - 3946 +
3947 define List(DispatcherInfo) 3947 define List(DispatcherInfo)
3948 delete_info 3948 delete_info
3949 ( 3949 (
3950 - List(DispatcherInfo) l, 3950 + List(DispatcherInfo) l,
3951 String site_name, 3951 String site_name,
3952 - ) =  
3953 - if l is 3952 + ) =
  3953 + if l is
3954 { 3954 {
3955 - [ ] then print("ALERT: Empty list into delete_info() [" + __FILE__ + "]\n"); [],  
3956 - [h . t] then if h is site(n,_) then 3955 + [ ] then print("ALERT: Empty list into delete_info() [" + __FILE__ + "]\n"); [],
  3956 + [h . t] then if h is site(n,_) then
3957 if n = site_name 3957 if n = site_name
3958 - then t 3958 + then t
3959 else [h . delete_info(t,site_name)] 3959 else [h . delete_info(t,site_name)]
3960 }. 3960 }.
3961 -  
3962 - 3961 +
  3962 +
3963 define One 3963 define One
3964 update_site 3964 update_site
3965 ( 3965 (
@@ -3969,54 +3969,54 @@ define One @@ -3969,54 +3969,54 @@ define One
3969 ) = 3969 ) =
3970 print("\n"); 3970 print("\n");
3971 print(" Updating site '"+site_name+"': (currently: "+old_port+")\n"); 3971 print(" Updating site '"+site_name+"': (currently: "+old_port+")\n");
3972 - with new_port = register_ip_port, 3972 + with new_port = register_ip_port,
3973 answer = prompt(" Update '"+site_name+"' as: "+new_port+" [Y/N] ? "), 3973 answer = prompt(" Update '"+site_name+"' as: "+new_port+" [Y/N] ? "),
3974 if (answer = "Y" | answer = "y") 3974 if (answer = "Y" | answer = "y")
3975 then info_v <- replace_info(*info_v,site_name,new_port) 3975 then info_v <- replace_info(*info_v,site_name,new_port)
3976 - else unique.  
3977 -  
3978 -  
3979 - 3976 + else unique.
  3977 +
  3978 +
  3979 +
3980 define Bool 3980 define Bool
3981 compare 3981 compare
3982 ( 3982 (
3983 - DispatcherInfo d1, 3983 + DispatcherInfo d1,
3984 DispatcherInfo d2 3984 DispatcherInfo d2
3985 ) = 3985 ) =
3986 - if d1 is site(n1,_) then 3986 + if d1 is site(n1,_) then
3987 if d2 is site(n2,_) then 3987 if d2 is site(n2,_) then
3988 - string_less(n1,n2).  
3989 -  
3990 -  
3991 - 3988 + string_less(n1,n2).
  3989 +
  3990 +
  3991 +
3992 define One 3992 define One
3993 update_site 3993 update_site
3994 ( 3994 (
3995 Var(List(DispatcherInfo)) info_v 3995 Var(List(DispatcherInfo)) info_v
3996 ) = 3996 ) =
3997 - print("\n");  
3998 - with prefix = prompt(" Search for site to update: "),  
3999 - if find_sites(*info_v,prefix) is 3997 + print("\n");
  3998 + with prefix = prompt(" Search for site to update: "),
  3999 + if find_sites(*info_v,prefix) is
4000 { 4000 {
4001 [ ] then print(" No site found.\n"); 4001 [ ] then print(" No site found.\n");
4002 update_site(info_v), 4002 update_site(info_v),
4003 - [h . t] then 4003 + [h . t] then
4004 show_sites(qsort([h . t],compare),1); 4004 show_sites(qsort([h . t],compare),1);
4005 with i1 = prompt(" Choose a site to update [1/.../"+(length(t)+1)+"]: "), 4005 with i1 = prompt(" Choose a site to update [1/.../"+(length(t)+1)+"]: "),
4006 - if decimal_scan(i1) is 4006 + if decimal_scan(i1) is
4007 { 4007 {
4008 failure then print(" *** Error: site number not recognized.\n"); 4008 failure then print(" *** Error: site number not recognized.\n");
4009 update_site(info_v), 4009 update_site(info_v),
4010 - success(ii1) then if nth(ii1-1,*info_v) is 4010 + success(ii1) then if nth(ii1-1,*info_v) is
4011 { 4011 {
4012 failure then print(" *** Error: site number "+i1+" does not exist.\n"); 4012 failure then print(" *** Error: site number "+i1+" does not exist.\n");
4013 update_site(info_v), 4013 update_site(info_v),
4014 - success(site_info) then if site_info is site(name,old_port) then 4014 + success(site_info) then if site_info is site(name,old_port) then
4015 update_site(info_v,name,old_port) 4015 update_site(info_v,name,old_port)
4016 } 4016 }
4017 } 4017 }
4018 }. 4018 }.
4019 - 4019 +
4020 4020
4021 define One 4021 define One
4022 delete_site 4022 delete_site
@@ -4030,38 +4030,38 @@ define One @@ -4030,38 +4030,38 @@ define One
4030 with answer = prompt(" Are you sure you want to delete site: '"+site_name+"' [Y/N] ? "), 4030 with answer = prompt(" Are you sure you want to delete site: '"+site_name+"' [Y/N] ? "),
4031 if (answer = "Y" | answer = "y") 4031 if (answer = "Y" | answer = "y")
4032 then info_v <- delete_info(*info_v,site_name) 4032 then info_v <- delete_info(*info_v,site_name)
4033 - else print(" Site '"+site_name+"' not deleted.\n").  
4034 -  
4035 - 4033 + else print(" Site '"+site_name+"' not deleted.\n").
  4034 +
  4035 +
4036 define One 4036 define One
4037 delete_site 4037 delete_site
4038 ( 4038 (
4039 Var(List(DispatcherInfo)) info_v 4039 Var(List(DispatcherInfo)) info_v
4040 ) = 4040 ) =
4041 - print("\n");  
4042 - with prefix = prompt(" Search for site to delete: "),  
4043 - if find_sites(*info_v,prefix) is 4041 + print("\n");
  4042 + with prefix = prompt(" Search for site to delete: "),
  4043 + if find_sites(*info_v,prefix) is
4044 { 4044 {
4045 [ ] then print(" No site found.\n"); 4045 [ ] then print(" No site found.\n");
4046 delete_site(info_v), 4046 delete_site(info_v),
4047 - [h . t] then 4047 + [h . t] then
4048 show_sites(qsort([h . t],compare),1); 4048 show_sites(qsort([h . t],compare),1);
4049 with i1 = prompt(" Choose a site to delete [1/.../"+(length(t)+1)+"]: "), 4049 with i1 = prompt(" Choose a site to delete [1/.../"+(length(t)+1)+"]: "),
4050 - if decimal_scan(i1) is 4050 + if decimal_scan(i1) is
4051 { 4051 {
4052 failure then print(" *** Error: site number not recognized.\n"); 4052 failure then print(" *** Error: site number not recognized.\n");
4053 delete_site(info_v), 4053 delete_site(info_v),
4054 - success(ii1) then if nth(ii1-1,*info_v) is 4054 + success(ii1) then if nth(ii1-1,*info_v) is
4055 { 4055 {
4056 failure then print(" *** Error: site number "+i1+" does not exist.\n"); 4056 failure then print(" *** Error: site number "+i1+" does not exist.\n");
4057 delete_site(info_v), 4057 delete_site(info_v),
4058 - success(site_info) then if site_info is site(name,old_port) then 4058 + success(site_info) then if site_info is site(name,old_port) then
4059 delete_site(info_v,name,old_port) 4059 delete_site(info_v,name,old_port)
4060 } 4060 }
4061 } 4061 }
4062 }. 4062 }.
4063 -  
4064 - 4063 +
  4064 +
4065 define One 4065 define One
4066 manager 4066 manager
4067 ( 4067 (
@@ -4071,64 +4071,64 @@ define One @@ -4071,64 +4071,64 @@ define One
4071 print("\n"); 4071 print("\n");
4072 print(" --- Welcome to the Web Dispatcher Manager ---\n"); 4072 print(" --- Welcome to the Web Dispatcher Manager ---\n");
4073 with l = length(*info_v), 4073 with l = length(*info_v),
4074 - print(" "+l+" site"+(if l>1 then "s" else "")+" currently registred.\n"); 4074 + print(" "+l+" site"+(if l>1 then "s" else "")+" currently registred.\n");
4075 print(" [L] List registered sites.\n"); 4075 print(" [L] List registered sites.\n");
4076 print(" [R] Register a new site.\n"); 4076 print(" [R] Register a new site.\n");
4077 - print(" [U] Update a registred site.\n");  
4078 - print(" [D] Delete a registred site.\n");  
4079 - with propose_write_v = var((Bool)true),  
4080 - action = prompt(" Choose an action [L/R/U/D]: "), 4077 + print(" [U] Update a registred site.\n");
  4078 + print(" [D] Delete a registred site.\n");
  4079 + with propose_write_v = var((Bool)true),
  4080 + action = prompt(" Choose an action [L/R/U/D]: "),
4081 (if (action = "L" | action = "l") then (show_sites(*info_v,1); propose_write_v <- false) else 4081 (if (action = "L" | action = "l") then (show_sites(*info_v,1); propose_write_v <- false) else
4082 if (action = "R" | action = "r") then register_new_site(info_v) else 4082 if (action = "R" | action = "r") then register_new_site(info_v) else
4083 if (action = "U" | action = "u") then update_site(info_v) else 4083 if (action = "U" | action = "u") then update_site(info_v) else
4084 if (action = "D" | action = "d") then delete_site(info_v) else 4084 if (action = "D" | action = "d") then delete_site(info_v) else
4085 print("Action not recognized.\n")); 4085 print("Action not recognized.\n"));
4086 - print("\n");  
4087 - if *propose_write_v then 4086 + print("\n");
  4087 + if *propose_write_v then
4088 with result = prompt(" Write modifications to data base [Y/N] ?"), 4088 with result = prompt(" Write modifications to data base [Y/N] ?"),
4089 if (result = "Y" | result = "y") 4089 if (result = "Y" | result = "y")
4090 - then if save(*info_v,file_path) is 4090 + then if save(*info_v,file_path) is
4091 { 4091 {
4092 cannot_open_file then print(" File '"+file_path+"' not found.\n"), 4092 cannot_open_file then print(" File '"+file_path+"' not found.\n"),
4093 write_error then print(" Error while writing file '"+file_path+"'.\n"), 4093 write_error then print(" Error while writing file '"+file_path+"'.\n"),
4094 ok then print(" Data base has been modified.\n") 4094 ok then print(" Data base has been modified.\n")
4095 } 4095 }
4096 else print(" Data base not modified.\n") 4096 else print(" Data base not modified.\n")
4097 - else unique.  
4098 -  
4099 -  
4100 - 4097 + else unique.
  4098 +
  4099 +
  4100 +
4101 global define One 4101 global define One
4102 manage_web_dispatcher 4102 manage_web_dispatcher
4103 ( 4103 (
4104 List(String) args 4104 List(String) args
4105 ) = 4105 ) =
4106 - with info_v = var((List(DispatcherInfo))[]),  
4107 - with file_path = my_anubis_directory+"/web_sites/dispatcher.info", 4106 + with info_v = var((List(DispatcherInfo))[]),
  4107 + with file_path = my_anubis_directory+"/web_sites/dispatcher.info",
4108 if (RetrieveResult(List(DispatcherInfo)))retrieve(file_path) is 4108 if (RetrieveResult(List(DispatcherInfo)))retrieve(file_path) is
4109 { 4109 {
4110 cannot_find_file then print("File '"+file_path+"' does not exist.\n"); 4110 cannot_find_file then print("File '"+file_path+"' does not exist.\n");
4111 with answer = prompt("Create it [Y/N] ? "), 4111 with answer = prompt("Create it [Y/N] ? "),
4112 if (answer = "Y" | answer = "y") 4112 if (answer = "Y" | answer = "y")
4113 - then if save((List(DispatcherInfo))[],file_path) is 4113 + then if save((List(DispatcherInfo))[],file_path) is
4114 { 4114 {
4115 - cannot_open_file then 4115 + cannot_open_file then
4116 print("Cannot create file '"+file_path+"'.\n"), 4116 print("Cannot create file '"+file_path+"'.\n"),
4117 write_error then 4117 write_error then
4118 print("Error while creating file '"+file_path+"'.\n"), 4118 print("Error while creating file '"+file_path+"'.\n"),
4119 ok then manager(info_v,file_path) 4119 ok then manager(info_v,file_path)
4120 } 4120 }
4121 else unique, 4121 else unique,
4122 - read_error then print("Error while reading file '"+file_path+"'.\n"),  
4123 - type_error then print("File '"+file_path+"' is corrupted.\n"),  
4124 - ok(info) then info_v <- info; 4122 + read_error then print("Error while reading file '"+file_path+"'.\n"),
  4123 + type_error then print("File '"+file_path+"' is corrupted.\n"),
  4124 + ok(info) then info_v <- info;
4125 manager(info_v,file_path) 4125 manager(info_v,file_path)
4126 }. 4126 }.
4127 -  
4128 -  
4129 -  
4130 -  
4131 - 4127 +
  4128 +
  4129 +
  4130 +
  4131 +
4132 public define (String, List(HTTP_header)) 4132 public define (String, List(HTTP_header))
4133 format 4133 format
4134 ( 4134 (
@@ -4138,7 +4138,7 @@ public define (String, List(HTTP_header)) @@ -4138,7 +4138,7 @@ public define (String, List(HTTP_header))
4138 { 4138 {
4139 http_continue then ("100 Continue", []), 4139 http_continue then ("100 Continue", []),
4140 http_switching_protocol then ("101 Switching Protocols", []), 4140 http_switching_protocol then ("101 Switching Protocols", []),
4141 - 4141 +
4142 http_ok then ("200 OK", []), 4142 http_ok then ("200 OK", []),
4143 http_created then ("201 Created", []), 4143 http_created then ("201 Created", []),
4144 http_accepted then ("202 Accepted", []), 4144 http_accepted then ("202 Accepted", []),
@@ -4146,7 +4146,7 @@ public define (String, List(HTTP_header)) @@ -4146,7 +4146,7 @@ public define (String, List(HTTP_header))
4146 http_no_content then ("204 No Content", []), 4146 http_no_content then ("204 No Content", []),
4147 http_reset_content then ("205 Reset Content", []), 4147 http_reset_content then ("205 Reset Content", []),
4148 http_partial_content then ("206 Partial Content", []), 4148 http_partial_content then ("206 Partial Content", []),
4149 - 4149 +
4150 http_multiple_choices then ("300 Multiple Choices", []), 4150 http_multiple_choices then ("300 Multiple Choices", []),
4151 http_moved_permanently(loc) then ("301 Moved Permanently", [http_header("Location", loc)]), 4151 http_moved_permanently(loc) then ("301 Moved Permanently", [http_header("Location", loc)]),
4152 http_moved_temporarily(loc) then ("302 Moved Temporarily", [http_header("Location", loc)]), 4152 http_moved_temporarily(loc) then ("302 Moved Temporarily", [http_header("Location", loc)]),
@@ -4154,7 +4154,7 @@ public define (String, List(HTTP_header)) @@ -4154,7 +4154,7 @@ public define (String, List(HTTP_header))
4154 http_not_modified then ("304 Not Modified", []), 4154 http_not_modified then ("304 Not Modified", []),
4155 http_use_proxy(loc) then ("305 Use Proxy", [http_header("Location", loc)]), 4155 http_use_proxy(loc) then ("305 Use Proxy", [http_header("Location", loc)]),
4156 http_temporary_redirect(loc) then ("307 Temporary Redirect", [http_header("Location", loc)]), 4156 http_temporary_redirect(loc) then ("307 Temporary Redirect", [http_header("Location", loc)]),
4157 - 4157 +
4158 http_bad_request then ("400 Bad Request", []), 4158 http_bad_request then ("400 Bad Request", []),
4159 http_unauthorized then ("401 Unauthorized", []), 4159 http_unauthorized then ("401 Unauthorized", []),
4160 http_payment_required then ("402 Payment Required", []), 4160 http_payment_required then ("402 Payment Required", []),
@@ -4173,15 +4173,13 @@ public define (String, List(HTTP_header)) @@ -4173,15 +4173,13 @@ public define (String, List(HTTP_header))
4173 http_unsupported_media_type then ("415 Unsupported Media Type", []), 4173 http_unsupported_media_type then ("415 Unsupported Media Type", []),
4174 http_request_range_unsatisfiable then ("416 Requested range unsatisfiable", []), 4174 http_request_range_unsatisfiable then ("416 Requested range unsatisfiable", []),
4175 http_expectation_failed then ("417 Expectation failed", []), 4175 http_expectation_failed then ("417 Expectation failed", []),
4176 - 4176 +
4177 http_internal_server_error then ("500 Internal Server Error", []), 4177 http_internal_server_error then ("500 Internal Server Error", []),
4178 http_not_implemented then ("501 Not Implemented", []), 4178 http_not_implemented then ("501 Not Implemented", []),
4179 http_bad_gateway then ("502 Bad Gateway", []), 4179 http_bad_gateway then ("502 Bad Gateway", []),
4180 http_service_unavailable then ("503 Service Unavailable", []), 4180 http_service_unavailable then ("503 Service Unavailable", []),
4181 http_gateway_timeout then ("504 Gateway Time-out", []), 4181 http_gateway_timeout then ("504 Gateway Time-out", []),
4182 http_version_not_supported then ("505 HTTP Version not supported", []), 4182 http_version_not_supported then ("505 HTTP Version not supported", []),
4183 - 4183 +
4184 http_error(code, message) then (abs_to_decimal(code) + " " + message, []) 4184 http_error(code, message) then (abs_to_decimal(code) + " " + message, [])
4185 }. 4185 }.
4186 -  
4187 -  
web/jQuery/CXM_jq_checkbox.anubis
1 /* 1 /*
2 * Created by PyramIDE. 2 * Created by PyramIDE.
3 - * User: フランスのトトロ 3 + * User: フランスのトトロ
4 * Date: 28/06/2015 4 * Date: 28/06/2015
5 * Time: 02:22 5 * Time: 02:22
6 - * © Calexium 6 + * © Calexium
7 */ 7 */
8 8
9 transmit calexium_lib/web/CXM_making_a_web_site.anubis 9 transmit calexium_lib/web/CXM_making_a_web_site.anubis
@@ -15,25 +15,25 @@ transmit tools/basis.anubis @@ -15,25 +15,25 @@ transmit tools/basis.anubis
15 transmit system/string.anubis 15 transmit system/string.anubis
16 transmit tools/random.anubis 16 transmit tools/random.anubis
17 17
18 -define String 18 +define String
19 checkbox_init_script 19 checkbox_init_script
20 ( 20 (
21 String checkbox_id, 21 String checkbox_id,
22 Bool initial_state 22 Bool initial_state
23 - ) = 23 + ) =
24 "var checkbox = $('#" + checkbox_id + "');" + 24 "var checkbox = $('#" + checkbox_id + "');" +
25 - if initial_state then 25 + if initial_state then
26 "checkbox.addClass('checked');" 26 "checkbox.addClass('checked');"
27 else 27 else
28 "checkbox.addClass('unchecked');". 28 "checkbox.addClass('unchecked');".
29 29
30 -define String 30 +define String
31 checkbox_onclick_script 31 checkbox_onclick_script
32 ( 32 (
33 String checkbox_id, 33 String checkbox_id,
34 String on_script, 34 String on_script,
35 String off_script, 35 String off_script,
36 - ) = 36 + ) =
37 "var checkbox = $('#" + checkbox_id + "'); 37 "var checkbox = $('#" + checkbox_id + "');
38 checkbox.toggleClass('checked'); 38 checkbox.toggleClass('checked');
39 checkbox.toggleClass('unchecked'); 39 checkbox.toggleClass('unchecked');
@@ -42,14 +42,14 @@ define String @@ -42,14 +42,14 @@ define String
42 } else { 42 } else {
43 " + off_script + " 43 " + off_script + "
44 }". 44 }".
45 - 45 +
46 public define HTML_Partial_Content 46 public define HTML_Partial_Content
47 jq_img_checkbox 47 jq_img_checkbox
48 ( 48 (
49 String checkbox_id, 49 String checkbox_id,
50 Bool initial_state, 50 Bool initial_state,
51 String image_url, 51 String image_url,
52 - String checkbox_label, 52 + String checkbox_label,
53 String on_script, 53 String on_script,
54 String off_script, 54 String off_script,
55 Icon_orientation orientation 55 Icon_orientation orientation
@@ -60,14 +60,14 @@ public define HTML_Partial_Content @@ -60,14 +60,14 @@ public define HTML_Partial_Content
60 ], 60 ],
61 jquery_button(jquery_img_button(image_url, checkbox_label, checkbox_id, jQuery_actioner(same, jqscript, checkbox_onclick_script(checkbox_id, on_script, off_script)), orientation)) 61 jquery_button(jquery_img_button(image_url, checkbox_label, checkbox_id, jQuery_actioner(same, jqscript, checkbox_onclick_script(checkbox_id, on_script, off_script)), orientation))
62 ). 62 ).
63 - 63 +
64 public define HTML_Partial_Content 64 public define HTML_Partial_Content
65 jq_img_checkbox 65 jq_img_checkbox
66 ( 66 (
67 String checkbox_id, 67 String checkbox_id,
68 Bool initial_state, 68 Bool initial_state,
69 String image_url, 69 String image_url,
70 - String checkbox_label, 70 + String checkbox_label,
71 String script, 71 String script,
72 Icon_orientation orientation 72 Icon_orientation orientation
73 ) = 73 ) =
web/jQuery/CXM_jq_radio.anubis 0 → 100644
  1 +/*
  2 + * Created by PyramIDE.
  3 + * User: フランスのトトロ
  4 + * Date: 28/06/2015
  5 + * Time: 02:22
  6 + * © Calexium
  7 + */
  8 +
  9 +transmit calexium_lib/web/CXM_making_a_web_site.anubis
  10 +transmit calexium_lib/web/CXM_jquery.anubis
  11 +transmit calexium_lib/web/jQuery/CXM_jquery_button.anubis
  12 +transmit calexium_lib/web/jQuery/CXM_jquery_icons.anubis
  13 +transmit calexium_lib/web/js_tools.anubis
  14 +transmit tools/basis.anubis
  15 +transmit system/string.anubis
  16 +transmit tools/random.anubis
  17 +
  18 +public type RadioGroup:
  19 + group(String name),
  20 + none.
  21 +
  22 +define String
  23 + radio_init_script
  24 + (
  25 + String radio_id,
  26 + RadioGroup radio_group,
  27 + Bool initial_state
  28 + ) =
  29 + "var radio = $('#" + radio_id + "');" +
  30 +
  31 + if radio_group is
  32 + {
  33 + group(name) then
  34 + "radio.addClass('radio-group-" + name + "');",
  35 +
  36 + none then
  37 + ""
  38 + } +
  39 +
  40 + if initial_state then
  41 + "radio.addClass('checked');"
  42 + else
  43 + "radio.addClass('unchecked');".
  44 +
  45 +define String
  46 + radio_onclick_script
  47 + (
  48 + String radio_id,
  49 + RadioGroup radio_group,
  50 + String on_script
  51 + ) =
  52 + "
  53 + var radio = $('#" + radio_id + "');
  54 + if (radio.hasClass('checked')) return;
  55 + " +
  56 +
  57 + if radio_group is
  58 + {
  59 + group(name) then
  60 + "$('.radio-group-" + name + "').addClass('unchecked');",
  61 +
  62 + none then
  63 + ""
  64 + } +
  65 +
  66 + "radio.removeClass('unchecked');
  67 + radio.addClass('checked');" + on_script.
  68 +
  69 +public define HTML_Partial_Content
  70 + jq_img_radio
  71 + (
  72 + String radio_id,
  73 + RadioGroup radio_group,
  74 + Bool initial_state,
  75 +//Bool multi_select_with_shift,
  76 + String image_url,
  77 + String checkbox_label,
  78 + String on_script,
  79 + Icon_orientation orientation
  80 + ) =
  81 + partial_content(
  82 + [
  83 + js_inline(jquery_ready(radio_init_script(radio_id, radio_group, initial_state)))
  84 + ],
  85 + jquery_button(jquery_img_button(image_url, checkbox_label, radio_id, jQuery_actioner(same, jqscript, radio_onclick_script(radio_id, radio_group, on_script)), orientation))
  86 + ).
  87 +
  88 +public define HTML_Partial_Content
  89 + jq_img_radio
  90 + (
  91 + String radio_id,
  92 + Bool initial_state,
  93 + String image_url,
  94 + String checkbox_label,
  95 + String script,
  96 + Icon_orientation orientation
  97 + ) =
  98 + jq_img_radio(radio_id, none, initial_state, image_url, checkbox_label, script, orientation).
web/jQuery/CXM_jquery_button.anubis
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 * User: Jeremy 3 * User: Jeremy
4 * Date: 07/09/2012 4 * Date: 07/09/2012
5 * Time: 15:10 5 * Time: 15:10
6 - * 6 + *
7 */ 7 */
8 8
9 transmit calexium_lib/web/CXM_making_a_web_site.anubis 9 transmit calexium_lib/web/CXM_making_a_web_site.anubis
@@ -18,14 +18,14 @@ transmit tools/random.anubis @@ -18,14 +18,14 @@ transmit tools/random.anubis
18 public type JQuery_button_type: 18 public type JQuery_button_type:
19 button, 19 button,
20 reset, 20 reset,
21 - submit. //button with confirmation dialog  
22 - 21 + submit. //button with confirmation dialog
  22 +
23 public define String 23 public define String
24 to_String 24 to_String
25 ( 25 (
26 JQuery_button_type bt_type 26 JQuery_button_type bt_type
27 )= 27 )=
28 - if bt_type is 28 + if bt_type is
29 { 29 {
30 button then "button", 30 button then "button",
31 reset then "reset", 31 reset then "reset",
@@ -33,7 +33,7 @@ public define String @@ -33,7 +33,7 @@ public define String
33 }. 33 }.
34 34
35 public type JQuery_button: 35 public type JQuery_button:
36 - jQuery_button( JQuery_button_type bt_type, 36 + jQuery_button( JQuery_button_type bt_type,
37 String button_id, String button_name, String button_label, JQuery_Actioner actioner, JQuery_icon primary, JQuery_icon secondary // primary icon is for left icon, secondary icon is for right icon and button_id must set with an unique ID in order to have icons working 37 String button_id, String button_name, String button_label, JQuery_Actioner actioner, JQuery_icon primary, JQuery_icon secondary // primary icon is for left icon, secondary icon is for right icon and button_id must set with an unique ID in order to have icons working
38 ) 38 )
39 . 39 .
@@ -42,43 +42,12 @@ public define JQuery_button @@ -42,43 +42,12 @@ public define JQuery_button
42 jQuery_button 42 jQuery_button
43 ( 43 (
44 JQuery_button_type bt_type, 44 JQuery_button_type bt_type,
45 - String button_id,  
46 - String button_name,  
47 - String button_label, 45 + String button_id,
  46 + String button_name,
  47 + String button_label,
48 JQuery_Actioner actioner 48 JQuery_Actioner actioner
49 ) = 49 ) =
50 jQuery_button(bt_type, button_id, button_name, button_label, actioner, jq_icon_none, jq_icon_none). 50 jQuery_button(bt_type, button_id, button_name, button_label, actioner, jq_icon_none, jq_icon_none).
51 -  
52 -define String  
53 - jquery_button_get_onclick_action_window_options  
54 - (  
55 - List(Other_Window_Option) options,  
56 - String formated_options  
57 - )  
58 - =  
59 - //if there is already formated_options add a comma + space between the options  
60 - with comma = if formated_options="" then "" else ", ",  
61 -  
62 - if options is  
63 - {  
64 - [ ] then formated_options,  
65 - [ h . t ] then  
66 - if h is  
67 - {  
68 - resizable then jquery_button_get_onclick_action_window_options(  
69 - t, formated_options+ comma+ "resizable=yes" ),  
70 -  
71 - scrollbars then jquery_button_get_onclick_action_window_options(  
72 - t, formated_options+ comma + "scrollbars=yes"),  
73 -  
74 - width(w) then jquery_button_get_onclick_action_window_options(  
75 - t, formated_options+ comma + "width="+w),  
76 -  
77 - height(h) then jquery_button_get_onclick_action_window_options(  
78 - t, formated_options+ comma + "height="+h)  
79 - }  
80 - }  
81 - .  
82 51
83 define HTML_Head_Tag 52 define HTML_Head_Tag
84 jquery_button_get_onclick_action 53 jquery_button_get_onclick_action
@@ -87,31 +56,8 @@ define HTML_Head_Tag @@ -87,31 +56,8 @@ define HTML_Head_Tag
87 JQuery_Actioner actioner 56 JQuery_Actioner actioner
88 ) 57 )
89 = 58 =
90 - if actioner is jQuery_actioner(target, act_type, str) then  
91 - if target is  
92 - {  
93 - same then  
94 - if act_type is  
95 - {  
96 - jqform then js_inline(jquery_ready("$('#"+button_id+"').click(function(){$('#"+str+"').submit();});")),  
97 - jqlink then js_inline(jquery_ready("$('#"+button_id+"').click(function(){document.location='/?a="+str+"';});")),  
98 - jqscript then js_inline(jquery_ready("$('#"+button_id+"').click(function(){"+str+"});"))  
99 - },  
100 - same(label) then  
101 - if act_type is  
102 - {  
103 - jqform then js_inline(jquery_ready("$('#"+button_id+"').click(function(){$('#"+str+"').submit();});")),  
104 - jqlink then js_inline(jquery_ready("$('#"+button_id+"').click(function(){document.location='/?a="+str+"';});")),  
105 - jqscript then js_inline(jquery_ready("$('#"+button_id+"').click(function(){"+str+"});"))  
106 - },  
107 - other(window_name, window_options) then  
108 - if act_type is  
109 - {  
110 - jqform then js_inline(jquery_ready("$('#"+button_id+"').click(function(){$('#"+str+"').submit();});")), //il s'agit d'une soumision d'un formulaire => cela se fait uniquement dans la même fenêtre !  
111 - jqlink then js_inline(jquery_ready("$('#"+button_id+"').click(function(){window.open('"+str+"', '"+window_name+"', '"+jquery_button_get_onclick_action_window_options(window_options, "")+"');});")),  
112 - jqscript then js_inline(jquery_ready("$('#"+button_id+"').click(function(){"+str+"});"))  
113 - }  
114 - } 59 + with js_action = jquery_button_get_onclick_action(actioner),
  60 + js_inline(jquery_ready("$('#"+button_id+"').click(function(e){" + js_action + "});"))
115 . 61 .
116 62
117 define HTML_Partial_Content 63 define HTML_Partial_Content
@@ -138,7 +84,7 @@ define HTML_Partial_Content @@ -138,7 +84,7 @@ define HTML_Partial_Content
138 [ onclick_action . html_tags ], 84 [ onclick_action . html_tags ],
139 [ 85 [
140 literal("<button type=\""+to_String(bt_type)+"\" name=\""+name+"\">"+label+"</button>") 86 literal("<button type=\""+to_String(bt_type)+"\" name=\""+name+"\">"+label+"</button>")
141 - 87 +
142 . 88 .
143 html_buttons 89 html_buttons
144 ] 90 ]
@@ -265,7 +211,7 @@ public define HTML_Partial_Content @@ -265,7 +211,7 @@ public define HTML_Partial_Content
265 literal("<button type=\""+to_String(bt_type)+"\" id=\""+id+"\">"+label+"</button>") 211 literal("<button type=\""+to_String(bt_type)+"\" id=\""+id+"\">"+label+"</button>")
266 ) 212 )
267 . 213 .
268 - 214 +
269 public type Icon_orientation: 215 public type Icon_orientation:
270 top, 216 top,
271 bottom, 217 bottom,
@@ -274,7 +220,7 @@ public type Icon_orientation: @@ -274,7 +220,7 @@ public type Icon_orientation:
274 220
275 public type JQuery_img_button: 221 public type JQuery_img_button:
276 jquery_img_button(String img_url, String label_text, String id, JQuery_Actioner jq_action, Icon_orientation orientation). 222 jquery_img_button(String img_url, String label_text, String id, JQuery_Actioner jq_action, Icon_orientation orientation).
277 - 223 +
278 public define HTML_Off_Form 224 public define HTML_Off_Form
279 jquery_button_html 225 jquery_button_html
280 ( 226 (
@@ -292,7 +238,7 @@ public define HTML_Off_Form @@ -292,7 +238,7 @@ public define HTML_Off_Form
292 }). 238 }).
293 239
294 240
295 - 241 +
296 public define HTML_Partial_Content 242 public define HTML_Partial_Content
297 jquery_button 243 jquery_button
298 ( 244 (
@@ -309,9 +255,9 @@ public define HTML_Partial_Content @@ -309,9 +255,9 @@ public define HTML_Partial_Content
309 css(css_file("css/cxm/cxm_button.css")), 255 css(css_file("css/cxm/cxm_button.css")),
310 js_inline(jquery_ready("$('.jq_img_btn').button();")) 256 js_inline(jquery_ready("$('.jq_img_btn').button();"))
311 ], 257 ],
312 - jquery_button_html(button, button_id_str)) 258 + jquery_button_html(button, button_id_str))
313 . 259 .
314 - 260 +
315 public define HTML_Partial_Content 261 public define HTML_Partial_Content
316 jq_button_confirm 262 jq_button_confirm
317 ( 263 (
@@ -320,10 +266,10 @@ public define HTML_Partial_Content @@ -320,10 +266,10 @@ public define HTML_Partial_Content
320 String dlg_text, 266 String dlg_text,
321 String dlg_ok, 267 String dlg_ok,
322 String dlg_cancel, 268 String dlg_cancel,
323 - String url,  
324 - List((String, String)) extra_ops 269 + //String url,
  270 + JQuery_Actioner actioner
325 )= 271 )=
326 - with uid = generate_random_string(20), 272 + with uid = generate_random_string(10),
327 273
328 js_confirm_dialog_data_obj = "CalexiumToolBox.data.confirm_dialog[" + to_js_string(uid) + "]", 274 js_confirm_dialog_data_obj = "CalexiumToolBox.data.confirm_dialog[" + to_js_string(uid) + "]",
329 js_data = js_confirm_dialog_data_obj + " = { 275 js_data = js_confirm_dialog_data_obj + " = {
@@ -333,26 +279,12 @@ public define HTML_Partial_Content @@ -333,26 +279,12 @@ public define HTML_Partial_Content
333 cancel: " + to_js_string(dlg_cancel) + "};", 279 cancel: " + to_js_string(dlg_cancel) + "};",
334 280
335 button_name = uid, 281 button_name = uid,
336 - actioner = jQuery_actioner(same, jqscript, "CalexiumToolBox.make_confirm_dialog(this, " + to_js_string("/?a=" + url + format_extra_operands(extra_ops))+");"), 282 + actioner = jQuery_actioner(same, jqscript, "CalexiumToolBox.make_confirm_dialog(this, " /*+ to_js_string("/?a=" + url + format_extra_operands(extra_ops))+*/ + to_js_string(jquery_button_get_onclick_action(actioner)) + ");"),
337 283
338 partial_content([js(js_file("js/cxm/cxm.js")), js_inline(jquery_ready(js_data))],sequence([ 284 partial_content([js(js_file("js/cxm/cxm.js")), js_inline(jquery_ready(js_data))],sequence([
339 - partial(jquery_button(jQuery_button(button, uid, button_name, button_label, actioner, jq_icon_none, jq_icon_none)))  
340 - ])). 285 + partial(jquery_button(jQuery_button(button, uid, button_name, button_label, actioner, jq_icon_none, jq_icon_none)))
  286 + ])).
341 287
342 -  
343 -  
344 -public define HTML_Partial_Content  
345 - jq_button_confirm  
346 - (  
347 - String button_label,  
348 - String dlg_title,  
349 - String dlg_text,  
350 - String dlg_ok,  
351 - String dlg_cancel,  
352 - String url  
353 - )=  
354 - jq_button_confirm(button_label, dlg_title, dlg_text, dlg_ok, dlg_cancel, url, []).  
355 -  
356 public define HTML_Partial_Content 288 public define HTML_Partial_Content
357 img_submit_button 289 img_submit_button
358 ( 290 (
web/jQuery/ui-addon/datetimepicker.anubis
1 /* 1 /*
2 * Created by PyramIDE. 2 * Created by PyramIDE.
3 - * User: フランスのトトロ 3 + * User: フランスのトトロ
4 * Date: 16/11/2014 4 * Date: 16/11/2014
5 * Time: 12:14 5 * Time: 12:14
6 - * © Calexium 6 + * © Calexium
7 */ 7 */
8 8
9 read calexium_lib/web/CXM_making_a_web_site.anubis 9 read calexium_lib/web/CXM_making_a_web_site.anubis
@@ -13,7 +13,7 @@ read calexium_lib/web/CXM_jquery.anubis @@ -13,7 +13,7 @@ read calexium_lib/web/CXM_jquery.anubis
13 public define List(HTML_Head_Tag) 13 public define List(HTML_Head_Tag)
14 jq_ui_datetimepicker_init 14 jq_ui_datetimepicker_init
15 = 15 =
16 - [ 16 + [
17 css(css_file("/css/jquery/ui/datetimepicker.css")), 17 css(css_file("/css/jquery/ui/datetimepicker.css")),
18 js(js_file("js/jquery/ui/jquery-ui-timepicker-addon.js")), 18 js(js_file("js/jquery/ui/jquery-ui-timepicker-addon.js")),
19 js_inline(jquery_ready("// Datepicker\n 19 js_inline(jquery_ready("// Datepicker\n
@@ -23,7 +23,7 @@ read calexium_lib/web/CXM_jquery.anubis @@ -23,7 +23,7 @@ read calexium_lib/web/CXM_jquery.anubis
23 ] 23 ]
24 . 24 .
25 25
26 - 26 +
27 /* Initialize jQuery datetimepicker */ 27 /* Initialize jQuery datetimepicker */
28 public define List(HTML_Head_Tag) 28 public define List(HTML_Head_Tag)
29 jq_datetimepicker_init 29 jq_datetimepicker_init
@@ -31,7 +31,7 @@ public define List(HTML_Head_Tag) @@ -31,7 +31,7 @@ public define List(HTML_Head_Tag)
31 String lang 31 String lang
32 ) 32 )
33 = 33 =
34 - [ 34 + [
35 css(css_file("js/jquery/plug-in/datetimepicker/datetimepicker.css")), 35 css(css_file("js/jquery/plug-in/datetimepicker/datetimepicker.css")),
36 js(js_file("js/jquery/plug-in/datetimepicker/datetimepicker.js")), 36 js(js_file("js/jquery/plug-in/datetimepicker/datetimepicker.js")),
37 js_inline(jquery_ready("// Datetimepicker\n 37 js_inline(jquery_ready("// Datetimepicker\n
web/widgets/button.anubis
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 * User: フランスのトトロ & Juju 3 * User: フランスのトトロ & Juju
4 * Date: 18/04/2015 4 * Date: 18/04/2015
5 * Time: 20:46 5 * Time: 20:46
6 - * © Calexium 6 + * © Calexium
7 */ 7 */
8 8
9 read calexium_lib/web/CXM_making_a_web_site.anubis 9 read calexium_lib/web/CXM_making_a_web_site.anubis
@@ -33,7 +33,7 @@ public define HTML_Partial_Content @@ -33,7 +33,7 @@ public define HTML_Partial_Content
33 String url 33 String url
34 )= 34 )=
35 img_button_flink(img_path, same, url). 35 img_button_flink(img_path, same, url).
36 - 36 +
37 public define HTML_Partial_Content 37 public define HTML_Partial_Content
38 img_button 38 img_button
39 ( 39 (
@@ -43,7 +43,7 @@ public define HTML_Partial_Content @@ -43,7 +43,7 @@ public define HTML_Partial_Content
43 List((String, String)) extra_ops 43 List((String, String)) extra_ops
44 )= 44 )=
45 partial_content(actioner(same, same, img_link(img_path, ""), url, extra_ops)). 45 partial_content(actioner(same, same, img_link(img_path, ""), url, extra_ops)).
46 - 46 +
47 public define HTML_Partial_Content 47 public define HTML_Partial_Content
48 img_button 48 img_button
49 ( 49 (
@@ -60,7 +60,7 @@ public define HTML_Partial_Content @@ -60,7 +60,7 @@ public define HTML_Partial_Content
60 List((String, String)) extra_ops 60 List((String, String)) extra_ops
61 )= 61 )=
62 img_button(img_path, same, url, extra_ops). 62 img_button(img_path, same, url, extra_ops).
63 - 63 +
64 define inline String 64 define inline String
65 img_button_confirm_js 65 img_button_confirm_js
66 ( 66 (
@@ -70,10 +70,10 @@ define inline String @@ -70,10 +70,10 @@ define inline String
70 String dlg_ok, 70 String dlg_ok,
71 String dlg_cancel 71 String dlg_cancel
72 ) = 72 ) =
73 - "CalexiumToolBox.data.confirm_dialog[" + to_js_string(uid) + "] = " +  
74 - "{ title: " + to_js_string(dlg_title) + 73 + "CalexiumToolBox.data.confirm_dialog[" + to_js_string(uid) + "] = " +
  74 + "{ title: " + to_js_string(dlg_title) +
75 ", text: " + to_js_string(dlg_text) + 75 ", text: " + to_js_string(dlg_text) +
76 - ", ok : " + to_js_string(dlg_ok) + 76 + ", ok : " + to_js_string(dlg_ok) +
77 ", cancel: " + to_js_string(dlg_cancel) + 77 ", cancel: " + to_js_string(dlg_cancel) +
78 "};". 78 "};".
79 79
@@ -82,10 +82,9 @@ define List(CoreAttrs) @@ -82,10 +82,9 @@ define List(CoreAttrs)
82 ( 82 (
83 List(CoreAttrs) core_attrs, 83 List(CoreAttrs) core_attrs,
84 String uid, 84 String uid,
85 - String url,  
86 - List((String, String)) extra_ops 85 + JQuery_Actioner actioner
87 ) = 86 ) =
88 - core_attrs + [id(uid), style("cursor: pointer"), event(onclick, "CalexiumToolBox.make_confirm_dialog(this, " + to_js_string("/?a=" + url + format_extra_operands(extra_ops))+");")]. 87 + core_attrs + [id(uid), style("cursor: pointer"), event(onclick, "CalexiumToolBox.make_confirm_dialog(this, "/* + to_js_string("/?a=" + url + format_extra_operands(extra_ops))+*/+ to_js_string(jquery_button_get_onclick_action(actioner)) +");")].
89 88
90 public define HTML_Partial_Content 89 public define HTML_Partial_Content
91 img_button_confirm 90 img_button_confirm
@@ -96,13 +95,12 @@ public define HTML_Partial_Content @@ -96,13 +95,12 @@ public define HTML_Partial_Content
96 String dlg_text, 95 String dlg_text,
97 String dlg_ok, 96 String dlg_ok,
98 String dlg_cancel, 97 String dlg_cancel,
99 - String url,  
100 - List((String, String)) extra_ops 98 + JQuery_Actioner actioner
101 )= 99 )=
102 with uid = generate_random_string(20), 100 with uid = generate_random_string(20),
103 101
104 partial_content([js(js_file("js/cxm/cxm.js")), js_inline(jquery_ready(img_button_confirm_js(uid, dlg_title, dlg_text, dlg_ok, dlg_cancel)))], 102 partial_content([js(js_file("js/cxm/cxm.js")), js_inline(jquery_ready(img_button_confirm_js(uid, dlg_title, dlg_text, dlg_ok, dlg_cancel)))],
105 - image(img_button_confirm_image_attrs(core_attrs, uid, url, extra_ops), img_path, "")). 103 + image(img_button_confirm_image_attrs(core_attrs, uid, actioner), img_path, "")).
106 104
107 public define HTML_Partial_Content 105 public define HTML_Partial_Content
108 img_button_confirm 106 img_button_confirm
@@ -112,35 +110,9 @@ public define HTML_Partial_Content @@ -112,35 +110,9 @@ public define HTML_Partial_Content
112 String dlg_text, 110 String dlg_text,
113 String dlg_ok, 111 String dlg_ok,
114 String dlg_cancel, 112 String dlg_cancel,
115 - String url  
116 - )=  
117 - img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, url, []).  
118 -  
119 -public define HTML_Partial_Content  
120 - img_button_confirm  
121 - (  
122 - String img_path,  
123 - List(CoreAttrs) core_attrs,  
124 - String dlg_title,  
125 - String dlg_text,  
126 - String dlg_ok,  
127 - String dlg_cancel,  
128 - String url  
129 - )=  
130 - img_button_confirm(img_path, core_attrs, dlg_title, dlg_text, dlg_ok, dlg_cancel, url, []).  
131 -  
132 -public define HTML_Partial_Content  
133 - img_button_confirm  
134 - (  
135 - String img_path,  
136 - String dlg_title,  
137 - String dlg_text,  
138 - String dlg_ok,  
139 - String dlg_cancel,  
140 - String url,  
141 - List((String, String)) extra_ops 113 + JQuery_Actioner actioner
142 )= 114 )=
143 - img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, url, extra_ops). 115 + img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, actioner).
144 116
145 public define String 117 public define String
146 img_button_confirm 118 img_button_confirm
@@ -151,13 +123,12 @@ public define String @@ -151,13 +123,12 @@ public define String
151 String dlg_text, 123 String dlg_text,
152 String dlg_ok, 124 String dlg_ok,
153 String dlg_cancel, 125 String dlg_cancel,
154 - String url,  
155 - List((String, String)) extra_ops 126 + JQuery_Actioner actioner
156 ) = 127 ) =
157 with uid = generate_random_string(20), 128 with uid = generate_random_string(20),
158 129
159 - "<script type=\"text/javascript\">" + jquery_ready(img_button_confirm_js(uid, dlg_title, dlg_text, dlg_ok, dlg_cancel)) + "</script>" +  
160 - "<img " + format_attrs(img_button_confirm_image_attrs(core_attrs, uid, url, extra_ops)) + " src=\"" + img_path + "\"></img>". 130 + "<script type=\"text/javascript\">" + jquery_ready(img_button_confirm_js(uid, dlg_title, dlg_text, dlg_ok, dlg_cancel)) + "</script>" +
  131 + "<img " + format_attrs(img_button_confirm_image_attrs(core_attrs, uid, actioner)) + " src=\"" + img_path + "\"></img>".
161 132
162 public define String 133 public define String
163 img_button_confirm 134 img_button_confirm
@@ -167,33 +138,6 @@ public define String @@ -167,33 +138,6 @@ public define String
167 String dlg_text, 138 String dlg_text,
168 String dlg_ok, 139 String dlg_ok,
169 String dlg_cancel, 140 String dlg_cancel,
170 - String url  
171 - )=  
172 - img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, url, []).  
173 -  
174 -public define String  
175 - img_button_confirm  
176 - (  
177 - String img_path,  
178 - List(CoreAttrs) core_attrs,  
179 - String dlg_title,  
180 - String dlg_text,  
181 - String dlg_ok,  
182 - String dlg_cancel,  
183 - String url  
184 - )=  
185 - img_button_confirm(img_path, core_attrs, dlg_title, dlg_text, dlg_ok, dlg_cancel, url, []).  
186 -  
187 -public define String  
188 - img_button_confirm  
189 - (  
190 - String img_path,  
191 - String dlg_title,  
192 - String dlg_text,  
193 - String dlg_ok,  
194 - String dlg_cancel,  
195 - String url,  
196 - List((String, String)) extra_ops 141 + JQuery_Actioner actioner
197 )= 142 )=
198 - img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, url, extra_ops).  
199 - 143 + img_button_confirm(img_path, [], dlg_title, dlg_text, dlg_ok, dlg_cancel, actioner).