package handlers import ( "encoding/json" "net/http" "opds-explorer/internal/proxy" ) type Handler struct { proxy proxyClient } type proxyClient interface { Fetch(method, targetURL string, headers http.Header, body []byte) (*proxy.FetchResult, error) } func New(p proxyClient) *Handler { return &Handler{proxy: p} } // FetchFeed handles GET/POST /api/fetch?url=... or JSON body { "url": "...", "method": "GET", "headers": {}, "body": "" } func (h *Handler) FetchFeed(w http.ResponseWriter, r *http.Request) { var method, targetURL string var headers http.Header var body []byte if r.Method == http.MethodPost { var req struct { URL string `json:"url"` Method string `json:"method"` Headers map[string]string `json:"headers"` Body string `json:"body"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "invalid JSON body", http.StatusBadRequest) return } targetURL = req.URL method = req.Method if method == "" { method = "GET" } headers = make(http.Header) for k, v := range req.Headers { headers.Set(k, v) } body = []byte(req.Body) } else { targetURL = r.URL.Query().Get("url") method = r.Method } if targetURL == "" { http.Error(w, "missing url", http.StatusBadRequest) return } result, err := h.proxy.Fetch(method, targetURL, headers, body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(result) } // ProxyResource streams a GET request to the given url (e.g. for images). Requires proxyClientStream interface. func (h *Handler) ProxyResource(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } targetURL := r.URL.Query().Get("url") if targetURL == "" { http.Error(w, "missing url", http.StatusBadRequest) return } streamer, ok := h.proxy.(interface { ProxyStream(string, http.ResponseWriter) (int, error) }) if !ok { http.Error(w, "proxy does not support streaming", http.StatusInternalServerError) return } _, err := streamer.ProxyStream(targetURL, w) if err != nil { http.Error(w, err.Error(), http.StatusBadGateway) } }