func (s *Session) doProxy(xReq *PxReq, w http.ResponseWriter) (err error) { var req *http.Request var resp *http.Response req, err = NewRequest(s.dMethod, xReq.url, s.body) req.Header = xReq.header if log.V(3) { dumpHeader("<- Header/ActualReq", req.Header) } resp, err = http_client.Do(req) if log.V(1) { if resp != nil { log.Infof("%s %s %s [%d] %s", s.aAddr, s.aMethod, s.dUserAgent, resp.StatusCode, xReq.url.String()) } else { log.Infof("%s %s %s [Err] %s", s.aAddr, s.aMethod, s.dUserAgent, xReq.url.String()) } } if log.V(3) && resp != nil { dumpHeader("-> Header/OriginalResp", resp.Header) } if resp != nil && resp.Body != nil { defer resp.Body.Close() } if err != nil { if e, y := err.(*url.Error); y && e.Err == err30xRedirect { s.redirected, err = true, nil } else { return dumpError(err) } } err = s.processOutputHeader(xReq, resp, w) if err != nil { err = s.avoidCountryRedirect(xReq, w) return } pMethod := determineHandler(resp.Header.Get("Content-Type")) if pMethod == HD_unknown || resp.ContentLength > maxAcceptedLength { w.WriteHeader(resp.StatusCode) io.Copy(w, resp.Body) } else { err = pMethod.processText(s, w, resp) } return }
func (s *Session) processOutputHeader(xReq *PxReq, resp *http.Response, w http.ResponseWriter) (err error) { defer func() { if e := recover(); e != nil { err = e.(error) } }() wHeader := w.Header() for k, array := range resp.Header { switch k { case "Set-Cookie": continue case "Location": targetUrl := array[0] nextUrl := s.processRedirect(targetUrl) if log.V(1) { log.Infof("Cook redirection %s -> %s", targetUrl, nextUrl) } wHeader.Set(k, nextUrl) default: // Alt-Svc, Alternate-Protocol if strings.HasPrefix(k, "Alt") { continue } for _, v := range array { wHeader.Add(k, v) } } } wHeader.Set("Server", "ezgoo") var alterCookiePath = xReq.nondefault == 0xf for _, ck := range resp.Cookies() { if alterCookiePath { if ck.Domain == NULL || strings.HasPrefix(ck.Domain, ".") { // prevent ck.path==/!.some-host ck.Path = fmt.Sprintf("/!%s%s", xReq.url.Host, ck.Path) } else { ck.Path = fmt.Sprintf("/!%s%s", ck.Domain, ck.Path) } } if v := cookieString(ck, &s.plainHost, true); v != NULL { wHeader.Add("Set-Cookie", v) } } return }
func (p Handler) processText(s *Session, w http.ResponseWriter, resp *http.Response) (err error) { var ( zr *gzip.Reader zw *gzip.Writer body []byte gzipped bool = resp.Header.Get("Content-Encoding") == "gzip" reqHost string = resp.Request.URL.Host reqPath string = resp.Request.URL.Path ) if resp.ContentLength != 0 && resp.Request.Method != "HEAD" { if gzipped { zr, err = gzip.NewReader(resp.Body) if err == nil { body, err = ioutil.ReadAll(zr) if !consumeError(&err) { return dumpError(err) } } } else { body, err = ioutil.ReadAll(resp.Body) if !consumeError(&err) { return dumpError(err) } } } w.Header().Del("Content-Length") w.Header().Set("Content-Encoding", "gzip") w.WriteHeader(resp.StatusCode) if len(body) <= 0 { return } var ( rules []ReRule bodyExtraHeader string ) switch p { case HD_html: rules = reRules.Html case HD_javascript: rules = reRules.Js case HD_json: rules = reRules.Json case HD_css: rules = reRules.Css } if log.V(5) { log.Infof("Original entity %s\n%s", reqPath, string(body)) } if s.abusing { imgSrc := fmt.Sprintf(`<img src="/!%s/sorry`, reqHost) body = bytes.Replace(body, []byte(`<img src="/sorry`), []byte(imgSrc), 1) rules = nil } for i, r := range rules { if r.PathRe != nil && r.PathRe.FindString(reqPath) == NULL { if log.V(4) { log.Infof("re.%d=[%s] pathRe=deny", i, r.ContentPattern.Pattern) } continue } if log.V(4) { log.Infof("re.%d=[%s] applied", i, r.ContentPattern.Pattern) } if r.Scheme&0xff > 0 { body = r.ContentRe.Replace(body, r.Replacement) } if r.Scheme&0xff00 > 0 { bodyExtraHeader += r.InsertHeader } } zw = gzip.NewWriter(w) if len(bodyExtraHeader) > 0 { zw.Write([]byte(bodyExtraHeader)) } zw.Write(body) err = zw.Flush() return }