]> Cypherpunks repositories - gostls13.git/commitdiff
http: revised http Handler interface
authorStephen Ma <stephenm@golang.org>
Wed, 29 Sep 2010 04:30:12 +0000 (14:30 +1000)
committerStephen Ma <stephenm@golang.org>
Wed, 29 Sep 2010 04:30:12 +0000 (14:30 +1000)
R=rsc
CC=golang-dev
https://golang.org/cl/1993043

src/cmd/godoc/codewalk.go
src/cmd/godoc/godoc.go
src/cmd/godoc/main.go
src/pkg/expvar/expvar.go
src/pkg/http/fs.go
src/pkg/http/pprof/pprof.go
src/pkg/http/server.go
src/pkg/http/status.go
src/pkg/rpc/debug.go
src/pkg/rpc/server.go
src/pkg/websocket/server.go

index 02417bfefbbf14d6e958597a2d3bdf46994766d5..442ba7b1ddccf8edd1dc7bf052ae06d14852c046 100644 (file)
@@ -31,26 +31,26 @@ import (
 
 
 // Handler for /doc/codewalk/ and below.
-func codewalk(c *http.Conn, r *http.Request) {
+func codewalk(w http.ResponseWriter, r *http.Request) {
        relpath := r.URL.Path[len("/doc/codewalk/"):]
        abspath := absolutePath(r.URL.Path[1:], *goroot)
 
        r.ParseForm()
        if f := r.FormValue("fileprint"); f != "" {
-               codewalkFileprint(c, r, f)
+               codewalkFileprint(w, r, f)
                return
        }
 
        // If directory exists, serve list of code walks.
        dir, err := os.Lstat(abspath)
        if err == nil && dir.IsDirectory() {
-               codewalkDir(c, r, relpath, abspath)
+               codewalkDir(w, r, relpath, abspath)
                return
        }
 
        // If file exists, serve using standard file server.
        if err == nil {
-               serveFile(c, r)
+               serveFile(w, r)
                return
        }
 
@@ -59,17 +59,17 @@ func codewalk(c *http.Conn, r *http.Request) {
        cw, err := loadCodewalk(abspath + ".xml")
        if err != nil {
                log.Stderr(err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
        // Canonicalize the path and redirect if changed
-       if redirect(c, r) {
+       if redirect(w, r) {
                return
        }
 
        b := applyTemplate(codewalkHTML, "codewalk", cw)
-       servePage(c, "Codewalk: "+cw.Title, "", "", b)
+       servePage(w, "Codewalk: "+cw.Title, "", "", b)
 }
 
 
@@ -178,7 +178,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
 // codewalkDir serves the codewalk directory listing.
 // It scans the directory for subdirectories or files named *.xml
 // and prepares a table.
-func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
+func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
        type elem struct {
                Name  string
                Title string
@@ -187,7 +187,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
        dir, err := ioutil.ReadDir(abspath)
        if err != nil {
                log.Stderr(err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
        var v vector.Vector
@@ -204,7 +204,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
        }
 
        b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
-       servePage(c, "Codewalks", "", "", b)
+       servePage(w, "Codewalks", "", "", b)
 }
 
 
@@ -214,12 +214,12 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
 // in the response.  This format is used for the middle window pane
 // of the codewalk pages.  It is a separate iframe and does not get
 // the usual godoc HTML wrapper.
-func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
+func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
        abspath := absolutePath(f, *goroot)
        data, err := ioutil.ReadFile(abspath)
        if err != nil {
                log.Stderr(err)
-               serveError(c, r, f, err)
+               serveError(w, r, f, err)
                return
        }
        lo, _ := strconv.Atoi(r.FormValue("lo"))
@@ -243,17 +243,17 @@ func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
                }
        }
 
-       io.WriteString(c, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
-       template.HTMLEscape(c, data[0:mark])
-       io.WriteString(c, "<a name='mark'></a>")
-       template.HTMLEscape(c, data[mark:lo])
+       io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
+       template.HTMLEscape(w, data[0:mark])
+       io.WriteString(w, "<a name='mark'></a>")
+       template.HTMLEscape(w, data[mark:lo])
        if lo < hi {
-               io.WriteString(c, "<div class='codewalkhighlight'>")
-               template.HTMLEscape(c, data[lo:hi])
-               io.WriteString(c, "</div>")
+               io.WriteString(w, "<div class='codewalkhighlight'>")
+               template.HTMLEscape(w, data[lo:hi])
+               io.WriteString(w, "</div>")
        }
-       template.HTMLEscape(c, data[hi:])
-       io.WriteString(c, "</pre>")
+       template.HTMLEscape(w, data[hi:])
+       io.WriteString(w, "</pre>")
 }
 
 
index d85cb024e0dc407379b0affa803548ad859765ab..a101eb24c59467341802d21d15222dcd318b5a60 100644 (file)
@@ -792,7 +792,7 @@ func readTemplates() {
 // ----------------------------------------------------------------------------
 // Generic HTML wrapper
 
-func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
+func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
        type Data struct {
                Title    string
                Subtitle string
@@ -813,15 +813,15 @@ func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
                Content:  content,
        }
 
-       if err := godocHTML.Execute(&d, c); err != nil {
+       if err := godocHTML.Execute(&d, w); err != nil {
                log.Stderrf("godocHTML.Execute: %s", err)
        }
 }
 
 
-func serveText(c *http.Conn, text []byte) {
-       c.SetHeader("Content-Type", "text/plain; charset=utf-8")
-       c.Write(text)
+func serveText(w http.ResponseWriter, text []byte) {
+       w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+       w.Write(text)
 }
 
 
@@ -844,19 +844,19 @@ func extractString(src []byte, rx *regexp.Regexp) (s string) {
 }
 
 
-func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
        // get HTML body contents
        src, err := ioutil.ReadFile(abspath)
        if err != nil {
                log.Stderrf("ioutil.ReadFile: %s", err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
        // if it begins with "<!DOCTYPE " assume it is standalone
        // html that doesn't need the template wrapping.
        if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
-               c.Write(src)
+               w.Write(src)
                return
        }
 
@@ -875,7 +875,7 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
        }
        subtitle := extractString(src, subtitleRx)
 
-       servePage(c, title, subtitle, "", src)
+       servePage(w, title, subtitle, "", src)
 }
 
 
@@ -888,11 +888,11 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
 }
 
 
-func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveGoSource(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
        file, err := parser.ParseFile(abspath, nil, parser.ParseComments)
        if err != nil {
                log.Stderrf("parser.ParseFile: %s", err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
@@ -911,13 +911,13 @@ func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
        info := &SourceInfo{styler.idList(), buf.Bytes()}
 
        contents := applyTemplate(sourceHTML, "sourceHTML", info)
-       servePage(c, "Source file "+relpath, "", "", contents)
+       servePage(w, "Source file "+relpath, "", "", contents)
 }
 
 
-func redirect(c *http.Conn, r *http.Request) (redirected bool) {
+func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
        if canonical := pathutil.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
-               http.Redirect(c, canonical, http.StatusMovedPermanently)
+               http.Redirect(w, r, canonical, http.StatusMovedPermanently)
                redirected = true
        }
        return
@@ -971,11 +971,11 @@ func isTextFile(path string) bool {
 }
 
 
-func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
        src, err := ioutil.ReadFile(abspath)
        if err != nil {
                log.Stderrf("ioutil.ReadFile: %s", err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
@@ -984,19 +984,19 @@ func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
        template.HTMLEscape(&buf, src)
        fmt.Fprintln(&buf, "</pre>")
 
-       servePage(c, "Text file "+relpath, "", "", buf.Bytes())
+       servePage(w, "Text file "+relpath, "", "", buf.Bytes())
 }
 
 
-func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
-       if redirect(c, r) {
+func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+       if redirect(w, r) {
                return
        }
 
        list, err := ioutil.ReadDir(abspath)
        if err != nil {
                log.Stderrf("ioutil.ReadDir: %s", err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
@@ -1007,23 +1007,23 @@ func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
        }
 
        contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
-       servePage(c, "Directory "+relpath, "", "", contents)
+       servePage(w, "Directory "+relpath, "", "", contents)
 }
 
 
-func serveFile(c *http.Conn, r *http.Request) {
+func serveFile(w http.ResponseWriter, r *http.Request) {
        relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
        abspath := absolutePath(relpath, *goroot)
 
        // pick off special cases and hand the rest to the standard file server
        switch r.URL.Path {
        case "/":
-               serveHTMLDoc(c, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
+               serveHTMLDoc(w, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
                return
 
        case "/doc/root.html":
                // hide landing page from its real name
-               http.Redirect(c, "/", http.StatusMovedPermanently)
+               http.Redirect(w, r, "/", http.StatusMovedPermanently)
                return
        }
 
@@ -1032,42 +1032,42 @@ func serveFile(c *http.Conn, r *http.Request) {
                if strings.HasSuffix(abspath, "/index.html") {
                        // We'll show index.html for the directory.
                        // Use the dir/ version as canonical instead of dir/index.html.
-                       http.Redirect(c, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
+                       http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
                        return
                }
-               serveHTMLDoc(c, r, abspath, relpath)
+               serveHTMLDoc(w, r, abspath, relpath)
                return
 
        case ".go":
-               serveGoSource(c, r, abspath, relpath)
+               serveGoSource(w, r, abspath, relpath)
                return
        }
 
        dir, err := os.Lstat(abspath)
        if err != nil {
                log.Stderr(err)
-               serveError(c, r, relpath, err)
+               serveError(w, r, relpath, err)
                return
        }
 
        if dir != nil && dir.IsDirectory() {
-               if redirect(c, r) {
+               if redirect(w, r) {
                        return
                }
                if index := abspath + "/index.html"; isTextFile(index) {
-                       serveHTMLDoc(c, r, index, relativePath(index))
+                       serveHTMLDoc(w, r, index, relativePath(index))
                        return
                }
-               serveDirectory(c, r, abspath, relpath)
+               serveDirectory(w, r, abspath, relpath)
                return
        }
 
        if isTextFile(abspath) {
-               serveTextFile(c, r, abspath, relpath)
+               serveTextFile(w, r, abspath, relpath)
                return
        }
 
-       fileServer.ServeHTTP(c, r)
+       fileServer.ServeHTTP(w, r)
 }
 
 
@@ -1243,8 +1243,8 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
 }
 
 
-func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
-       if redirect(c, r) {
+func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+       if redirect(w, r) {
                return
        }
 
@@ -1257,13 +1257,13 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
        info := h.getPageInfo(abspath, relpath, r.FormValue("p"), mode)
        if info.Err != nil {
                log.Stderr(info.Err)
-               serveError(c, r, relpath, info.Err)
+               serveError(w, r, relpath, info.Err)
                return
        }
 
        if r.FormValue("f") == "text" {
                contents := applyTemplate(packageText, "packageText", info)
-               serveText(c, contents)
+               serveText(w, contents)
                return
        }
 
@@ -1290,7 +1290,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
        }
 
        contents := applyTemplate(packageHTML, "packageHTML", info)
-       servePage(c, title, subtitle, "", contents)
+       servePage(w, title, subtitle, "", contents)
 }
 
 
@@ -1319,13 +1319,13 @@ func lookup(query string) (result SearchResult) {
 }
 
 
-func search(c *http.Conn, r *http.Request) {
+func search(w http.ResponseWriter, r *http.Request) {
        query := strings.TrimSpace(r.FormValue("q"))
        result := lookup(query)
 
        if r.FormValue("f") == "text" {
                contents := applyTemplate(searchText, "searchText", result)
-               serveText(c, contents)
+               serveText(w, contents)
                return
        }
 
@@ -1337,7 +1337,7 @@ func search(c *http.Conn, r *http.Request) {
        }
 
        contents := applyTemplate(searchHTML, "searchHTML", result)
-       servePage(c, title, "", query, contents)
+       servePage(w, title, "", query, contents)
 }
 
 
index c13979968a453f9bf691571f6702d3397d1b3601..4a913a0172dce2cfe782deca44598bd22c30eec1 100644 (file)
@@ -64,14 +64,14 @@ var (
 )
 
 
-func serveError(c *http.Conn, r *http.Request, relpath string, err os.Error) {
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
        contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
-       c.WriteHeader(http.StatusNotFound)
-       servePage(c, "File "+relpath, "", "", contents)
+       w.WriteHeader(http.StatusNotFound)
+       servePage(w, "File "+relpath, "", "", contents)
 }
 
 
-func exec(c *http.Conn, args []string) (status int) {
+func exec(rw http.ResponseWriter, args []string) (status int) {
        r, w, err := os.Pipe()
        if err != nil {
                log.Stderrf("os.Pipe(): %v\n", err)
@@ -109,18 +109,18 @@ func exec(c *http.Conn, args []string) (status int) {
        if *verbose {
                os.Stderr.Write(buf.Bytes())
        }
-       if c != nil {
-               c.SetHeader("content-type", "text/plain; charset=utf-8")
-               c.Write(buf.Bytes())
+       if rw != nil {
+               rw.SetHeader("content-type", "text/plain; charset=utf-8")
+               rw.Write(buf.Bytes())
        }
 
        return
 }
 
 
-func dosync(c *http.Conn, r *http.Request) {
+func dosync(w http.ResponseWriter, r *http.Request) {
        args := []string{"/bin/sh", "-c", *syncCmd}
-       switch exec(c, args) {
+       switch exec(w, args) {
        case 0:
                // sync succeeded and some files have changed;
                // update package tree.
@@ -150,9 +150,9 @@ func usage() {
 
 
 func loggingHandler(h http.Handler) http.Handler {
-       return http.HandlerFunc(func(c *http.Conn, req *http.Request) {
-               log.Stderrf("%s\t%s", c.RemoteAddr, req.URL)
-               h.ServeHTTP(c, req)
+       return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+               log.Stderrf("%s\t%s", w.RemoteAddr(), req.URL)
+               h.ServeHTTP(w, req)
        })
 }
 
index 4017027b77685262685835b061e28ebc17c7c40e..9435481dbc47cb40f6e368b7d82a7cd47806a518 100644 (file)
@@ -210,18 +210,18 @@ func Iter() <-chan KeyValue {
        return c
 }
 
-func expvarHandler(c *http.Conn, req *http.Request) {
-       c.SetHeader("content-type", "application/json; charset=utf-8")
-       fmt.Fprintf(c, "{\n")
+func expvarHandler(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "application/json; charset=utf-8")
+       fmt.Fprintf(w, "{\n")
        first := true
        for name, value := range vars {
                if !first {
-                       fmt.Fprintf(c, ",\n")
+                       fmt.Fprintf(w, ",\n")
                }
                first = false
-               fmt.Fprintf(c, "%q: %s", name, value)
+               fmt.Fprintf(w, "%q: %s", name, value)
        }
-       fmt.Fprintf(c, "\n}\n")
+       fmt.Fprintf(w, "\n}\n")
 }
 
 func memstats() string {
index db80b2f4dfd1b4ce9dfed9fca5d4d985925a6b08..b3047f18275243edef48fe824b4b3a89d4583951 100644 (file)
@@ -43,8 +43,8 @@ func isText(b []byte) bool {
        return true
 }
 
-func dirList(c *Conn, f *os.File) {
-       fmt.Fprintf(c, "<pre>\n")
+func dirList(w ResponseWriter, f *os.File) {
+       fmt.Fprintf(w, "<pre>\n")
        for {
                dirs, err := f.Readdir(100)
                if err != nil || len(dirs) == 0 {
@@ -56,25 +56,25 @@ func dirList(c *Conn, f *os.File) {
                                name += "/"
                        }
                        // TODO htmlescape
-                       fmt.Fprintf(c, "<a href=\"%s\">%s</a>\n", name, name)
+                       fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
                }
        }
-       fmt.Fprintf(c, "</pre>\n")
+       fmt.Fprintf(w, "</pre>\n")
 }
 
-func serveFile(c *Conn, r *Request, name string, redirect bool) {
+func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
        const indexPage = "/index.html"
 
        // redirect .../index.html to .../
        if strings.HasSuffix(r.URL.Path, indexPage) {
-               Redirect(c, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+               Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
                return
        }
 
        f, err := os.Open(name, os.O_RDONLY, 0)
        if err != nil {
                // TODO expose actual error?
-               NotFound(c, r)
+               NotFound(w, r)
                return
        }
        defer f.Close()
@@ -82,7 +82,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
        d, err1 := f.Stat()
        if err1 != nil {
                // TODO expose actual error?
-               NotFound(c, r)
+               NotFound(w, r)
                return
        }
 
@@ -92,22 +92,22 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
                url := r.URL.Path
                if d.IsDirectory() {
                        if url[len(url)-1] != '/' {
-                               Redirect(c, url+"/", StatusMovedPermanently)
+                               Redirect(w, r, url+"/", StatusMovedPermanently)
                                return
                        }
                } else {
                        if url[len(url)-1] == '/' {
-                               Redirect(c, url[0:len(url)-1], StatusMovedPermanently)
+                               Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
                                return
                        }
                }
        }
 
        if t, _ := time.Parse(TimeFormat, r.Header["If-Modified-Since"]); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
-               c.WriteHeader(StatusNotModified)
+               w.WriteHeader(StatusNotModified)
                return
        }
-       c.SetHeader("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+       w.SetHeader("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
 
        // use contents of index.html for directory, if present
        if d.IsDirectory() {
@@ -125,7 +125,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
        }
 
        if d.IsDirectory() {
-               dirList(c, f)
+               dirList(w, f)
                return
        }
 
@@ -133,25 +133,25 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
        // use extension to find content type.
        ext := path.Ext(name)
        if ctype := mime.TypeByExtension(ext); ctype != "" {
-               c.SetHeader("Content-Type", ctype)
+               w.SetHeader("Content-Type", ctype)
        } else {
                // read first chunk to decide between utf-8 text and binary
                var buf [1024]byte
                n, _ := io.ReadFull(f, buf[0:])
                b := buf[0:n]
                if isText(b) {
-                       c.SetHeader("Content-Type", "text-plain; charset=utf-8")
+                       w.SetHeader("Content-Type", "text-plain; charset=utf-8")
                } else {
-                       c.SetHeader("Content-Type", "application/octet-stream") // generic binary
+                       w.SetHeader("Content-Type", "application/octet-stream") // generic binary
                }
-               c.Write(b)
+               w.Write(b)
        }
-       io.Copy(c, f)
+       io.Copy(w, f)
 }
 
 // ServeFile replies to the request with the contents of the named file or directory.
-func ServeFile(c *Conn, r *Request, name string) {
-       serveFile(c, r, name, false)
+func ServeFile(w ResponseWriter, r *Request, name string) {
+       serveFile(w, r, name, false)
 }
 
 type fileHandler struct {
@@ -165,12 +165,12 @@ type fileHandler struct {
 // looking up the file name in the file system.
 func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
 
-func (f *fileHandler) ServeHTTP(c *Conn, r *Request) {
+func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
        path := r.URL.Path
        if !strings.HasPrefix(path, f.prefix) {
-               NotFound(c, r)
+               NotFound(w, r)
                return
        }
        path = path[len(f.prefix):]
-       serveFile(c, r, f.root+"/"+path, true)
+       serveFile(w, r, f.root+"/"+path, true)
 }
index 38d91afbf8238d1fae1989b8271324e8d7d49295..f7db9aab93bf220d916c83e27f943a63fa1ef5fc 100644 (file)
@@ -40,28 +40,28 @@ func init() {
 // Cmdline responds with the running program's
 // command line, with arguments separated by NUL bytes.
 // The package initialization registers it as /debug/pprof/cmdline.
-func Cmdline(c *http.Conn, r *http.Request) {
-       c.SetHeader("content-type", "text/plain; charset=utf-8")
-       fmt.Fprintf(c, strings.Join(os.Args, "\x00"))
+func Cmdline(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
+       fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
 }
 
 // Heap responds with the pprof-formatted heap profile.
 // The package initialization registers it as /debug/pprof/heap.
-func Heap(c *http.Conn, r *http.Request) {
-       c.SetHeader("content-type", "text/plain; charset=utf-8")
-       pprof.WriteHeapProfile(c)
+func Heap(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
+       pprof.WriteHeapProfile(w)
 }
 
 // Symbol looks up the program counters listed in the request,
 // responding with a table mapping program counters to function names.
 // The package initialization registers it as /debug/pprof/symbol.
-func Symbol(c *http.Conn, r *http.Request) {
-       c.SetHeader("content-type", "text/plain; charset=utf-8")
+func Symbol(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
 
        // We don't know how many symbols we have, but we
        // do have symbol information.  Pprof only cares whether
        // this number is 0 (no symbols available) or > 0.
-       fmt.Fprintf(c, "num_symbols: 1\n")
+       fmt.Fprintf(w, "num_symbols: 1\n")
 
        var b *bufio.Reader
        if r.Method == "POST" {
@@ -71,15 +71,15 @@ func Symbol(c *http.Conn, r *http.Request) {
        }
 
        for {
-               w, err := b.ReadSlice('+')
+               word, err := b.ReadSlice('+')
                if err == nil {
-                       w = w[0 : len(w)-1] // trim +
+                       word = word[0 : len(word)-1] // trim +
                }
-               pc, _ := strconv.Btoui64(string(w), 0)
+               pc, _ := strconv.Btoui64(string(word), 0)
                if pc != 0 {
                        f := runtime.FuncForPC(uintptr(pc))
                        if f != nil {
-                               fmt.Fprintf(c, "%#x %s\n", pc, f.Name())
+                               fmt.Fprintf(w, "%#x %s\n", pc, f.Name())
                        }
                }
 
index 99d5f6b517770cbb189808bdedce41934f6c9b14..4404dda978b48111ba1541f5bafc47f662d4919a 100644 (file)
@@ -37,32 +37,78 @@ var (
 // registered to serve a particular path or subtree
 // in the HTTP server.
 //
-// ServeHTTP should write reply headers and data to the Conn
+// ServeHTTP should write reply headers and data to the ResponseWriter
 // and then return.  Returning signals that the request is finished
 // and that the HTTP server can move on to the next request on
 // the connection.
 type Handler interface {
-       ServeHTTP(*Conn, *Request)
-}
-
-// A Conn represents the server side of a single active HTTP connection.
-type Conn struct {
-       RemoteAddr string   // network address of remote side
-       Req        *Request // current HTTP request
-
-       rwc      io.ReadWriteCloser // i/o connection
-       buf      *bufio.ReadWriter  // buffered rwc
-       handler  Handler            // request handler
-       hijacked bool               // connection has been hijacked by handler
-
-       // state for the current reply
+       ServeHTTP(ResponseWriter, *Request)
+}
+
+// A ResponseWriter interface is used by an HTTP handler to
+// construct an HTTP response.
+type ResponseWriter interface {
+       // RemoteAddr returns the address of the client that sent the current request
+       RemoteAddr() string
+
+       // UsingTLS returns true if the client is connected using TLS
+       UsingTLS() bool
+
+       // SetHeader sets a header line in the eventual response.
+       // For example, SetHeader("Content-Type", "text/html; charset=utf-8")
+       // will result in the header line
+       //
+       //      Content-Type: text/html; charset=utf-8
+       //
+       // being sent.  UTF-8 encoded HTML is the default setting for
+       // Content-Type in this library, so users need not make that
+       // particular call.  Calls to SetHeader after WriteHeader (or Write)
+       // are ignored.
+       SetHeader(string, string)
+
+       // Write writes the data to the connection as part of an HTTP reply.
+       // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
+       // before writing the data.
+       Write([]byte) (int, os.Error)
+
+       // WriteHeader sends an HTTP response header with status code.
+       // If WriteHeader is not called explicitly, the first call to Write
+       // will trigger an implicit WriteHeader(http.StatusOK).
+       // Thus explicit calls to WriteHeader are mainly used to
+       // send error codes.
+       WriteHeader(int)
+
+       // Flush sends any buffered data to the client.
+       Flush()
+
+       // Hijack lets the caller take over the connection.
+       // After a call to Hijack(), the HTTP server library
+       // will not do anything else with the connection.
+       // It becomes the caller's responsibility to manage
+       // and close the connection.
+       Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error)
+}
+
+// A conn represents the server side of an HTTP connection.
+type conn struct {
+       remoteAddr string             // network address of remote side
+       handler    Handler            // request handler
+       rwc        io.ReadWriteCloser // i/o connection
+       buf        *bufio.ReadWriter  // buffered rwc
+       hijacked   bool               // connection has been hijacked by handler
+       usingTLS   bool               // a flag indicating connection over TLS
+}
+
+// A response represents the server side of an HTTP response.
+type response struct {
+       conn          *conn
+       req           *Request          // request for this response
        chunking      bool              // using chunked transfer encoding for reply body
        wroteHeader   bool              // reply header has been written
        wroteContinue bool              // 100 Continue response was written
        header        map[string]string // reply header parameters
        written       int64             // number of bytes written in body
        status        int               // status code passed to WriteHeader
-       usingTLS      bool              // a flag indicating connection over TLS
 
        // close connection after this reply.  set on request and
        // updated after response from handler if there's a
@@ -72,11 +118,9 @@ type Conn struct {
 }
 
 // Create new connection from rwc.
-func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
-       c = new(Conn)
-       if a := rwc.RemoteAddr(); a != nil {
-               c.RemoteAddr = a.String()
-       }
+func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
+       c = new(conn)
+       c.remoteAddr = rwc.RemoteAddr().String()
        c.handler = handler
        c.rwc = rwc
        _, c.usingTLS = rwc.(*tls.Conn)
@@ -89,17 +133,15 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
 // wrapper around io.ReaderCloser which on first read, sends an
 // HTTP/1.1 100 Continue header
 type expectContinueReader struct {
-       conn       *Conn
+       resp       *response
        readCloser io.ReadCloser
 }
 
 func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
-       if !ecr.conn.wroteContinue && !ecr.conn.hijacked {
-               ecr.conn.wroteContinue = true
-               if ecr.conn.Req.ProtoAtLeast(1, 1) {
-                       io.WriteString(ecr.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
-                       ecr.conn.buf.Flush()
-               }
+       if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
+               ecr.resp.wroteContinue = true
+               io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+               ecr.resp.conn.buf.Flush()
        }
        return ecr.readCloser.Read(p)
 }
@@ -115,92 +157,80 @@ func (ecr *expectContinueReader) Close() os.Error {
 const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
 
 // Read next request from connection.
-func (c *Conn) readRequest() (req *Request, err os.Error) {
+func (c *conn) readRequest() (w *response, err os.Error) {
        if c.hijacked {
                return nil, ErrHijacked
        }
+       var req *Request
        if req, err = ReadRequest(c.buf.Reader); err != nil {
                return nil, err
        }
 
-       // Reset per-request connection state.
-       c.header = make(map[string]string)
-       c.wroteHeader = false
-       c.wroteContinue = false
-       c.Req = req
+       w = new(response)
+       w.conn = c
+       w.req = req
+       w.header = make(map[string]string)
 
        // Expect 100 Continue support
-       if req.expectsContinue() {
+       if req.expectsContinue() && req.ProtoAtLeast(1, 1) {
                // Wrap the Body reader with one that replies on the connection
-               req.Body = &expectContinueReader{readCloser: req.Body, conn: c}
+               req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
        }
 
        // Default output is HTML encoded in UTF-8.
-       c.SetHeader("Content-Type", "text/html; charset=utf-8")
-       c.SetHeader("Date", time.UTC().Format(TimeFormat))
+       w.SetHeader("Content-Type", "text/html; charset=utf-8")
+       w.SetHeader("Date", time.UTC().Format(TimeFormat))
 
        if req.ProtoAtLeast(1, 1) {
                // HTTP/1.1 or greater: use chunked transfer encoding
                // to avoid closing the connection at EOF.
-               c.chunking = true
-               c.SetHeader("Transfer-Encoding", "chunked")
+               w.chunking = true
+               w.SetHeader("Transfer-Encoding", "chunked")
        } else {
                // HTTP version < 1.1: cannot do chunked transfer
                // encoding, so signal EOF by closing connection.
                // Will be overridden if the HTTP handler ends up
                // writing a Content-Length and the client requested
                // "Connection: keep-alive"
-               c.closeAfterReply = true
-               c.chunking = false
+               w.closeAfterReply = true
        }
 
-       return req, nil
+       return w, nil
 }
 
-// UsingTLS returns true if the connection uses transport layer security (TLS).
-func (c *Conn) UsingTLS() bool {
-       return c.usingTLS
+// UsingTLS implements the ResponseWriter.UsingTLS
+func (w *response) UsingTLS() bool {
+       return w.conn.usingTLS
 }
 
-// SetHeader sets a header line in the eventual reply.
-// For example, SetHeader("Content-Type", "text/html; charset=utf-8")
-// will result in the header line
-//
-//     Content-Type: text/html; charset=utf-8
-//
-// being sent.  UTF-8 encoded HTML is the default setting for
-// Content-Type in this library, so users need not make that
-// particular call.  Calls to SetHeader after WriteHeader (or Write)
-// are ignored.
-func (c *Conn) SetHeader(hdr, val string) { c.header[CanonicalHeaderKey(hdr)] = val }
-
-// WriteHeader sends an HTTP response header with status code.
-// If WriteHeader is not called explicitly, the first call to Write
-// will trigger an implicit WriteHeader(http.StatusOK).
-// Thus explicit calls to WriteHeader are mainly used to
-// send error codes.
-func (c *Conn) WriteHeader(code int) {
-       if c.hijacked {
-               log.Stderr("http: Conn.WriteHeader on hijacked connection")
+// RemoteAddr implements the ResponseWriter.RemoteAddr method
+func (w *response) RemoteAddr() string { return w.conn.remoteAddr }
+
+// SetHeader implements the ResponseWriter.SetHeader method
+func (w *response) SetHeader(hdr, val string) { w.header[CanonicalHeaderKey(hdr)] = val }
+
+// WriteHeader implements the ResponseWriter.WriteHeader method
+func (w *response) WriteHeader(code int) {
+       if w.conn.hijacked {
+               log.Stderr("http: response.WriteHeader on hijacked connection")
                return
        }
-       if c.wroteHeader {
-               log.Stderr("http: multiple Conn.WriteHeader calls")
+       if w.wroteHeader {
+               log.Stderr("http: multiple response.WriteHeader calls")
                return
        }
-       c.wroteHeader = true
-       c.status = code
+       w.wroteHeader = true
+       w.status = code
        if code == StatusNotModified {
                // Must not have body.
-               c.header["Content-Type"] = "", false
-               c.header["Transfer-Encoding"] = "", false
+               w.header["Content-Type"] = "", false
+               w.header["Transfer-Encoding"] = "", false
        }
-       c.written = 0
-       if !c.Req.ProtoAtLeast(1, 0) {
+       if !w.req.ProtoAtLeast(1, 0) {
                return
        }
        proto := "HTTP/1.0"
-       if c.Req.ProtoAtLeast(1, 1) {
+       if w.req.ProtoAtLeast(1, 1) {
                proto = "HTTP/1.1"
        }
        codestring := strconv.Itoa(code)
@@ -208,57 +238,55 @@ func (c *Conn) WriteHeader(code int) {
        if !ok {
                text = "status code " + codestring
        }
-       io.WriteString(c.buf, proto+" "+codestring+" "+text+"\r\n")
-       for k, v := range c.header {
-               io.WriteString(c.buf, k+": "+v+"\r\n")
+       io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
+       for k, v := range w.header {
+               io.WriteString(w.conn.buf, k+": "+v+"\r\n")
        }
-       io.WriteString(c.buf, "\r\n")
+       io.WriteString(w.conn.buf, "\r\n")
 }
 
-// Write writes the data to the connection as part of an HTTP reply.
-// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
-// before writing the data.
-func (c *Conn) Write(data []byte) (n int, err os.Error) {
-       if c.hijacked {
-               log.Stderr("http: Conn.Write on hijacked connection")
+// Write implements the ResponseWriter.Write method
+func (w *response) Write(data []byte) (n int, err os.Error) {
+       if w.conn.hijacked {
+               log.Stderr("http: response.Write on hijacked connection")
                return 0, ErrHijacked
        }
-       if !c.wroteHeader {
-               if c.Req.wantsHttp10KeepAlive() {
-                       _, hasLength := c.header["Content-Length"]
+       if !w.wroteHeader {
+               if w.req.wantsHttp10KeepAlive() {
+                       _, hasLength := w.header["Content-Length"]
                        if hasLength {
-                               _, connectionHeaderSet := c.header["Connection"]
+                               _, connectionHeaderSet := w.header["Connection"]
                                if !connectionHeaderSet {
-                                       c.header["Connection"] = "keep-alive"
+                                       w.header["Connection"] = "keep-alive"
                                }
                        }
                }
-               c.WriteHeader(StatusOK)
+               w.WriteHeader(StatusOK)
        }
        if len(data) == 0 {
                return 0, nil
        }
 
-       if c.status == StatusNotModified {
+       if w.status == StatusNotModified {
                // Must not have body.
                return 0, ErrBodyNotAllowed
        }
 
-       c.written += int64(len(data)) // ignoring errors, for errorKludge
+       w.written += int64(len(data)) // ignoring errors, for errorKludge
 
        // TODO(rsc): if chunking happened after the buffering,
        // then there would be fewer chunk headers.
        // On the other hand, it would make hijacking more difficult.
-       if c.chunking {
-               fmt.Fprintf(c.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
+       if w.chunking {
+               fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
        }
-       n, err = c.buf.Write(data)
-       if err == nil && c.chunking {
+       n, err = w.conn.buf.Write(data)
+       if err == nil && w.chunking {
                if n != len(data) {
                        err = io.ErrShortWrite
                }
                if err == nil {
-                       io.WriteString(c.buf, "\r\n")
+                       io.WriteString(w.conn.buf, "\r\n")
                }
        }
 
@@ -272,22 +300,22 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) {
 // long enough.  The minimum lengths used in those
 // browsers are in the 256-512 range.
 // Pad to 1024 bytes.
-func errorKludge(c *Conn, req *Request) {
+func errorKludge(w *response) {
        const min = 1024
 
        // Is this an error?
-       if kind := c.status / 100; kind != 4 && kind != 5 {
+       if kind := w.status / 100; kind != 4 && kind != 5 {
                return
        }
 
        // Did the handler supply any info?  Enough?
-       if c.written == 0 || c.written >= min {
+       if w.written == 0 || w.written >= min {
                return
        }
 
        // Is it a broken browser?
        var msg string
-       switch agent := req.UserAgent; {
+       switch agent := w.req.UserAgent; {
        case strings.Index(agent, "MSIE") >= 0:
                msg = "Internet Explorer"
        case strings.Index(agent, "Chrome/") >= 0:
@@ -298,53 +326,53 @@ func errorKludge(c *Conn, req *Request) {
        msg += " would ignore this error page if this text weren't here.\n"
 
        // Is it text?  ("Content-Type" is always in the map)
-       baseType := strings.Split(c.header["Content-Type"], ";", 2)[0]
+       baseType := strings.Split(w.header["Content-Type"], ";", 2)[0]
        switch baseType {
        case "text/html":
-               io.WriteString(c, "<!-- ")
-               for c.written < min {
-                       io.WriteString(c, msg)
+               io.WriteString(w, "<!-- ")
+               for w.written < min {
+                       io.WriteString(w, msg)
                }
-               io.WriteString(c, " -->")
+               io.WriteString(w, " -->")
        case "text/plain":
-               io.WriteString(c, "\n")
-               for c.written < min {
-                       io.WriteString(c, msg)
+               io.WriteString(w, "\n")
+               for w.written < min {
+                       io.WriteString(w, msg)
                }
        }
 }
 
-func (c *Conn) finishRequest() {
+func (w *response) finishRequest() {
        // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
        // back, we can make this a keep-alive response ...
-       if c.Req.wantsHttp10KeepAlive() {
-               _, sentLength := c.header["Content-Length"]
-               if sentLength && c.header["Connection"] == "keep-alive" {
-                       c.closeAfterReply = false
+       if w.req.wantsHttp10KeepAlive() {
+               _, sentLength := w.header["Content-Length"]
+               if sentLength && w.header["Connection"] == "keep-alive" {
+                       w.closeAfterReply = false
                }
        }
-       if !c.wroteHeader {
-               c.WriteHeader(StatusOK)
+       if !w.wroteHeader {
+               w.WriteHeader(StatusOK)
        }
-       errorKludge(c, c.Req)
-       if c.chunking {
-               io.WriteString(c.buf, "0\r\n")
+       errorKludge(w)
+       if w.chunking {
+               io.WriteString(w.conn.buf, "0\r\n")
                // trailer key/value pairs, followed by blank line
-               io.WriteString(c.buf, "\r\n")
+               io.WriteString(w.conn.buf, "\r\n")
        }
-       c.buf.Flush()
+       w.conn.buf.Flush()
 }
 
-// Flush sends any buffered data to the client.
-func (c *Conn) Flush() {
-       if !c.wroteHeader {
-               c.WriteHeader(StatusOK)
+// Flush implements the ResponseWriter.Flush method.
+func (w *response) Flush() {
+       if !w.wroteHeader {
+               w.WriteHeader(StatusOK)
        }
-       c.buf.Flush()
+       w.conn.buf.Flush()
 }
 
 // Close the connection.
-func (c *Conn) close() {
+func (c *conn) close() {
        if c.buf != nil {
                c.buf.Flush()
                c.buf = nil
@@ -356,9 +384,9 @@ func (c *Conn) close() {
 }
 
 // Serve a new connection.
-func (c *Conn) serve() {
+func (c *conn) serve() {
        for {
-               req, err := c.readRequest()
+               w, err := c.readRequest()
                if err != nil {
                        break
                }
@@ -367,32 +395,28 @@ func (c *Conn) serve() {
                // so we might as well run the handler in this goroutine.
                // [*] Not strictly true: HTTP pipelining.  We could let them all process
                // in parallel even if their responses need to be serialized.
-               c.handler.ServeHTTP(c, req)
+               c.handler.ServeHTTP(w, w.req)
                if c.hijacked {
                        return
                }
-               c.finishRequest()
-               if c.closeAfterReply {
+               w.finishRequest()
+               if w.closeAfterReply {
                        break
                }
        }
        c.close()
 }
 
-// Hijack lets the caller take over the connection.
-// After a call to c.Hijack(), the HTTP server library
-// will not do anything else with the connection.
-// It becomes the caller's responsibility to manage
-// and close the connection.
-func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
-       if c.hijacked {
+// Hijack impements the ResponseWriter.Hijack method.
+func (w *response) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
+       if w.conn.hijacked {
                return nil, nil, ErrHijacked
        }
-       c.hijacked = true
-       rwc = c.rwc
-       buf = c.buf
-       c.rwc = nil
-       c.buf = nil
+       w.conn.hijacked = true
+       rwc = w.conn.rwc
+       buf = w.conn.buf
+       w.conn.rwc = nil
+       w.conn.buf = nil
        return
 }
 
@@ -400,24 +424,24 @@ func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.E
 // ordinary functions as HTTP handlers.  If f is a function
 // with the appropriate signature, HandlerFunc(f) is a
 // Handler object that calls f.
-type HandlerFunc func(*Conn, *Request)
+type HandlerFunc func(ResponseWriter, *Request)
 
 // ServeHTTP calls f(c, req).
-func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
-       f(c, req)
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+       f(w, r)
 }
 
 // Helper handlers
 
 // Error replies to the request with the specified error message and HTTP code.
-func Error(c *Conn, error string, code int) {
-       c.SetHeader("Content-Type", "text/plain; charset=utf-8")
-       c.WriteHeader(code)
-       fmt.Fprintln(c, error)
+func Error(w ResponseWriter, error string, code int) {
+       w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+       w.WriteHeader(code)
+       fmt.Fprintln(w, error)
 }
 
 // NotFound replies to the request with an HTTP 404 not found error.
-func NotFound(c *Conn, req *Request) { Error(c, "404 page not found", StatusNotFound) }
+func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
 
 // NotFoundHandler returns a simple request handler
 // that replies to each request with a ``404 page not found'' reply.
@@ -425,11 +449,11 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
 
 // Redirect replies to the request with a redirect to url,
 // which may be a path relative to the request path.
-func Redirect(c *Conn, url string, code int) {
+func Redirect(w ResponseWriter, r *Request, url string, code int) {
        // RFC2616 recommends that a short note "SHOULD" be included in the
        // response because older user agents may not understand 301/307.
        note := "<a href=\"%v\">" + statusText[code] + "</a>.\n"
-       if c.Req.Method == "POST" {
+       if r.Method == "POST" {
                note = ""
        }
 
@@ -454,7 +478,7 @@ func Redirect(c *Conn, url string, code int) {
        // Because of this problem, no one pays attention
        // to the RFC; they all send back just a new path.
        // So do we.
-       oldpath := c.Req.URL.Path
+       oldpath := r.URL.Path
        if oldpath == "" { // should not happen, but avoid a crash if it does
                oldpath = "/"
        }
@@ -475,9 +499,9 @@ func Redirect(c *Conn, url string, code int) {
        }
 
 finish:
-       c.SetHeader("Location", url)
-       c.WriteHeader(code)
-       fmt.Fprintf(c, note, url)
+       w.SetHeader("Location", url)
+       w.WriteHeader(code)
+       fmt.Fprintf(w, note, url)
 }
 
 // Redirect to a fixed URL
@@ -486,8 +510,8 @@ type redirectHandler struct {
        code int
 }
 
-func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) {
-       Redirect(c, rh.url, rh.code)
+func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
+       Redirect(w, r, rh.url, rh.code)
 }
 
 // RedirectHandler returns a request handler that redirects
@@ -563,11 +587,11 @@ func cleanPath(p string) string {
 
 // ServeHTTP dispatches the request to the handler whose
 // pattern most closely matches the request URL.
-func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
+func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
        // Clean path to canonical form and redirect.
-       if p := cleanPath(req.URL.Path); p != req.URL.Path {
-               c.SetHeader("Location", p)
-               c.WriteHeader(StatusMovedPermanently)
+       if p := cleanPath(r.URL.Path); p != r.URL.Path {
+               w.SetHeader("Location", p)
+               w.WriteHeader(StatusMovedPermanently)
                return
        }
 
@@ -575,7 +599,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
        var h Handler
        var n = 0
        for k, v := range mux.m {
-               if !pathMatch(k, req.URL.Path) {
+               if !pathMatch(k, r.URL.Path) {
                        continue
                }
                if h == nil || len(k) > n {
@@ -586,7 +610,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
        if h == nil {
                h = NotFoundHandler()
        }
-       h.ServeHTTP(c, req)
+       h.ServeHTTP(w, r)
 }
 
 // Handle registers the handler for the given pattern.
@@ -606,7 +630,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
 }
 
 // HandleFunc registers the handler function for the given pattern.
-func (mux *ServeMux) HandleFunc(pattern string, handler func(*Conn, *Request)) {
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        mux.Handle(pattern, HandlerFunc(handler))
 }
 
@@ -616,7 +640,7 @@ func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, h
 
 // HandleFunc registers the handler function for the given pattern
 // in the DefaultServeMux.
-func HandleFunc(pattern string, handler func(*Conn, *Request)) {
+func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
 }
 
@@ -658,8 +682,8 @@ func Serve(l net.Listener, handler Handler) os.Error {
 //     )
 //
 //     // hello world, the web server
-//     func HelloServer(c *http.Conn, req *http.Request) {
-//             io.WriteString(c, "hello, world!\n")
+//     func HelloServer(w http.ResponseWriter, req *http.Request) {
+//             io.WriteString(w, "hello, world!\n")
 //     }
 //
 //     func main() {
@@ -690,9 +714,9 @@ func ListenAndServe(addr string, handler Handler) os.Error {
 //             "log"
 //     )
 //
-//     func handler(conn *http.Conn, req *http.Request) {
-//             conn.SetHeader("Content-Type", "text/plain")
-//             conn.Write([]byte("This is an example server.\n"))
+//     func handler(w http.ResponseWriter, req *http.Request) {
+//             w.SetHeader("Content-Type", "text/plain")
+//             w.Write([]byte("This is an example server.\n"))
 //     }
 //
 //     func main() {
index 82a66d7ad77728e68b82ed66cccbf8ca6e461189..b6e2d65c6a5019d8586186e1935835b6ce3cc025 100644 (file)
@@ -98,3 +98,9 @@ var statusText = map[int]string{
        StatusGatewayTimeout:          "Gateway Timeout",
        StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
 }
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+       return statusText[code]
+}
index 638584f497cfab4542a50495932ee0d03cacec85..e1e53f09056a53efa6f5fa007ac10f36f99f24d3 100644 (file)
@@ -62,7 +62,7 @@ func (m methodArray) Less(i, j int) bool { return m[i].name < m[j].name }
 func (m methodArray) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }
 
 // Runs at /debug/rpc
-func debugHTTP(c *http.Conn, req *http.Request) {
+func debugHTTP(w http.ResponseWriter, req *http.Request) {
        // Build a sorted version of the data.
        var services = make(serviceArray, len(server.serviceMap))
        i := 0
@@ -79,8 +79,8 @@ func debugHTTP(c *http.Conn, req *http.Request) {
        }
        server.Unlock()
        sort.Sort(services)
-       err := debug.Execute(services, c)
+       err := debug.Execute(services, w)
        if err != nil {
-               fmt.Fprintln(c, "rpc: error executing template:", err.String())
+               fmt.Fprintln(w, "rpc: error executing template:", err.String())
        }
 }
index 91b88e23de8ef9fe83c52dc04cf3474ff798186d..db46e35db7b813369dfaf275112125168841b780 100644 (file)
@@ -445,16 +445,16 @@ var rpcPath string = "/_goRPC_"
 var debugPath string = "/debug/rpc"
 var connected = "200 Connected to Go RPC"
 
-func serveHTTP(c *http.Conn, req *http.Request) {
+func serveHTTP(w http.ResponseWriter, req *http.Request) {
        if req.Method != "CONNECT" {
-               c.SetHeader("Content-Type", "text/plain; charset=utf-8")
-               c.WriteHeader(http.StatusMethodNotAllowed)
-               io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n")
+               w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+               w.WriteHeader(http.StatusMethodNotAllowed)
+               io.WriteString(w, "405 must CONNECT to "+rpcPath+"\n")
                return
        }
-       conn, _, err := c.Hijack()
+       conn, _, err := w.Hijack()
        if err != nil {
-               log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String())
+               log.Stderr("rpc hijacking ", w.RemoteAddr(), ": ", err.String())
                return
        }
        io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
index b884884fa53b194e536478d135e7760e65be2be4..dd797f24e0ec0c6b2dde9d0b82692b2c903ca8ff 100644 (file)
@@ -57,8 +57,8 @@ func getKeyNumber(s string) (r uint32) {
 }
 
 // ServeHTTP implements the http.Handler interface for a Web Socket
-func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
-       rwc, buf, err := c.Hijack()
+func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       rwc, buf, err := w.Hijack()
        if err != nil {
                panic("Hijack failed: " + err.String())
                return
@@ -98,7 +98,7 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
        }
 
        var location string
-       if c.UsingTLS() {
+       if w.UsingTLS() {
                location = "wss://" + req.Host + req.URL.RawPath
        } else {
                location = "ws://" + req.Host + req.URL.RawPath
@@ -161,30 +161,30 @@ Draft75Handler is an interface to a WebSocket based on the
 type Draft75Handler func(*Conn)
 
 // ServeHTTP implements the http.Handler interface for a Web Socket.
-func (f Draft75Handler) ServeHTTP(c *http.Conn, req *http.Request) {
+func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        if req.Method != "GET" || req.Proto != "HTTP/1.1" {
-               c.WriteHeader(http.StatusBadRequest)
-               io.WriteString(c, "Unexpected request")
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "Unexpected request")
                return
        }
        if req.Header["Upgrade"] != "WebSocket" {
-               c.WriteHeader(http.StatusBadRequest)
-               io.WriteString(c, "missing Upgrade: WebSocket header")
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Upgrade: WebSocket header")
                return
        }
        if req.Header["Connection"] != "Upgrade" {
-               c.WriteHeader(http.StatusBadRequest)
-               io.WriteString(c, "missing Connection: Upgrade header")
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Connection: Upgrade header")
                return
        }
        origin, found := req.Header["Origin"]
        if !found {
-               c.WriteHeader(http.StatusBadRequest)
-               io.WriteString(c, "missing Origin header")
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Origin header")
                return
        }
 
-       rwc, buf, err := c.Hijack()
+       rwc, buf, err := w.Hijack()
        if err != nil {
                panic("Hijack failed: " + err.String())
                return
@@ -192,7 +192,7 @@ func (f Draft75Handler) ServeHTTP(c *http.Conn, req *http.Request) {
        defer rwc.Close()
 
        var location string
-       if c.UsingTLS() {
+       if w.UsingTLS() {
                location = "wss://" + req.Host + req.URL.RawPath
        } else {
                location = "ws://" + req.Host + req.URL.RawPath