Created
November 25, 2019 14:27
-
-
Save belljustin/8a3e9b15d6c2cf533a25aef6cde9ba07 to your computer and use it in GitHub Desktop.
Server that consumes HTTP messages sent from a SNS subscription.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "log" | |
| "net/http" | |
| ) | |
| const ( | |
| headerAmzSnsMsgType = "x-amz-sns-message-type" | |
| ) | |
| // SnsMsg is a generic base for topic messages. | |
| type SnsMsg struct { | |
| Type string `json:"Type"` | |
| MessageId string `json:"MessageId"` | |
| TopicArn string `json:"TopicArn"` | |
| Message string `json:"Message"` | |
| Timestamp string `json:"Timestamp"` | |
| SignatureVersion string `json:"Version"` | |
| Signature string `json:"Signature"` | |
| SigningCertURL string `json:SigningCertURL"` | |
| } | |
| // verify the signature of the message. | |
| func (m SnsMsg) verify() error { | |
| // TODO: implement this | |
| return nil | |
| } | |
| // SubscriptionConfirmationMsg contain information for confirming a topic subscription. | |
| type SubscriptionConfirmationMsg struct { | |
| SnsMsg | |
| Token string `json:"Token"` | |
| SubscribeURL string `json:"SubscribeURL"` | |
| } | |
| // NotificationMsg contain generic plaintext messages from a topic. | |
| type NotificationMsg struct { | |
| SnsMsg | |
| UnsubscribeURL string `json:"UnsubscribeURL"` | |
| Subject string `json:"Subject"` | |
| } | |
| | |
| // notification handles all message types. | |
| func notification(w http.ResponseWriter, r *http.Request) { | |
| if r.Method != http.MethodPost { | |
| http.NotFound(w, r) | |
| return | |
| } | |
| switch msgType := r.Header.Get(headerAmzSnsMsgType); msgType { | |
| case "SubscriptionConfirmation": | |
| handleSubscriptionConfirmation(w, r) | |
| case "Notification": | |
| handleNotification(w, r) | |
| default: | |
| errMsg := fmt.Sprintf("Header '%s' must be one of 'SubscriptionConfirmation' or 'Notification'", headerAmzSnsMsgType) | |
| http.Error(w, errMsg, http.StatusBadRequest) | |
| } | |
| } | |
| // handleSubscriptionConfirmation responds to messages of type 'SubscriptionConfirmation'. | |
| func handleSubscriptionConfirmation(w http.ResponseWriter, r *http.Request) { | |
| decoder := json.NewDecoder(r.Body) | |
| var msg SubscriptionConfirmationMsg | |
| if err := decoder.Decode(&msg); err != nil { | |
| errMsg := fmt.Sprintf("The message is malformed: %s", err.Error()) | |
| http.Error(w, errMsg, http.StatusBadRequest) | |
| return | |
| } | |
| if err := msg.verify(); err != nil { | |
| errMsg := fmt.Sprintf("Unable to verify message: %s", err.Error()) | |
| http.Error(w, errMsg, http.StatusUnauthorized) | |
| return | |
| } | |
| resp, err := http.Get(msg.SubscribeURL) | |
| if err != nil || resp.StatusCode != http.StatusOK { | |
| if err == nil { | |
| err = fmt.Errorf("subscription url responded with '%s'", resp.Status) | |
| } | |
| errMsg := fmt.Sprintf("There was an error requesting the subscription url '%s': %s", msg.SubscribeURL, err.Error()) | |
| http.Error(w, errMsg, http.StatusInternalServerError) | |
| } | |
| } | |
| // handleNotification responds and processes messages of type 'Notification'. | |
| func handleNotification(w http.ResponseWriter, r *http.Request) { | |
| decoder := json.NewDecoder(r.Body) | |
| var msg NotificationMsg | |
| if err := decoder.Decode(&msg); err != nil { | |
| errMsg := fmt.Sprintf("The message is malformed: %s", err.Error()) | |
| http.Error(w, errMsg, http.StatusBadRequest) | |
| return | |
| } | |
| if err := msg.verify(); err != nil { | |
| errMsg := fmt.Sprintf("Unable to verify message: %s", err.Error()) | |
| http.Error(w, errMsg, http.StatusUnauthorized) | |
| return | |
| } | |
| log.Printf("%+v\n", msg) | |
| } | |
| func main() { | |
| http.HandleFunc("/notification", notification) | |
| log.Println("Serving notification client at 127.0.0.1:8080") | |
| log.Fatal(http.ListenAndServe(":8080", nil)) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment