2008-09-24 16:26:55 -06:00
|
|
|
// 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.
|
|
|
|
|
2009-02-02 19:01:32 -07:00
|
|
|
// HTTP server. See RFC 2616.
|
2008-09-24 16:26:55 -06:00
|
|
|
|
2009-02-02 19:01:32 -07:00
|
|
|
// TODO(rsc):
|
|
|
|
// logging
|
|
|
|
// cgi support
|
|
|
|
// post support
|
2008-09-24 16:26:55 -06:00
|
|
|
|
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2009-02-02 19:01:32 -07:00
|
|
|
"bufio";
|
|
|
|
"fmt";
|
|
|
|
"http";
|
2008-09-24 16:26:55 -06:00
|
|
|
"io";
|
2009-02-03 15:16:22 -07:00
|
|
|
"log";
|
2008-09-24 16:26:55 -06:00
|
|
|
"net";
|
2009-02-02 19:01:32 -07:00
|
|
|
"os";
|
2009-04-07 01:40:07 -06:00
|
|
|
"path";
|
2008-11-17 13:34:03 -07:00
|
|
|
"strconv";
|
2008-09-24 16:26:55 -06:00
|
|
|
)
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// Errors introduced by the HTTP server.
|
|
|
|
var (
|
|
|
|
ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush");
|
|
|
|
ErrHijacked = os.NewError("Conn has been hijacked");
|
|
|
|
)
|
2009-02-02 19:01:32 -07:00
|
|
|
|
|
|
|
type Conn struct
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// Objects implemeting the Handler interface can be
|
|
|
|
// registered to serve a particular path or subtree
|
|
|
|
// in the HTTP server.
|
2009-02-02 19:01:32 -07:00
|
|
|
type Handler interface {
|
|
|
|
ServeHTTP(*Conn, *Request);
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// A Conn represents the server side of a single active HTTP connection.
|
2009-02-02 19:01:32 -07:00
|
|
|
type Conn struct {
|
2009-02-03 15:16:22 -07:00
|
|
|
RemoteAddr string; // network address of remote side
|
2009-03-11 13:51:10 -06:00
|
|
|
Req *Request; // current HTTP request
|
2009-02-03 15:16:22 -07:00
|
|
|
|
2009-05-08 12:22:57 -06:00
|
|
|
rwc io.ReadWriteCloser; // i/o connection
|
2009-05-08 12:52:39 -06:00
|
|
|
buf *bufio.ReadWriter; // buffered rwc
|
2009-02-03 15:16:22 -07:00
|
|
|
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
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create new connection from rwc.
|
2009-05-08 12:22:57 -06:00
|
|
|
func newConn(rwc io.ReadWriteCloser, raddr string, handler Handler) (c *Conn, err os.Error) {
|
2009-02-02 19:01:32 -07:00
|
|
|
c = new(Conn);
|
|
|
|
c.RemoteAddr = raddr;
|
|
|
|
c.handler = handler;
|
2009-03-11 13:51:10 -06:00
|
|
|
c.rwc = rwc;
|
2009-05-08 12:52:39 -06:00
|
|
|
br := bufio.NewReader(rwc);
|
|
|
|
bw := bufio.NewWriter(rwc);
|
|
|
|
c.buf = bufio.NewReadWriter(br, bw);
|
2009-02-02 19:01:32 -07:00
|
|
|
return c, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Conn) SetHeader(hdr, val string)
|
|
|
|
|
|
|
|
// Read next request from connection.
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *Conn) readRequest() (req *Request, err os.Error) {
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
|
|
|
return nil, ErrHijacked
|
|
|
|
}
|
2009-05-08 12:52:39 -06:00
|
|
|
if req, err = ReadRequest(c.buf.Reader); err != nil {
|
2009-02-02 19:01:32 -07:00
|
|
|
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.
|
2009-02-03 15:16:22 -07:00
|
|
|
c.closeAfterReply = true;
|
2009-02-02 19:01:32 -07:00
|
|
|
c.chunking = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-02-02 19:01:32 -07:00
|
|
|
func (c *Conn) SetHeader(hdr, val string) {
|
|
|
|
c.header[CanonicalHeaderKey(hdr)] = val;
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-02-02 19:01:32 -07:00
|
|
|
func (c *Conn) WriteHeader(code int) {
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
|
|
|
log.Stderr("http: Conn.WriteHeader on hijacked connection");
|
|
|
|
return
|
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
if c.wroteHeader {
|
2009-02-03 15:16:22 -07:00
|
|
|
log.Stderr("http: multiple Conn.WriteHeader calls");
|
2009-02-02 19:01:32 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
c.wroteHeader = true;
|
|
|
|
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;
|
|
|
|
}
|
2009-02-03 15:16:22 -07:00
|
|
|
io.WriteString(c.buf, proto + " " + codestring + " " + text + "\r\n");
|
2009-02-02 19:01:32 -07:00
|
|
|
for k,v := range c.header {
|
2009-02-03 15:16:22 -07:00
|
|
|
io.WriteString(c.buf, k + ": " + v + "\r\n");
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
2009-02-03 15:16:22 -07:00
|
|
|
io.WriteString(c.buf, "\r\n");
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *Conn) Write(data []byte) (n int, err os.Error) {
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
|
|
|
log.Stderr("http: Conn.Write on hijacked connection");
|
|
|
|
return 0, ErrHijacked
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
if !c.wroteHeader {
|
|
|
|
c.WriteHeader(StatusOK);
|
|
|
|
}
|
|
|
|
if len(data) == 0 {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(rsc): if chunking happened after the buffering,
|
2009-02-03 15:16:22 -07:00
|
|
|
// then there would be fewer chunk headers.
|
|
|
|
// On the other hand, it would make hijacking more difficult.
|
2009-02-02 19:01:32 -07:00
|
|
|
if c.chunking {
|
2009-02-03 15:16:22 -07:00
|
|
|
fmt.Fprintf(c.buf, "%x\r\n", len(data)); // TODO(rsc): use strconv not fmt
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
2009-04-27 01:38:04 -06:00
|
|
|
n, err = c.buf.Write(data);
|
|
|
|
if err == nil && c.chunking {
|
|
|
|
if n != len(data) {
|
2009-05-18 12:47:35 -06:00
|
|
|
err = io.ErrShortWrite;
|
2009-04-27 01:38:04 -06:00
|
|
|
}
|
|
|
|
if err == nil {
|
|
|
|
io.WriteString(c.buf, "\r\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, err;
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-02-03 15:16:22 -07:00
|
|
|
func (c *Conn) flush() {
|
2009-02-02 19:01:32 -07:00
|
|
|
if !c.wroteHeader {
|
|
|
|
c.WriteHeader(StatusOK);
|
|
|
|
}
|
|
|
|
if c.chunking {
|
2009-02-03 15:16:22 -07:00
|
|
|
io.WriteString(c.buf, "0\r\n");
|
2009-02-02 19:01:32 -07:00
|
|
|
// trailer key/value pairs, followed by blank line
|
2009-02-03 15:16:22 -07:00
|
|
|
io.WriteString(c.buf, "\r\n");
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
2009-02-03 15:16:22 -07:00
|
|
|
c.buf.Flush();
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close the connection.
|
2009-02-03 15:16:22 -07:00
|
|
|
func (c *Conn) close() {
|
|
|
|
if c.buf != nil {
|
|
|
|
c.buf.Flush();
|
|
|
|
c.buf = nil;
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
2009-03-11 13:51:10 -06:00
|
|
|
if c.rwc != nil {
|
|
|
|
c.rwc.Close();
|
|
|
|
c.rwc = nil;
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serve a new connection.
|
|
|
|
func (c *Conn) serve() {
|
2008-09-24 16:26:55 -06:00
|
|
|
for {
|
2009-02-02 19:01:32 -07:00
|
|
|
req, err := c.readRequest();
|
2008-09-24 16:26:55 -06:00
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
// HTTP cannot have multiple simultaneous active requests.
|
|
|
|
// Until the server replies to this request, it can't read another,
|
2009-04-07 01:40:07 -06:00
|
|
|
// so we might as well run the handler in this goroutine.
|
2009-02-02 19:01:32 -07:00
|
|
|
c.handler.ServeHTTP(c, req);
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
2009-02-02 19:01:32 -07:00
|
|
|
return;
|
|
|
|
}
|
2009-02-03 15:16:22 -07:00
|
|
|
c.flush();
|
|
|
|
if c.closeAfterReply {
|
2009-02-02 19:01:32 -07:00
|
|
|
break;
|
2008-09-24 16:26:55 -06:00
|
|
|
}
|
|
|
|
}
|
2009-02-03 15:16:22 -07:00
|
|
|
c.close();
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-05-08 12:52:39 -06:00
|
|
|
func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
|
|
|
return nil, nil, ErrHijacked;
|
|
|
|
}
|
|
|
|
c.hijacked = true;
|
2009-03-11 13:51:10 -06:00
|
|
|
rwc = c.rwc;
|
2009-02-03 15:16:22 -07:00
|
|
|
buf = c.buf;
|
2009-03-11 13:51:10 -06:00
|
|
|
c.rwc = nil;
|
2009-02-03 15:16:22 -07:00
|
|
|
c.buf = nil;
|
|
|
|
return;
|
2008-09-24 16:26:55 -06:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-02-02 19:01:32 -07:00
|
|
|
type HandlerFunc func(*Conn, *Request)
|
2009-03-11 13:51:10 -06:00
|
|
|
|
|
|
|
// ServeHTTP calls f(c, req).
|
2009-02-02 19:01:32 -07:00
|
|
|
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
f(c, req);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper handlers
|
|
|
|
|
2009-04-14 21:31:31 -06:00
|
|
|
// NotFound replies to the request with an HTTP 404 not found error.
|
|
|
|
func NotFound(c *Conn, req *Request) {
|
2009-02-02 19:01:32 -07:00
|
|
|
c.SetHeader("Content-Type", "text/plain; charset=utf-8");
|
|
|
|
c.WriteHeader(StatusNotFound);
|
|
|
|
io.WriteString(c, "404 page not found\n");
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// NotFoundHandler returns a simple request handler
|
|
|
|
// that replies to each request with a ``404 page not found'' reply.
|
|
|
|
func NotFoundHandler() Handler {
|
2009-04-14 21:31:31 -06:00
|
|
|
return HandlerFunc(NotFound)
|
2009-03-11 13:51:10 -06:00
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
|
2009-04-14 21:31:31 -06:00
|
|
|
// Redirect replies to the request with a redirect to url,
|
|
|
|
// which may be a path relative to the request path.
|
2009-05-12 16:41:19 -06:00
|
|
|
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 = "";
|
|
|
|
}
|
|
|
|
|
2009-04-15 19:40:55 -06:00
|
|
|
u, err := ParseURL(url);
|
|
|
|
if err != nil {
|
2009-05-12 16:41:19 -06:00
|
|
|
goto finish
|
2009-04-15 19:40:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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, oldfile := 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 += "/";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-12 16:41:19 -06:00
|
|
|
finish:
|
2009-04-14 21:31:31 -06:00
|
|
|
c.SetHeader("Location", url);
|
2009-05-12 16:41:19 -06:00
|
|
|
c.WriteHeader(code);
|
|
|
|
fmt.Fprintf(c, note, url);
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-04-14 21:31:31 -06:00
|
|
|
// Redirect to a fixed URL
|
2009-05-12 16:41:19 -06:00
|
|
|
type redirectHandler struct {
|
|
|
|
url string;
|
|
|
|
code int;
|
|
|
|
}
|
|
|
|
func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
Redirect(c, rh.url, rh.code);
|
2009-04-14 21:31:31 -06:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// RedirectHandler returns a request handler that redirects
|
2009-05-12 16:41:19 -06:00
|
|
|
// each request it receives to the given url using the given
|
|
|
|
// status code.
|
|
|
|
func RedirectHandler(url string, code int) Handler {
|
|
|
|
return &redirectHandler{ url, code }
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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/.
|
2009-04-07 01:40:07 -06:00
|
|
|
//
|
|
|
|
// ServeMux also takes care of sanitizing the URL request path,
|
|
|
|
// redirecting any request containing . or .. elements to an
|
|
|
|
// equivalent .- and ..-free URL.
|
2009-02-02 19:01:32 -07:00
|
|
|
type ServeMux struct {
|
|
|
|
m map[string] Handler
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// NewServeMux allocates and returns a new ServeMux.
|
2009-02-02 19:01:32 -07:00
|
|
|
func NewServeMux() *ServeMux {
|
2009-03-03 09:39:12 -07:00
|
|
|
return &ServeMux{make(map[string] Handler)};
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// DefaultServeMux is the default ServeMux used by Serve.
|
2009-02-02 19:01:32 -07:00
|
|
|
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
|
2008-09-24 16:26:55 -06:00
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
return len(path) >= n && path[0:n] == pattern;
|
|
|
|
}
|
|
|
|
|
2009-04-07 01:40:07 -06:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// ServeHTTP dispatches the request to the handler whose
|
|
|
|
// pattern most closely matches the request URL.
|
2009-02-02 19:01:32 -07:00
|
|
|
func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
|
2009-04-07 01:40:07 -06:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2009-02-02 19:01:32 -07:00
|
|
|
// 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 {
|
2009-03-11 13:51:10 -06:00
|
|
|
h = NotFoundHandler();
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
h.ServeHTTP(c, req);
|
|
|
|
}
|
2008-09-24 16:26:55 -06:00
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// Handle registers the handler for the given pattern.
|
2009-02-02 19:01:32 -07:00
|
|
|
func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
|
|
|
if pattern == "" || pattern[0] != '/' {
|
|
|
|
panicln("http: invalid pattern", pattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
mux.m[pattern] = handler;
|
|
|
|
|
|
|
|
// Helpful behavior:
|
2009-05-12 16:41:19 -06:00
|
|
|
// If pattern is /tree/, insert permanent redirect for /tree.
|
2009-02-02 19:01:32 -07:00
|
|
|
n := len(pattern);
|
|
|
|
if n > 0 && pattern[n-1] == '/' {
|
2009-05-12 16:41:19 -06:00
|
|
|
mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently);
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// Handle registers the handler for the given pattern
|
|
|
|
// in the DefaultServeMux.
|
|
|
|
func Handle(pattern string, handler Handler) {
|
|
|
|
DefaultServeMux.Handle(pattern, handler);
|
2009-02-02 19:01:32 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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.
|
2009-04-17 01:08:24 -06:00
|
|
|
func Serve(l net.Listener, handler Handler) os.Error {
|
2009-02-02 19:01:32 -07:00
|
|
|
if handler == nil {
|
|
|
|
handler = DefaultServeMux;
|
|
|
|
}
|
2008-09-24 16:26:55 -06:00
|
|
|
for {
|
2008-10-08 10:34:50 -06:00
|
|
|
rw, raddr, e := l.Accept();
|
2008-09-24 16:26:55 -06:00
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
c, err := newConn(rw, raddr, handler);
|
|
|
|
if err != nil {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
go c.serve();
|
2008-09-24 16:26:55 -06:00
|
|
|
}
|
|
|
|
panic("not reached")
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
// 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())
|
|
|
|
// }
|
|
|
|
// }
|
2009-04-17 01:08:24 -06:00
|
|
|
func ListenAndServe(addr string, handler Handler) os.Error {
|
2008-10-08 10:34:50 -06:00
|
|
|
l, e := net.Listen("tcp", addr);
|
2008-09-24 16:26:55 -06:00
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
e = Serve(l, handler);
|
2008-10-08 10:34:50 -06:00
|
|
|
l.Close();
|
2008-09-24 16:26:55 -06:00
|
|
|
return e
|
|
|
|
}
|
2009-02-02 19:01:32 -07:00
|
|
|
|