Wapp

Diff
Login

Differences From Artifact [2decf67ffd]:

To Artifact [0417d2d2a6]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
Introducing To Writing Wapp Applications
========================================

1.0 Hello World
---------------

Wapp applications are easy to develop.  A hello-world program is as follows:

>
    #!/usr/bin/wapptclsh
    package require wapp
    proc wapp-default {} {
       wapp-subst {<h1>Hello, World!</h1>\n}
    }
    wapp-start $::argv

Every Wapp application defines one or more procedures that accept HTTP
requests and generate appropriate replies.
For an HTTP request where the initial portion of the URI path is "abcde", the
procedure named "wapp-page-abcde" will be invoked to construct the reply.
If no such procedure exists, "wapp-default" is invoked instead.  The latter
technique is used for the hello-world example above.

The hello-world example generates the reply using a single call to the "wapp-subst"
command.  Each "wapp-subst" command appends new text to the reply, applying
various substitutions as it goes.  The only substitution in this example is
the \\n at the end of the line.

The "wapp-start" command starts up the application.

1.1 Running A Wapp Application
------------------------------

To run this application, copy the code above into a file named "main.tcl"
and then enter the following command:

>
    wapptclsh main.tcl

That command will start up a web-server bound to the loopback
IP address, then launch a web-browser pointing at that web-server.
The result is that the "Hello, World!" page will automatically
appear in your web browser.

To run this same program as a traditional web-server on TCP port 8080, enter:

>
    wapptclsh main.tcl --server 8080

Here the built-in web-server listens on all IP addresses and so the
web page is available on other machines.  But the web-browser is not
automatically started in this case, so you will have to manually enter
"http://localhost:8080/" into your web-browser in order to see the page.

To run this program as CGI, put the main.tcl script in your web-servers
file hierarchy, in the appropriate place for CGI scripts, and make any
other web-server specific configuration changes so that the web-server
understands that the main.tcl file is a CGI script.  Then point your
web-browser at that script.

Run the hello-world program as SCGI like this:

>
    wapptclsh main.tcl --scgi 9000

Then configure your web-server to send SCGI requests to TCP port 9000
for some specific URI, and point your web-browser at that URI.  By
default, the web-server must be on the same machine as the wapp script.
The --scgi option only accepts SCGI requests from IP address 127.0.0.1.
If your webserver is running on a different machine, use the --remote-scgi
option instead, probably with a --fromip option to specify the IP address
of the machine that is running the webserver.

1.2 Using Plain Old Tclsh
-------------------------

Wapp applications are pure TCL code.  You can run them using an ordinary
"tclsh" command if desired, instead of the "wapptclsh" shown above.  We
normally use "wapptclsh" for the following reasons:

   +  Wapptclsh is statically linked, so there is never a worry about
      having the right shared libraries on hand.  This is particularly
      important if the application will ultimately be deployed into a
      chroot jail.

   +  Wapptclsh has SQLite built-in and SQLite turns out to be very
      useful for the kinds of small applications where Wapp excels.

   +  Wapptclsh knows how to process "package require wapp".  If you
      run with ordinary tclsh, you might need to change the 
      "package require wapp" into "source wapp.tcl" and ship the separate
      "wapp.tcl" script together with your application.

We prefer to use wapptclsh and wapptclsh is shown in all of the examples.
But ordinary "tclsh" will work in the examples too.

2.0 Longer Examples
-------------------

Wapp keeps track of various [parameters](params.md) that describe
each HTTP request.  Those parameters are accessible using routines
like "wapp-param _NAME_"
The following sample program gives some examples:

>
    package require wapp
    proc wapp-default {} {
      set B [wapp-param BASE_URL]
      wapp-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>Wapp
        Environment</a></p>
      }
    }
    proc wapp-page-env {} {
      wapp-allow-xorigin-params
      wapp-subst {<h1>Wapp Environment</h1>\n<pre>\n}
      foreach var [lsort [wapp-param-list]] {
        if {[string index $var 0]=="."} continue
        wapp-subst {%html($var) = %html([list [wapp-param $var]])\n}
      }
      wapp-subst {</pre>\n}
    }
    wapp-start $argv

