get_short.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package ui
  2. import (
  3. "code.osinet.fr/fgm/kurz/web/i18n"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "strings"
  8. "code.osinet.fr/fgm/kurz/domain"
  9. "github.com/gorilla/mux"
  10. )
  11. /*
  12. Template variables:
  13. - assetsBaseURL http://plusvite-cdn.osinet.eu
  14. - FullyQualifiedShortURL (short string)
  15. - SiteBaseURL http://plusvite.net/
  16. - FullyQualifiedTargetURL (target string)
  17. - RefreshDelay (seconds int)
  18. - SiteName PlusVite
  19. */
  20. func build403(w http.ResponseWriter, short string) {
  21. data := struct {
  22. FullyQualifiedShortURL string
  23. Globals
  24. }{
  25. short,
  26. globals,
  27. }
  28. sw := &strings.Builder{}
  29. err := tmpl.ExecuteTemplate(sw, "403", data)
  30. if err != nil {
  31. w.WriteHeader(http.StatusInternalServerError)
  32. } else {
  33. w.WriteHeader(http.StatusForbidden)
  34. io.Copy(w, strings.NewReader(sw.String()))
  35. }
  36. }
  37. func build404(w http.ResponseWriter, short string) {
  38. data := struct {
  39. FullyQualifiedShortURL string
  40. Globals
  41. }{
  42. short,
  43. globals,
  44. }
  45. sw := &strings.Builder{}
  46. err := tmpl.ExecuteTemplate(sw, "404", data)
  47. if err != nil {
  48. fmt.Println(err)
  49. w.WriteHeader(http.StatusInternalServerError)
  50. } else {
  51. w.WriteHeader(http.StatusNotFound)
  52. io.Copy(w, strings.NewReader(sw.String()))
  53. }
  54. }
  55. func build451(w http.ResponseWriter, router *mux.Router, short string) {
  56. hr := router.Get(RouteGetRoot)
  57. _, err := hr.URL()
  58. if err != nil {
  59. fmt.Println(err)
  60. w.WriteHeader(http.StatusInternalServerError)
  61. return
  62. }
  63. data := struct {
  64. FullyQualifiedShortURL string
  65. Globals
  66. }{
  67. short,
  68. globals,
  69. }
  70. sw := &strings.Builder{}
  71. err = tmpl.ExecuteTemplate(sw, "404", data)
  72. if err != nil {
  73. fmt.Println(err)
  74. w.WriteHeader(http.StatusInternalServerError)
  75. } else {
  76. w.WriteHeader(http.StatusNotFound)
  77. io.Copy(w, strings.NewReader(sw.String()))
  78. }
  79. }
  80. // handleGetShort handles path /<short>
  81. func handleGetShort(w http.ResponseWriter, r *http.Request, router *mux.Router) {
  82. short, ok := mux.Vars(r)["short"]
  83. if !ok {
  84. w.WriteHeader(http.StatusBadRequest)
  85. return
  86. }
  87. target, err := domain.GetTargetURL(short, i18n.Localizer(r))
  88. // Happy path.
  89. if err == nil {
  90. w.Header().Set("Location", target)
  91. w.WriteHeader(http.StatusSeeOther)
  92. return
  93. }
  94. // Very sad path.
  95. domainErr, ok := err.(domain.Error)
  96. if !ok {
  97. // All errors return by the API should be domain-specific errors.
  98. w.WriteHeader(http.StatusInternalServerError)
  99. return
  100. }
  101. // Normal sad paths.
  102. switch domainErr.Kind {
  103. case domain.ShortNotFound.ID:
  104. build404(w, short)
  105. case domain.TargetBlocked.ID:
  106. build403(w, short)
  107. case domain.TargetCensored.ID:
  108. build451(w, router, short)
  109. default:
  110. // TargetInvalid is not supposed to happen in this case, so it is an internal error too.
  111. w.WriteHeader(http.StatusInternalServerError)
  112. }
  113. }