Check-in [c62e5a1b5d]

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

Overview
Comment:Incorporate patch for HTTP/1.0 and connection: close from andrewsh. Reference http://wiki.tcl.tk/_/revision?N=27382&V=54#pagetoc0aa08018 for discussion.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c62e5a1b5dea564f754b83fecb0b2ded5da03520
User & Date: andy 2014-04-21 00:01:59
Context
2014-05-02
21:14
Correct HTTP/1.1 comparison per comment from andrewsh. check-in: 6dc367091c user: andy tags: trunk
2014-04-21
00:01
Incorporate patch for HTTP/1.0 and connection: close from andrewsh. Reference http://wiki.tcl.tk/_/revision?N=27382&V=54#pagetoc0aa08018 for discussion. check-in: c62e5a1b5d user: andy tags: trunk
2012-04-13
16:50
Friday the Thirteenth special edition

Source, announcement.

Only two things are fixed in this version.

  • Quote ' (apostrophe) as ' in HTML attributes.
  • Automatically focus the entry widget when using the non-console Tk command interface.
  • Bump version number.
check-in: dc124f9048 user: andy tags: trunk, version-0.4
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to wibble.tcl.

1
2


3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env tclsh
# Wibble - a pure-Tcl Web server.  http://wiki.tcl.tk/23626


# Copyright 2012 Andy Goth.  mailto/andrew.m.goth/at/gmail/dot/com
# Available under the Tcl/Tk license.  http://tcl.tk/software/tcltk/license.html

package require Tcl 8.6
package provide wibble 0.4

# Define the wibble namespace.
namespace eval ::wibble {
    variable zonehandlers
}

# ============================== zone handlers ================================

|
>
>
|



<







1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
#!/usr/bin/env tclsh
# Wibble - a pure-Tcl Web server.
# Code: https://chiselapp.com/user/andy/repository/wibble/timeline
# Discussion: http://wiki.tcl.tk/23626
# Copyright 2009-2014 Andy Goth.  mailto/andrew.m.goth/at/gmail/dot/com
# Available under the Tcl/Tk license.  http://tcl.tk/software/tcltk/license.html

package require Tcl 8.6


# Define the wibble namespace.
namespace eval ::wibble {
    variable zonehandlers
}

# ============================== zone handlers ================================
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
        # Wait for an event.  Maintain each feed's list of suspended coroutines.
        foreach fid $fids {
            dict set feeds $fid suspended $coro $filters
        }
        set result [list [yield]]
        if {[lindex $result 0 0] eq "exception"} {
            set code 7
        } elseif {![llength [lindex $result 0]]} { 
            set result {}
        }
        foreach fid $fids {
            if {[dict exists $feeds $fid]} {
                dict unset feeds $fid suspended $coro
            }
        }







|







786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
        # Wait for an event.  Maintain each feed's list of suspended coroutines.
        foreach fid $fids {
            dict set feeds $fid suspended $coro $filters
        }
        set result [list [yield]]
        if {[lindex $result 0 0] eq "exception"} {
            set code 7
        } elseif {![llength [lindex $result 0]]} {
            set result {}
        }
        foreach fid $fids {
            if {[dict exists $feeds $fid]} {
                dict unset feeds $fid suspended $coro
            }
        }
913
914
915
916
917
918
919

