os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/tests/httpd
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
#
sl@0
     2
# The httpd_ procedures implement a stub http server.
sl@0
     3
#
sl@0
     4
# Copyright (c) 1997-1998 Sun Microsystems, Inc.
sl@0
     5
# Copyright (c) 1999-2000 Scriptics Corporation
sl@0
     6
#
sl@0
     7
# See the file "license.terms" for information on usage and redistribution
sl@0
     8
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
     9
#
sl@0
    10
# SCCS: @(#) httpd 1.2 98/02/20 14:51:59
sl@0
    11
sl@0
    12
#set httpLog 1
sl@0
    13
sl@0
    14
proc httpd_init {{port 8015}} {
sl@0
    15
    socket -server httpdAccept $port
sl@0
    16
}
sl@0
    17
proc httpd_log {args} {
sl@0
    18
    global httpLog
sl@0
    19
    if {[info exists httpLog] && $httpLog} {
sl@0
    20
	puts stderr "httpd: [join $args { }]"
sl@0
    21
    }
sl@0
    22
}
sl@0
    23
array set httpdErrors {
sl@0
    24
    204 {No Content}
sl@0
    25
    400 {Bad Request}
sl@0
    26
    401 {Authorization Required}
sl@0
    27
    404 {Not Found}
sl@0
    28
    503 {Service Unavailable}
sl@0
    29
    504 {Service Temporarily Unavailable}
sl@0
    30
    }
sl@0
    31
sl@0
    32
proc httpdError {sock code args} {
sl@0
    33
    global httpdErrors
sl@0
    34
    puts $sock "$code $httpdErrors($code)"
sl@0
    35
    httpd_log "error: [join $args { }]"
sl@0
    36
}
sl@0
    37
proc httpdAccept {newsock ipaddr port} {
sl@0
    38
    global httpd
sl@0
    39
    upvar #0 httpd$newsock data
sl@0
    40
sl@0
    41
    fconfigure $newsock -blocking 0 -translation {auto crlf}
sl@0
    42
    httpd_log $newsock Connect $ipaddr $port
sl@0
    43
    set data(ipaddr) $ipaddr
sl@0
    44
    fileevent $newsock readable [list httpdRead $newsock]
sl@0
    45
}
sl@0
    46
sl@0
    47
# read data from a client request
sl@0
    48
sl@0
    49
proc httpdRead { sock } {
sl@0
    50
    upvar #0 httpd$sock data
sl@0
    51
sl@0
    52
    if {[eof $sock]} {
sl@0
    53
	set readCount -1
sl@0
    54
    } elseif {![info exists data(state)]} {
sl@0
    55
sl@0
    56
	# Read the protocol line and parse out the URL and query
sl@0
    57
sl@0
    58
	set readCount [gets $sock line]
sl@0
    59
	if [regexp {(POST|GET|HEAD) ([^?]+)\??([^ ]*) HTTP/(1.[01])} \
sl@0
    60
		$line x data(proto) data(url) data(query) data(httpversion)] {
sl@0
    61
	    set data(state) mime
sl@0
    62
	    httpd_log $sock Query $line
sl@0
    63
	} else {
sl@0
    64
	    httpdError $sock 400
sl@0
    65
	    httpd_log $sock Error "bad first line:$line"
sl@0
    66
	    httpdSockDone $sock
sl@0
    67
	}
sl@0
    68
	return
sl@0
    69
    } elseif {$data(state) == "mime"} {
sl@0
    70
sl@0
    71
	# Read the HTTP headers
sl@0
    72
sl@0
    73
	set readCount [gets $sock line]
sl@0
    74
    } elseif {$data(state) == "query"} {
sl@0
    75
sl@0
    76
	# Read the query data
sl@0
    77
sl@0
    78
	if {![info exists data(length_orig)]} {
sl@0
    79
	    set data(length_orig) $data(length)
sl@0
    80
	}
sl@0
    81
	set line [read $sock $data(length)]
sl@0
    82
	set readCount [string length $line]
sl@0
    83
	incr data(length) -$readCount
sl@0
    84
    }
sl@0
    85
sl@0
    86
    # string compare $readCount 0 maps -1 to -1, 0 to 0, and > 0 to 1
sl@0
    87
sl@0
    88
    set state [string compare $readCount 0],$data(state),$data(proto)
sl@0
    89
    httpd_log $sock $state
sl@0
    90
    switch -- $state {
sl@0
    91
	-1,mime,HEAD	-
sl@0
    92
	-1,mime,GET	-
sl@0
    93
	-1,mime,POST	{
sl@0
    94
	    # gets would block
sl@0
    95
	    return
sl@0
    96
	}
sl@0
    97
	0,mime,HEAD	-
sl@0
    98
	0,mime,GET	-
sl@0
    99
	0,query,POST	{ 
sl@0
   100
	    # Empty line at end of headers,
sl@0
   101
	    # or eof after query data
sl@0
   102
	    httpdRespond $sock
sl@0
   103
	}
sl@0
   104
	0,mime,POST	{
sl@0
   105
	    # Empty line between headers and query data
sl@0
   106
	    if {![info exists data(mime,content-length)]} {
sl@0
   107
		httpd_log $sock Error "No Content-Length for POST"
sl@0
   108
		httpdError $sock 400
sl@0
   109
		httpdSockDone $sock
sl@0
   110
	    } else {
sl@0
   111
		set data(state) query
sl@0
   112
		set data(length) $data(mime,content-length)
sl@0
   113
sl@0
   114
		# Special case to simulate servers that respond
sl@0
   115
		# without reading the post data.
sl@0
   116
sl@0
   117
		if {[string match *droppost* $data(url)]} {
sl@0
   118
		    fileevent $sock readable {}
sl@0
   119
		    httpdRespond $sock
sl@0
   120
		}
sl@0
   121
	    }
sl@0
   122
	}
sl@0
   123
	1,mime,HEAD	-
sl@0
   124
	1,mime,POST	-
sl@0
   125
	1,mime,GET	{
sl@0
   126
	    # A line of HTTP headers
sl@0
   127
	    if {[regexp {([^:]+):[ 	]*(.*)}  $line dummy key value]} {
sl@0
   128
		set data(mime,[string tolower $key]) $value
sl@0
   129
	    }
sl@0
   130
	}
sl@0
   131
	-1,query,POST	{
sl@0
   132
	    httpd_log $sock Error "unexpected eof on <$data(url)> request"
sl@0
   133
	    httpdError $sock 400
sl@0
   134
	    httpdSockDone $sock
sl@0
   135
	}
sl@0
   136
	1,query,POST	{
sl@0
   137
	    append data(query) $line
sl@0
   138
	    if {$data(length) <= 0} {
sl@0
   139
		set data(length) $data(length_orig)
sl@0
   140
		httpdRespond $sock
sl@0
   141
	    }
sl@0
   142
	}
sl@0
   143
	default {
sl@0
   144
	    if {[eof $sock]} {
sl@0
   145
		httpd_log $sock Error "unexpected eof on <$data(url)> request"
sl@0
   146
	    } else {
sl@0
   147
		httpd_log $sock Error "unhandled state <$state> fetching <$data(url)>"
sl@0
   148
	    }
sl@0
   149
	    httpdError $sock 404
sl@0
   150
	    httpdSockDone $sock
sl@0
   151
	}
sl@0
   152
    }
sl@0
   153
}
sl@0
   154
