예제 #1
0
파일: proxy.go 프로젝트: clarelin/asuran
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)
		}
	}
}
예제 #2
0
파일: proxy.go 프로젝트: BillSun/asuran
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)
		}
	}
}