-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
152 lines (123 loc) · 3.81 KB
/
main.go
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
"sync"
"time"
)
type ModifyResponseWriter struct {
http.ResponseWriter
}
func (w *ModifyResponseWriter) Write(b []byte) (int, error) {
// Add a custom response header
w.Header().Set("X-Custom-Response-Header", "Modified-Response")
// Modify the response body based on a condition
originalBody := string(b)
modifiedBody := originalBody
// Check if the original body contains a specific string
if strings.Contains(originalBody, "Hello") {
// If the string is found, replace it with a custom message
modifiedBody = strings.Replace(originalBody, "Hello", "Modified Hello", -1)
}
// Write the modified response body
return w.ResponseWriter.Write([]byte(modifiedBody))
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Serve the request
next.ServeHTTP(w, r)
// Log the request details
log.Printf(
"Method: %s\tURL: %s\tHeaders: %v\tStatus: %d\tDuration: %v\n",
r.Method, r.URL, r.Header, w.(ModifyResponseWriter).Status(), time.Since(start),
)
})
}
type rateLimiter struct {
mu sync.Mutex
clients map[string]int
rateLimit int
interval time.Duration
}
func newRateLimiter(rateLimit int, interval time.Duration) *rateLimiter {
return &rateLimiter{
clients: make(map[string]int),
rateLimit: rateLimit,
interval: interval,
}
}
func (rl *rateLimiter) isAllowed(clientIP string) bool {
rl.mu.Lock()
defer rl.mu.Unlock()
now := time.Now()
count, exists := rl.clients[clientIP]
if !exists || now.Sub(time.Unix(int64(count), 0)) > rl.interval {
// Reset the counter if the interval has passed
rl.clients[clientIP] = int(now.Unix())
return true
}
// Increment the counter if within the interval
if count < rl.rateLimit {
rl.clients[clientIP]++
return true
}
return false
}
func rateLimitingMiddleware(rl *rateLimiter, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
clientIP := strings.Split(r.RemoteAddr, ":")[0]
if rl.isAllowed(clientIP) {
next.ServeHTTP(w, r)
} else {
http.Error(w, "Rate Limit Exceeded", http.StatusTooManyRequests)
}
})
}
func handleProxy(w http.ResponseWriter, r *http.Request) {
// Your dynamic target URL configuration logic here
// For simplicity, let's set the target URL based on a query parameter
targetQueryParam := r.URL.Query().Get("target")
if targetQueryParam == "" {
http.Error(w, "Target query parameter is required", http.StatusBadRequest)
return
}
targetURL := targetQueryParam
// Create a reverse proxy
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http", // You can modify this based on your needs
Host: targetURL,
})
// Update headers to allow CORS
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE")
w.Header().Set("Access-Control-Allow-Headers", r.Header.Get("access-control-request-headers"))
// Create a custom response writer for potential modification
modifyResponseWriter := &ModifyResponseWriter{ResponseWriter: w}
// Handle the actual proxying of the request
proxy.ServeHTTP(modifyResponseWriter, r)
}
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "3000"
}
// Set up rate limiting with a limit of 10 requests per minute per IP
rl := newRateLimiter(10, time.Minute)
// Use the default ServeMux, which is a basic router
mux := http.NewServeMux()
// Register middleware
mux.HandleFunc("/", handleProxy)
handler := loggingMiddleware(rateLimitingMiddleware(rl, mux))
server := &http.Server{
Addr: ":" + port,
Handler: handler,
}
fmt.Printf("Proxy server listening on port %s\n", port)
log.Fatal(server.ListenAndServe())
}