| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // HTTP server. See RFC 2616. | |
| // TODO(rsc): | |
| // logging | |
| // cgi support | |
| // post support | |
| package http | |
| import ( | |
| "bufio" | |
| "fmt" | |
| "io" | |
| "log" | |
| "net" | |
| "os" | |
| "path" | |
| "strconv" | |
| "strings" | |
| ) | |
| // Errors introduced by the HTTP server. | |
| var ( | |
| ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush") | |
| ErrBodyNotAllowed = os.NewError("http: response status code does not allow body") | |
| 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. | |
| // | |
| // ServeHTTP should write reply headers and data to the Conn | |
| // 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 | |
| closeAfterReply bool // close connection after this reply | |
| 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 | |
| } | |
| // 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() | |
| } | |
| c.handler = handler | |
| c.rwc = rwc | |
| br := bufio.NewReader(rwc) | |
| bw := bufio.NewWriter(rwc) | |
| c.buf = bufio.NewReadWriter(br, bw) | |
| return c, nil | |
| } | |
| // wrapper around io.ReaderCloser which on first read, sends an | |
| // HTTP/1.1 100 Continue header | |
| type expectContinueReader struct { | |
| conn *Conn | |
| 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() | |
| } | |
| } | |
| return ecr.readCloser.Read(p) | |
| } | |
| func (ecr *expectContinueReader) Close() os.Error { | |
| return ecr.readCloser.Close() | |
| } | |
| // Read next request from connection. | |
| func (c *Conn) readRequest() (req *Request, err os.Error) { | |
| if c.hijacked { | |
| return nil, ErrHijacked | |
| } | |
| 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 | |
| // Expect 100 Continue support | |
| if req.expectsContinue() { | |
| // Wrap the Body reader with one that replies on the connection | |
| req.Body = &expectContinueReader{readCloser: req.Body, conn: c} | |
| } | |
| // Default output is HTML encoded in 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") | |
| } else { | |
| // HTTP version < 1.1: cannot do chunked transfer | |
| // encoding, so signal EOF by closing connection. | |
| // Could avoid closing the connection if there is | |
| // a Content-Length: header in the response, | |
| // but everyone who expects persistent connections | |
| // does HTTP/1.1 now. | |
| c.closeAfterReply = true | |
| c.chunking = false | |
| } | |
| return req, nil | |
| } | |
| // 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") | |
| return | |
| } | |
| if c.wroteHeader { | |
| log.Stderr("http: multiple Conn.WriteHeader calls") | |
| return | |
| } | |
| c.wroteHeader = true | |
| c.status = code | |
| if code == StatusNotModified { | |
| // Must not have body. | |
| c.header["Content-Type"] = "", false | |
| c.header["Transfer-Encoding"] = "", false | |
| } | |
| c.written = 0 | |
| if !c.Req.ProtoAtLeast(1, 0) { | |
| return | |
| } | |
| proto := "HTTP/1.0" | |
| if c.Req.ProtoAtLeast(1, 1) { | |
| proto = "HTTP/1.1" | |
| } | |
| codestring := strconv.Itoa(code) | |
| text, ok := statusText[code] | |
| 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(c.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") | |
| return 0, ErrHijacked | |
| } | |
| if !c.wroteHeader { | |
| c.WriteHeader(StatusOK) | |
| } | |
| if len(data) == 0 { | |
| return 0, nil | |
| } | |
| if c.status == StatusNotModified { | |
| // Must not have body. | |
| return 0, ErrBodyNotAllowed | |
| } | |
| 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 | |
| } | |
| n, err = c.buf.Write(data) | |
| if err == nil && c.chunking { | |
| if n != len(data) { | |
| err = io.ErrShortWrite | |
| } | |
| if err == nil { | |
| io.WriteString(c.buf, "\r\n") | |
| } | |
| } | |
| return n, err | |
| } | |
| // If this is an error reply (4xx or 5xx) | |
| // and the handler wrote some data explaining the error, | |
| // some browsers (i.e., Chrome, Internet Explorer) | |
| // will show their own error instead unless the error is | |
| // 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) { | |
| const min = 1024 | |
| // Is this an error? | |
| if kind := c.status / 100; kind != 4 && kind != 5 { | |
| return | |
| } | |
| // Did the handler supply any info? Enough? | |
| if c.written == 0 || c.written >= min { | |
| return | |
| } | |
| // Is it a broken browser? | |
| var msg string | |
| switch agent := req.UserAgent; { | |
| case strings.Index(agent, "MSIE") >= 0: | |
| msg = "Internet Explorer" | |
| case strings.Index(agent, "Chrome/") >= 0: | |
| msg = "Chrome" | |
| default: | |
| return | |
| } | |
| 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] | |
| switch baseType { | |
| case "text/html": | |
| io.WriteString(c, "<!-- ") | |
| for c.written < min { | |
| io.WriteString(c, msg) | |
| } | |
| io.WriteString(c, " -->") | |
| case "text/plain": | |
| io.WriteString(c, "\n") | |
| for c.written < min { | |
| io.WriteString(c, msg) | |
| } | |
| } | |
| } | |
| func (c *Conn) finishRequest() { | |
| if !c.wroteHeader { | |
| c.WriteHeader(StatusOK) | |
| } | |
| errorKludge(c, c.Req) | |
| if c.chunking { | |
| io.WriteString(c.buf, "0\r\n") | |
| // trailer key/value pairs, followed by blank line | |
| io.WriteString(c.buf, "\r\n") | |
| } | |
| c.buf.Flush() | |
| } | |
| // Flush sends any buffered data to the client. | |
| func (c *Conn) Flush() { | |
| if !c.wroteHeader { | |
| c.WriteHeader(StatusOK) | |
| } | |
| c.buf.Flush() | |
| } | |
| // Close the connection. | |
| func (c *Conn) close() { | |
| if c.buf != nil { | |
| c.buf.Flush() | |
| c.buf = nil | |
| } | |
| if c.rwc != nil { | |
| c.rwc.Close() | |
| c.rwc = nil | |
| } | |
| } | |
| // Serve a new connection. | |
| func (c *Conn) serve() { | |
| for { | |
| 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) | |
| if c.hijacked { | |
| return | |
| } | |
| c.finishRequest() | |
| if c.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 { | |
| return nil, nil, ErrHijacked | |
| } | |
| 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 | |
| // 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) | |
| // ServeHTTP calls f(c, req). | |
| func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { | |
| f(c, req) | |
| } | |
| // 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) | |
| } | |
| // 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) } | |
| // NotFoundHandler returns a simple request handler | |
| // that replies to each request with a ``404 page not found'' reply. | |
| 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" | |
| if c.Req.Method == "POST" { | |
| note = "" | |
| } | |
| u, err := ParseURL(url) | |
| if err != nil { | |
| goto finish | |
| } | |
| // If url was relative, make absolute by | |
| // combining with request path. | |
| // The browser would probably do this for us, | |
| // but doing it ourselves is more reliable. | |
| // NOTE(rsc): RFC 2616 says that the Location | |
| // line must be an absolute URI, like | |
| // "http://www.google.com/redirect/", | |
| // not a path like "/redirect/". | |
| // Unfortunately, we don't know what to | |
| // put in the host name section to get the | |
| // client to connect to us again, so we can't | |
| // know the right absolute URI to send back. | |
| // 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 = "/" | |
| } | |
| if u.Scheme == "" { | |
| // no leading http://server | |
| if url == "" || url[0] != '/' { | |
| // make relative path absolute | |
| olddir, _ := path.Split(oldpath) | |
| url = olddir + url | |
| } | |
| // clean up but preserve trailing slash | |
| 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) | |
| } | |
| // Redirect to a fixed URL | |
| type redirectHandler struct { | |
| url string | |
| code int | |
| } | |
| func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) { | |
| Redirect(c, rh.url, rh.code) | |
| } | |
| // RedirectHandler returns a request handler that redirects | |
| // each request it receives to the given url using the given | |
| // status code. | |
| func RedirectHandler(url string, code int) Handler { | |
| return &redirectHandler{url, code} | |
| } | |
| // ServeMux is an HTTP request multiplexer. | |
| // It matches the URL of each incoming request against a list of registered | |
| // patterns and calls the handler for the pattern that | |
| // most closely matches the URL. | |
| // | |
| // Patterns named fixed paths, like "/favicon.ico", | |
| // or subtrees, like "/images/" (note the trailing slash). | |
| // Patterns must begin with /. | |
| // Longer patterns take precedence over shorter ones, so that | |
| // if there are handlers registered for both "/images/" | |
| // and "/images/thumbnails/", the latter handler will be | |
| // called for paths beginning "/images/thumbnails/" and the | |
| // former will receiver requests for any other paths in the | |
| // "/images/" subtree. | |
| // | |
| // In the future, the pattern syntax may be relaxed to allow | |
| // an optional host-name at the beginning of the pattern, | |
| // so that a handler might register for the two patterns | |
| // "/codesearch" and "codesearch.google.com/" | |
| // without taking over requests for http://www.google.com/. | |
| // | |
| // ServeMux also takes care of sanitizing the URL request path, | |
| // redirecting any request containing . or .. elements to an | |
| // equivalent .- and ..-free URL. | |
| type ServeMux struct { | |
| m map[string]Handler | |
| } | |
| // NewServeMux allocates and returns a new ServeMux. | |
| func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} } | |
| // DefaultServeMux is the default ServeMux used by Serve. | |
| var DefaultServeMux = NewServeMux() | |
| // Does path match pattern? | |
| func pathMatch(pattern, path string) bool { | |
| if len(pattern) == 0 { | |
| // should not happen | |
| return false | |
| } | |
| n := len(pattern) | |
| if pattern[n-1] != '/' { | |
| return pattern == path | |
| } | |
| return len(path) >= n && path[0:n] == pattern | |
| } | |
| // Return the canonical path for p, eliminating . and .. elements. | |
| func cleanPath(p string) string { | |
| if p == "" { | |
| return "/" | |
| } | |
| if p[0] != '/' { | |
| p = "/" + 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 | |
| } | |
| // ServeHTTP dispatches the request to the handler whose | |
| // pattern most closely matches the request URL. | |
| 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 | |
| } | |
| // Most-specific (longest) pattern wins. | |
| 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 | |
| } | |
| } | |
| if h == nil { | |
| h = NotFoundHandler() | |
| } | |
| h.ServeHTTP(c, req) | |
| } | |
| // Handle registers the handler for the given pattern. | |
| func (mux *ServeMux) Handle(pattern string, handler Handler) { | |
| if pattern == "" || pattern[0] != '/' { | |
| panic("http: invalid pattern " + pattern) | |
| } | |
| mux.m[pattern] = handler | |
| // Helpful behavior: | |
| // If pattern is /tree/, insert permanent redirect for /tree. | |
| n := len(pattern) | |
| if n > 0 && pattern[n-1] == '/' { | |
| mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently) | |
| } | |
| } | |
| // HandleFunc registers the handler function for the given pattern. | |
| func (mux *ServeMux) HandleFunc(pattern string, handler func(*Conn, *Request)) { | |
| mux.Handle(pattern, HandlerFunc(handler)) | |
| } | |
| // Handle registers the handler for the given pattern | |
| // in the DefaultServeMux. | |
| func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } | |
| // HandleFunc registers the handler function for the given pattern | |
| // in the DefaultServeMux. | |
| func HandleFunc(pattern string, handler func(*Conn, *Request)) { | |
| DefaultServeMux.HandleFunc(pattern, handler) | |
| } | |
| // Serve accepts incoming HTTP connections on the listener l, | |
| // creating a new service thread for each. The service threads | |
| // read requests and then call handler to reply to them. | |
| // Handler is typically nil, in which case the DefaultServeMux is used. | |
| func Serve(l net.Listener, handler Handler) os.Error { | |
| if handler == nil { | |
| handler = DefaultServeMux | |
| } | |
| for { | |
| rw, e := l.Accept() | |
| if e != nil { | |
| return e | |
| } | |
| c, err := newConn(rw, handler) | |
| if err != nil { | |
| continue | |
| } | |
| go c.serve() | |
| } | |
| panic("not reached") | |
| } | |
| // ListenAndServe listens on the TCP network address addr | |
| // and then calls Serve with handler to handle requests | |
| // on incoming connections. Handler is typically nil, | |
| // in which case the DefaultServeMux is used. | |
| // | |
| // A trivial example server is: | |
| // | |
| // package main | |
| // | |
| // import ( | |
| // "http" | |
| // "io" | |
| // "log" | |
| // ) | |
| // | |
| // // hello world, the web server | |
| // func HelloServer(c *http.Conn, req *http.Request) { | |
| // io.WriteString(c, "hello, world!\n") | |
| // } | |
| // | |
| // func main() { | |
| // http.HandleFunc("/hello", HelloServer) | |
| // err := http.ListenAndServe(":12345", nil) | |
| // if err != nil { | |
| // log.Exit("ListenAndServe: ", err.String()) | |
| // } | |
| // } | |
| func ListenAndServe(addr string, handler Handler) os.Error { | |
| l, e := net.Listen("tcp", addr) | |
| if e != nil { | |
| return e | |
| } | |
| e = Serve(l, handler) | |
| l.Close() | |
| return e | |
| } |