triv.go 3.46 KB
Newer Older
1 2 3 4 5 6 7
// 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.

package main

import (
8 9 10 11
	"bytes"
	"expvar"
	"flag"
	"fmt"
12
	"http"
13 14 15 16
	"io"
	"log"
	"os"
	"strconv"
17 18
)

Russ Cox's avatar
Russ Cox committed
19 20

// hello world, the web server
21 22
var helloRequests = expvar.NewInt("hello-requests")

23
func HelloServer(w http.ResponseWriter, req *http.Request) {
24
	helloRequests.Add(1)
25
	io.WriteString(w, "hello, world!\n")
Russ Cox's avatar
Russ Cox committed
26 27
}

David Symonds's avatar
David Symonds committed
28
// Simple counter server. POSTing to it will set the value.
Russ Cox's avatar
Russ Cox committed
29
type Counter struct {
30
	n int
Russ Cox's avatar
Russ Cox committed
31 32
}

33
// This makes Counter satisfy the expvar.Var interface, so we can export
34
// it directly.
35
func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
36

37
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
David Symonds's avatar
David Symonds committed
38 39
	switch req.Method {
	case "GET":
40
		ctr.n++
David Symonds's avatar
David Symonds committed
41
	case "POST":
42 43 44
		buf := new(bytes.Buffer)
		io.Copy(buf, req.Body)
		body := buf.String()
David Symonds's avatar
David Symonds committed
45
		if n, err := strconv.Atoi(body); err != nil {
46
			fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
David Symonds's avatar
David Symonds committed
47
		} else {
48
			ctr.n = n
49
			fmt.Fprint(w, "counter reset\n")
David Symonds's avatar
David Symonds committed
50 51
		}
	}
52
	fmt.Fprintf(w, "counter = %d\n", ctr.n)
Russ Cox's avatar
Russ Cox committed
53 54
}

55 56
// simple flag server
var booleanflag = flag.Bool("boolean", true, "another flag for testing")
57

58 59 60
func FlagServer(w http.ResponseWriter, req *http.Request) {
	w.SetHeader("content-type", "text/plain; charset=utf-8")
	fmt.Fprint(w, "Flags:\n")
61
	flag.VisitAll(func(f *flag.Flag) {
62
		if f.Value.String() != f.DefValue {
63
			fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
64
		} else {
65
			fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
66
		}
67
	})
68 69 70
}

// simple argument server
71
func ArgServer(w http.ResponseWriter, req *http.Request) {
72
	for _, s := range os.Args {
73
		fmt.Fprint(w, s, " ")
74 75 76
	}
}

77 78 79 80
// a channel (just for the fun of it)
type Chan chan int

func ChanCreate() Chan {
81
	c := make(Chan)
82
	go func(c Chan) {
83
		for x := 0; ; x++ {
84
			c <- x
85
		}
86 87
	}(c)
	return c
88 89
}

90 91
func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
92 93
}

Russ Cox's avatar
Russ Cox committed
94
// exec a program, redirecting output
95 96
func DateServer(rw http.ResponseWriter, req *http.Request) {
	rw.SetHeader("content-type", "text/plain; charset=utf-8")
97
	r, w, err := os.Pipe()
Russ Cox's avatar
Russ Cox committed
98
	if err != nil {
99
		fmt.Fprintf(rw, "pipe: %s\n", err)
100
		return
Russ Cox's avatar
Russ Cox committed
101
	}
102 103 104
	pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
	defer r.Close()
	w.Close()
Russ Cox's avatar
Russ Cox committed
105
	if err != nil {
106
		fmt.Fprintf(rw, "fork/exec: %s\n", err)
107
		return
Russ Cox's avatar
Russ Cox committed
108
	}
109
	io.Copy(rw, r)
110
	wait, err := os.Wait(pid, 0)
Russ Cox's avatar
Russ Cox committed
111
	if err != nil {
112
		fmt.Fprintf(rw, "wait: %s\n", err)
113
		return
Russ Cox's avatar
Russ Cox committed
114 115
	}
	if !wait.Exited() || wait.ExitStatus() != 0 {
116
		fmt.Fprintf(rw, "date: %v\n", wait)
117
		return
Russ Cox's avatar
Russ Cox committed
118 119 120
	}
}

121
func Logger(w http.ResponseWriter, req *http.Request) {
122
	log.Stdout(req.URL.Raw)
123 124
	w.WriteHeader(404)
	w.Write([]byte("oops"))
125 126 127
}


128 129
var webroot = flag.String("root", "/home/rsc", "web root directory")

130
func main() {
131
	flag.Parse()
132 133

	// The counter is published as a variable directly.
134 135 136 137
	ctr := new(Counter)
	http.Handle("/counter", ctr)
	expvar.Publish("counter", ctr)

138
	http.Handle("/", http.HandlerFunc(Logger))
139
	http.Handle("/go/", http.FileServer(*webroot, "/go/"))
140 141 142 143 144 145
	http.Handle("/flags", http.HandlerFunc(FlagServer))
	http.Handle("/args", http.HandlerFunc(ArgServer))
	http.Handle("/go/hello", http.HandlerFunc(HelloServer))
	http.Handle("/chan", ChanCreate())
	http.Handle("/date", http.HandlerFunc(DateServer))
	err := http.ListenAndServe(":12345", nil)
146
	if err != nil {
147
		log.Crash("ListenAndServe: ", err)
148 149
	}
}