| // 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 |
| |
| package http |
| |
| import ( |
| "bufio" |
| "bytes" |
| "crypto/rand" |
| "crypto/tls" |
| "fmt" |
| "io" |
| "log" |
| "net" |
| "os" |
| "path" |
| "runtime/debug" |
| "strconv" |
| "strings" |
| "sync" |
| "time" |
| ) |
| |
| // 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") |
| ErrContentLength = os.NewError("Conn.Write wrote more than the declared Content-Length") |
| ) |
| |
| // 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 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(ResponseWriter, *Request) |
| } |
| |
| // A ResponseWriter interface is used by an HTTP handler to |
| // construct an HTTP response. |
| type ResponseWriter interface { |
| // Header returns the header map that will be sent by WriteHeader. |
| // Changing the header after a call to WriteHeader (or Write) has |
| // no effect. |
| Header() Header |
| |
| // 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) |
| } |
| |
| // The Flusher interface is implemented by ResponseWriters that allow |
| // an HTTP handler to flush buffered data to the client. |
| // |
| // Note that even for ResponseWriters that support Flush, |
| // if the client is connected through an HTTP proxy, |
| // the buffered data may not reach the client until the response |
| // completes. |
| type Flusher interface { |
| // Flush sends any buffered data to the client. |
| Flush() |
| } |
| |
| // The Hijacker interface is implemented by ResponseWriters that allow |
| // an HTTP handler to take over the connection. |
| type Hijacker interface { |
| // 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() (net.Conn, *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 net.Conn // i/o connection |
| buf *bufio.ReadWriter // buffered rwc |
| hijacked bool // connection has been hijacked by handler |
| tlsState *tls.ConnectionState // or nil when not using 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 Header // reply header parameters |
| written int64 // number of bytes written in body |
| contentLength int64 // explicitly-declared Content-Length; or -1 |
| status int // status code passed to WriteHeader |
| |
| // close connection after this reply. set on request and |
| // updated after response from handler if there's a |
| // "Connection: keep-alive" response header and a |
| // Content-Length. |
| closeAfterReply bool |
| } |
| |
| type writerOnly struct { |
| io.Writer |
| } |
| |
| func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) { |
| // Flush before checking r.chunking, as Flush will call |
| // WriteHeader if it hasn't been called yet, and WriteHeader |
| // is what sets r.chunking. |
| r.Flush() |
| if !r.chunking && r.bodyAllowed() { |
| if rf, ok := r.conn.rwc.(io.ReaderFrom); ok { |
| n, err = rf.ReadFrom(src) |
| r.written += n |
| return |
| } |
| } |
| // Fall back to default io.Copy implementation. |
| // Use wrapper to hide r.ReadFrom from io.Copy. |
| return io.Copy(writerOnly{r}, src) |
| } |
| |
| // Create new connection from rwc. |
| 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 |
| br := bufio.NewReader(rwc) |
| bw := bufio.NewWriter(rwc) |
| c.buf = bufio.NewReadWriter(br, bw) |
| |
| if tlsConn, ok := rwc.(*tls.Conn); ok { |
| c.tlsState = new(tls.ConnectionState) |
| *c.tlsState = tlsConn.ConnectionState() |
| } |
| |
| return c, nil |
| } |
| |
| // wrapper around io.ReaderCloser which on first read, sends an |
| // HTTP/1.1 100 Continue header |
| type expectContinueReader struct { |
| resp *response |
| readCloser io.ReadCloser |
| closed bool |
| } |
| |
| func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) { |
| if ecr.closed { |
| return 0, os.NewError("http: Read after Close on request Body") |
| } |
| 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) |
| } |
| |
| func (ecr *expectContinueReader) Close() os.Error { |
| ecr.closed = true |
| return ecr.readCloser.Close() |
| } |
| |
| // TimeFormat is the time format to use with |
| // time.Parse and time.Time.Format when parsing |
| // or generating times in HTTP headers. |
| // It is like time.RFC1123 but hard codes GMT as the time zone. |
| const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" |
| |
| // Read next request from connection. |
| 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 |
| } |
| |
| req.RemoteAddr = c.remoteAddr |
| req.TLS = c.tlsState |
| |
| w = new(response) |
| w.conn = c |
| w.req = req |
| w.header = make(Header) |
| w.contentLength = -1 |
| return w, nil |
| } |
| |
| func (w *response) Header() Header { |
| return w.header |
| } |
| |
| func (w *response) WriteHeader(code int) { |
| if w.conn.hijacked { |
| log.Print("http: response.WriteHeader on hijacked connection") |
| return |
| } |
| if w.wroteHeader { |
| log.Print("http: multiple response.WriteHeader calls") |
| return |
| } |
| |
| // Per RFC 2616, we should consume the request body before |
| // replying, if the handler hasn't already done so. |
| if w.req.ContentLength != 0 { |
| ecr, isExpecter := w.req.Body.(*expectContinueReader) |
| if !isExpecter || ecr.resp.wroteContinue { |
| w.req.Body.Close() |
| } |
| } |
| |
| w.wroteHeader = true |
| w.status = code |
| if code == StatusNotModified { |
| // Must not have body. |
| for _, header := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} { |
| if w.header.Get(header) != "" { |
| // TODO: return an error if WriteHeader gets a return parameter |
| // or set a flag on w to make future Writes() write an error page? |
| // for now just log and drop the header. |
| log.Printf("http: StatusNotModified response with header %q defined", header) |
| w.header.Del(header) |
| } |
| } |
| } else { |
| // Default output is HTML encoded in UTF-8. |
| if w.header.Get("Content-Type") == "" { |
| w.header.Set("Content-Type", "text/html; charset=utf-8") |
| } |
| } |
| |
| if _, ok := w.header["Date"]; !ok { |
| w.Header().Set("Date", time.UTC().Format(TimeFormat)) |
| } |
| |
| // Check for a explicit (and valid) Content-Length header. |
| var hasCL bool |
| var contentLength int64 |
| if clenStr := w.header.Get("Content-Length"); clenStr != "" { |
| var err os.Error |
| contentLength, err = strconv.Atoi64(clenStr) |
| if err == nil { |
| hasCL = true |
| } else { |
| log.Printf("http: invalid Content-Length of %q sent", clenStr) |
| w.header.Del("Content-Length") |
| } |
| } |
| |
| te := w.header.Get("Transfer-Encoding") |
| hasTE := te != "" |
| if hasCL && hasTE && te != "identity" { |
| // TODO: return an error if WriteHeader gets a return parameter |
| // For now just ignore the Content-Length. |
| log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", |
| te, contentLength) |
| w.header.Del("Content-Length") |
| hasCL = false |
| } |
| |
| if w.req.Method == "HEAD" || code == StatusNotModified { |
| // do nothing |
| } else if hasCL { |
| w.contentLength = contentLength |
| w.header.Del("Transfer-Encoding") |
| } else if w.req.ProtoAtLeast(1, 1) { |
| // HTTP/1.1 or greater: use chunked transfer encoding |
| // to avoid closing the connection at EOF. |
| // TODO: this blows away any custom or stacked Transfer-Encoding they |
| // might have set. Deal with that as need arises once we have a valid |
| // use case. |
| w.chunking = true |
| w.header.Set("Transfer-Encoding", "chunked") |
| } else { |
| // HTTP version < 1.1: cannot do chunked transfer |
| // encoding and we don't know the Content-Length so |
| // signal EOF by closing connection. |
| w.closeAfterReply = true |
| w.header.Del("Transfer-Encoding") // in case already set |
| } |
| |
| if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) { |
| _, connectionHeaderSet := w.header["Connection"] |
| if !connectionHeaderSet { |
| w.header.Set("Connection", "keep-alive") |
| } |
| } else if !w.req.ProtoAtLeast(1, 1) { |
| // Client did not ask to keep connection alive. |
| w.closeAfterReply = true |
| } |
| |
| // Cannot use Content-Length with non-identity Transfer-Encoding. |
| if w.chunking { |
| w.header.Del("Content-Length") |
| } |
| if !w.req.ProtoAtLeast(1, 0) { |
| return |
| } |
| proto := "HTTP/1.0" |
| if w.req.ProtoAtLeast(1, 1) { |
| proto = "HTTP/1.1" |
| } |
| codestring := strconv.Itoa(code) |
| text, ok := statusText[code] |
| if !ok { |
| text = "status code " + codestring |
| } |
| io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n") |
| w.header.Write(w.conn.buf) |
| io.WriteString(w.conn.buf, "\r\n") |
| } |
| |
| // bodyAllowed returns true if a Write is allowed for this response type. |
| // It's illegal to call this before the header has been flushed. |
| func (w *response) bodyAllowed() bool { |
| if !w.wroteHeader { |
| panic("") |
| } |
| return w.status != StatusNotModified && w.req.Method != "HEAD" |
| } |
| |
| func (w *response) Write(data []byte) (n int, err os.Error) { |
| if w.conn.hijacked { |
| log.Print("http: response.Write on hijacked connection") |
| return 0, ErrHijacked |
| } |
| if !w.wroteHeader { |
| w.WriteHeader(StatusOK) |
| } |
| if len(data) == 0 { |
| return 0, nil |
| } |
| if !w.bodyAllowed() { |
| return 0, ErrBodyNotAllowed |
| } |
| |
| w.written += int64(len(data)) // ignoring errors, for errorKludge |
| if w.contentLength != -1 && w.written > w.contentLength { |
| return 0, ErrContentLength |
| } |
| |
| // 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 w.chunking { |
| fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt |
| } |
| n, err = w.conn.buf.Write(data) |
| if err == nil && w.chunking { |
| if n != len(data) { |
| err = io.ErrShortWrite |
| } |
| if err == nil { |
| io.WriteString(w.conn.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(w *response) { |
| const min = 1024 |
| |
| // Is this an error? |
| if kind := w.status / 100; kind != 4 && kind != 5 { |
| return |
| } |
| |
| // Did the handler supply any info? Enough? |
| if w.written == 0 || w.written >= min { |
| return |
| } |
| |
| // Is it a broken browser? |
| var msg string |
| switch agent := w.req.UserAgent(); { |
| case strings.Contains(agent, "MSIE"): |
| msg = "Internet Explorer" |
| case strings.Contains(agent, "Chrome/"): |
| 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(w.header.Get("Content-Type"), ";", 2)[0] |
| switch baseType { |
| case "text/html": |
| io.WriteString(w, "<!-- ") |
| for w.written < min { |
| io.WriteString(w, msg) |
| } |
| io.WriteString(w, " -->") |
| case "text/plain": |
| io.WriteString(w, "\n") |
| for w.written < min { |
| io.WriteString(w, msg) |
| } |
| } |
| } |
| |
| 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 w.req.wantsHttp10KeepAlive() { |
| sentLength := w.header.Get("Content-Length") != "" |
| if sentLength && w.header.Get("Connection") == "keep-alive" { |
| w.closeAfterReply = false |
| } |
| } |
| if !w.wroteHeader { |
| w.WriteHeader(StatusOK) |
| } |
| errorKludge(w) |
| if w.chunking { |
| io.WriteString(w.conn.buf, "0\r\n") |
| // trailer key/value pairs, followed by blank line |
| io.WriteString(w.conn.buf, "\r\n") |
| } |
| w.conn.buf.Flush() |
| w.req.Body.Close() |
| if w.req.MultipartForm != nil { |
| w.req.MultipartForm.RemoveAll() |
| } |
| |
| if w.contentLength != -1 && w.contentLength != w.written { |
| // Did not write enough. Avoid getting out of sync. |
| w.closeAfterReply = true |
| } |
| } |
| |
| func (w *response) Flush() { |
| if !w.wroteHeader { |
| w.WriteHeader(StatusOK) |
| } |
| w.conn.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() { |
| defer func() { |
| err := recover() |
| if err == nil { |
| return |
| } |
| c.rwc.Close() |
| |
| var buf bytes.Buffer |
| fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err) |
| buf.Write(debug.Stack()) |
| log.Print(buf.String()) |
| }() |
| |
| for { |
| w, err := c.readRequest() |
| if err != nil { |
| break |
| } |
| |
| // Expect 100 Continue support |
| req := w.req |
| if req.expectsContinue() { |
| if req.ProtoAtLeast(1, 1) { |
| // Wrap the Body reader with one that replies on the connection |
| req.Body = &expectContinueReader{readCloser: req.Body, resp: w} |
| } |
| if req.ContentLength == 0 { |
| w.Header().Set("Connection", "close") |
| w.WriteHeader(StatusBadRequest) |
| break |
| } |
| req.Header.Del("Expect") |
| } else if req.Header.Get("Expect") != "" { |
| // TODO(bradfitz): let ServeHTTP handlers handle |
| // requests with non-standard expectation[s]? Seems |
| // theoretical at best, and doesn't fit into the |
| // current ServeHTTP model anyway. We'd need to |
| // make the ResponseWriter an optional |
| // "ExpectReplier" interface or something. |
| // |
| // For now we'll just obey RFC 2616 14.20 which says |
| // "If a server receives a request containing an |
| // Expect field that includes an expectation- |
| // extension that it does not support, it MUST |
| // respond with a 417 (Expectation Failed) status." |
| w.Header().Set("Connection", "close") |
| w.WriteHeader(StatusExpectationFailed) |
| 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. |
| // [*] Not strictly true: HTTP pipelining. We could let them all process |
| // in parallel even if their responses need to be serialized. |
| c.handler.ServeHTTP(w, w.req) |
| if c.hijacked { |
| return |
| } |
| w.finishRequest() |
| if w.closeAfterReply { |
| break |
| } |
| } |
| c.close() |
| } |
| |
| // Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter |
| // and a Hijacker. |
| func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err os.Error) { |
| if w.conn.hijacked { |
| return nil, nil, ErrHijacked |
| } |
| w.conn.hijacked = true |
| rwc = w.conn.rwc |
| buf = w.conn.buf |
| w.conn.rwc = nil |
| w.conn.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(ResponseWriter, *Request) |
| |
| // ServeHTTP calls f(w, r). |
| 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(w ResponseWriter, error string, code int) { |
| w.Header().Set("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(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. |
| 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(w ResponseWriter, r *Request, url string, code int) { |
| if u, err := ParseURL(url); err == nil { |
| // 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 := r.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 |
| } |
| |
| var query string |
| if i := strings.Index(url, "?"); i != -1 { |
| url, query = url[:i], url[i:] |
| } |
| |
| // clean up but preserve trailing slash |
| trailing := url[len(url)-1] == '/' |
| url = path.Clean(url) |
| if trailing && url[len(url)-1] != '/' { |
| url += "/" |
| } |
| url += query |
| } |
| } |
| |
| w.Header().Set("Location", url) |
| w.WriteHeader(code) |
| |
| // RFC2616 recommends that a short note "SHOULD" be included in the |
| // response because older user agents may not understand 301/307. |
| // Shouldn't send the response for POST or HEAD; that leaves GET. |
| if r.Method == "GET" { |
| note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n" |
| fmt.Fprintln(w, note) |
| } |
| } |
| |
| func htmlEscape(s string) string { |
| s = strings.Replace(s, "&", "&", -1) |
| s = strings.Replace(s, "<", "<", -1) |
| s = strings.Replace(s, ">", ">", -1) |
| s = strings.Replace(s, "\"", """, -1) |
| s = strings.Replace(s, "'", "'", -1) |
| return s |
| } |
| |
| // Redirect to a fixed URL |
| type redirectHandler struct { |
| url string |
| code int |
| } |
| |
| func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { |
| Redirect(w, r, 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, rooted paths, like "/favicon.ico", |
| // or rooted subtrees, like "/images/" (note the trailing slash). |
| // 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. |
| // |
| // Patterns may optionally begin with a host name, restricting matches to |
| // URLs on that host only. Host-specific patterns take precedence over |
| // general patterns, so that a handler might register for the two patterns |
| // "/codesearch" and "codesearch.google.com/" without also 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 |
| } |
| |
| // Find a handler on a handler map given a path string |
| // Most-specific (longest) pattern wins |
| func (mux *ServeMux) match(path string) Handler { |
| var h Handler |
| var n = 0 |
| for k, v := range mux.m { |
| if !pathMatch(k, path) { |
| continue |
| } |
| if h == nil || len(k) > n { |
| n = len(k) |
| h = v |
| } |
| } |
| return h |
| } |
| |
| // ServeHTTP dispatches the request to the handler whose |
| // pattern most closely matches the request URL. |
| func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { |
| // Clean path to canonical form and redirect. |
| if p := cleanPath(r.URL.Path); p != r.URL.Path { |
| w.Header().Set("Location", p) |
| w.WriteHeader(StatusMovedPermanently) |
| return |
| } |
| // Host-specific pattern takes precedence over generic ones |
| h := mux.match(r.Host + r.URL.Path) |
| if h == nil { |
| h = mux.match(r.URL.Path) |
| } |
| if h == nil { |
| h = NotFoundHandler() |
| } |
| h.ServeHTTP(w, r) |
| } |
| |
| // Handle registers the handler for the given pattern. |
| func (mux *ServeMux) Handle(pattern string, handler Handler) { |
| if pattern == "" { |
| 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(ResponseWriter, *Request)) { |
| mux.Handle(pattern, HandlerFunc(handler)) |
| } |
| |
| // Handle registers the handler for the given pattern |
| // in the DefaultServeMux. |
| // The documentation for ServeMux explains how patterns are matched. |
| func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } |
| |
| // HandleFunc registers the handler function for the given pattern |
| // in the DefaultServeMux. |
| // The documentation for ServeMux explains how patterns are matched. |
| func HandleFunc(pattern string, handler func(ResponseWriter, *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 { |
| srv := &Server{Handler: handler} |
| return srv.Serve(l) |
| } |
| |
| // A Server defines parameters for running an HTTP server. |
| type Server struct { |
| Addr string // TCP address to listen on, ":http" if empty |
| Handler Handler // handler to invoke, http.DefaultServeMux if nil |
| ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections |
| WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections |
| } |
| |
| // ListenAndServe listens on the TCP network address srv.Addr and then |
| // calls Serve to handle requests on incoming connections. If |
| // srv.Addr is blank, ":http" is used. |
| func (srv *Server) ListenAndServe() os.Error { |
| addr := srv.Addr |
| if addr == "" { |
| addr = ":http" |
| } |
| l, e := net.Listen("tcp", addr) |
| if e != nil { |
| return e |
| } |
| return srv.Serve(l) |
| } |
| |
| // Serve accepts incoming connections on the Listener l, creating a |
| // new service thread for each. The service threads read requests and |
| // then call srv.Handler to reply to them. |
| func (srv *Server) Serve(l net.Listener) os.Error { |
| defer l.Close() |
| handler := srv.Handler |
| if handler == nil { |
| handler = DefaultServeMux |
| } |
| for { |
| rw, e := l.Accept() |
| if e != nil { |
| if ne, ok := e.(net.Error); ok && ne.Temporary() { |
| log.Printf("http: Accept error: %v", e) |
| continue |
| } |
| return e |
| } |
| if srv.ReadTimeout != 0 { |
| rw.SetReadTimeout(srv.ReadTimeout) |
| } |
| if srv.WriteTimeout != 0 { |
| rw.SetWriteTimeout(srv.WriteTimeout) |
| } |
| 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(w http.ResponseWriter, req *http.Request) { |
| // io.WriteString(w, "hello, world!\n") |
| // } |
| // |
| // func main() { |
| // http.HandleFunc("/hello", HelloServer) |
| // err := http.ListenAndServe(":12345", nil) |
| // if err != nil { |
| // log.Fatal("ListenAndServe: ", err.String()) |
| // } |
| // } |
| func ListenAndServe(addr string, handler Handler) os.Error { |
| server := &Server{Addr: addr, Handler: handler} |
| return server.ListenAndServe() |
| } |
| |
| // ListenAndServeTLS acts identically to ListenAndServe, except that it |
| // expects HTTPS connections. Additionally, files containing a certificate and |
| // matching private key for the server must be provided. If the certificate |
| // is signed by a certificate authority, the certFile should be the concatenation |
| // of the server's certificate followed by the CA's certificate. |
| // |
| // A trivial example server is: |
| // |
| // import ( |
| // "http" |
| // "log" |
| // ) |
| // |
| // func handler(w http.ResponseWriter, req *http.Request) { |
| // w.Header().Set("Content-Type", "text/plain") |
| // w.Write([]byte("This is an example server.\n")) |
| // } |
| // |
| // func main() { |
| // http.HandleFunc("/", handler) |
| // log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") |
| // err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil) |
| // if err != nil { |
| // log.Fatal(err) |
| // } |
| // } |
| // |
| // One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem. |
| func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) os.Error { |
| server := &Server{Addr: addr, Handler: handler} |
| return server.ListenAndServeTLS(certFile, keyFile) |
| } |
| |
| // ListenAndServeTLS listens on the TCP network address srv.Addr and |
| // then calls Serve to handle requests on incoming TLS connections. |
| // |
| // Filenames containing a certificate and matching private key for |
| // the server must be provided. If the certificate is signed by a |
| // certificate authority, the certFile should be the concatenation |
| // of the server's certificate followed by the CA's certificate. |
| // |
| // If srv.Addr is blank, ":https" is used. |
| func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error { |
| addr := s.Addr |
| if addr == "" { |
| addr = ":https" |
| } |
| config := &tls.Config{ |
| Rand: rand.Reader, |
| Time: time.Seconds, |
| NextProtos: []string{"http/1.1"}, |
| } |
| |
| var err os.Error |
| config.Certificates = make([]tls.Certificate, 1) |
| config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) |
| if err != nil { |
| return err |
| } |
| |
| conn, err := net.Listen("tcp", addr) |
| if err != nil { |
| return err |
| } |
| |
| tlsListener := tls.NewListener(conn, config) |
| return s.Serve(tlsListener) |
| } |
| |
| // TimeoutHandler returns a Handler that runs h with the given time limit. |
| // |
| // The new Handler calls h.ServeHTTP to handle each request, but if a |
| // call runs for more than ns nanoseconds, the handler responds with |
| // a 503 Service Unavailable error and the given message in its body. |
| // (If msg is empty, a suitable default message will be sent.) |
| // After such a timeout, writes by h to its ResponseWriter will return |
| // ErrHandlerTimeout. |
| func TimeoutHandler(h Handler, ns int64, msg string) Handler { |
| f := func() <-chan int64 { |
| return time.After(ns) |
| } |
| return &timeoutHandler{h, f, msg} |
| } |
| |
| // ErrHandlerTimeout is returned on ResponseWriter Write calls |
| // in handlers which have timed out. |
| var ErrHandlerTimeout = os.NewError("http: Handler timeout") |
| |
| type timeoutHandler struct { |
| handler Handler |
| timeout func() <-chan int64 // returns channel producing a timeout |
| body string |
| } |
| |
| func (h *timeoutHandler) errorBody() string { |
| if h.body != "" { |
| return h.body |
| } |
| return "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>" |
| } |
| |
| func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { |
| done := make(chan bool) |
| tw := &timeoutWriter{w: w} |
| go func() { |
| h.handler.ServeHTTP(tw, r) |
| done <- true |
| }() |
| select { |
| case <-done: |
| return |
| case <-h.timeout(): |
| tw.mu.Lock() |
| defer tw.mu.Unlock() |
| if !tw.wroteHeader { |
| tw.w.WriteHeader(StatusServiceUnavailable) |
| tw.w.Write([]byte(h.errorBody())) |
| } |
| tw.timedOut = true |
| } |
| } |
| |
| type timeoutWriter struct { |
| w ResponseWriter |
| |
| mu sync.Mutex |
| timedOut bool |
| wroteHeader bool |
| } |
| |
| func (tw *timeoutWriter) Header() Header { |
| return tw.w.Header() |
| } |
| |
| func (tw *timeoutWriter) Write(p []byte) (int, os.Error) { |
| tw.mu.Lock() |
| timedOut := tw.timedOut |
| tw.mu.Unlock() |
| if timedOut { |
| return 0, ErrHandlerTimeout |
| } |
| return tw.w.Write(p) |
| } |
| |
| func (tw *timeoutWriter) WriteHeader(code int) { |
| tw.mu.Lock() |
| if tw.timedOut || tw.wroteHeader { |
| tw.mu.Unlock() |
| return |
| } |
| tw.wroteHeader = true |
| tw.mu.Unlock() |
| tw.w.WriteHeader(code) |
| } |