Given an HTTP "Range:" header value, parses it and returns the approppriate HTTP status code, and the numeric byte range if appropriate: - If the Range header is empty or syntactically invalid, it ignores it and returns status=200. - If the header is valid but exceeds the contentLength, it returns s
(rangeStr string, contentLength uint64)
| 1746 | // - Otherwise it returns status=206 and sets the start and end values in HTTP terms, i.e. with |
| 1747 | // the first byte numbered 0, and the end value inclusive (so the first 100 bytes are 0-99.) |
| 1748 | func parseHTTPRangeHeader(rangeStr string, contentLength uint64) (status int, start uint64, end uint64) { |
| 1749 | // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 |
| 1750 | status = http.StatusOK |
| 1751 | if rangeStr == "" { |
| 1752 | return |
| 1753 | } |
| 1754 | match := kRangeRegex.FindStringSubmatch(rangeStr) |
| 1755 | if match == nil || (match[1] == "" && match[2] == "") { |
| 1756 | return |
| 1757 | } |
| 1758 | startStr, endStr := match[1], match[2] |
| 1759 | var err error |
| 1760 | |
| 1761 | start = 0 |
| 1762 | if startStr != "" { |
| 1763 | // byte-range-spec |
| 1764 | if start, err = strconv.ParseUint(startStr, 10, 64); err != nil { |
| 1765 | start = math.MaxUint64 // string is all digits, so must just be too big for uint64 |
| 1766 | } |
| 1767 | } else if endStr == "" { |
| 1768 | return // "-" is an invalid range spec |
| 1769 | } |
| 1770 | |
| 1771 | end = contentLength - 1 |
| 1772 | if endStr != "" { |
| 1773 | if end, err = strconv.ParseUint(endStr, 10, 64); err != nil { |
| 1774 | end = math.MaxUint64 // string is all digits, so must just be too big for uint64 |
| 1775 | } |
| 1776 | if startStr == "" { |
| 1777 | // suffix-range-spec ("-nnn" means the last nnn bytes) |
| 1778 | if end == 0 { |
| 1779 | return http.StatusRequestedRangeNotSatisfiable, 0, 0 |
| 1780 | } else if contentLength == 0 { |
| 1781 | return |
| 1782 | } else if end > contentLength { |
| 1783 | end = contentLength |
| 1784 | } |
| 1785 | start = contentLength - end |
| 1786 | end = contentLength - 1 |
| 1787 | } else { |
| 1788 | if end < start { |
| 1789 | return // invalid range |
| 1790 | } |
| 1791 | if end >= contentLength { |
| 1792 | end = contentLength - 1 // trim to end of content |
| 1793 | } |
| 1794 | } |
| 1795 | } |
| 1796 | if start >= contentLength { |
| 1797 | return http.StatusRequestedRangeNotSatisfiable, 0, 0 |
| 1798 | } else if start == 0 && end == contentLength-1 { |
| 1799 | return // no-op |
| 1800 | } |
| 1801 | |
| 1802 | // OK, it's a subrange: |
| 1803 | status = http.StatusPartialContent |
| 1804 | return |
| 1805 | } |
no outgoing calls