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