github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/hook/server.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package hook 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "net/http" 24 25 "github.com/sirupsen/logrus" 26 27 "k8s.io/test-infra/prow/config" 28 "k8s.io/test-infra/prow/github" 29 "k8s.io/test-infra/prow/plugins" 30 ) 31 32 // Server implements http.Handler. It validates incoming GitHub webhooks and 33 // then dispatches them to the appropriate plugins. 34 type Server struct { 35 Plugins *plugins.PluginAgent 36 ConfigAgent *config.Agent 37 HMACSecret []byte 38 Metrics *Metrics 39 } 40 41 // ServeHTTP validates an incoming webhook and puts it into the event channel. 42 func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 43 defer r.Body.Close() 44 45 // Header checks: It must be a POST with an event type and a signature. 46 if r.Method != http.MethodPost { 47 http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) 48 return 49 } 50 eventType := r.Header.Get("X-GitHub-Event") 51 if eventType == "" { 52 http.Error(w, "400 Bad Request: Missing X-GitHub-Event Header", http.StatusBadRequest) 53 return 54 } 55 eventGUID := r.Header.Get("X-GitHub-Delivery") 56 if eventGUID == "" { 57 http.Error(w, "400 Bad Request: Missing X-GitHub-Delivery Header", http.StatusBadRequest) 58 return 59 } 60 sig := r.Header.Get("X-Hub-Signature") 61 if sig == "" { 62 http.Error(w, "403 Forbidden: Missing X-Hub-Signature", http.StatusForbidden) 63 return 64 } 65 contentType := r.Header.Get("content-type") 66 if contentType != "application/json" { 67 http.Error(w, "400 Bad Request: Hook only accepts content-type: application/json - please reconfigure this hook on GitHub", http.StatusBadRequest) 68 return 69 } 70 71 payload, err := ioutil.ReadAll(r.Body) 72 if err != nil { 73 http.Error(w, "500 Internal Server Error: Failed to read request body", http.StatusInternalServerError) 74 return 75 } 76 77 // Validate the payload with our HMAC secret. 78 if !github.ValidatePayload(payload, sig, s.HMACSecret) { 79 http.Error(w, "403 Forbidden: Invalid X-Hub-Signature", http.StatusForbidden) 80 return 81 } 82 fmt.Fprint(w, "Event received. Have a nice day.") 83 84 if err := s.demuxEvent(eventType, eventGUID, payload); err != nil { 85 logrus.WithError(err).Error("Error parsing event.") 86 } 87 } 88 89 func (s *Server) demuxEvent(eventType, eventGUID string, payload []byte) error { 90 l := logrus.WithFields( 91 logrus.Fields{ 92 "event-type": eventType, 93 "event-GUID": eventGUID, 94 }, 95 ) 96 // We don't want to fail the webhook due to a metrics error. 97 if counter, err := s.Metrics.WebhookCounter.GetMetricWithLabelValues(eventType); err != nil { 98 l.WithError(err).Warn("Failed to get metric for eventType " + eventType) 99 } else { 100 counter.Inc() 101 } 102 switch eventType { 103 case "issues": 104 var i github.IssueEvent 105 if err := json.Unmarshal(payload, &i); err != nil { 106 return err 107 } 108 go s.handleIssueEvent(l, i) 109 case "issue_comment": 110 var ic github.IssueCommentEvent 111 if err := json.Unmarshal(payload, &ic); err != nil { 112 return err 113 } 114 go s.handleIssueCommentEvent(l, ic) 115 case "pull_request": 116 var pr github.PullRequestEvent 117 if err := json.Unmarshal(payload, &pr); err != nil { 118 return err 119 } 120 go s.handlePullRequestEvent(l, pr) 121 case "pull_request_review": 122 var re github.ReviewEvent 123 if err := json.Unmarshal(payload, &re); err != nil { 124 return err 125 } 126 go s.handleReviewEvent(l, re) 127 case "pull_request_review_comment": 128 var rce github.ReviewCommentEvent 129 if err := json.Unmarshal(payload, &rce); err != nil { 130 return err 131 } 132 go s.handleReviewCommentEvent(l, rce) 133 case "push": 134 var pe github.PushEvent 135 if err := json.Unmarshal(payload, &pe); err != nil { 136 return err 137 } 138 go s.handlePushEvent(l, pe) 139 case "status": 140 var se github.StatusEvent 141 if err := json.Unmarshal(payload, &se); err != nil { 142 return err 143 } 144 go s.handleStatusEvent(l, se) 145 } 146 return nil 147 }