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";
|
2008-11-17 13:34:03 -07:00
|
|
|
"strconv";
|
2008-09-24 16:26:55 -06:00
|
|
|
)
|
|
|
|
|
2009-02-02 19:01:32 -07:00
|
|
|
var ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
|
2009-02-03 15:16:22 -07:00
|
|
|
var ErrHijacked = os.NewError("Conn has been hijacked")
|
2009-02-02 19:01:32 -07:00
|
|
|
|
|
|
|
type Conn struct
|
|
|
|
|
|
|
|
// Interface implemented by servers using this library.
|
|
|
|
type Handler interface {
|
|
|
|
ServeHTTP(*Conn, *Request);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Active HTTP connection (server side).
|
|
|
|
type Conn struct {
|
2009-02-03 15:16:22 -07:00
|
|
|
RemoteAddr string; // network address of remote side
|
|
|
|
Req *Request; // current HTTP request
|
|
|
|
|
|
|
|
fd io.ReadWriteClose; // i/o connection
|
|
|
|
buf *bufio.BufReadWrite; // buffered fd
|
|
|
|
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.
|
|
|
|
func newConn(rwc io.ReadWriteClose, raddr string, handler Handler) (c *Conn, err *os.Error) {
|
|
|
|
c = new(Conn);
|
|
|
|
c.RemoteAddr = raddr;
|
|
|
|
c.handler = handler;
|
2009-02-03 15:16:22 -07:00
|
|
|
c.fd = rwc;
|
|
|
|
br := bufio.NewBufRead(rwc);
|
|
|
|
bw := bufio.NewBufWrite(rwc);
|
|
|
|
c.buf = bufio.NewBufReadWrite(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.
|
|
|
|
func (c *Conn) readRequest() (req *Request, err *os.Error) {
|
2009-02-03 15:16:22 -07:00
|
|
|
if c.hijacked {
|
|
|
|
return nil, ErrHijacked
|
|
|
|
}
|
|
|
|
if req, err = ReadRequest(c.buf.BufRead); 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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Conn) SetHeader(hdr, val string) {
|
|
|
|
c.header[CanonicalHeaderKey(hdr)] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write header.
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(rsc): BUG in 6g: must return "nn int" not "n int"
|
|
|
|
// so that the implicit struct assignment in
|
2009-02-03 15:16:22 -07:00
|
|
|
// return c.buf.Write(data) works. oops
|
2009-02-02 19:01:32 -07:00
|
|
|
func (c *Conn) Write(data []byte) (nn 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-02-03 15:16:22 -07:00
|
|
|
return c.buf.Write(data);
|
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-02-03 15:16:22 -07:00
|
|
|
if c.fd != nil {
|
|
|
|
c.fd.Close();
|
|
|
|
c.fd = 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,
|
|
|
|
// so we might as well run the handler in this thread.
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow client to take over the connection.
|
|
|
|
// After a handler calls c.Hijack(), the HTTP server library
|
|
|
|
// will never touch the connection again.
|
|
|
|
// It is the caller's responsibility to manage and close
|
|
|
|
// the connection.
|
|
|
|
func (c *Conn) Hijack() (fd io.ReadWriteClose, buf *bufio.BufReadWrite, err *os.Error) {
|
|
|
|
if c.hijacked {
|
|
|
|
return nil, nil, ErrHijacked;
|
|
|
|
}
|
|
|
|
c.hijacked = true;
|
|
|
|
fd = c.fd;
|
|
|
|
buf = c.buf;
|
|
|
|
c.fd = nil;
|
|
|
|
c.buf = nil;
|
|
|
|
return;
|
2008-09-24 16:26:55 -06:00
|
|
|
}
|
|
|
|
|
2009-02-02 19:01:32 -07:00
|
|
|
// Adapter: can use RequestFunction(f) as Handler
|
|
|
|
type handlerFunc struct {
|
|
|
|
f func(*Conn, *Request)
|
|
|
|
}
|
|
|
|
func (h handlerFunc) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
h.f(c, req)
|
|
|
|
}
|
|
|
|
func HandlerFunc(f func(*Conn, *Request)) Handler {
|
|
|
|
return handlerFunc{f}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* simpler version of above, not accepted by 6g:
|
|
|
|
|
|
|
|
type HandlerFunc func(*Conn, *Request)
|
|
|
|
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
f(c, req);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Helper handlers
|
|
|
|
|
|
|
|
// 404 not found
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
var NotFoundHandler = HandlerFunc(notFound)
|
|
|
|
|
|
|
|
// Redirect to a fixed URL
|
|
|
|
type redirectHandler struct {
|
|
|
|
to string;
|
|
|
|
}
|
|
|
|
func (h *redirectHandler) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
c.SetHeader("Location", h.to);
|
|
|
|
c.WriteHeader(StatusMovedPermanently);
|
|
|
|
}
|
|
|
|
|
|
|
|
func RedirectHandler(to string) Handler {
|
|
|
|
return &redirectHandler{to};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Path-based HTTP request multiplexer.
|
|
|
|
// Patterns name fixed paths, like "/favicon.ico",
|
|
|
|
// or subtrees, like "/images/".
|
|
|
|
// For now, patterns must begin with /.
|
|
|
|
// Eventually, might want to allow host name
|
|
|
|
// at beginning of pattern, so that you could register
|
|
|
|
// /codesearch
|
|
|
|
// codesearch.google.com/
|
|
|
|
// but not take over /.
|
|
|
|
|
|
|
|
type ServeMux struct {
|
|
|
|
m map[string] Handler
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServeMux() *ServeMux {
|
|
|
|
return &ServeMux{make(map[string] Handler)};
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
|
|
|
|
// 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);
|
|
|
|
}
|
2008-09-24 16:26:55 -06:00
|
|
|
|
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:
|
|
|
|
// If pattern is /tree/, insert redirect for /tree.
|
|
|
|
n := len(pattern);
|
|
|
|
if n > 0 && pattern[n-1] == '/' {
|
|
|
|
mux.m[pattern[0:n-1]] = RedirectHandler(pattern);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Handle(pattern string, h Handler) {
|
|
|
|
DefaultServeMux.Handle(pattern, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Web server: listening on l, call handler.ServeHTTP for each request.
|
|
|
|
func Serve(l net.Listener, handler Handler) *os.Error {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Web server: listen on address, call f for each request.
|
2009-02-02 19:01:32 -07: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
|
|
|
|