func (h *methodHandler) HandleRequest(c *gmvc.Context) error { in := make([]reflect.Value, len(h.args)+1) in[0] = h.controller for i, arg := range h.args { v, err := arg.Get(c) if err != nil { c.ErrorStatus(err, http.StatusBadRequest) return nil } in[i+1] = v } out := h.method.Func.Call(in) if h.outErr != -1 { errv := out[h.outErr] if !errv.IsNil() { return errv.Interface().(error) } } return nil }
func (v *FileView) Render(c *gmvc.Context, name string, data interface{}) error { w := c.ResponseWriter r := c.Request root, err := filepath.Abs(v.root) if err != nil { return err } p := path.Join(root, name) if !strings.HasPrefix(p, root) { c.Status(http.StatusBadRequest) return nil } f, err := os.Open(p) if err != nil { c.Status(http.StatusNotFound) return nil } defer f.Close() d, err1 := f.Stat() if err1 != nil { c.Status(http.StatusNotFound) return nil } if d.IsDir() { c.Status(http.StatusNotFound) return nil } if v.checkLastModified(w, r, d.ModTime()) { return nil } code := http.StatusOK ctype := w.Header().Get("Content-Type") if ctype == "" { ctype = mime.TypeByExtension(filepath.Ext(name)) if ctype != "" { w.Header().Set("Content-Type", ctype) } } size := d.Size() sendSize := size var sendContent io.Reader = f if size >= 0 { ranges, err := v.parseRange(r.Header.Get("Range"), size) if err != nil { c.ErrorStatus(err, http.StatusRequestedRangeNotSatisfiable) return nil } if v.sumRangesSize(ranges) >= size { ranges = nil } switch { case len(ranges) == 1: ra := ranges[0] if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil { c.ErrorStatus(err, http.StatusRequestedRangeNotSatisfiable) return nil } sendSize = ra.length code = http.StatusPartialContent w.Header().Set("Content-Range", ra.contentRange(size)) case len(ranges) > 1: for _, ra := range ranges { if ra.start > size { c.ErrorStatus(err, http.StatusRequestedRangeNotSatisfiable) return nil } } sendSize = v.rangesMIMESize(ranges, ctype, size) code = http.StatusPartialContent pr, pw := io.Pipe() mw := multipart.NewWriter(pw) w.Header().Set("Content-Type", "multipart/byteranges; boundary="+mw.Boundary()) sendContent = pr defer pr.Close() go func() { for _, ra := range ranges { part, err := mw.CreatePart(ra.mimeHeader(ctype, size)) if err != nil { pw.CloseWithError(err) return } if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil { pw.CloseWithError(err) return } if _, err := io.CopyN(part, f, ra.length); err != nil { pw.CloseWithError(err) return } } mw.Close() pw.Close() }() } w.Header().Set("Accept-Ranges", "bytes") if w.Header().Get("Content-Encoding") == "" { w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10)) } } w.WriteHeader(code) if r.Method != "HEAD" { io.CopyN(w, sendContent, sendSize) } return nil }