get_short.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package web
  2. import (
  3. "io"
  4. "net/http"
  5. "strings"
  6. "code.osinet.fr/fgm/kurz/domain"
  7. "github.com/gorilla/mux"
  8. )
  9. /*
  10. Template variables:
  11. - FullyQualifiedAssetsBaseURL http://plusvite-cdn.osinet.eu
  12. - FullyQualifiedShortURL (short string)
  13. - FullyQualifiedSiteURL http://plusvite.net/
  14. - FullyQualifiedTargetURL (target string)
  15. - RefreshDelay (seconds int)
  16. - SiteName PlusVite
  17. */
  18. type bytes = []byte
  19. func build403(w http.ResponseWriter, short string) error {
  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. return err
  36. }
  37. func build404(w http.ResponseWriter, short string) error {
  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. w.WriteHeader(http.StatusInternalServerError)
  49. } else {
  50. w.WriteHeader(http.StatusNotFound)
  51. io.Copy(w, strings.NewReader(sw.String()))
  52. }
  53. return err
  54. }
  55. func build451(w http.ResponseWriter, short string) error {
  56. return nil
  57. }
  58. // handleGetShort handles path /<short>
  59. func handleGetShort(w http.ResponseWriter, r *http.Request) {
  60. short, ok := mux.Vars(r)["short"]
  61. if !ok {
  62. w.WriteHeader(http.StatusBadRequest)
  63. return
  64. }
  65. target, err := domain.GetTargetURL(short)
  66. // Happy path.
  67. if err == nil {
  68. w.Header().Set("Location", target)
  69. w.WriteHeader(http.StatusTemporaryRedirect)
  70. return
  71. }
  72. // Very sad path.
  73. domainErr, ok := err.(domain.Error)
  74. if !ok {
  75. // All errors return by the API should be domain-specific errors.
  76. w.WriteHeader(http.StatusInternalServerError)
  77. return
  78. }
  79. // Normal sad paths.
  80. switch domainErr.Kind {
  81. case domain.ShortNotFound:
  82. build404(w, short)
  83. case domain.TargetBlockedError:
  84. build403(w, short)
  85. case domain.TargetCensoredError:
  86. build451(w, short)
  87. default:
  88. // TargetInvalid is not supposed to happen in this case, so it is an internal error too.
  89. w.WriteHeader(http.StatusInternalServerError)
  90. }
  91. }