opds-explorer/internal/handlers/fetch.go
Vibe Kanban d41f6859f4 OPDS-PS Explorer (vibe-kanban 1dc76aea)
Create a server (go) and webapp (vue) development tool to explore OPDS-PS capable servers. This tool is intended for development purposes only, it should allow to navigate the server, view raw requests and responses and interact with the API in a general way. I think it's best if we provide a columns layout to navigate the OPDS-PS server much like the macos finder does, with a panel with details to the far right for technical information.

Here's the SPEC: https://specs.opds.io/
2026-02-11 09:36:23 +01:00

91 lines
2.3 KiB
Go

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)
}
}