Example #1
0
func (h *reqHandler) getUpstreamReader(start, end uint64) io.ReadCloser {
	subh := *h
	subh.req = subh.getNormalizedRequest()
	subh.req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))

	h.Logger.Debugf("[%p] Making upstream request for %s, bytes [%d-%d]...",
		subh.req, subh.req.URL, start, end)

	//!TODO: optimize requests for the same pieces? if possible, make only 1 request to the upstream for the same part

	r, w := io.Pipe()
	subh.resp = httputils.NewFlexibleResponseWriter(func(rw *httputils.FlexibleResponseWriter) {
		respRng, err := httputils.GetResponseRange(rw.Code, rw.Headers)
		if err != nil {
			h.Logger.Errorf("[%p] Could not parse the content-range for the partial upstream request: %s", subh.req, err)
			_ = w.CloseWithError(err)
		}
		h.Logger.Debugf("[%p] Received response with status %d and range %v", subh.req, rw.Code, respRng)
		if rw.Code == http.StatusPartialContent {
			//!TODO: check whether the returned range corresponds to the requested range
			rw.BodyWriter = w
		} else if rw.Code == http.StatusOK {
			//!TODO: handle this, use skipWriter or something like that
			_ = w.CloseWithError(fmt.Errorf("NOT IMPLEMENTED"))
		} else {
			_ = w.CloseWithError(fmt.Errorf("Upstream responded with status %d", rw.Code))
		}
	})
	go subh.carbonCopyProxy()
	return newWholeChunkReadCloser(r, h.Cache.PartSize.Bytes())
}
Example #2
0
func (h *Headers) wrapResponseWriter(w http.ResponseWriter) http.ResponseWriter {
	var newW = httputils.NewFlexibleResponseWriter(func(frw *httputils.FlexibleResponseWriter) {
		httputils.CopyHeaders(frw.Header(), w.Header())
		h.response.rewrite(w.Header())
		frw.BodyWriter = utils.NopCloser(w)
		w.WriteHeader(frw.Code)
	})
	httputils.CopyHeaders(w.Header(), newW.Header())
	return newW
}
Example #3
0
func (h *reqHandler) carbonCopyProxy() {
	flexibleResp := httputils.NewFlexibleResponseWriter(h.getResponseHook())
	defer func() {
		if flexibleResp.BodyWriter != nil {
			if err := flexibleResp.BodyWriter.Close(); err != nil {
				h.Logger.Errorf("[%p] Error while closing flexibleResponse: %s", h.req, err)
			}
		}
		//!TODO: cache small upstream responses that we did not cache because
		// there was no Content-Length header in the upstream response but it
		// was otherwise cacheable? Examples are folder listings for apache and
		// ngingx: `curl -i http://mirror.rackspace.com/` or `curl -i
		// https://mirrors.uni-plovdiv.net/`

	}()

	h.next.RequestHandle(h.ctx, flexibleResp, h.getNormalizedRequest())
}
Example #4
0
func (rr *rangeReader) Range(start, length uint64) io.ReadCloser {
	newreq := copyRequest(rr.req)
	newreq.Header.Set("Range", httputils.Range{Start: start, Length: length}.Range())
	var in, out = io.Pipe()
	flexible := httputils.NewFlexibleResponseWriter(func(frw *httputils.FlexibleResponseWriter) {
		if frw.Code != http.StatusPartialContent || !rr.callback(frw) {
			_ = out.CloseWithError(errUnsatisfactoryResponse)
		}
		frw.BodyWriter = out
	})
	go func() {
		defer func() {
			if err := out.Close(); err != nil {
				rr.location.Logger.Errorf("handler.mp4[%p]: error on closing rangeReaders output: %s", rr.req, err)
			}
		}()
		rr.next.RequestHandle(rr.ctx, flexible, newreq)
	}()

	return in
}