http.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package appservice
  2. import (
  3. "context"
  4. "encoding/json"
  5. "github.com/gorilla/mux"
  6. "io/ioutil"
  7. "net/http"
  8. "time"
  9. )
  10. // Listen starts the HTTP server that listens for calls from the Matrix homeserver.
  11. func (as *AppService) Start() {
  12. r := mux.NewRouter()
  13. r.HandleFunc("/transactions/{txnID}", as.PutTransaction).Methods(http.MethodPut)
  14. r.HandleFunc("/rooms/{roomAlias}", as.GetRoom).Methods(http.MethodGet)
  15. r.HandleFunc("/users/{userID}", as.GetUser).Methods(http.MethodGet)
  16. var err error
  17. as.server = &http.Server{
  18. Addr: as.Host.Address(),
  19. Handler: r,
  20. }
  21. as.Log.Infoln("Listening on", as.Host.Address())
  22. if len(as.Host.TLSCert) == 0 || len(as.Host.TLSKey) == 0 {
  23. err = as.server.ListenAndServe()
  24. } else {
  25. err = as.server.ListenAndServeTLS(as.Host.TLSCert, as.Host.TLSKey)
  26. }
  27. if err != nil && err.Error() != "http: Server closed" {
  28. as.Log.Fatalln("Error while listening:", err)
  29. } else {
  30. as.Log.Debugln("Listener stopped.")
  31. }
  32. }
  33. func (as *AppService) Stop() {
  34. if as.server == nil {
  35. return
  36. }
  37. ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
  38. as.server.Shutdown(ctx)
  39. as.server = nil
  40. }
  41. // CheckServerToken checks if the given request originated from the Matrix homeserver.
  42. func (as *AppService) CheckServerToken(w http.ResponseWriter, r *http.Request) bool {
  43. query := r.URL.Query()
  44. val, ok := query["access_token"]
  45. if !ok {
  46. Error{
  47. ErrorCode: ErrForbidden,
  48. HTTPStatus: http.StatusForbidden,
  49. Message: "Bad token supplied.",
  50. }.Write(w)
  51. return false
  52. }
  53. for _, str := range val {
  54. return str == as.Registration.ServerToken
  55. }
  56. return false
  57. }
  58. // PutTransaction handles a /transactions PUT call from the homeserver.
  59. func (as *AppService) PutTransaction(w http.ResponseWriter, r *http.Request) {
  60. if !as.CheckServerToken(w, r) {
  61. return
  62. }
  63. vars := mux.Vars(r)
  64. txnID := vars["txnID"]
  65. if len(txnID) == 0 {
  66. Error{
  67. ErrorCode: ErrNoTransactionID,
  68. HTTPStatus: http.StatusBadRequest,
  69. Message: "Missing transaction ID.",
  70. }.Write(w)
  71. return
  72. }
  73. defer r.Body.Close()
  74. body, err := ioutil.ReadAll(r.Body)
  75. if err != nil || len(body) == 0 {
  76. Error{
  77. ErrorCode: ErrNoBody,
  78. HTTPStatus: http.StatusBadRequest,
  79. Message: "Missing request body.",
  80. }.Write(w)
  81. return
  82. }
  83. if as.lastProcessedTransaction == txnID {
  84. // Duplicate transaction ID: no-op
  85. WriteBlankOK(w)
  86. return
  87. }
  88. eventList := EventList{}
  89. err = json.Unmarshal(body, &eventList)
  90. if err != nil {
  91. Error{
  92. ErrorCode: ErrInvalidJSON,
  93. HTTPStatus: http.StatusBadRequest,
  94. Message: "Failed to parse body JSON.",
  95. }.Write(w)
  96. return
  97. }
  98. for _, event := range eventList.Events {
  99. as.UpdateState(event)
  100. as.Events <- event
  101. }
  102. as.lastProcessedTransaction = txnID
  103. WriteBlankOK(w)
  104. }
  105. // GetRoom handles a /rooms GET call from the homeserver.
  106. func (as *AppService) GetRoom(w http.ResponseWriter, r *http.Request) {
  107. if !as.CheckServerToken(w, r) {
  108. return
  109. }
  110. vars := mux.Vars(r)
  111. roomAlias := vars["roomAlias"]
  112. ok := as.QueryHandler.QueryAlias(roomAlias)
  113. if ok {
  114. WriteBlankOK(w)
  115. } else {
  116. Error{
  117. ErrorCode: ErrUnknown,
  118. HTTPStatus: http.StatusNotFound,
  119. }.Write(w)
  120. }
  121. }
  122. // GetUser handles a /users GET call from the homeserver.
  123. func (as *AppService) GetUser(w http.ResponseWriter, r *http.Request) {
  124. if !as.CheckServerToken(w, r) {
  125. return
  126. }
  127. vars := mux.Vars(r)
  128. userID := vars["userID"]
  129. ok := as.QueryHandler.QueryUser(userID)
  130. if ok {
  131. WriteBlankOK(w)
  132. } else {
  133. Error{
  134. ErrorCode: ErrUnknown,
  135. HTTPStatus: http.StatusNotFound,
  136. }.Write(w)
  137. }
  138. }