In this application, the default "Hello, World!" page has been extended
with a hyperlink to the /env page.  The "wapp-subst" command has been
replaced by "wapp-trim", which works the same way with the addition that
it removes surplus whitespace from the left margin, so that the generated
HTML text does not come out indented.  The "wapp-trim" and "wapp-subst"
commands in this example use "%html(...)" substitutions.  The "..." argument 
is expanded using the usual TCL rules, but then the result is escaped so
that it is safe to include in an HTML document.  Other supported
substitutions are "%url(...)" for
URLs on the href= and src= attributes of HTML entities, "%qp(...)" for
query parameters, "%string(...)" for string literals within javascript,
and "%unsafe(...)" for direct literal substitution.  As its name implies,
the %unsafe() substitution should be avoided whenever possible.

The /env page is implemented by the "wapp-page-env" proc.  This proc
generates HTML that describes all of the query parameters. Parameter names
that begin with "." are for internal use by Wapp and are skipped
for this display.  Notice the use of "wapp-subst" to safely escape text
for inclusion in an HTML document.

The printing of all the parameters as is done by the /env page turns
out to be so useful that there is a special "wapp-debug-env" command
to render the text for us.  Using "wapp-debug-env", the program
above can be simplified to the following:

>
    package require wapp
    proc wapp-default {} {
      set B [wapp-param BASE_URL]
      wapp-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>Wapp
        Environment</a></p>
      }
    }
    proc wapp-page-env {} {
      wapp-allow-xorigin-params
      wapp-trim {
        <h1>Wapp Environment</h1>\n<pre>
        <pre>%html([wapp-debug-env])</pre>
      }
    }
    wapp-start $argv

Many Wapp applications contain an /env page for debugging and
trouble-shooting purpose.  Examples:
<https://sqlite.org/src/ext/checklist/top/env> and
<https://sqlite.org/search?env=1>


2.1 Binary Resources
--------------------

Here is another variation on the same "hello, world" program that adds an
image to the main page:

>
    package require wapp
    proc wapp-default {} {
      set B [wapp-param BASE_URL]
      wapp-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>Wapp
        Environment</a></p>
        <p>Broccoli: <img src='broccoli.gif'></p>
      }
    }
    proc wapp-page-env {} {
      wapp-allow-xorigin-params
      wapp-trim {
        <h1>Wapp Environment</h1>\n<pre>
        <pre>%html([wapp-debug-env])</pre>
      }
    }
    proc wapp-page-broccoli.gif {} {
      wapp-mimetype image/gif
      wapp-cache-control max-age=3600
      wapp-unsafe [binary decode base64 {
        R0lGODlhIAAgAPMAAAAAAAAiAAAzMwBEAABVAABmMwCZMzPMM2bMM5nMM5nMmZn/
        mczMmcz/mQAAAAAAACH5BAEAAA4ALAAAAAAgACAAAAT+0MlJXbmF1M35VUcojNJI
        dh5YKEbRmqthAABaFaFsKG4hxJhCzSbBxXSGgYD1wQw7mENLd1FOMa3nZhUauFoY
        K/YioEEP4WB1pB4NtJMMgTCoe3NWg2lfh68SCSEHP2hkYD4yPgJ9FFwGUkiHij87
        ZF5vjQmPO4kuOZCIPYsFmEUgkIlJOVcXAS8DSVoxB0xgA6hqAZaksiCpPThghwO6
        i0kBvb9BU8KkASPHfrXAF4VqSgAGAbpwDgRSaqQXrLwDCF5CG9/hpJKkb17n6RwA
        18To7whJX0k2NHYjtgXoAwCWPgMM+hEBIFDguDrjZCBIOICIg4J27Lg4aGCBPn0/
        FS1itJdNX4OPChditGOmpIGTMkJavEjDzASXMFPO7IAT5M6FBvQtiPnTX9CjdYqi
        cFlgoNKlLbbJfLqh5pAIADs=
      }]
    }
    wapp-start $argv

This application is the same as the previous except that it adds the
"broccoli.gif" image on the main "Hello, World" page.  The image file is
a separate resource, which is provided by the new "wapp-page-broccoli.gif"
proc.  The image is a GIF which has been encoded using base64 so that
it can be put into an text TCL script.  The "[binary decode base64 ...]"
command is used to convert the image back into binary before returning
it.

