github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/server/v2/get_handler.go (about) 1 package v2 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/url" 8 "strconv" 9 10 etcdErr "github.com/coreos/etcd/error" 11 "github.com/coreos/etcd/log" 12 "github.com/coreos/etcd/third_party/github.com/coreos/raft" 13 "github.com/coreos/etcd/third_party/github.com/gorilla/mux" 14 ) 15 16 func GetHandler(w http.ResponseWriter, req *http.Request, s Server) error { 17 vars := mux.Vars(req) 18 key := "/" + vars["key"] 19 20 // Help client to redirect the request to the current leader 21 if req.FormValue("consistent") == "true" && s.State() != raft.Leader { 22 leader := s.Leader() 23 hostname, _ := s.ClientURL(leader) 24 25 url, err := url.Parse(hostname) 26 if err != nil { 27 log.Warn("Redirect cannot parse hostName ", hostname) 28 return err 29 } 30 url.RawQuery = req.URL.RawQuery 31 url.Path = req.URL.Path 32 33 log.Debugf("Redirect consistent get to %s", url.String()) 34 http.Redirect(w, req, url.String(), http.StatusTemporaryRedirect) 35 return nil 36 } 37 38 recursive := (req.FormValue("recursive") == "true") 39 sort := (req.FormValue("sorted") == "true") 40 waitIndex := req.FormValue("waitIndex") 41 stream := (req.FormValue("stream") == "true") 42 43 if req.FormValue("wait") == "true" { 44 return handleWatch(key, recursive, stream, waitIndex, w, s) 45 } 46 47 return handleGet(key, recursive, sort, w, s) 48 } 49 50 func handleWatch(key string, recursive, stream bool, waitIndex string, w http.ResponseWriter, s Server) error { 51 // Create a command to watch from a given index (default 0). 52 var sinceIndex uint64 = 0 53 var err error 54 55 if waitIndex != "" { 56 sinceIndex, err = strconv.ParseUint(waitIndex, 10, 64) 57 if err != nil { 58 return etcdErr.NewError(etcdErr.EcodeIndexNaN, "Watch From Index", s.Store().Index()) 59 } 60 } 61 62 watcher, err := s.Store().Watch(key, recursive, stream, sinceIndex) 63 if err != nil { 64 return err 65 } 66 67 cn, _ := w.(http.CloseNotifier) 68 closeChan := cn.CloseNotify() 69 70 writeHeaders(w, s) 71 72 if stream { 73 // watcher hub will not help to remove stream watcher 74 // so we need to remove here 75 defer watcher.Remove() 76 for { 77 select { 78 case <-closeChan: 79 return nil 80 case event, ok := <-watcher.EventChan: 81 if !ok { 82 // If the channel is closed this may be an indication of 83 // that notifications are much more than we are able to 84 // send to the client in time. Then we simply end streaming. 85 return nil 86 } 87 88 b, _ := json.Marshal(event) 89 _, err := w.Write(b) 90 if err != nil { 91 return nil 92 } 93 w.(http.Flusher).Flush() 94 } 95 } 96 } 97 98 select { 99 case <-closeChan: 100 watcher.Remove() 101 case event := <-watcher.EventChan: 102 b, _ := json.Marshal(event) 103 w.Write(b) 104 } 105 return nil 106 } 107 108 func handleGet(key string, recursive, sort bool, w http.ResponseWriter, s Server) error { 109 event, err := s.Store().Get(key, recursive, sort) 110 if err != nil { 111 return err 112 } 113 114 writeHeaders(w, s) 115 b, _ := json.Marshal(event) 116 w.Write(b) 117 return nil 118 } 119 120 func writeHeaders(w http.ResponseWriter, s Server) { 121 w.Header().Set("Content-Type", "application/json") 122 w.Header().Add("X-Etcd-Index", fmt.Sprint(s.Store().Index())) 123 w.Header().Add("X-Raft-Index", fmt.Sprint(s.CommitIndex())) 124 w.Header().Add("X-Raft-Term", fmt.Sprint(s.Term())) 125 w.WriteHeader(http.StatusOK) 126 }