func (gae *GAEHttpConnection) handleHttpRes(conn *SessionConnection, req *event.HTTPRequestEvent, ev *event.HTTPResponseEvent) (*http.Response, error) { originRange := req.RawReq.Header.Get("Range") contentRange := ev.GetHeader("Content-Range") if ev.Status == 206 && len(contentRange) > 0 && strings.EqualFold(req.Method, "GET") { _, end, length := util.ParseContentRangeHeaderValue(contentRange) if len(originRange) > 0 { _, oe := util.ParseRangeHeaderValue(originRange) if oe > 0 { length = oe + 1 } } if length > end+1 { gae.doRangeFetch(req.RawReq, ev.ToResponse()) return nil, nil } if len(originRange) == 0 { ev.Status = 200 ev.RemoveHeader("Content-Range") } } httpres := ev.ToResponse() err := httpres.Write(conn.LocalRawConn) return httpres, err }
func (r *rangeFetchTask) processResponse(res *http.Response) error { if r.closed { return fmt.Errorf("Session[%d] already closed for handling range response.", r.SessionID) } if nil != r.TaskValidation { if !r.TaskValidation() { r.Close() return fmt.Errorf("Task ternminated by callback") } } if r.rangeState != STATE_WAIT_NORMAL_RES && res.StatusCode != 206 { return fmt.Errorf("Expected 206 response, but got %d", res.StatusCode) } switch r.rangeState { case STATE_WAIT_NORMAL_RES: r.res = res return nil case STATE_WAIT_HEAD_RES: contentRangeHeader := res.Header.Get("Content-Range") if len(contentRangeHeader) > 0 { _, _, length := util.ParseContentRangeHeaderValue(contentRangeHeader) res.ContentLength = int64(length) } if r.contentEnd == -1 { r.contentEnd = int(res.ContentLength) - 1 r.originRangeHader = "" } resbody := res.Body r.res = res r.res.Request = r.req if r.res.StatusCode < 300 { if len(r.originRangeHader) > 0 { r.res.StatusCode = 206 r.res.Status = "" r.res.Header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", r.contentBegin, r.contentEnd, res.ContentLength)) } else { r.res.StatusCode = 200 r.res.Status = "" r.res.Header.Del("Content-Range") } res.ContentLength = int64(r.contentEnd - r.contentBegin + 1) res.Header.Set("Content-Length", fmt.Sprintf("%d", res.ContentLength)) rb := newRangeBody() r.res.Body = rb } log.Printf("Session[%d]Recv first range chunk:%s, %d %d ", r.SessionID, contentRangeHeader, r.contentEnd, r.contentBegin) if nil != resbody && r.res.StatusCode < 300 { var n int rb := r.res.Body.(*rangeBody) tmpbuf, ok := resbody.(*util.BufferCloseWrapper) if ok { n = tmpbuf.Buf.Len() rb.buf = tmpbuf.Buf } else { nn, _ := io.Copy(rb.buf, resbody) n = int(nn) } r.expectedRangePos += int(n) r.rangePos += int(n) } return nil case STATE_WAIT_RANGE_GET_RES: if nil == res.Body { return fmt.Errorf("Nil body for response:%d", res.StatusCode) } contentRange := res.Header.Get("Content-Range") start, _, _ := util.ParseContentRangeHeaderValue(contentRange) log.Printf("Session[%d]Recv range chunk:%s", r.SessionID, contentRange) body := r.res.Body.(*rangeBody) r.chunkMutex.Lock() if start == r.expectedRangePos { r.expectedRangePos += body.WriteHttpBody(res.Body) } else { r.chunks[start] = res.Body } for { if chunk, exist := r.chunks[r.expectedRangePos]; exist { delete(r.chunks, r.expectedRangePos) r.expectedRangePos += body.WriteHttpBody(chunk) } else { if r.expectedRangePos < r.contentEnd { log.Printf("Session[%d]Expect range chunk:%d\n", r.SessionID, r.expectedRangePos) } else { body.c <- nil } break } } r.chunkMutex.Unlock() } return nil }