Пример #1
0
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
}
Пример #2
0
Файл: file.go Проект: hujh/gmvc
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
}