|
8 | 8 | "net/http" |
9 | 9 | "net/url" |
10 | 10 | "strconv" |
| 11 | + "strings" |
11 | 12 | "time" |
12 | 13 |
|
13 | 14 | "github.com/air-gapped/cooked/internal/cache" |
@@ -88,7 +89,9 @@ func New(cfg *config.Config, version string, assets fs.FS, extraFetchOpts ...fet |
88 | 89 | func (s *Server) routes() { |
89 | 90 | s.mux.HandleFunc("GET /healthz", s.handleHealthz) |
90 | 91 | s.mux.HandleFunc("GET /_cooked/docs", s.handleDocs) |
| 92 | + s.mux.HandleFunc("GET /_cooked/raw/{upstream...}", s.handleRaw) |
91 | 93 | s.mux.HandleFunc("GET /_cooked/{path...}", s.handleAsset) |
| 94 | + s.mux.HandleFunc("GET /.well-known/{path...}", s.handleWellKnown) |
92 | 95 | s.mux.HandleFunc("GET /{$}", s.handleLanding) |
93 | 96 | s.mux.HandleFunc("GET /{upstream...}", s.handleRender) |
94 | 97 | } |
@@ -179,6 +182,50 @@ func (s *Server) handleAsset(w http.ResponseWriter, r *http.Request) { |
179 | 182 | w.Write(data) |
180 | 183 | } |
181 | 184 |
|
| 185 | +func (s *Server) handleRaw(w http.ResponseWriter, r *http.Request) { |
| 186 | + rawUpstream := ExtractUpstreamFromPath( |
| 187 | + strings.TrimPrefix(r.URL.Path, "/_cooked/raw"), |
| 188 | + r.URL.RawQuery, |
| 189 | + ) |
| 190 | + |
| 191 | + upstream, err := ParseUpstreamURL(rawUpstream) |
| 192 | + if err != nil { |
| 193 | + http.Error(w, "bad request", http.StatusBadRequest) |
| 194 | + return |
| 195 | + } |
| 196 | + |
| 197 | + if !s.allowlist.Allows(upstream.Host) { |
| 198 | + http.Error(w, "forbidden", http.StatusForbidden) |
| 199 | + return |
| 200 | + } |
| 201 | + |
| 202 | + if s.allowlist == nil { |
| 203 | + private, err := IsPrivateAddress(upstream.Host) |
| 204 | + if err != nil || private { |
| 205 | + http.Error(w, "forbidden", http.StatusForbidden) |
| 206 | + return |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + result, err := s.fetcher.Client().Fetch(rawUpstream, "", "") |
| 211 | + if err != nil { |
| 212 | + http.Error(w, "upstream fetch failed", http.StatusBadGateway) |
| 213 | + return |
| 214 | + } |
| 215 | + |
| 216 | + if result.StatusCode != 200 { |
| 217 | + http.Error(w, fmt.Sprintf("upstream returned %d", result.StatusCode), result.StatusCode) |
| 218 | + return |
| 219 | + } |
| 220 | + |
| 221 | + w.Header().Set("Content-Type", "text/plain; charset=utf-8") |
| 222 | + w.Write(result.Body) |
| 223 | +} |
| 224 | + |
| 225 | +func (s *Server) handleWellKnown(w http.ResponseWriter, _ *http.Request) { |
| 226 | + w.WriteHeader(http.StatusNotFound) |
| 227 | +} |
| 228 | + |
182 | 229 | func (s *Server) handleRender(w http.ResponseWriter, r *http.Request) { |
183 | 230 | start := time.Now() |
184 | 231 |
|
|
0 commit comments