diff options
Diffstat (limited to 'src/pkg/http/server.go')
| -rw-r--r-- | src/pkg/http/server.go | 254 |
1 files changed, 127 insertions, 127 deletions
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go index 9178d5438..f9771f9b4 100644 --- a/src/pkg/http/server.go +++ b/src/pkg/http/server.go @@ -12,61 +12,61 @@ package http import ( - "bufio"; - "fmt"; - "io"; - "log"; - "net"; - "os"; - "path"; - "strconv"; - "strings"; + "bufio" + "fmt" + "io" + "log" + "net" + "os" + "path" + "strconv" + "strings" ) // Errors introduced by the HTTP server. var ( - ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush"); - ErrHijacked = os.NewError("Conn has been hijacked"); + ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush") + ErrHijacked = os.NewError("Conn has been hijacked") ) // Objects implementing the Handler interface can be // registered to serve a particular path or subtree // in the HTTP server. type Handler interface { - ServeHTTP(*Conn, *Request); + 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 + 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 + 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 - closeAfterReply bool; // close connection after this reply - chunking bool; // using chunked transfer encoding for reply body - wroteHeader bool; // reply header has been written - header map[string]string; // reply header parameters - written int64; // number of bytes written in body - status int; // status code passed to WriteHeader + closeAfterReply bool // close connection after this reply + chunking bool // using chunked transfer encoding for reply body + wroteHeader bool // reply header has been written + header map[string]string // reply header parameters + written int64 // number of bytes written in body + status int // status code passed to WriteHeader } // Create new connection from rwc. func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) { - c = new(Conn); + c = new(Conn) if a := rwc.RemoteAddr(); a != nil { c.RemoteAddr = a.String() } - c.handler = handler; - c.rwc = rwc; - br := bufio.NewReader(rwc); - bw := bufio.NewWriter(rwc); - c.buf = bufio.NewReadWriter(br, bw); - return c, nil; + c.handler = handler + c.rwc = rwc + br := bufio.NewReader(rwc) + bw := bufio.NewWriter(rwc) + c.buf = bufio.NewReadWriter(br, bw) + return c, nil } // Read next request from connection. @@ -79,18 +79,18 @@ func (c *Conn) readRequest() (req *Request, err os.Error) { } // Reset per-request connection state. - c.header = make(map[string]string); - c.wroteHeader = false; - c.Req = req; + c.header = make(map[string]string) + c.wroteHeader = false + c.Req = req // Default output is HTML encoded in UTF-8. - c.SetHeader("Content-Type", "text/html; charset=utf-8"); + c.SetHeader("Content-Type", "text/html; charset=utf-8") 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"); + c.chunking = true + c.SetHeader("Transfer-Encoding", "chunked") } else { // HTTP version < 1.1: cannot do chunked transfer // encoding, so signal EOF by closing connection. @@ -98,11 +98,11 @@ func (c *Conn) readRequest() (req *Request, err os.Error) { // a Content-Length: header in the response, // but everyone who expects persistent connections // does HTTP/1.1 now. - c.closeAfterReply = true; - c.chunking = false; + c.closeAfterReply = true + c.chunking = false } - return req, nil; + return req, nil } // SetHeader sets a header line in the eventual reply. @@ -115,7 +115,7 @@ func (c *Conn) readRequest() (req *Request, err os.Error) { // 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 } +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 @@ -124,33 +124,33 @@ func (c *Conn) SetHeader(hdr, val string) { c.header[CanonicalHeaderKey(hdr)] = // send error codes. func (c *Conn) WriteHeader(code int) { if c.hijacked { - log.Stderr("http: Conn.WriteHeader on hijacked connection"); - return; + log.Stderr("http: Conn.WriteHeader on hijacked connection") + return } if c.wroteHeader { - log.Stderr("http: multiple Conn.WriteHeader calls"); - return; + log.Stderr("http: multiple Conn.WriteHeader calls") + return } - c.wroteHeader = true; - c.status = code; - c.written = 0; + c.wroteHeader = true + c.status = code + c.written = 0 if !c.Req.ProtoAtLeast(1, 0) { return } - proto := "HTTP/1.0"; + proto := "HTTP/1.0" if c.Req.ProtoAtLeast(1, 1) { proto = "HTTP/1.1" } - codestring := strconv.Itoa(code); - text, ok := statusText[code]; + codestring := strconv.Itoa(code) + text, ok := statusText[code] if !ok { text = "status code " + codestring } - io.WriteString(c.buf, proto+" "+codestring+" "+text+"\r\n"); + 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(c.buf, "\r\n"); + io.WriteString(c.buf, "\r\n") } // Write writes the data to the connection as part of an HTTP reply. @@ -158,8 +158,8 @@ func (c *Conn) WriteHeader(code int) { // 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"); - return 0, ErrHijacked; + log.Stderr("http: Conn.Write on hijacked connection") + return 0, ErrHijacked } if !c.wroteHeader { c.WriteHeader(StatusOK) @@ -168,15 +168,15 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) { return 0, nil } - c.written += int64(len(data)); // ignoring errors, for errorKludge + c.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 + fmt.Fprintf(c.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt } - n, err = c.buf.Write(data); + n, err = c.buf.Write(data) if err == nil && c.chunking { if n != len(data) { err = io.ErrShortWrite @@ -186,7 +186,7 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) { } } - return n, err; + return n, err } // If this is an error reply (4xx or 5xx) @@ -197,7 +197,7 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) { // browsers are in the 256-512 range. // Pad to 1024 bytes. func errorKludge(c *Conn, req *Request) { - const min = 1024; + const min = 1024 // Is this an error? if kind := c.status / 100; kind != 4 && kind != 5 { @@ -210,7 +210,7 @@ func errorKludge(c *Conn, req *Request) { } // Is it a broken browser? - var msg string; + var msg string switch agent := req.UserAgent; { case strings.Index(agent, "MSIE") >= 0: msg = "Internet Explorer" @@ -219,19 +219,19 @@ func errorKludge(c *Conn, req *Request) { default: return } - msg += " would ignore this error page if this text weren't here.\n"; + 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(c.header["Content-Type"], ";", 2)[0] switch baseType { case "text/html": - io.WriteString(c, "<!-- "); + io.WriteString(c, "<!-- ") for c.written < min { io.WriteString(c, msg) } - io.WriteString(c, " -->"); + io.WriteString(c, " -->") case "text/plain": - io.WriteString(c, "\n"); + io.WriteString(c, "\n") for c.written < min { io.WriteString(c, msg) } @@ -242,13 +242,13 @@ func (c *Conn) finishRequest() { if !c.wroteHeader { c.WriteHeader(StatusOK) } - errorKludge(c, c.Req); + errorKludge(c, c.Req) if c.chunking { - io.WriteString(c.buf, "0\r\n"); + io.WriteString(c.buf, "0\r\n") // trailer key/value pairs, followed by blank line - io.WriteString(c.buf, "\r\n"); + io.WriteString(c.buf, "\r\n") } - c.buf.Flush(); + c.buf.Flush() } // Flush sends any buffered data to the client. @@ -256,41 +256,41 @@ func (c *Conn) Flush() { if !c.wroteHeader { c.WriteHeader(StatusOK) } - c.buf.Flush(); + c.buf.Flush() } // Close the connection. func (c *Conn) close() { if c.buf != nil { - c.buf.Flush(); - c.buf = nil; + c.buf.Flush() + c.buf = nil } if c.rwc != nil { - c.rwc.Close(); - c.rwc = nil; + c.rwc.Close() + c.rwc = nil } } // Serve a new connection. func (c *Conn) serve() { for { - req, err := c.readRequest(); + req, err := c.readRequest() if err != nil { break } // HTTP cannot have multiple simultaneous active requests. // Until the server replies to this request, it can't read another, // so we might as well run the handler in this goroutine. - c.handler.ServeHTTP(c, req); + c.handler.ServeHTTP(c, req) if c.hijacked { return } - c.finishRequest(); + c.finishRequest() if c.closeAfterReply { break } } - c.close(); + c.close() } // Hijack lets the caller take over the connection. @@ -302,12 +302,12 @@ func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.E if c.hijacked { return nil, nil, ErrHijacked } - c.hijacked = true; - rwc = c.rwc; - buf = c.buf; - c.rwc = nil; - c.buf = nil; - return; + c.hijacked = true + rwc = c.rwc + buf = c.buf + c.rwc = nil + c.buf = nil + return } // The HandlerFunc type is an adapter to allow the use of @@ -325,26 +325,26 @@ func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { // NotFound replies to the request with an HTTP 404 not found error. func NotFound(c *Conn, req *Request) { - c.SetHeader("Content-Type", "text/plain; charset=utf-8"); - c.WriteHeader(StatusNotFound); - io.WriteString(c, "404 page not found\n"); + c.SetHeader("Content-Type", "text/plain; charset=utf-8") + c.WriteHeader(StatusNotFound) + io.WriteString(c, "404 page not found\n") } // NotFoundHandler returns a simple request handler // that replies to each request with a ``404 page not found'' reply. -func NotFoundHandler() Handler { return HandlerFunc(NotFound) } +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) { // 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"; + note := "<a href=\"%v\">" + statusText[code] + "</a>.\n" if c.Req.Method == "POST" { note = "" } - u, err := ParseURL(url); + u, err := ParseURL(url) if err != nil { goto finish } @@ -365,36 +365,36 @@ 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; - if oldpath == "" { // should not happen, but avoid a crash if it does + oldpath := c.Req.URL.Path + if oldpath == "" { // should not happen, but avoid a crash if it does oldpath = "/" } if u.Scheme == "" { // no leading http://server if url == "" || url[0] != '/' { // make relative path absolute - olddir, _ := path.Split(oldpath); - url = olddir + url; + olddir, _ := path.Split(oldpath) + url = olddir + url } // clean up but preserve trailing slash - trailing := url[len(url)-1] == '/'; - url = path.Clean(url); + trailing := url[len(url)-1] == '/' + url = path.Clean(url) if trailing && url[len(url)-1] != '/' { url += "/" } } finish: - c.SetHeader("Location", url); - c.WriteHeader(code); - fmt.Fprintf(c, note, url); + c.SetHeader("Location", url) + c.WriteHeader(code) + fmt.Fprintf(c, note, url) } // Redirect to a fixed URL type redirectHandler struct { - url string; - code int; + url string + code int } func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) { @@ -433,11 +433,11 @@ func RedirectHandler(url string, code int) Handler { // redirecting any request containing . or .. elements to an // equivalent .- and ..-free URL. type ServeMux struct { - m map[string]Handler; + m map[string]Handler } // NewServeMux allocates and returns a new ServeMux. -func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} } +func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} } // DefaultServeMux is the default ServeMux used by Serve. var DefaultServeMux = NewServeMux() @@ -448,11 +448,11 @@ func pathMatch(pattern, path string) bool { // should not happen return false } - n := len(pattern); + n := len(pattern) if pattern[n-1] != '/' { return pattern == path } - return len(path) >= n && path[0:n] == pattern; + return len(path) >= n && path[0:n] == pattern } // Return the canonical path for p, eliminating . and .. elements. @@ -463,13 +463,13 @@ func cleanPath(p string) string { if p[0] != '/' { p = "/" + p } - np := path.Clean(p); + np := path.Clean(p) // path.Clean removes trailing slash except for root; // put the trailing slash back if necessary. if p[len(p)-1] == '/' && np != "/" { np += "/" } - return np; + return np } // ServeHTTP dispatches the request to the handler whose @@ -477,27 +477,27 @@ func cleanPath(p string) string { func (mux *ServeMux) ServeHTTP(c *Conn, req *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); - return; + c.SetHeader("Location", p) + c.WriteHeader(StatusMovedPermanently) + return } // Most-specific (longest) pattern wins. - var h Handler; - var n = 0; + var h Handler + var n = 0 for k, v := range mux.m { if !pathMatch(k, req.URL.Path) { continue } if h == nil || len(k) > n { - n = len(k); - h = v; + n = len(k) + h = v } } if h == nil { h = NotFoundHandler() } - h.ServeHTTP(c, req); + h.ServeHTTP(c, req) } // Handle registers the handler for the given pattern. @@ -506,11 +506,11 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { panicln("http: invalid pattern", pattern) } - mux.m[pattern] = handler; + mux.m[pattern] = handler // Helpful behavior: // If pattern is /tree/, insert permanent redirect for /tree. - n := len(pattern); + n := len(pattern) if n > 0 && pattern[n-1] == '/' { mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently) } @@ -518,7 +518,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { // Handle registers the handler for the given pattern // in the DefaultServeMux. -func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } +func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } // Serve accepts incoming HTTP connections on the listener l, // creating a new service thread for each. The service threads @@ -529,17 +529,17 @@ func Serve(l net.Listener, handler Handler) os.Error { handler = DefaultServeMux } for { - rw, e := l.Accept(); + rw, e := l.Accept() if e != nil { return e } - c, err := newConn(rw, handler); + c, err := newConn(rw, handler) if err != nil { continue } - go c.serve(); + go c.serve() } - panic("not reached"); + panic("not reached") } // ListenAndServe listens on the TCP network address addr @@ -569,11 +569,11 @@ func Serve(l net.Listener, handler Handler) os.Error { // } // } func ListenAndServe(addr string, handler Handler) os.Error { - l, e := net.Listen("tcp", addr); + l, e := net.Listen("tcp", addr) if e != nil { return e } - e = Serve(l, handler); - l.Close(); - return e; + e = Serve(l, handler) + l.Close() + return e } |