Other resources might be added using procs like "wapp-page-style.css"
or "wapp-page-script.js".

3.0 General Structure Of A Wapp Application
-------------------------------------------

Wapp applications all follow the same basic template:

>
    package require wapp;
    proc wapp-page-XXXXX {} {
      # code to generate page XXXXX
    }
    proc wapp-page-YYYYY {} {
      # code to generate page YYYYY
    }
    proc wapp-default {} {
      # code to generate any page not otherwise
      # covered by wapp-page-* procs
    }
    wapp-start $argv

The application script first loads the Wapp code itself using
the "package require" at the top.  (Some applications may choose
to substitute "source wapp.tcl" to accomplish the same thing.)
Next the application defines various procs that will generate the
replies to HTTP requests.  Different procs are invoked based on the
first element of the URI past the Wapp script name.  Finally,
the "wapp-start" routine is called to start Wapp running.  The
"wapp-start" routine never returns (or in the case of CGI, it only
returns after the HTTP request has been completely processed), 
so it should be the very last command in the application script.

3.1 Wapp Applications As Model-View-Controller
----------------------------------------------

If you are accustomed to thinking of web applications using the
Model-View-Controller (MVC) design pattern, Wapp supports that
point of view.  A basic template for an MVC Wapp application
is like this:

>
    package require wapp;
    # procs to implement the model go here
    proc wapp-page-XXXXX {} {
      # code to implement controller for XXXXX
      # code to implement view for XXXXX
    }
    proc wapp-page-YYYYY {} {
      # code to implement controller for YYYYY
      # code to implement view for YYYYY
    }
    proc wapp-default {} {
      # code to implement controller for all other pages
      # code to implement view for all other pages
    }
    wapp-start $argv

The controller and view portions of each page need not be coded
together into the same proc.  They can each be sub-procs that
are invoked from the main proc, if separating the functions make
code clearer.

So Wapp does support MVC, but without a lot of complex
machinary and syntax.
|





|


|
|
|
|

|

|


|
|


|
|



|

|






|









|















|



|








|
|
|

|




|
|

|

|
|

|





|

|



|
|
|
|

|



|
|
|
|

|

|

|


|
|

|









|

|
|



|
|



|
|
|
|

|



|
|
|
|
|


|

|












|
|
|
|

|




|
|
|
|
|


|
|
|
|











|



|





|
|

|


|


|
|


|


|

|

|

|

|


|
|
|



|



|
|



|

|



|



|



|






|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
Introducing To Writing W3 Applications
========================================

1.0 Hello World
---------------

W3 applications are easy to develop.  A hello-world program is as follows:

>
    #!/usr/bin/w3tclsh
    package require w3
    proc w3-default {} {
       w3-subst {<h1>Hello, World!</h1>\n}
    }
    w3-start $::argv

Every W3 application defines one or more procedures that accept HTTP
requests and generate appropriate replies.
For an HTTP request where the initial portion of the URI path is "abcde", the
procedure named "w3-page-abcde" will be invoked to construct the reply.
If no such procedure exists, "w3-default" is invoked instead.  The latter
technique is used for the hello-world example above.

The hello-world example generates the reply using a single call to the "w3-subst"
command.  Each "w3-subst" command appends new text to the reply, applying
various substitutions as it goes.  The only substitution in this example is
the \\n at the end of the line.

The "w3-start" command starts up the application.

1.1 Running A W3 Application
------------------------------

To run this application, copy the code above into a file named "main.tcl"
and then enter the following command:

>
    w3tclsh main.tcl

That command will start up a web-server bound to the loopback
IP address, then launch a web-browser pointing at that web-server.
The result is that the "Hello, World!" page will automatically
appear in your web browser.

To run this same program as a traditional web-server on TCP port 8080, enter:

>
    w3tclsh main.tcl --server 8080

Here the built-in web-server listens on all IP addresses and so the
web page is available on other machines.  But the web-browser is not
automatically started in this case, so you will have to manually enter
"http://localhost:8080/" into your web-browser in order to see the page.

