1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
package main
import (
"flag"
"log"
"math/rand"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
host := flag.String("host", "localhost:6969", "host to bind to")
upstreamFlag := flag.String("upstream", "", "upstream host to proxy to (required)")
only404 := flag.Bool("only404", false, "only change status code to 404")
flag.Parse()
if *upstreamFlag == "" {
log.Fatal("--upstream is required")
}
upstream, err := url.Parse(*upstreamFlag)
if err != nil {
log.Fatal(err)
}
if upstream.Host == "" {
log.Fatal("upstream host is required (you may be missing the protocol, ie http://)")
}
if upstream.Scheme == "" {
upstream.Scheme = "http"
}
statusCodes := [...]int{
http.StatusContinue,
http.StatusSwitchingProtocols,
http.StatusProcessing,
http.StatusEarlyHints,
http.StatusOK,
http.StatusCreated,
http.StatusAccepted,
http.StatusNonAuthoritativeInfo,
http.StatusNoContent,
http.StatusResetContent,
http.StatusPartialContent,
http.StatusMultiStatus,
http.StatusAlreadyReported,
http.StatusIMUsed,
http.StatusMultipleChoices,
http.StatusMovedPermanently,
http.StatusFound,
http.StatusSeeOther,
http.StatusNotModified,
http.StatusUseProxy,
http.StatusTemporaryRedirect,
http.StatusPermanentRedirect,
http.StatusBadRequest,
http.StatusUnauthorized,
http.StatusPaymentRequired,
http.StatusForbidden,
http.StatusNotFound,
http.StatusMethodNotAllowed,
http.StatusNotAcceptable,
http.StatusProxyAuthRequired,
http.StatusRequestTimeout,
http.StatusConflict,
http.StatusGone,
http.StatusLengthRequired,
http.StatusPreconditionFailed,
http.StatusRequestEntityTooLarge,
http.StatusRequestURITooLong,
http.StatusUnsupportedMediaType,
http.StatusRequestedRangeNotSatisfiable,
http.StatusExpectationFailed,
http.StatusTeapot,
http.StatusMisdirectedRequest,
http.StatusUnprocessableEntity,
http.StatusLocked,
http.StatusFailedDependency,
http.StatusTooEarly,
http.StatusUpgradeRequired,
http.StatusPreconditionRequired,
http.StatusTooManyRequests,
http.StatusRequestHeaderFieldsTooLarge,
http.StatusUnavailableForLegalReasons,
http.StatusInternalServerError,
http.StatusNotImplemented,
http.StatusBadGateway,
http.StatusServiceUnavailable,
http.StatusGatewayTimeout,
http.StatusHTTPVersionNotSupported,
http.StatusVariantAlsoNegotiates,
http.StatusInsufficientStorage,
http.StatusLoopDetected,
http.StatusNotExtended,
http.StatusNetworkAuthenticationRequired,
}
proxy := &httputil.ReverseProxy{
Rewrite: func(req *httputil.ProxyRequest) {
req.SetURL(upstream)
},
}
proxy.ModifyResponse = func(resp *http.Response) error {
originStatus := resp.StatusCode
if *only404 {
resp.StatusCode = http.StatusNotFound
} else {
resp.StatusCode = statusCodes[rand.Intn(len(statusCodes))]
}
log.Printf("status code %d (%s) changed to %d (%s) for path %s", originStatus, http.StatusText(originStatus), resp.StatusCode, http.StatusText(resp.StatusCode), resp.Request.URL.Path)
return nil
}
log.Println("listening on", *host)
log.Println("proxying requests to", upstream.String())
log.Fatal(http.ListenAndServe(*host, proxy))
}
|