Wapp

Check-in [e82121be4d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add wapp-allow-xorigin-params and SAME_ORIGIN. Update the documentation accordingly.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e82121be4d2be5fa96cae2b1a610b67bbdb26e9fb7386d4576031d026b2e5b46
User & Date: drh 2018-01-30 23:46:10.970
Context
2018-01-31
00:19
Add a restrictive default Content Security Policy and provide the wapp-content-security-policy command to change it if necessary. (check-in: 4022bf292d user: drh tags: trunk)
2018-01-30
23:46
Add wapp-allow-xorigin-params and SAME_ORIGIN. Update the documentation accordingly. (check-in: e82121be4d user: drh tags: trunk)
20:36
Update example scripts to remove uses of the ::wapp dict. Improvements to the documentation. (check-in: 5d5c1559d7 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to README.md.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
      wapp-trim {
        <h1>Hello, World!</h1>
        <p>See the <a href='%html($B)/env'>Wapp
        Environment</a></p>
      }
    }
    proc wapp-page-env {} {
      global wapp
      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}
    }







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
      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}
    }
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
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.

4.0 Parameters
--------------------------

To better understand Wapp parameters, try running the previous
sample program, but extend the /env URL with extra path elements and query
parameters.  For example:
<http://localhost:8080/env/longer/path?q1=5&title=hello+world%21>

Notice how the query parameters in the input URL are decoded and become
parameters.  The same thing occurs with POST parameters
and cookies - they are all converted into parameters accessible
using the "wapp-param" interface.






















Wapp also provides parameters that describe the execution environment.
These parameter look like CGI environment variables.  To prevent environment
information from overlapping and overwriting query parameters, all the
environment information uses upper-case names and all query parameters
are required to be lower case.  If an input URL contains an upper-case
query parameter (or POST parameter or cookie), that parameter is silently
omitted.

The following environment parameters are always available:











  +  **HTTP\_HOST**  
     The hostname (or IP address) and port that the client used to create
     the current HTTP request.  This is the first part of the request URL,
     right after the "http://" or "https://".  The format for this value
     is "HOST:PORT".  Examples:  "sqlite.org:80" or "127.0.0.1:32172".

  +  **HTTP\_USER\_AGENT**  
     The name of the web-browser or other client program that generated
     the current HTTP request.

  +  **HTTP\_COOKIE**  
     The values of all cookies in the HTTP header

  +  **HTTPS**  
     If the HTTP request arrived of SSL (via "https://"), then this variable
     has the value "on".  For an unencrypted request ("http://"), this
     variable does not exist.






  +  **REMOTE\_ADDR**  
     The IP address from which the HTTP request originated.

  +  **REMOTE\_PORT**  
     The TCP port from which teh HTTP request originated.

  +  **SCRIPT_NAME**  
     In CGI mode, this is the name of the CGI script in the URL.  In other
     words, this is the initial part of the URL path that identifies the
     CGI script.  For other modes, this variable is an empty string.

  +  **PATH\_INFO**  
     The part of the URL path that follows the SCRIPT\_NAME.  For all modes
     other than CGI, this is exactly the URL pathname, though with the
     query parameters removed.  PATH_INFO begins with a "/".

  +  **REQUEST\_URI**  
     The URL for the inbound request, without the initial "http://" or
     "https://" and without the HTTP\_HOST.  This variable is the same as
     the concatenation of $SCRIPT\_NAME and $PATH\_INFO.

  +  **REQUEST\_METHOD**  
     "GET" or "HEAD" or "POST"

  *  **CONTENT\_LENGTH**  
     The number of bytes of POST data.

  *  **CONTENT\_TYPE**  
     The mimetype of the POST data.  Usually this is
     application/x-www-form-urlencoded.


All of the above are standard CGI environment values.
The following are supplemental environment parameters are added by Wapp:


  *  **CONTENT**  
     The raw POST data text.

  +  **BASE\_URL**  
     The text of the request URL through the SCRIPT\_NAME.  This value can
     be prepended to hyperlinks to ensure that the correct page is reached by
     those hyperlinks.




  +  **PATH\_HEAD**  
     The first element in the PATH\_INFO.  The value of PATH\_HEAD is used to
     select one of the "wapp-page-XXXXX" commands to run in order to generate
     the output web page.

  +  **PATH\_TAIL**  
     All of PATH\_INFO that follows PATH\_HEAD.










  +  **SELF\_URL**  
     The URL for the current page, stripped of query parameter. This is
     useful for filling in the action= attribute of forms.


