extractor.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package request
  2. import (
  3. "errors"
  4. "net/http"
  5. )
  6. // Errors
  7. var (
  8. ErrNoTokenInRequest = errors.New("no token present in request")
  9. )
  10. // Interface for extracting a token from an HTTP request.
  11. // The ExtractToken method should return a token string or an error.
  12. // If no token is present, you must return ErrNoTokenInRequest.
  13. type Extractor interface {
  14. ExtractToken(*http.Request) (string, error)
  15. }
  16. // Extractor for finding a token in a header. Looks at each specified
  17. // header in order until there's a match
  18. type HeaderExtractor []string
  19. func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
  20. // loop over header names and return the first one that contains data
  21. for _, header := range e {
  22. if ah := req.Header.Get(header); ah != "" {
  23. return ah, nil
  24. }
  25. }
  26. return "", ErrNoTokenInRequest
  27. }
  28. // Extract token from request arguments. This includes a POSTed form or
  29. // GET URL arguments. Argument names are tried in order until there's a match.
  30. // This extractor calls `ParseMultipartForm` on the request
  31. type ArgumentExtractor []string
  32. func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
  33. // Make sure form is parsed
  34. req.ParseMultipartForm(10e6)
  35. // loop over arg names and return the first one that contains data
  36. for _, arg := range e {
  37. if ah := req.Form.Get(arg); ah != "" {
  38. return ah, nil
  39. }
  40. }
  41. return "", ErrNoTokenInRequest
  42. }
  43. // Tries Extractors in order until one returns a token string or an error occurs
  44. type MultiExtractor []Extractor
  45. func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
  46. // loop over header names and return the first one that contains data
  47. for _, extractor := range e {
  48. if tok, err := extractor.ExtractToken(req); tok != "" {
  49. return tok, nil
  50. } else if err != ErrNoTokenInRequest {
  51. return "", err
  52. }
  53. }
  54. return "", ErrNoTokenInRequest
  55. }
  56. // Wrap an Extractor in this to post-process the value before it's handed off.
  57. // See AuthorizationHeaderExtractor for an example
  58. type PostExtractionFilter struct {
  59. Extractor
  60. Filter func(string) (string, error)
  61. }
  62. func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string, error) {
  63. if tok, err := e.Extractor.ExtractToken(req); tok != "" {
  64. return e.Filter(tok)
  65. } else {
  66. return "", err
  67. }
  68. }