| // 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"); | |
| 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); | |
| } | |
| // 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 | |
| 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; | |
| } | |
| // 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.Req = req; | |
| // 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; | |
| 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 | |
| } | |
| 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 | |
| // 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"); | |
| } | |
| // 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] != '/' { | |
| panicln("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) | |
| } | |
| } | |
| // Handle registers the handler for the given pattern | |
| // in the DefaultServeMux. | |
| 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 | |
| // 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"; | |
| // ) | |
| // | |
| // // hello world, the web server | |
| // func HelloServer(c *http.Conn, req *http.Request) { | |
| // io.WriteString(c, "hello, world!\n"); | |
| // } | |
| // | |
| // func main() { | |
| // http.Handle("/hello", http.HandlerFunc(HelloServer)); | |
| // err := http.ListenAndServe(":12345", nil); | |
| // if err != nil { | |
| // panic("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; | |
| } |