httprange.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package httprange
  2. import (
  3. "errors"
  4. "net/http"
  5. "net/textproto"
  6. "strconv"
  7. "strings"
  8. )
  9. func Parse(s string) (int64, int64, error) {
  10. if s == "" {
  11. return 0, 0, nil // header not present
  12. }
  13. const b = "bytes="
  14. if !strings.HasPrefix(s, b) {
  15. return 0, 0, errors.New("invalid range")
  16. }
  17. for _, ra := range strings.Split(s[len(b):], ",") {
  18. ra = textproto.TrimString(ra)
  19. if ra == "" {
  20. continue
  21. }
  22. i := strings.Index(ra, "-")
  23. if i < 0 {
  24. return 0, 0, errors.New("invalid range")
  25. }
  26. start, end := textproto.TrimString(ra[:i]), textproto.TrimString(ra[i+1:])
  27. if start == "" {
  28. // Don't support ranges without start since it looks like FFmpeg doesn't use ones
  29. return 0, 0, errors.New("invalid range")
  30. }
  31. istart, err := strconv.ParseInt(start, 10, 64)
  32. if err != nil || i < 0 {
  33. return 0, 0, errors.New("invalid range")
  34. }
  35. var iend int64
  36. if end == "" {
  37. iend = -1
  38. } else {
  39. iend, err = strconv.ParseInt(end, 10, 64)
  40. if err != nil || istart > iend {
  41. return 0, 0, errors.New("invalid range")
  42. }
  43. }
  44. return istart, iend, nil
  45. }
  46. return 0, 0, errors.New("invalid range")
  47. }
  48. func InvalidHTTPRangeResponse(req *http.Request) *http.Response {
  49. return &http.Response{
  50. StatusCode: http.StatusRequestedRangeNotSatisfiable,
  51. Proto: "HTTP/1.0",
  52. ProtoMajor: 1,
  53. ProtoMinor: 0,
  54. Header: make(http.Header),
  55. ContentLength: 0,
  56. Body: nil,
  57. Close: false,
  58. Request: req,
  59. }
  60. }