if name is empty, filename is unknown. (used for mime type, before sniffing) if modtime.IsZero(), modtime is unknown. content must be seeked to the beginning of the file. The sizeFunc is called at most once. Its error, if any, is sent in the HTTP response.
(ci inject.CopyInject, w http.ResponseWriter, r *http.Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker)
| 94 | // content must be seeked to the beginning of the file. |
| 95 | // The sizeFunc is called at most once. Its error, if any, is sent in the HTTP response. |
| 96 | func serveContent(ci inject.CopyInject, w http.ResponseWriter, r *http.Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) error { |
| 97 | if checkLastModified(w, r, modtime) { |
| 98 | return nil |
| 99 | } |
| 100 | done := checkETag(w, r) |
| 101 | if done { |
| 102 | return nil |
| 103 | } |
| 104 | |
| 105 | code := http.StatusOK |
| 106 | |
| 107 | // If Content-Type isn't set, use the file's extension to find it, but |
| 108 | // if the Content-Type is unset explicitly, do not sniff the type. |
| 109 | ctypes, haveType := w.Header()["Content-Type"] |
| 110 | var ctype string |
| 111 | if !haveType { |
| 112 | ctype = mime.TypeByExtension(filepath.Ext(name)) |
| 113 | if ctype == "" { |
| 114 | // read a chunk to decide between utf-8 text and binary |
| 115 | var buf [sniffLen]byte |
| 116 | n, _ := io.ReadFull(content, buf[:]) |
| 117 | ctype = http.DetectContentType(buf[:n]) |
| 118 | _, err := content.Seek(0, os.SEEK_SET) // rewind to output whole file |
| 119 | if err != nil { |
| 120 | http.Error(w, "seeker can't seek", http.StatusInternalServerError) |
| 121 | return err |
| 122 | } |
| 123 | } |
| 124 | w.Header().Set("Content-Type", ctype) |
| 125 | } else if len(ctypes) > 0 { |
| 126 | ctype = ctypes[0] |
| 127 | } |
| 128 | |
| 129 | injector, err := ci.Sniff(content, ctype) |
| 130 | if err != nil { |
| 131 | http.Error(w, err.Error(), http.StatusInternalServerError) |
| 132 | return err |
| 133 | } |
| 134 | |
| 135 | size, err := sizeFunc() |
| 136 | if err != nil { |
| 137 | http.Error(w, err.Error(), http.StatusInternalServerError) |
| 138 | return err |
| 139 | } |
| 140 | |
| 141 | if injector.Found() { |
| 142 | size = size + int64(injector.Extra()) |
| 143 | } |
| 144 | |
| 145 | if size >= 0 { |
| 146 | if w.Header().Get("Content-Encoding") == "" { |
| 147 | w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | w.WriteHeader(code) |
| 152 | if r.Method != "HEAD" { |
| 153 | _, err := injector.Copy(w) |