To run this program as CGI, put the main.tcl script in your web-servers
file hierarchy, in the appropriate place for CGI scripts, and make any
other web-server specific configuration changes so that the web-server
understands that the main.tcl file is a CGI script.  Then point your
web-browser at that script.

Run the hello-world program as SCGI like this:

>
    w3tclsh main.tcl --scgi 9000

Then configure your web-server to send SCGI requests to TCP port 9000
for some specific URI, and point your web-browser at that URI.  By
default, the web-server must be on the same machine as the w3 script.
The --scgi option only accepts SCGI requests from IP address 127.0.0.1.
If your webserver is running on a different machine, use the --remote-scgi
option instead, probably with a --fromip option to specify the IP address
of the machine that is running the webserver.

1.2 Using Plain Old Tclsh
-------------------------

W3 applications are pure TCL code.  You can run them using an ordinary
"tclsh" command if desired, instead of the "w3tclsh" shown above.  We
normally use "w3tclsh" for the following reasons:

   +  W3tclsh is statically linked, so there is never a worry about
      having the right shared libraries on hand.  This is particularly
      important if the application will ultimately be deployed into a
      chroot jail.

   +  W3tclsh has SQLite built-in and SQLite turns out to be very
      useful for the kinds of small applications where W3 excels.

   +  W3tclsh knows how to process "package require w3".  If you
      run with ordinary tclsh, you might need to change the 
      "package require w3" into "source w3.tcl" and ship the separate
      "w3.tcl" script together with your application.

We prefer to use w3tclsh and w3tclsh is shown in all of the examples.
But ordinary "tclsh" will work in the examples too.

2.0 Longer Examples
-------------------

W3 keeps track of various [parameters](params.md) that describe
each HTTP request.  Those parameters are accessible using routines
like "w3-param _NAME_"
The following sample program gives some examples:

>
    package require w3
    proc w3-default {} {
      set B [w3-param BASE_URL]
      w3-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>W3
        Environment</a></p>
      }
    }
    proc w3-page-env {} {
      w3-allow-xorigin-params
      w3-subst {<h1>W3 Environment</h1>\n<pre>\n}
      foreach var [lsort [w3-param-list]] {
        if {[string index $var 0]=="."} continue
        w3-subst {%html($var) = %html([list [w3-param $var]])\n}
      }
      w3-subst {</pre>\n}
    }
    w3-start $argv

In this application, the default "Hello, World!" page has been extended
with a hyperlink to the /env page.  The "w3-subst" command has been
replaced by "w3-trim", which works the same way with the addition that
it removes surplus whitespace from the left margin, so that the generated
HTML text does not come out indented.  The "w3-trim" and "w3-subst"
commands in this example use "%html(...)" substitutions.  The "..." argument 
is expanded using the usual TCL rules, but then the result is escaped so
that it is safe to include in an HTML document.  Other supported
substitutions are "%url(...)" for
URLs on the href= and src= attributes of HTML entities, "%qp(...)" for
query parameters, "%string(...)" for string literals within javascript,
and "%unsafe(...)" for direct literal substitution.  As its name implies,
the %unsafe() substitution should be avoided whenever possible.

The /env page is implemented by the "w3-page-env" proc.  This proc
generates HTML that describes all of the query parameters. Parameter names
that begin with "." are for internal use by W3 and are skipped
for this display.  Notice the use of "w3-subst" to safely escape text
for inclusion in an HTML document.

The printing of all the parameters as is done by the /env page turns
out to be so useful that there is a special "w3-debug-env" command
to render the text for us.  Using "w3-debug-env", the program
above can be simplified to the following:

>
    package require w3
    proc w3-default {} {
      set B [w3-param BASE_URL]
      w3-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>W3
        Environment</a></p>
      }
    }
    proc w3-page-env {} {
      w3-allow-xorigin-params
      w3-trim {
        <h1>W3 Environment</h1>\n<pre>
        <pre>%html([w3-debug-env])</pre>
      }
    }
    w3-start $argv

Many W3 applications contain an /env page for debugging and
trouble-shooting purpose.  Examples:
<https://sqlite.org/src/ext/checklist/top/env> and
<https://sqlite.org/search?env=1>


2.1 Binary Resources
--------------------

Here is another variation on the same "hello, world" program that adds an
image to the main page:

>
    package require w3
    proc w3-default {} {
      set B [w3-param BASE_URL]
      w3-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>W3
        Environment</a></p>
        <p>Broccoli: <img src='broccoli.gif'></p>
      }
    }
    proc w3-page-env {} {
      w3-allow-xorigin-params
      w3-trim {
        <h1>W3 Environment</h1>\n<pre>
        <pre>%html([w3-debug-env])</pre>
      }
    }
    proc w3-page-broccoli.gif {} {
      w3-mimetype image/gif
      w3-cache-control max-age=3600
      w3-unsafe [binary decode base64 {
        R0lGODlhIAAgAPMAAAAAAAAiAAAzMwBEAABVAABmMwCZMzPMM2bMM5nMM5nMmZn/
        mczMmcz/mQAAAAAAACH5BAEAAA4ALAAAAAAgACAAAAT+0MlJXbmF1M35VUcojNJI
        dh5YKEbRmqthAABaFaFsKG4hxJhCzSbBxXSGgYD1wQw7mENLd1FOMa3nZhUauFoY
        K/YioEEP4WB1pB4NtJMMgTCoe3NWg2lfh68SCSEHP2hkYD4yPgJ9FFwGUkiHij87
        ZF5vjQmPO4kuOZCIPYsFmEUgkIlJOVcXAS8DSVoxB0xgA6hqAZaksiCpPThghwO6
        i0kBvb9BU8KkASPHfrXAF4VqSgAGAbpwDgRSaqQXrLwDCF5CG9/hpJKkb17n6RwA
        18To7whJX0k2NHYjtgXoAwCWPgMM+hEBIFDguDrjZCBIOICIg4J27Lg4aGCBPn0/
        FS1itJdNX4OPChditGOmpIGTMkJavEjDzASXMFPO7IAT5M6FBvQtiPnTX9CjdYqi
        cFlgoNKlLbbJfLqh5pAIADs=
      }]
    }
    w3-start $argv

This application is the same as the previous except that it adds the
"broccoli.gif" image on the main "Hello, World" page.  The image file is
a separate resource, which is provided by the new "w3-page-broccoli.gif"
proc.  The image is a GIF which has been encoded using base64 so that
it can be put into an text TCL script.  The "[binary decode base64 ...]"
command is used to convert the image back into binary before returning
it.

Other resources might be added using procs like "w3-page-style.css"
or "w3-page-script.js".

3.0 General Structure Of A W3 Application
-------------------------------------------

W3 applications all follow the same basic template:

>
    package require w3;
    proc w3-page-XXXXX {} {
      # code to generate page XXXXX
    }
    proc w3-page-YYYYY {} {
      # code to generate page YYYYY
    }
    proc w3-default {} {
      # code to generate any page not otherwise
      # covered by w3-page-* procs
    }
    w3-start $argv

The application script first loads the W3 code itself using
the "package require" at the top.  (Some applications may choose
to substitute "source w3.tcl" to accomplish the same thing.)
Next the application defines various procs that will generate the
replies to HTTP requests.  Different procs are invoked based on the
first element of the URI past the W3 script name.  Finally,
the "w3-start" routine is called to start W3 running.  The
"w3-start" routine never returns (or in the case of CGI, it only
returns after the HTTP request has been completely processed), 
so it should be the very last command in the application script.

3.1 W3 Applications As Model-View-Controller
----------------------------------------------

If you are accustomed to thinking of web applications using the
Model-View-Controller (MVC) design pattern, W3 supports that
point of view.  A basic template for an MVC W3 application
is like this:

>
    package require w3;
    # procs to implement the model go here
    proc w3-page-XXXXX {} {
      # code to implement controller for XXXXX
      # code to implement view for XXXXX
    }
    proc w3-page-YYYYY {} {
      # code to implement controller for YYYYY
      # code to implement view for YYYYY
    }
    proc w3-default {} {
      # code to implement controller for all other pages
      # code to implement view for all other pages
    }
    w3-start $argv

The controller and view portions of each page need not be coded
together into the same proc.  They can each be sub-procs that
are invoked from the main proc, if separating the functions make
code clearer.

So W3 does support MVC, but without a lot of complex
machinary and syntax.