Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/tests/httpd @ 25

Last change on this file since 25 was 25, checked in by landauf, 17 years ago

added tcl to libs

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