proc httpdSockDone { sock } {
sl@0
   155
    upvar #0 httpd$sock data
sl@0
   156
    unset data
sl@0
   157
    catch {close $sock}
sl@0
   158
}
sl@0
   159
sl@0
   160
# Respond to the query.
sl@0
   161
sl@0
   162
proc httpdRespond { sock } {
sl@0
   163
    global httpd bindata port
sl@0
   164
    upvar #0 httpd$sock data
sl@0
   165
sl@0
   166
    switch -glob -- $data(url) {
sl@0
   167
	*binary* {
sl@0
   168
	    set html "$bindata[info hostname]:$port$data(url)"
sl@0
   169
	    set type application/octet-stream
sl@0
   170
	}
sl@0
   171
	*post* {
sl@0
   172
	    set html "Got [string length $data(query)] bytes"
sl@0
   173
	    set type text/plain
sl@0
   174
	}
sl@0
   175
	default {
sl@0
   176
	    set type text/html
sl@0
   177
sl@0
   178
	    set html "<html><head><title>HTTP/1.0 TEST</title></head><body>
sl@0
   179
<h1>Hello, World!</h1>
sl@0
   180
<h2>$data(proto) $data(url)</h2>
sl@0
   181
"
sl@0
   182
	    if {[info exists data(query)] && [string length $data(query)]} {
sl@0
   183
		append html "<h2>Query</h2>\n<dl>\n"
sl@0
   184
		foreach {key value} [split $data(query) &=] {
sl@0
   185
		    append html "<dt>$key<dd>$value\n"
sl@0
   186
		    if {$key == "timeout"} {
sl@0
   187
			after $value	;# pause
sl@0
   188
		    }
sl@0
   189
		}
sl@0
   190
		append html </dl>\n
sl@0
   191
	    }
sl@0
   192
	    append html </body></html>
sl@0
   193
	}
sl@0
   194
    }
sl@0
   195
    
sl@0
   196
    # Catch errors from premature client closes
sl@0
   197
sl@0
   198
    catch {
sl@0
   199
	if {$data(proto) == "HEAD"} {
sl@0
   200
	    puts $sock "HTTP/1.0 200 OK"
sl@0
   201
	} else {
sl@0
   202
	    puts $sock "HTTP/1.0 200 Data follows"
sl@0
   203
	}
sl@0
   204
	puts $sock "Date: [clock format [clock clicks]]"
sl@0
   205
	puts $sock "Content-Type: $type"
sl@0
   206
	puts $sock "Content-Length: [string length $html]"
sl@0
   207
	puts $sock ""
sl@0
   208
	flush $sock
sl@0
   209
	if {$data(proto) != "HEAD"} {
sl@0
   210
	    fconfigure $sock -translation binary
sl@0
   211
	    puts -nonewline $sock $html
sl@0
   212
	}
sl@0
   213
    }
sl@0
   214
    httpd_log $sock Done ""
sl@0
   215
    httpdSockDone $sock
sl@0
   216
}
sl@0
   217
sl@0
   218