func (d *delayWriter) Write(p []byte) (n int, err error) { if d.first { d.first = false d.Flush() } switch d.delay.Act { case profile.DelayActDelayEach: if !d.hasDelayed { d.hasDelayed = true <-time.NewTimer(d.d).C } case profile.DelayActTimeout: once := len(p) / 1024 sum := 0 if once < 1 { once = 1 } else if once > 10*1024 { once = 10 * 1024 } i := 0 for { duration := time.Now().Sub(d.start) if duration >= d.d { gonet.ResetResponse(d.w) return sum, fmt.Errorf("http body timeout in %v(set %v)", duration, d.d) } c := len(p) - i if c == 0 { break } else if c > once { c = once } oc, err := d.w.Write(p[i : i+c]) sum += oc i = sum if err != nil { return sum, err } } return sum, nil } return d.w.Write(p) }
func (p *Proxy) remoteProxyUrl(remoteIP, target string, w http.ResponseWriter, r *http.Request) { needCache := false fullUrl := target if len(r.URL.RawQuery) > 0 { fullUrl += "?" + r.URL.RawQuery } requestUrl := fullUrl requestR := r contentSource := "" var prof *profile.Profile if !p.isSelfAddr(remoteIP) { prof = p.profileOp.Open(remoteIP) } rangeInfo := cache.CheckRange(r) f := p.lives.Open(remoteIP) var u *life.UrlState if f != nil { u = f.OpenUrl(fullUrl) } var writeWrap io.Writer = nil if p.urlOp != nil { delay := p.urlOp.Delay(remoteIP, fullUrl) //fmt.Println("url delay: " + delay.String()) switch delay.Act { case profile.DelayActDelayEach: if delay.Time > 0 { // TODO: create request before sleep, more effective d := delay.RandDuration(p.r) time.Sleep(d) f.Log("proxy " + fullUrl + " delay " + d.String()) } break case profile.DelayActDropUntil: d := delay.RandDuration(p.r) if u != nil && u.DropUntil(d) { f.Log("proxy " + fullUrl + " drop " + d.String()) net.ResetResponse(w) return } break case profile.DelayActTimeout: if delay.Time > 0 { d := delay.RandDuration(p.r) time.Sleep(d) f.Log("proxy " + fullUrl + " timeout " + d.String()) } else { f.Log("proxy " + fullUrl + " timeout") } net.ResetResponse(w) return break } act := p.urlOp.Action(remoteIP, fullUrl) //fmt.Println("url act: " + act.String()) speed := p.urlOp.Speed(remoteIP, fullUrl) bodyDelay := p.urlOp.BodyDelay(remoteIP, fullUrl) switch act.Act { case profile.UrlActCache: needCache = true case profile.UrlActStatus: status := 502 if c, err := strconv.Atoi(act.ContentValue); err == nil { status = c } w.WriteHeader(status) f.Log("proxy " + fullUrl + " status " + strconv.Itoa(status)) return case profile.UrlActMap: requestUrl = act.ContentValue requestR = nil contentSource = "map " + act.ContentValue case profile.UrlActRedirect: http.Redirect(w, r, act.ContentValue, 302) f.Log("proxy " + fullUrl + " redirect " + act.ContentValue) return case profile.UrlActRewritten: fallthrough case profile.UrlActRestore: fallthrough case profile.UrlActTcpWritten: if p.rewriteUrl(fullUrl, w, r, rangeInfo, prof, f, act, speed, bodyDelay) { return } } switch bodyDelay.Act { case profile.DelayActDelayEach: fallthrough case profile.DelayActTimeout: if writeWrap == nil { writeWrap = w } writeWrap = newDelayWriter(bodyDelay, writeWrap, p.r) } switch speed.Act { case profile.SpeedActConstant: if writeWrap == nil { writeWrap = w } writeWrap = newSpeedWriter(speed, writeWrap) } } if needCache && r.Method == "GET" && f != nil { c := f.CheckCache(fullUrl, rangeInfo) if c != nil && c.Error == nil { c.Response(w, writeWrap) return } } dont302 := true settingContentType := "default" if prof != nil { dont302 = prof.SettingDont302(fullUrl) settingContentType = prof.SettingStringDef(fullUrl, "content-type", settingContentType) if prof.SettingSwitch(fullUrl, "disable304") { p.disable304FromHeader(requestR.Header) } } httpStart := time.Now() resp, postBody, redirection, err := net.NewHttp(requestUrl, requestR, p.parseDomainAsDial(target, remoteIP), dont302) if err != nil { c := cache.NewUrlCache(fullUrl, r, nil, nil, contentSource, nil, rangeInfo, httpStart, time.Now(), err) if f != nil { go p.saveContentToCache(fullUrl, f, c, false) } http.Error(w, "Bad Gateway", 502) } else if len(redirection) > 0 { http.Redirect(w, r, redirection, 302) if f != nil { f.Log("proxy " + fullUrl + " redirect " + redirection) } } else { defer resp.Close() p.procHeader(resp.Header(), settingContentType) content, err := resp.ProxyReturn(w, writeWrap) httpEnd := time.Now() c := cache.NewUrlCache(fullUrl, r, postBody, resp, contentSource, content, rangeInfo, httpStart, httpEnd, err) if f != nil { go p.saveContentToCache(fullUrl, f, c, needCache) } } }