### 4.1 URL Parsing Example








|











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>
>
>
>
>
>
>
>
>










<
<
<





>
>
>
>
>






|
<
<
<
|
<
<
<
<






|
|
|
<
<
|
<
<
<






<
<
<





>
>
>








>
>
>
>
>
>
>
>
>







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
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.

4.0 Parameters
--------------

To better understand Wapp parameters, try running the previous
sample program, but extend the /env URL with extra path elements and query
parameters.  For example:
<http://localhost:8080/env/longer/path?q1=5&title=hello+world%21>

Notice how the query parameters in the input URL are decoded and become
parameters.  The same thing occurs with POST parameters
and cookies - they are all converted into parameters accessible
using the "wapp-param" interface.

4.1 Security By Default
-----------------------

For security reasons, this automatic decoding of GET and POST parameters
only occurs if inbound request is from the "same origin" or if the
special "wapp-allow-xorigin-params" interface is called.  An inbound
request is from the same origin if it is in response to clicking on a
hyperlink or form on a page that was generated by the same website.
Manually typing in a URL does not constitute the "same origin".  Hence,
in the example above the "wapp-allow-xorigin-params" interface is used
so that you can manually extend the URL to add new query parameters.

If query parameters can have side effects, then you should omit the
wapp-allow-xorigin-params call.  Only invoke wapp-allow-xorigin-params
for web pages that only query information.  Do not invoke 
wapp-allow-xorigin-params on pages where the parameters can be used
to change server-side state.

4.2 Environment Parameters
--------------------------

Wapp also provides parameters that describe the execution environment.
These parameter look like CGI environment variables.  To prevent environment
information from overlapping and overwriting query parameters, all the
environment information uses upper-case names and all query parameters
are required to be lower case.  If an input URL contains an upper-case
query parameter (or POST parameter or cookie), that parameter is silently
omitted.

The following environment parameters are always available:

  +  **CONTENT\_LENGTH**  
     The number of bytes of POST data.

  +  **CONTENT\_TYPE**  
     The mimetype of the POST data.  Usually this is
     application/x-www-form-urlencoded.

  +  **HTTP\_COOKIE**  
     The values of all cookies in the HTTP header

  +  **HTTP\_HOST**  
     The hostname (or IP address) and port that the client used to create
     the current HTTP request.  This is the first part of the request URL,
     right after the "http://" or "https://".  The format for this value
     is "HOST:PORT".  Examples:  "sqlite.org:80" or "127.0.0.1:32172".

  +  **HTTP\_USER\_AGENT**  
     The name of the web-browser or other client program that generated
     the current HTTP request.




  +  **HTTPS**  
     If the HTTP request arrived of SSL (via "https://"), then this variable
     has the value "on".  For an unencrypted request ("http://"), this
     variable does not exist.

  +  **PATH\_INFO**  
     The part of the URL path that follows the SCRIPT\_NAME.  For all modes
     other than CGI, this is exactly the URL pathname, though with the
     query parameters removed.  PATH_INFO begins with a "/".

  +  **REMOTE\_ADDR**  
     The IP address from which the HTTP request originated.

  +  **REMOTE\_PORT**  
     The TCP port from which teh HTTP request originated.

  +  **REQUEST\_METHOD**  



     "GET" or "HEAD" or "POST"





  +  **REQUEST\_URI**  
     The URL for the inbound request, without the initial "http://" or
     "https://" and without the HTTP\_HOST.  This variable is the same as
     the concatenation of $SCRIPT\_NAME and $PATH\_INFO.

  +  **SCRIPT_NAME**  
     In CGI mode, this is the name of the CGI script in the URL.  In other
     words, this is the initial part of the URL path that identifies the


     CGI script.  For other modes, this variable is an empty string.





