package http import ( "bytes" "encoding/json" "io" "mime" "net/http" "time" ) const maxUpdateResultBody = 8 << 20 type resultHTTPClient interface { Do(*http.Request) (*http.Response, error) } type updateResultForwarder struct { targetURL string client resultHTTPClient } // NewUpdateResultForwarder relays the original JSON body to CPONE without // forwarding the caller's Authorization header or cookies. func NewUpdateResultForwarder(targetURL string, client resultHTTPClient) http.Handler { if client == nil { client = &http.Client{Timeout: 30 * time.Second} } return updateResultForwarder{ targetURL: targetURL, client: client, } } func (h updateResultForwarder) ServeHTTP(w http.ResponseWriter, r *http.Request) { mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil || mediaType != "application/json" { WriteJSON(w, http.StatusUnsupportedMediaType, Response{Success: false, Message: "Content-Type harus application/json"}) return } body, err := io.ReadAll(io.LimitReader(r.Body, maxUpdateResultBody+1)) if err != nil { WriteJSON(w, http.StatusBadRequest, Response{Success: false, Message: "Gagal membaca payload hasil pemeriksaan"}) return } if len(body) > maxUpdateResultBody { WriteJSON(w, http.StatusRequestEntityTooLarge, Response{Success: false, Message: "Payload hasil pemeriksaan terlalu besar"}) return } var payload map[string]json.RawMessage if err := json.Unmarshal(body, &payload); err != nil || payload == nil { WriteJSON(w, http.StatusBadRequest, Response{Success: false, Message: "Payload harus berupa object JSON"}) return } upstreamRequest, err := http.NewRequestWithContext(r.Context(), http.MethodPost, h.targetURL, bytes.NewReader(body)) if err != nil { WriteJSON(w, http.StatusBadGateway, Response{Success: false, Message: "URL tujuan CPONE tidak valid"}) return } upstreamRequest.Header.Set("Content-Type", "application/json") upstreamRequest.Header.Set("Accept", "application/json") upstreamResponse, err := h.client.Do(upstreamRequest) if err != nil { WriteJSON(w, http.StatusBadGateway, Response{Success: false, Message: "Gagal menghubungi API hasil pemeriksaan CPONE"}) return } defer upstreamResponse.Body.Close() if contentType := upstreamResponse.Header.Get("Content-Type"); contentType != "" { w.Header().Set("Content-Type", contentType) } w.WriteHeader(upstreamResponse.StatusCode) _, _ = io.Copy(w, upstreamResponse.Body) }