920
921
922
923
924
925
926

    # Receive and parse the first line.  Normalize the path.
    regexp {^\s*(\S*)\s+(\S*)\s+(\S*)} [getline] _ method uri protocol
    regexp {^([^?]*)(\?.*)?$} $uri _ path query
    regsub -all {(?:/|^)\.(?=/|$)} [dehex $path] / path
    while {[regsub {(?:/[^/]*/+|^[^/]*/+|^)\.\.(?=/|$)} $path "" path]} {}
    regsub -all {//+} /$path / path


    # Start building the request structure.
    set request [dict create socket $chan peerhost $peerhost peerport $peerport\
        port $port rawtime [clock seconds] time [clock format [clock seconds]]\
        method $method uri $uri path $path protocol $protocol rawheader {}]

    # Parse the query string.







>







914
915
916
917
918
919
920
921
922
923
924
925
926
927
928

    # Receive and parse the first line.  Normalize the path.
    regexp {^\s*(\S*)\s+(\S*)\s+(\S*)} [getline] _ method uri protocol
    regexp {^([^?]*)(\?.*)?$} $uri _ path query
    regsub -all {(?:/|^)\.(?=/|$)} [dehex $path] / path
    while {[regsub {(?:/[^/]*/+|^[^/]*/+|^)\.\.(?=/|$)} $path "" path]} {}
    regsub -all {//+} /$path / path
    set protocol [string toupper $protocol]

    # Start building the request structure.
    set request [dict create socket $chan peerhost $peerhost peerport $peerport\
        port $port rawtime [clock seconds] time [clock format [clock seconds]]\
        method $method uri $uri path $path protocol $protocol rawheader {}]

    # Parse the query string.
1066
1067
1068
1069
1070
1071
1072






1073
1074
1075
1076
1077
1078
1079
    # Return 501 as default response.
    dict create status 501 header {content-type {"" text/plain charset utf-8}}\
        content "not implemented: [dict get $request uri]\n"
}

# Default send handler: send the response to the client using HTTP.
proc ::wibble::defaultsend {socket request response} {






    # Get the content channel and/or size.
    set size 0
    if {[dict exists $response contentfile]} {
        set size [file size [dict get $response contentfile]]
        if {[dict get $request method] ne "HEAD"} {
            set file [open [dict get $response contentfile]]
            cleanup close_content_file [list chan close $file]







>
>
>
>
>
>







1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
    # Return 501 as default response.
    dict create status 501 header {content-type {"" text/plain charset utf-8}}\
        content "not implemented: [dict get $request uri]\n"
}

# Default send handler: send the response to the client using HTTP.
proc ::wibble::defaultsend {socket request response} {
    # Determine if the connection is persistent.
    set persist [expr {
        [dict get $request protocol] >= "http/1.1"
     && ![string equal -nocase [dict getnull $request header connection] close]
    }]

    # Get the content channel and/or size.
    set size 0
    if {[dict exists $response contentfile]} {
        set size [file size [dict get $response contentfile]]
        if {[dict get $request method] ne "HEAD"} {
            set file [open [dict get $response contentfile]]
            cleanup close_content_file [list chan close $file]
1101
1102
1103
1104
1105
1106
1107
1108





1109
1110
1111
1112
1113
1114
1115
1116
1117
        }
        if {$end eq "" || $end >= $size || $end < $begin} {
            set end [expr {$size - 1}]
        }
        dict set response header content-range "bytes $begin-$end/$size"
    }
    dict set response header content-length [expr {$end - $begin + 1}]






    # Send the response header to the client.
    chan puts $socket "HTTP/1.1 [dict get $response status]"
    chan puts $socket [enheader [dict get $response header]]\n

    # If requested, send the response content to the client.
    if {[dict get $request method] ne "HEAD"} {
        chan configure $socket -translation binary
        if {[info exists file]} {
            # Asynchronously send response content from a channel.








>
>
>
>
>

|







1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
        }
        if {$end eq "" || $end >= $size || $end < $begin} {
            set end [expr {$size - 1}]
        }
        dict set response header content-range "bytes $begin-$end/$size"
    }
    dict set response header content-length [expr {$end - $begin + 1}]

    # Add connection: close if this is not a persistent connection.
    if {!$persist} {
        dict set response header connection close
    }

    # Send the response header to the client.
    chan puts $socket "[dict get $request protocol] [dict get $response status]"
    chan puts $socket [enheader [dict get $response header]]\n

    # If requested, send the response content to the client.
    if {[dict get $request method] ne "HEAD"} {
        chan configure $socket -translation binary
        if {[info exists file]} {
            # Asynchronously send response content from a channel.
1222
1223
1224
1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
1237
1238



1239
1240
1241
1242
1243
1244
1245
    }
    append message "\nerrorinfo: [dict get $options -errorinfo]"
    append message "\n*** INTERNAL SERVER ERROR (END #$errorcount) ***"
    log $message
    if {![dict exists $response nonhttp] && $socket ne ""} {
        catch {
            chan configure $socket -translation crlf
            chan puts $socket "HTTP/1.1 500 Internal Server Error"

            chan puts $socket "Content-Type: text/plain;charset=utf-8"
            chan puts $socket "Content-Length: [string length $message]"
            chan puts $socket "Connection: close"
            chan puts $socket ""
            chan configure $socket -translation lf -encoding utf-8
            chan puts $socket $message
        }
    }
}




# =============================== example code ================================

# Demonstrate Wibble if being run directly.
if {$argv0 eq [info script]} {
    # Guess the root directory.
    set root [file normalize [file dirname [info script]]]







|
>
|
|
|
<





>
>
>







1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246

1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
    }
    append message "\nerrorinfo: [dict get $options -errorinfo]"
    append message "\n*** INTERNAL SERVER ERROR (END #$errorcount) ***"
    log $message
    if {![dict exists $response nonhttp] && $socket ne ""} {
        catch {
            chan configure $socket -translation crlf
            chan puts $socket\
                "[dict get $request protocol] 500 Internal Server Error\
                \ncontent-type: text/plain;charset=utf-8\
                \ncontent-length: [string length $message]\
                \nconnection: close\n"

            chan configure $socket -translation lf -encoding utf-8
            chan puts $socket $message
        }
    }
}

# Wibble has been loaded successfully.
package provide wibble 0.4

# =============================== example code ================================

# Demonstrate Wibble if being run directly.
if {$argv0 eq [info script]} {
    # Guess the root directory.
    set root [file normalize [file dirname [info script]]]