All of the above are standard CGI environment values.
The following are supplemental environment parameters are added by Wapp:





  +  **BASE\_URL**  
     The text of the request URL through the SCRIPT\_NAME.  This value can
     be prepended to hyperlinks to ensure that the correct page is reached by
     those hyperlinks.

  +  **CONTENT**  
     The raw POST data text.

  +  **PATH\_HEAD**  
     The first element in the PATH\_INFO.  The value of PATH\_HEAD is used to
     select one of the "wapp-page-XXXXX" commands to run in order to generate
     the output web page.

  +  **PATH\_TAIL**  
     All of PATH\_INFO that follows PATH\_HEAD.

  +  **SAME\_ORIGIN**  
     This value is either "1" or "0" depending on whether the current HTTP
     request is a follow-on to another request from this same website or not.
     Query parameters and POST parameters are usually only decoded and added
     to Wapp's parameter list if SAME\_ORIGIN is 1.  If a webpage implemented
     by Wapp needs access to query parameters for a cross-origin request, then
     it should invoke the "wapp-allow-xorigin-params" interface to explicitly
     signal that cross-origin parameters are safe for that page.

  +  **SELF\_URL**  
     The URL for the current page, stripped of query parameter. This is
     useful for filling in the action= attribute of forms.


### 4.1 URL Parsing Example

297
298
299
300
301
302
303








304
305
306
307
308
309
310
     currentn request.

  +  **wapp-param-list** _NAME_  
     Return a TCL list containing the names of all parameters for the current
     request.  Note that there are several parameters that Wapp uses
     internally.  Those internal-use parameters all have names that begin
     with ".".









  +  **wapp-mimetype** _MIMETYPE_  
     Set the MIME-type for the generated web page.  The default is "text/html".

  +  **wapp-reply-code** _CODE_  
     Set the reply-code for the HTTP request.  The default is "200 Ok".








>
>
>
>
>
>
>
>







327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
     currentn request.

  +  **wapp-param-list** _NAME_  
     Return a TCL list containing the names of all parameters for the current
     request.  Note that there are several parameters that Wapp uses
     internally.  Those internal-use parameters all have names that begin
     with ".".

  +  **wapp-allow-xorigin-params**  
     Query parameters and POST parameters are usually only parsed and added
     to the set of parameters available to "wapp-param" for same-origin
     requests.  This restriction helps prevent cross-site request forgery
     (CSRF) attacks.  Query-only web pages for which it is safe to accept
     cross-site query parameters can invoke this routine to cause query
     parameters to be decoded.

  +  **wapp-mimetype** _MIMETYPE_  
     Set the MIME-type for the generated web page.  The default is "text/html".

  +  **wapp-reply-code** _CODE_  
     Set the reply-code for the HTTP request.  The default is "200 Ok".

438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
The POST data parser for Wapp currently only understands
application/x-www-form-urlencoded content.  Wapp does not (currently)
have a decoder for multipart/form-data content.  A multipart/form-data
decoder might be added in the future.  Or, individual applications can
implement their own multipart/form-data decoder using the raw POST data
held in the CONTENT parameter.

As a defense against
[Cross-Site Request Forgery (CSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery)
attacks, Wapp refuses to parse any POST query parameters unless there
is a Referer entry in the header that matches the request URI.  In other
words, Wapp assumes that POST requests originate from itself and any other
POST requests are treated as an attack and ignored.

8.0 Design Rules
----------------

All global procs and variables used by Wapp begin with the four character
prefix "wapp".  Procs and variable intended for internal use begin with
the seven character prefix "wappInt".







<
<
<
<
<
<
<






476
477
478
479
480
481
482







483
484
485
486
487
488
The POST data parser for Wapp currently only understands
application/x-www-form-urlencoded content.  Wapp does not (currently)
have a decoder for multipart/form-data content.  A multipart/form-data
decoder might be added in the future.  Or, individual applications can
implement their own multipart/form-data decoder using the raw POST data
held in the CONTENT parameter.








8.0 Design Rules
----------------

All global procs and variables used by Wapp begin with the four character
prefix "wapp".  Procs and variable intended for internal use begin with
the seven character prefix "wappInt".
Changes to examples/env.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
# This script is a template used for testing.
#
# After making modifications to this script to test out bits of HTML
# (or not - the script works fine as it is), invoke the script using
#
#   wapptclsh env.tcl
#
# All web pages show the Wapp execution environment, which includes
# CGI-line environment variables, decoded query and POST parameters, and 
# decoded cookies.
#
package require wapp
proc wapp-default {} {

  wapp-trim {
    <h1>Wapp Environment</h1>
    <pre>%html([wapp-debug-env])</pre>
  }
}
wapp-start $argv













>






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This script is a template used for testing.
#
# After making modifications to this script to test out bits of HTML
# (or not - the script works fine as it is), invoke the script using
#
#   wapptclsh env.tcl
#
# All web pages show the Wapp execution environment, which includes
# CGI-line environment variables, decoded query and POST parameters, and 
# decoded cookies.
#
package require wapp
proc wapp-default {} {
  wapp-allow-xorigin-params
  wapp-trim {
    <h1>Wapp Environment</h1>
    <pre>%html([wapp-debug-env])</pre>
  }
}
wapp-start $argv
Changes to test01.tcl.
41
42
43
44
45
46
47

48
49


50
51
52
53
54
55
56
  foreach vname [lsort [uplevel #0 info vars]] {
    set val ???
    catch {set val [set ::$vname]}
    wapp-subst {<li>%html($vname = [list $val])</li>\n}
  }
}
proc wapp-page-env2 {} {

  wapp-trim {
    <h1>Wapp Environment using wapp-debug-env</h1>


    <pre>%html([wapp-debug-env])</pre>
  }
}
proc wapp-page-env {} {
  global wapp
  wapp-set-cookie env-cookie simple
  wapp "<h1>Wapp Environment</h1>\n"







>


>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  foreach vname [lsort [uplevel #0 info vars]] {
    set val ???
    catch {set val [set ::$vname]}
    wapp-subst {<li>%html($vname = [list $val])</li>\n}
  }
}
proc wapp-page-env2 {} {
  wapp-allow-xorigin-params
  wapp-trim {
    <h1>Wapp Environment using wapp-debug-env</h1>
    <p>This page uses wapp-allow-xorigin-params so that new
       query parameters may be added manually to the URL.</p>
    <pre>%html([wapp-debug-env])</pre>
  }
}
proc wapp-page-env {} {
  global wapp
  wapp-set-cookie env-cookie simple
  wapp "<h1>Wapp Environment</h1>\n"
Changes to wapp.tcl.
242
243
244
245
246
247
248

























249
250
251
252
253
254
255
# Return all parameter names that match the GLOB pattern, or all
# names if the GLOB pattern is omitted.
#
proc wapp-param-list {{glob {*}}} {
  global wapp
  return [dict keys $wapp $glob]
}


























# Examine the bodys of all procedures in this program looking for
# unsafe calls to "wapp".  Return a text string containing warnings.
# Return an empty string if all is ok.
#
# This routine is advisory only.  It misses some constructs that are
# dangerous and flags others that are safe.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
# Return all parameter names that match the GLOB pattern, or all
# names if the GLOB pattern is omitted.
#
proc wapp-param-list {{glob {*}}} {
  global wapp
  return [dict keys $wapp $glob]
}

# By default, Wapp does not decode query parameters and POST parameters
# for cross-origin requests.  This is a security restriction, designed to
# help prevent cross-site request forgery (CSRF) attacks.
#
# As a consequence of this restriction, URLs for sites generated by Wapp
# that contain query parameters will not work as URLs found in other
# websites.  You cannot create a link from a second website into a Wapp
# website if the link contains query planner, by default.
#
# Of course, it is sometimes desirable to allow query parameters on external
# links.  For URLs for which this is safe, the application should invoke
# wapp-allow-xorigin-params.  This procedure tells Wapp that it is safe to
# go ahead and decode the query parameters even for cross-site requests.
#
# In other words, for Wapp security is the default setting.  Individual pages
# need to actively disable the cross-site request security if those pages
# are safe for cross-site access.
#
proc wapp-allow-xorigin-params {} {
  global wapp
  if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} {
    wappInt-decode-query-params
  }
}

# Examine the bodys of all procedures in this program looking for
# unsafe calls to "wapp".  Return a text string containing warnings.
# Return an empty string if all is ok.
#
# This routine is advisory only.  It misses some constructs that are
# dangerous and flags others that are safe.
526
527
528
529
530
531
532




































533
534
535
536
537
538
539
      ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING}
      default {set name .hdr:$name}
    }
    dict set W $name $value
  }
  return 0
}





































