This repository has been archived by the owner on Apr 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathhttp.go
101 lines (86 loc) · 2.58 KB
/
http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
import (
"fmt"
"net"
"net/http"
"strings"
"github.com/flynn/flynn-discovery/Godeps/_workspace/src/github.com/flynn/flynn/pkg/httphelper"
"github.com/flynn/flynn-discovery/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
)
type Server struct {
URL string
Backend StorageBackend
router *httprouter.Router
}
func NewServer(url string, backend StorageBackend) *Server {
s := &Server{
URL: url,
Backend: backend,
router: httprouter.New(),
}
s.router.POST("/clusters", s.CreateCluster)
s.router.POST("/clusters/:cluster_id/instances", s.CreateInstance)
s.router.GET("/clusters/:cluster_id/instances", s.GetInstances)
return s
}
func (s *Server) CreateCluster(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
cluster := &Cluster{
CreatorIP: sourceIP(req),
CreatorUserAgent: req.Header.Get("User-Agent"),
}
if len(cluster.CreatorUserAgent) > 1000 {
cluster.CreatorUserAgent = cluster.CreatorUserAgent[:1000]
}
if err := s.Backend.CreateCluster(cluster); err != nil {
httphelper.Error(w, err)
return
}
w.Header().Set("Location", fmt.Sprintf("%s/clusters/%s", s.URL, cluster.ID))
w.WriteHeader(http.StatusCreated)
}
func (s *Server) CreateInstance(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
var data struct {
Data *Instance `json:"data"`
}
if err := httphelper.DecodeJSON(req, &data); err != nil {
httphelper.Error(w, err)
return
}
inst := data.Data
inst.ClusterID = params.ByName("cluster_id")
inst.CreatorIP = sourceIP(req)
// TODO: validate with JSON schema
status := http.StatusCreated
if err := s.Backend.CreateInstance(inst); err == ErrExists {
status = http.StatusConflict
} else if err != nil {
httphelper.Error(w, err)
return
}
w.Header().Set("Location", fmt.Sprintf("%s/clusters/%s/instances/%s", s.URL, inst.ClusterID, inst.ID))
httphelper.JSON(w, status, data)
}
func (s *Server) GetInstances(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
instances, err := s.Backend.GetClusterInstances(params.ByName("cluster_id"))
if err != nil {
httphelper.Error(w, err)
return
}
if instances == nil {
instances = []*Instance{}
}
httphelper.JSON(w, 200, struct {
Data []*Instance `json:"data"`
}{instances})
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.router.ServeHTTP(w, r)
}
func sourceIP(req *http.Request) string {
if xff := req.Header.Get("X-Forwarded-For"); xff != "" {
ips := strings.Split(xff, ",")
return strings.TrimSpace(ips[len(ips)-1])
}
ip, _, _ := net.SplitHostPort(req.RemoteAddr)
return ip
}