func (p *Proxy) Command(commands string, f *profile.Profile, v *life.Life) { commandLines := strings.Split(commands, "\n") for _, line := range commandLines { line = strings.TrimSpace(line) if len(line) <= 0 || line[0] == '#' { continue } c, rest := cmd.TakeFirstArg(line) switch c { case "restart": if v != nil { v.Restart() } case "clear": f.Clear() case "domain": f.CommandDomain(rest) case "url": f.CommandUrl(rest) case "host": c, rest = cmd.TakeFirstArg(rest) if ip, domain, ok := parseIPDomain(c, rest); ok { f.CommandDomain(domain + " " + ip) } default: if ip, domain, ok := parseIPDomain(c, rest); ok { f.CommandDomain(domain + " " + ip) } } } }
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) writeStores(w http.ResponseWriter, profileIP string, prof *profile.Profile) { t, err := template.ParseFiles("template/stores.tmpl") list := formatStoreListData(prof.ListStored(), profileIP) err = t.Execute(w, storeListData{profileIP, list}) if err != nil { fmt.Fprintln(w, "内部错误:", err) } }
func formatEditStoreData(profileIP string, prof *profile.Profile, id string) editStoreData { encodedContent := "" if len(id) > 0 { c := prof.Restore(id) if len(c) > 0 { encodedContent = strings.Replace(url.QueryEscape(string(c)), "+", "%20", -1) } } return editStoreData{profileIP, id, encodedContent} }
func (p *Proxy) storeHistory(profileIP, id string, prof *profile.Profile) (string, string) { f := p.lives.OpenExists(profileIP) if f == nil { return "", "" } hID, err := strconv.ParseUint(id, 10, 32) if err != nil { return "", "" } h := f.LookHistoryByID(uint32(hID)) if h.Error == nil && len(h.Bytes) > 0 { saveID := prof.StoreID(h.Bytes) return h.Url, saveID } return "", "" }
func (p *Proxy) storeHistory(profileIP, id string, prof *profile.Profile) (string, string) { f := p.lives.OpenExists(profileIP) if f == nil { return "", "" } hID, err := strconv.ParseUint(id, 10, 32) if err != nil { return "", "" } h := f.LookHistoryByID(uint32(hID)) if h == nil { return "", "" } content, err := h.Content() if err == nil { saveID := prof.StoreID(content) return h.Url, saveID } return "", "" }
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) } } }