api/plugins/http_proxy/proxy_handler.go
Peter Kurfer 9236a38be0 Moved endpoint handling to new module
- introduce new endpoints module
- introduce Endpoint and EndpointManager
- introduce new Logging abstraction API to allow proper mocking
- add error return value to Start and Shutdown of endpoints
- add mocks of some internals to allow easier testing
- add generate target to take care of all code generation
2020-04-14 00:15:33 +02:00

100 lines
2.3 KiB
Go

package main
import (
"github.com/baez90/inetmock/pkg/logging"
"go.uber.org/zap"
"gopkg.in/elazarl/goproxy.v1"
"io"
"mime"
"net/http"
"os"
"path/filepath"
)
type proxyHttpHandler struct {
options httpProxyOptions
logger logging.Logger
}
/*
TODO implement HTTPS proxy like in TLS interceptor
func (p *proxyHttpHandler) HandleConnect(req string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
return &goproxy.ConnectAction{
Action: goproxy.OkConnect,
}, ""
}*/
func (p *proxyHttpHandler) Handle(req *http.Request, _ *goproxy.ProxyCtx) (retReq *http.Request, resp *http.Response) {
retReq = req
resp = &http.Response{
Request: req,
TransferEncoding: req.TransferEncoding,
Header: make(http.Header),
StatusCode: http.StatusOK,
}
p.logger.Info(
"Handling request",
zap.String("source", req.RemoteAddr),
zap.String("host", req.Host),
zap.String("method", req.Method),
zap.String("protocol", req.Proto),
zap.String("path", req.RequestURI),
zap.Reflect("headers", req.Header),
)
for _, rule := range p.options.Rules {
if rule.pattern.MatchString(req.URL.Path) {
if file, err := os.Open(rule.response); err != nil {
p.logger.Error(
"failed to open response target file",
zap.String("resonse", rule.response),
zap.Error(err),
)
continue
} else {
resp.Body = file
if stat, err := file.Stat(); err == nil {
resp.ContentLength = stat.Size()
}
if contentType, err := GetContentType(rule, file); err == nil {
resp.Header["Content-Type"] = []string{contentType}
}
p.logger.Info("returning fake response from rules")
return req, resp
}
}
}
if resp, err := p.options.FallbackStrategy.Apply(req); err != nil {
p.logger.Error(
"failed to apply fallback strategy",
zap.Error(err),
)
} else {
p.logger.Info("returning fake response from fallback strategy")
return req, resp
}
p.logger.Info("falling back to proxying request through")
return req, nil
}
func GetContentType(rule targetRule, file *os.File) (contentType string, err error) {
if contentType = mime.TypeByExtension(filepath.Ext(rule.response)); contentType != "" {
return
}
var buf [512]byte
n, _ := io.ReadFull(file, buf[:])
contentType = http.DetectContentType(buf[:n])
_, err = file.Seek(0, io.SeekStart)
return
}