# Invoke application-supplied methods to generate a reply to
# a single HTTP request.
#
# This routine always runs within [catch], so handle exceptions by
# invoking [error].
#







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
      ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING}
      default {set name .hdr:$name}
    }
    dict set W $name $value
  }
  return 0
}

# Decode the QUERY_STRING parameters from a GET request or the
# application/x-www-form-urlencoded CONTENT from a POST request.
#
# This routine sets the ".qp" element of the ::wapp dict as a signal
# that query parameters have already been decoded.
#
proc wappInt-decode-query-params {} {
  global wapp
  dict set wapp .qp 1
  if {[dict exists $wapp QUERY_STRING]} {
    foreach qterm [split [dict get $wapp QUERY_STRING] &] {
      set qsplit [split $qterm =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][a-z0-9]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  if {[dict exists $wapp CONTENT_TYPE]
   && [dict get $wapp CONTENT_TYPE]=="application/x-www-form-urlencoded"
   && [dict exists $wapp CONTENT]
  } {
    foreach qterm [split [string trim [dict get $wapp CONTENT]] &] {
      set qsplit [split $qterm =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  # To-Do:  Perhaps add support for multipart/form-data decoding.
  # Alternatively, perhaps multipart/form-data decoding can be done
  # by application code using a separate helper function, like
  # "wapp_decode_multipart_formdata" or somesuch.
}

# Invoke application-supplied methods to generate a reply to
# a single HTTP request.
#
# This routine always runs within [catch], so handle exceptions by
# invoking [error].
#
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

619

620
621
622
623
624
625
626
627
628
629
630
631
      set qsplit [split [string trim $qterm] =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  if {[dict exists $wapp QUERY_STRING]} {
    foreach qterm [split [dict get $wapp QUERY_STRING] &] {
      set qsplit [split $qterm =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][a-z0-9]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  # POST data is only decoded if the HTTP_REFERER is from the same
  # application, as a defense against Cross-Site Request Forgery (CSRF)
  # attacks.
  if {[dict exists $wapp CONTENT_TYPE]
   && [dict get $wapp CONTENT_TYPE]=="application/x-www-form-urlencoded"
   && [dict exists $wapp CONTENT]
   && [dict exists $wapp HTTP_REFERER]
   && [string match [dict get $wapp BASE_URL]/* [dict get $wapp HTTP_REFERER]]
  } {
    foreach qterm [split [string trim [dict get $wapp CONTENT]] &] {
      set qsplit [split $qterm =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }

    }

  }
  # To-Do:  Perhaps add support for multipart/form-data decoding.
  # Alternatively, perhaps multipart/form-data decoding can be done
  # by application code using a separate helper function, like
  # "wapp_decode_multipart_formdata" or somesuch.

  # Invoke the application-defined handler procedure for this page
  # request.  If an error occurs while running that procedure, generate
  # an HTTP reply that contains the error message.
  #
  wapp-before-dispatch-hook
  wappInt-trace







<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<


<
|
|
<
|
|
>
|
>

<
<
<
<







649
650
651
652
653
654
655












656



657
658

659
660

661
662
663
664
665
666




667
668
669
670
671
672
673
      set qsplit [split [string trim $qterm] =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }












  if {[dict exists $wapp HTTP_REFERER]



   && [string match [dict get $wapp BASE_URL]/* [dict get $wapp HTTP_REFERER]]
  } {

    set same_origin 1
  } else {

    set same_origin 0
  }
  dict set wapp SAME_ORIGIN $same_origin
  if {$same_origin} {
    wappInt-decode-query-params
  }





  # Invoke the application-defined handler procedure for this page
  # request.  If an error occurs while running that procedure, generate
  # an HTTP reply that contains the error message.
  #
  wapp-before-dispatch-hook
  wappInt-trace