func NewResponseHeader(header string) (h ResponseHeader) { headers := strings.Split(header, "\r\n") pattern := `(HTTP)/(\d+)\.(\d+) (\d+) (.+)` re, err := regexp.Compile(pattern) if err != nil { logger.Error(err) return } matches := re.FindStringSubmatch(headers[0]) h.Protocol = matches[1] h.Version = matches[2] + "." + matches[3] h.Major = matches[2] h.Minor = matches[3] h.Code = matches[4] h.Message = matches[5] pattern = `([^:]+):\s*(.*)` re, err = regexp.Compile(pattern) if err != nil { logger.Error(err) return } h.Headers = []HeaderKeyPair{} for _, v := range headers[1:] { matches = re.FindStringSubmatch(v) h.Headers = append(h.Headers, HeaderKeyPair{Key: matches[1], Value: matches[2]}) } return }
func startInTheMiddle(args Args) { proxy.WaitForExitSignal() tr := transport.Transport{Proxy: transport.ProxyFromEnvironment} proxy.Start(proxy.Options{ Ip: args.Ip, Port: args.Port, ExportFolder: args.ExportFolder, Record: args.Record, OnRequest: func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { ctx.RoundTripper = goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (resp *http.Response, err error) { ctx.UserData, resp, err = tr.DetailedRoundTrip(req) return }) reqBody, err := httputil.DumpRequest(req, true) if err != nil { logger.Error(err) os.Exit(1) } r := httper.NewRequest(string(reqBody)) logger.Info(inPFunc("--> ") + r.ToString()) if !args.Record { resp, err := cacher.Find(req) if err == nil { logger.Debug("Cache HIT") return req, resp } logger.Debug("Cache MISSED") } return req, nil }, OnResponse: func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { respBody, err := httputil.DumpResponse(resp, true) if err != nil { logger.Error(err) os.Exit(1) } r := httper.NewResponse(string(respBody)) logger.Info(outPFunc("<-- ") + r.ToString()) return resp }, }) }
func dumpCache(fileName string, content string) { finfo, err := os.Stat(toFolder) if err != nil || !finfo.IsDir() { err = os.MkdirAll(toFolder, 0755) if err != nil { logger.Error(err) os.Exit(1) } } b := []byte(content) err = ioutil.WriteFile(toFolder+"/"+fileName, b, 0755) if err != nil { logger.Error(err) os.Exit(1) } }
func (c *CacheItem) dispatchReturn(ret string) string { if ret[:7] == "file://" { data, err := ioutil.ReadFile(ret[7:]) if err != nil { logger.Error(err) return "" } return string(data) } return ret }
func (r *Response) parse(body string) { parts := strings.SplitN(body, "\r\n\r\n", 2) if len(parts) < 2 { logger.Error(errors.New("Invalid response format.")) return } header := parts[0] payload := parts[1] r.Header = NewResponseHeader(header) r.Payload = payload }
func NewRequestHeader(header string) (h RequestHeader) { headers := strings.Split(header, "\r\n") if len(headers) < 2 { logger.Error(errors.New("Invalid request format.")) return } pattern := `([A-Z]+) (.+) (HTTP)/(\d+\.\d+)` re, err := regexp.Compile(pattern) if err != nil { logger.Error(err) return } matches := re.FindStringSubmatch(headers[0]) h.method = matches[1] h.path = matches[2] h.protocol = matches[3] h.version = matches[4] pattern = `([^:]+):\s*(.*)` re, err = regexp.Compile(pattern) if err != nil { logger.Error(err) return } h.headers = []HeaderKeyPair{} for _, v := range headers[1:] { matches = re.FindStringSubmatch(v) h.headers = append(h.headers, HeaderKeyPair{Key: matches[1], Value: matches[2]}) } h.hostname = h.ExtractHostname() return }
func Flush() { for k, v := range cache { safeName := createSafeName(v.Key) body := v.ResponseStates["__default"].Return dumpCache(safeName, body) cache[k].Key = safeName cache[k].ResponseStates["__default"] = Responsible{ Return: "file://" + toFolder + "/" + safeName, } } jsonString, _ := json.MarshalIndent(cache, "", " ") err := ioutil.WriteFile(toFolder+"/stub.json", jsonString, 0755) if err != nil { logger.Error(err) os.Exit(1) } }