this file is inspired by GO_SDK net.http.ServeContent type RangeReadCloser struct { GetReaderForRange RangeReaderFunc } ServeHTTP replies to the request using the content in the provided RangeReadCloser. The main benefit of ServeHTTP over io.Copy is that it handles Range requests properly, sets the
(w http.ResponseWriter, r *http.Request, name string, modTime time.Time, size int64, RangeReadCloser model.RangeReadCloserIF)
| 53 | // If the caller has set w's ETag header formatted per RFC 7232, section 2.3, |
| 54 | // ServeHTTP uses it to handle requests using If-Match, If-None-Match, or If-Range. |
| 55 | func ServeHTTP(w http.ResponseWriter, r *http.Request, name string, modTime time.Time, size int64, RangeReadCloser model.RangeReadCloserIF) error { |
| 56 | defer RangeReadCloser.Close() |
| 57 | setLastModified(w, modTime) |
| 58 | done, rangeReq := checkPreconditions(w, r, modTime) |
| 59 | if done { |
| 60 | return nil |
| 61 | } |
| 62 | |
| 63 | if size < 0 { |
| 64 | // since too many functions need file size to work, |
| 65 | // will not implement the support of unknown file size here |
| 66 | http.Error(w, "negative content size not supported", http.StatusInternalServerError) |
| 67 | return nil |
| 68 | } |
| 69 | |
| 70 | code := http.StatusOK |
| 71 | |
| 72 | // If Content-Type isn't set, use the file's extension to find it, but |
| 73 | // if the Content-Type is unset explicitly, do not sniff the type. |
| 74 | contentTypes, haveType := w.Header()["Content-Type"] |
| 75 | var contentType string |
| 76 | if !haveType { |
| 77 | contentType = utils.GetMimeType(name) |
| 78 | w.Header().Set("Content-Type", contentType) |
| 79 | } else if len(contentTypes) > 0 { |
| 80 | contentType = contentTypes[0] |
| 81 | } |
| 82 | |
| 83 | // handle Content-Range header. |
| 84 | sendSize := size |
| 85 | var sendContent io.ReadCloser |
| 86 | ranges, err := http_range.ParseRange(rangeReq, size) |
| 87 | switch { |
| 88 | case err == nil: |
| 89 | case errors.Is(err, http_range.ErrNoOverlap): |
| 90 | if size == 0 { |
| 91 | // Some clients add a Range header to all requests to |
| 92 | // limit the size of the response. If the file is empty, |
| 93 | // ignore the range header and respond with a 200 rather |
| 94 | // than a 416. |
| 95 | ranges = nil |
| 96 | break |
| 97 | } |
| 98 | w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size)) |
| 99 | fallthrough |
| 100 | default: |
| 101 | http.Error(w, err.Error(), http.StatusRequestedRangeNotSatisfiable) |
| 102 | return nil |
| 103 | } |
| 104 | |
| 105 | if sumRangesSize(ranges) > size { |
| 106 | // The total number of bytes in all the ranges is larger than the size of the file |
| 107 | // or unknown file size, ignore the range request. |
| 108 | ranges = nil |
| 109 | } |
| 110 | |
| 111 | // 使用请求的Context |
| 112 | // 不然从sendContent读不到数据,即使请求断开CopyBuffer也会一直堵塞 |
no test coverage detected