// 回写Request内容 func (self *Param) writeback(resp *http.Response) *http.Response { if resp == nil { resp = new(http.Response) resp.Request = new(http.Request) } else if resp.Request == nil { resp.Request = new(http.Request) } resp.Request.Method = self.method resp.Request.Header = self.header resp.Request.Host = self.url.Host return resp }
// FileFetcher's Fetch() implementation func (this *fileFetcherExtender) Fetch(u *url.URL, userAgent string, headRequest bool) (*http.Response, error) { var res *http.Response = new(http.Response) var req *http.Request var e error if req, e = http.NewRequest("GET", u.String(), nil); e != nil { panic(e) } // Prepare the pseudo-request req.Header.Add("User-Agent", userAgent) // Open the file specified as path in u, relative to testdata/[host]/ f, e := os.Open(path.Join(FileFetcherBasePath, u.Host, u.Path)) if e != nil { // Treat errors as 404s - file not found res.Status = "404 Not Found" res.StatusCode = 404 } else { res.Status = "200 OK" res.StatusCode = 200 res.Body = f } res.Request = req return res, e }
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { var ( hashname = hashname.H(req.URL.Host) c *e3x.Channel resp *http.Response err error ) x := rt.Endpoint.GetExchange(hashname) if x == nil { return nil, e3x.UnreachableEndpointError(hashname) } c, err = x.Open("thtp", true) if err != nil { c.Close() return nil, err } err = rt.writeRequest(req, c) if err != nil { c.Close() return nil, err } resp, err = rt.readResponse(c) if err != nil { c.Close() return nil, err } resp.Request = req return resp, nil }
// ResponderFromResponse wraps an *http.Response in a Responder func ResponderFromResponse(resp *http.Response) Responder { return func(req *http.Request) (*http.Response, error) { res := new(http.Response) *res = *resp res.Request = req return res, nil } }
func RedirectResponse(req *http.Request, url string) *http.Response { res := new(http.Response) res.StatusCode = 302 res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = 0 res.Request = req res.Header = make(map[string][]string) res.Header.Set("Location", url) return res }
func (c *filterContext) Serve(res *http.Response) { res.Request = c.Request() if res.Header == nil { res.Header = make(http.Header) } if res.Body == nil { res.Body = &bodyBuffer{&bytes.Buffer{}} } c.servedWithResponse = true c.res = res }
func SimpleResponse(req *http.Request, status int, headers http.Header, body string) *http.Response { res := new(http.Response) body_rdr := (*fixedResBody)(strings.NewReader(body)) res.StatusCode = status res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = int64((*strings.Reader)(body_rdr).Len()) res.Request = req res.Header = make(map[string][]string) res.Body = body_rdr if headers != nil { res.Header = headers } return res }
// Generate an http.Response using the basic fields func SimpleResponse(req *http.Request, status int, headers http.Header, contentLength int64, body io.Reader) *http.Response { res := new(http.Response) res.StatusCode = status res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = contentLength res.Request = req res.Header = make(map[string][]string) if body_rdr, ok := body.(io.ReadCloser); ok { res.Body = body_rdr } else if body != nil { res.Body = ioutil.NopCloser(body) } if headers != nil { res.Header = headers } return res }
func (r *response) Response() *http.Response { if r.Data == nil { r.Data = new(bytes.Buffer) } out := new(http.Response) out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 out.Header = r.Header out.Body = &readCloser{r.Data} out.ContentLength = int64(r.Data.Len()) out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }
func (p *MockResponseWriter) String() string { resp := new(http.Response) resp.StatusCode = p.StatusCode resp.Proto = "HTTP/1.1" resp.ProtoMajor = 1 resp.ProtoMinor = 1 resp.Header = p.Headers resp.Body = ioutil.NopCloser(bytes.NewBuffer(p.Buffer.Bytes())) resp.ContentLength = int64(p.Buffer.Len()) if p.Headers.Get("Transfer-Encoding") != "" { resp.TransferEncoding = []string{p.Headers.Get("Transfer-Encoding")} } else { resp.TransferEncoding = nil } resp.Close = p.Headers.Get("Connection") == "close" resp.Trailer = make(http.Header) resp.Request = p.Request b, _ := httputil.DumpResponse(resp, true) return string(b) }
func (h Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { var err error remoteAddr := req.RemoteAddr // Prepare filter.Context ctx := filters.NewContext(req.Context(), h, h.Listener, rw, h.Branding) req = req.WithContext(ctx) // Enable transport http proxy if req.Method != "CONNECT" && !req.URL.IsAbs() { if req.URL.Scheme == "" { if req.TLS != nil && req.ProtoMajor == 1 { req.URL.Scheme = "https" } else { req.URL.Scheme = "http" } } if req.TLS != nil { if req.Host == "" { if req.URL.Host != "" { req.Host = req.URL.Host } else { req.Host = req.TLS.ServerName } } if req.URL.Host == "" { if req.Host != "" { req.URL.Host = req.Host } else { req.URL.Host = req.TLS.ServerName } } } } // Filter Request for _, f := range h.RequestFilters { ctx, req, err = f.Request(ctx, req) if req == filters.DummyRequest { return } if err != nil { if err != io.EOF { glog.Errorf("%s Filter Request %T error: %+v", remoteAddr, f, err) } return } // Update context for request req = req.WithContext(ctx) } if req.Body != nil { defer req.Body.Close() } // Filter Request -> Response var resp *http.Response for _, f := range h.RoundTripFilters { ctx, resp, err = f.RoundTrip(ctx, req) if resp == filters.DummyResponse { return } // Unexcepted errors if err != nil { filters.SetRoundTripFilter(ctx, f) glog.Errorf("%s Filter RoundTrip %T error: %+v", remoteAddr, f, err) http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway) return } // Update context for request req = req.WithContext(ctx) // A roundtrip filter give a response if resp != nil { resp.Request = req filters.SetRoundTripFilter(ctx, f) break } } // Filter Response for _, f := range h.ResponseFilters { if resp == nil || resp == filters.DummyResponse { return } ctx, resp, err = f.Response(ctx, resp) if err != nil { glog.Errorln("%s Filter %T Response error: %+v", remoteAddr, f, err) http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway) return } // Update context for request req = req.WithContext(ctx) } if resp == nil { glog.Errorln("%s Handler %#v Response empty response", remoteAddr, h) http.Error(rw, h.FormatError(ctx, fmt.Errorf("empty response")), http.StatusBadGateway) return } if resp.Header.Get("Content-Length") == "" && resp.ContentLength >= 0 { resp.Header.Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10)) } for key, values := range resp.Header { for _, value := range values { rw.Header().Add(key, value) } } rw.WriteHeader(resp.StatusCode) if resp.Body != nil { defer resp.Body.Close() n, err := helpers.IOCopy(rw, resp.Body) if err != nil { if isClosedConnError(err) { glog.Infof("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err) } else { glog.Warningf("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err) } } } }
// ReadResponse reads an HTTP response. The header is taken from h, // which must include the SPDY-specific fields starting with ':'. // If r is not nil, the body will be read from r. If t is not nil, // the trailer will be taken from t after the body is finished. func ReadResponse(h, t http.Header, r io.Reader, req *http.Request) (*http.Response, error) { for _, s := range badRespHeaderFields { if _, ok := h[s]; ok { return nil, &badStringError{"invalid header field", s} } } var err error resp := new(http.Response) resp.Request = req resp.Close = true resp.Header = make(http.Header) copyHeader(resp.Header, h) f := strings.SplitN(h.Get(":status"), " ", 2) var s string if len(f) > 1 { s = f[1] } resp.Status = f[0] + " " + s resp.StatusCode, err = strconv.Atoi(f[0]) if err != nil { return nil, &badStringError{"malformed HTTP status code", f[0]} } resp.Proto = h.Get(":version") var ok bool resp.ProtoMajor, resp.ProtoMinor, ok = http.ParseHTTPVersion(resp.Proto) if !ok { return nil, &badStringError{"malformed HTTP version", resp.Proto} } realLength, err := fixLength(true, resp.StatusCode, req.Method, resp.Header) if err != nil { return nil, err } if req.Method == "HEAD" { if n, err := parseContentLength(h.Get("Content-Length")); err != nil { return nil, err } else { resp.ContentLength = n } } else { resp.ContentLength = realLength } switch { case realLength == 0: r = eofReader case realLength > 0: if r == nil { // TODO(kr): return error } r = io.LimitReader(r, realLength) } if r == nil { r = eofReader } body := &body{r: r} resp.Body = body if t != nil { body.hdr = resp body.trailer = t } return resp, nil }
func filterByUrl(w icap.ResponseWriter, req *icap.Request) { h := w.Header() h.Set("ISTag", ISTag) h.Set("Service", "SquidBlocker filter ICAP service") if *debug { fmt.Fprintln(os.Stderr, "Printing the full ICAP request") fmt.Fprintln(os.Stderr, req) fmt.Fprintln(os.Stderr, req.Request) } switch req.Method { case "OPTIONS": h.Set("Methods", "REQMOD, RESPMOD") h.Set("Options-TTL", "1800") h.Set("Allow", "204") h.Set("Preview", "0") h.Set("Transfer-Preview", "*") h.Set("Max-Connections", "4000") h.Set("X-Include", "X-Client-IP, X-Authenticated-Groups, X-Authenticated-User, X-Subscriber-Id") w.WriteHeader(200, nil, false) case "REQMOD": // Check if the method is either OPTIONS\GET\POST\PUT etc // Also to analyse the request stucutre to verify what is the current one used // based on the RFC section at: http://tools.ietf.org/html/rfc7230#section-5.3 // Treat the CONNECT method in a special way due to the fact that it cannot actually be modified. checkhost := "" port := "0" answer := *defaultAnswer var err error if *debug { fmt.Fprintln(os.Stderr, "Default CASE. Request to host: "+req.Request.URL.Host+", Request Method: "+req.Request.Method) fmt.Fprintln(os.Stderr, "The full url from the ICAP client request: "+req.Request.URL.String()) } checkhost, port, err = net.SplitHostPort(req.Request.URL.Host) if err != nil { _ = err checkhost = req.Request.URL.Host } if port != "0" { if *debug { fmt.Fprintln(os.Stderr, "Rquest with port: "+port) } } if req.Request.Method == "CONNECT" && len(checkhost) > 0 && port != "0" { answer = check_tcp(checkhost, port) } else { answer = check(req.Request.URL.String()) } if *debug { fmt.Fprintln(os.Stderr, "ERRlog: reporting answer size => "+strconv.Itoa(len(answer))) fmt.Fprintln(os.Stderr, "ERRlog: reporitng answer => "+answer+", for =>"+req.Request.URL.String()) } // The next part comes to make sure that a DUNO respnse will be handled as the default answer/action if strings.HasPrefix(answer, "DUNO") { answer = *defaultAnswer + " rate=100 default_answer=yes" if *debug { fmt.Fprintln(os.Stderr, "ERRlog: reporting answer startsWith => \"DUNO\", taking default action") if len(*defaultAnswer) > 0 { fmt.Fprintln(os.Stderr, req.Request.URL.String()+" "+*defaultAnswer+" rate=40 default_answer=yes") } else { fmt.Fprintln(os.Stderr, req.Request.URL.String()+" OK state=DUNO") } } } if strings.HasPrefix(answer, "OK") { if *debug { fmt.Fprintln(os.Stderr, "OK response and sending 204 back") } w.WriteHeader(204, nil, false) return } if strings.HasPrefix(answer, "ERR") { if *debug { fmt.Fprintln(os.Stderr, "ERR response and sending 307 redirection back") } resp := new(http.Response) resp.Status = "307 SquidBlocker this url has been filtered!" resp.StatusCode = 307 resp.Proto = "HTTP/1.1" resp.ProtoMajor = 1 resp.ProtoMinor = 1 myMap := make(map[string][]string) //What if it is a connect request myMap["Location"] = append(myMap["Location"], *block_page+"?url="+url.QueryEscape(req.Request.URL.String())) resp.Header = myMap //resp.Body = ioutil.NopCloser(bytes.NewBufferString(body)) //resp.ContentLength = int64(len(body)) resp.Request = req.Request w.WriteHeader(200, resp, true) return } if *debug { fmt.Fprintln(os.Stderr, "Unknown asnwer and scenario, not adapting the request") } w.WriteHeader(204, nil, false) return case "RESPMOD": w.WriteHeader(204, nil, false) default: w.WriteHeader(405, nil, false) if *debug { fmt.Fprintln(os.Stderr, "Invalid request method") } } }
// This is the RoundTrip() call when we are in replay mode. func (r *roundTripper) replay(req *http.Request) (*http.Response, error) { // Ensure that the replay system is setup. isSetup.Do(r.replaySetup) // Read the body into a buffer. buffer := &bytes.Buffer{} var reqErr error if req.Body != nil { _, reqErr = io.Copy(buffer, req.Body) } // Since this function deals with the requestList we need to lock. requestLock.Lock() defer requestLock.Unlock() // Figure out which match function to use. f := Matcher if f == nil { f = matcher } // Walk through the objects in our archive list and see if any of them // match the incoming request. rrSource := &RequestResponse{ Request: req, RequestBody: buffer.Bytes(), RequestBodyError: reqErr, } var rrMatch *RequestResponse for _, rr := range requestList { if f(rrSource, rr) { rrMatch = rr break } } if rrMatch == nil { messageLines := []string{ "Matcher didn't match any execeted queries.\n", "Details of the failed request:", "", fmt.Sprintf("URL: %s", req.URL.String()), fmt.Sprintf("Method: %s", req.Method), } if len(req.Header) > 0 { messageLines = append(messageLines, "\nHeaders:") for key, value := range req.Header { messageLines = append(messageLines, fmt.Sprintf(" %s: %s", key, strings.Join(value, ", "))) } } if len(req.Trailer) > 0 { messageLines = append(messageLines, "\nTrailers:") for key, value := range req.Trailer { messageLines = append(messageLines, fmt.Sprintf(" %s: %s", key, strings.Join(value, ", "))) } } if len(buffer.Bytes()) > 0 { // This block is written a little funky in order to make testing // easier since it doesn't if/else as much. messageLines = append(messageLines, "Body:") length := len(buffer.Bytes()) warning := "" if length > 512 { length = 512 warning = "... (content truncated by dvr)" } messageLines = append(messageLines, string(buffer.Bytes()[:length])+warning) } panicIfError(fmt.Errorf(strings.Join(messageLines, "\n"))) } // Check to see if the response was an error when recorded. if rrMatch.Response == nil { return nil, rrMatch.Error } // Setup our response object. resp := new(http.Response) *resp = *rrMatch.Response resp.Request = req // Lastly we need to setup a bodyWriter for the Body. This will allow the // client to read the body we captured and it will return the error we // captured (if any) rather than EOF. resp.Body = &bodyWriter{ data: rrMatch.ResponseBody, err: rrMatch.ResponseBodyError, } // And lastly we return the response. return resp, rrMatch.Error }
func toShadowD(w icap.ResponseWriter, req *icap.Request) { local_debug := false if strings.Contains(req.URL.RawQuery, "debug=1") { local_debug = true } h := w.Header() h.Set("ISTag", ISTag) h.Set("Service", "Shadower ICAP to WAF Connector") if *debug { fmt.Fprintln(os.Stderr, "Printing the full ICAP request") fmt.Fprintln(os.Stderr, req) fmt.Fprintln(os.Stderr, req.Request) fmt.Fprintln(os.Stderr, req.Response) } switch req.Method { case "OPTIONS": h.Set("Methods", "REQMOD") h.Set("Options-TTL", "1800") h.Set("Allow", "204, 206") h.Set("Preview", "0") h.Set("Transfer-Preview", "*") h.Set("Max-Connections", *maxConnections) h.Set("X-Include", "X-Client-Ip, X-Authenticated-Groups, X-Authenticated-User, X-Subscriber-Id") w.WriteHeader(200, nil, false) case "REQMOD": modified := false nullBody := false allow206 := false allow204 := false xclientip := false if _, allow204Exists := req.Header["Allow"]; allow204Exists { if strings.Contains(req.Header["Allow"][0], "204") { allow204 = true } } if _, allow206Exists := req.Header["Allow"]; allow206Exists { if strings.Contains(req.Header["Allow"][0], "206") { allow206 = true } } if _, xclientipExists := req.Header["X-Client-Ip"]; xclientipExists { if len(req.Header["X-Client-Ip"][0]) > 1 { xclientip = true } } if _, encapsulationExists := req.Header["Encapsulated"]; encapsulationExists { if strings.Contains(req.Header["Encapsulated"][0], "null-body=") { nullBody = true } } if *debug || local_debug { for k, v := range req.Header { fmt.Fprintln(os.Stderr, "The ICAP headers:") fmt.Fprintln(os.Stderr, "key size:", len(req.Header[k])) fmt.Fprintln(os.Stderr, "key:", k, "value:", v) } } _, _, _, _ = nullBody, allow206, modified, allow204 if xclientip { req.Request.RemoteAddr = req.Header["X-Client-Ip"][0] } if wrongMethod(req) { if *debug { fmt.Println("This request has a", req.Request.Method, "method which is not being analyzed") } w.WriteHeader(204, nil, false) return } if *debug || local_debug { for k, v := range req.Request.Header { fmt.Fprintln(os.Stderr, "key:", k, "value:", v) } } // Send the request to ShadowD // If an attack(5,6) was declared then send a custom 500 page // If OK then send a 204 back var resStatus = 1 shodowdres, err := shadowServer.SendToShadowd(req.Request) newmap := make(map[string]interface{}) err = json.Unmarshal([]byte(shodowdres), &newmap) if err != nil { panic(err) } switch int(newmap["status"].(float64)) { case shadowd.STATUS_OK: if *debug || local_debug { fmt.Println("Request reported, OK") } w.WriteHeader(204, nil, false) return case shadowd.STATUS_BAD_REQUEST: resStatus = 400 case shadowd.STATUS_BAD_SIGNATURE: resStatus = 503 case shadowd.STATUS_BAD_JSON: resStatus = 504 case shadowd.STATUS_ATTACK: resStatus = 505 case shadowd.STATUS_CRITICAL_ATTACK: resStatus = 506 default: resStatus = 500 } resp := new(http.Response) resp.Status = "Internal Server Error" resp.StatusCode = resStatus resp.Proto = req.Request.Proto resp.ProtoMajor = req.Request.ProtoMajor resp.ProtoMinor = req.Request.ProtoMinor resp.Request = req.Request myHeaderMap := make(map[string][]string) resp.Header = myHeaderMap resp.Header.Set("X-Ngtech-Proxy", "Shadower") resp.Header.Set("X-Shadower", strconv.Itoa(resStatus)) resp.Header.Set("Content-Type", "text/html") resp.Header.Set("Content-Length", strconv.Itoa(len(internalerrorpage))) w.WriteHeader(200, resp, true) io.WriteString(w, internalerrorpage) return if *debug { fmt.Println("end of the line 204 response!.. Shouldn't happen.") } w.WriteHeader(204, nil, false) return case "RESPMOD": w.WriteHeader(204, nil, false) return default: w.WriteHeader(405, nil, false) if *debug || local_debug { fmt.Fprintln(os.Stderr, "Invalid request method") } } }
func (h Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { var err error remoteAddr := req.RemoteAddr // Prepare filter.Context ctx := filters.NewContext(h.Listener, rw, req) // Enable transport http proxy if req.Method != "CONNECT" && !req.URL.IsAbs() { if req.URL.Scheme == "" { if req.TLS != nil && req.ProtoMajor == 1 { req.URL.Scheme = "https" } else { req.URL.Scheme = "http" } } if req.URL.Host == "" { if req.Host != "" { req.URL.Host = req.Host } else { if req.TLS != nil { req.URL.Host = req.TLS.ServerName } } } } // Filter Request for _, f := range h.RequestFilters { ctx, req, err = f.Request(ctx, req) // A roundtrip filter hijacked if ctx.Hijacked() { return } if err != nil { if err != io.EOF { glog.Errorf("%s Filter Request %T(%v) error: %v", remoteAddr, f, f, err) } return } } // Filter Request -> Response var resp *http.Response for _, f := range h.RoundTripFilters { ctx, resp, err = f.RoundTrip(ctx, req) // A roundtrip filter hijacked if ctx.Hijacked() { return } // Unexcepted errors if err != nil { glog.Errorf("%s Filter RoundTrip %T(%v) error: %v", remoteAddr, f, f, err) return } // A roundtrip filter give a response if resp != nil { resp.Request = req break } } // Filter Response for _, f := range h.ResponseFilters { if resp == nil { return } ctx, resp, err = f.Response(ctx, resp) if err != nil { glog.Errorf("%s Filter Response %T(%v) error: %v", remoteAddr, f, f, err) return } } if resp == nil { return } for key, values := range resp.Header { for _, value := range values { rw.Header().Add(key, value) } } rw.WriteHeader(resp.StatusCode) if resp.Body != nil { defer resp.Body.Close() n, err := IoCopy(rw, resp.Body) if err != nil { glog.Errorf("IoCopy %#v return %#v %s", resp.Body, n, err) } } }
func (r *Response) Response() *http.Response { out := new(http.Response) r.headerM.Lock() out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Header = r.Header r.headerM.Unlock() out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 r.dataM.Lock() if r.data == nil { out.Body = &ReadCloser{new(bytes.Buffer)} } else if unrequestedGzip(r) { // User-agents MUST support gzip compression. // Regardless of the Accept-Encoding sent by the user-agent, the server may // always send content encoded with gzip or deflate encoding. r.data.Prep() out.Header.Del("Content-Encoding") out.Header.Del("Content-Length") out.ContentLength = -1 out.Body = &gzipReader{body: r.data} } else { r.data.Prep() out.Body = r.data out.ContentLength = r.data.written } r.dataM.Unlock() out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }