get_short.go 2.6 KB

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