func (p *Proxy) rewriteUrl(target string, w http.ResponseWriter, r *http.Request, rangeInfo string, prof *profile.Profile, f *life.Life, act profile.UrlProxyAction) bool { var content []byte = nil contentSource := "" switch act.Act { case profile.UrlActRewritten: u, err := url.QueryUnescape(act.ContentValue) if err != nil { return false } content = []byte(u) contentSource = "rewrite" case profile.UrlActRestore: content = prof.Restore(act.ContentValue) if content == nil { return false } default: return false } start := time.Now() w.Write(content) c := cache.NewUrlCache(target, r, nil, nil, contentSource, content, rangeInfo, start, time.Now(), nil) c.ResponseCode = 200 if f != nil { p.saveContentToCache(target, f, c, false) } return true }
func (p *Proxy) rewriteUrl(target string, w http.ResponseWriter, r *http.Request, rangeInfo string, prof *profile.Profile, f *life.Life, act profile.UrlProxyAction, speed profile.SpeedAction, bodyDelay profile.DelayAction) bool { var content []byte = nil contentSource := "" switch act.Act { case profile.UrlActRewritten: fallthrough case profile.UrlActTcpWritten: u, err := url.QueryUnescape(act.ContentValue) if err != nil { return false } content = []byte(u) if act.Act == profile.UrlActRewritten { contentSource = "rewrite" } else if act.Act == profile.UrlActTcpWritten { contentSource = "tcpwrite" } case profile.UrlActRestore: content = prof.Restore(act.ContentValue) if content == nil { return false } default: return false } if act.Act != profile.UrlActTcpWritten { p.procHeader(w.Header(), prof.SettingStringDef(target, "content-type", "default")) } var writeWrapper func(w io.Writer) io.Writer = nil switch bodyDelay.Act { case profile.DelayActDelayEach: fallthrough case profile.DelayActTimeout: writeWrapper = func(w io.Writer) io.Writer { return newDelayWriter(bodyDelay, w, p.r) } } switch speed.Act { case profile.SpeedActConstant: if writeWrapper != nil { wrap := writeWrapper writeWrapper = func(w io.Writer) io.Writer { return newSpeedWriter(speed, wrap(w)) } } else { writeWrapper = func(w io.Writer) io.Writer { return newSpeedWriter(speed, w) } } } start := time.Now() if act.Act == profile.UrlActTcpWritten { net.TcpWriteHttp(w, writeWrapper, content) } else { if writeWrapper != nil { writeWrapper(w).Write(content) } else { w.Write(content) } } c := cache.NewUrlCache(target, r, nil, nil, contentSource, content, rangeInfo, start, time.Now(), nil) if act.Act == profile.UrlActTcpWritten { c.ResponseCode = 599 } else { c.ResponseCode = 200 } if f != nil { p.saveContentToCache(target, f, c, false) } return true }
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) } } }
func (p *Proxy) proxyUrl(target string, w http.ResponseWriter, r *http.Request) { //fmt.Println("proxy: " + target) remoteIP := httpd.RemoteHost(r.RemoteAddr) needCache := false fullUrl := target if len(r.URL.RawQuery) > 0 { fullUrl += "?" + r.URL.RawQuery } requestUrl := fullUrl requestR := r contentSource := "" 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) } 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 time.Sleep(delay.RandDuration(p.r)) } break case profile.DelayActDropUntil: if u != nil && u.DropUntil(delay.RandDuration(p.r)) { // TODO: more safe method, maybe net.http.Hijacker panic("") } break case profile.DelayActTimeout: if delay.Time > 0 { // TODO: more safe method, maybe net.http.Hijacker time.Sleep(delay.RandDuration(p.r)) panic("") } break } act := p.urlOp.Action(remoteIP, fullUrl) //fmt.Println("url act: " + act.String()) switch act.Act { case profile.UrlActCache: needCache = true case profile.UrlActStatus: if c, err := strconv.Atoi(act.ContentValue); err == nil { w.WriteHeader(c) } else { w.WriteHeader(502) } return case profile.UrlActMap: requestUrl = act.ContentValue requestR = nil contentSource = "map " + act.ContentValue case profile.UrlActRedirect: http.Redirect(w, r, act.ContentValue, 302) return case profile.UrlActRewritten: fallthrough case profile.UrlActRestore: if p.rewriteUrl(fullUrl, w, r, rangeInfo, prof, f, act) { return } } } if needCache && r.Method == "GET" && f != nil { c := f.CheckCache(fullUrl, rangeInfo) if c != nil && c.Error == nil { c.Response(w) return } } httpStart := time.Now() resp, postBody, err := net.NewHttp(requestUrl, requestR, p.parseDomainAsDial(target, remoteIP)) 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 { defer resp.Close() content, err := resp.ProxyReturn(w) 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) } } }