From d1d41d6587cd4d21b56fa12a87308f60f1b89cf1 Mon Sep 17 00:00:00 2001 From: Ngoc Khuat <qn.khuat@gmail.com> Date: Mon, 16 Jan 2023 21:50:08 +0700 Subject: [PATCH] Fix returns 500 when exception is thrown from handle-page middleware (#27526) * fix throwing exceptions in handle-paging mw --- src/metabase/server/handler.clj | 5 +- .../server/middleware/offset_paging_test.clj | 74 +++++++++++-------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/metabase/server/handler.clj b/src/metabase/server/handler.clj index f0605aca6a7..f03c0ffbf1f 100644 --- a/src/metabase/server/handler.clj +++ b/src/metabase/server/handler.clj @@ -50,8 +50,8 @@ #'mw.browser-cookie/ensure-browser-id-cookie ; add cookie to identify browser; add `:browser-id` to the request #'mw.security/add-security-headers ; Add HTTP headers to API responses to prevent them from being cached #'mw.json/wrap-json-body ; extracts json POST body and makes it avaliable on request - #'mw.json/wrap-streamed-json-response ; middleware to automatically serialize suitable objects as JSON in responses #'mw.offset-paging/handle-paging ; binds per-request parameters to handle paging + #'mw.json/wrap-streamed-json-response ; middleware to automatically serialize suitable objects as JSON in responses #'wrap-keyword-params ; converts string keys in :params to keyword keys #'wrap-params ; parses GET and POST params as :query-params/:form-params and both as :params #'mw.misc/maybe-set-site-url ; set the value of `site-url` if it hasn't been set yet @@ -68,7 +68,8 @@ #'mw.ssl/redirect-to-https-middleware]) ;; ▲▲▲ PRE-PROCESSING ▲▲▲ happens from BOTTOM-TO-TOP -(defn- apply-middleware [handler] +(defn- apply-middleware + [handler] (reduce (fn [handler middleware-fn] (middleware-fn handler)) diff --git a/test/metabase/server/middleware/offset_paging_test.clj b/test/metabase/server/middleware/offset_paging_test.clj index 44b38d87bc2..81d9804694b 100644 --- a/test/metabase/server/middleware/offset_paging_test.clj +++ b/test/metabase/server/middleware/offset_paging_test.clj @@ -1,45 +1,55 @@ (ns metabase.server.middleware.offset-paging-test (:require + [cheshire.core :as json] + [clojure.java.io :as io] [clojure.test :refer :all] + [metabase.server.handler :as handler] [metabase.server.middleware.offset-paging :as mw.offset-paging] - [ring.middleware.keyword-params :refer [wrap-keyword-params]] - [ring.middleware.params :refer [wrap-params]] + [metabase.server.middleware.security :as mw.security] [ring.mock.request :as ring.mock] - [ring.util.response :as response] - [schema.core :as s])) + [ring.util.response :as response]) + (:import + (java.io PipedInputStream))) (defn- handler [request] - (let [handler* (-> (fn [request respond _] - (respond (response/response {:limit mw.offset-paging/*limit* - :offset mw.offset-paging/*offset* - :paged? mw.offset-paging/*paged?* - :params (:params request)}))) - mw.offset-paging/handle-paging - wrap-keyword-params - wrap-params) - respond identity - raise (fn [e] (throw e))] + (let [handler (fn [request respond _] + (respond (response/response {:limit mw.offset-paging/*limit* + :offset mw.offset-paging/*offset* + :paged? mw.offset-paging/*paged?* + :params (:params request)}))) + handler* (#'handler/apply-middleware handler) + respond identity + raise (fn [e] (throw e))] (handler* request respond raise))) +(defn- read-response + "Responses from our hanlders are inputstream, this is read the stream into real body." + [response] + (update response :body + (fn [body] + (if (instance? PipedInputStream body) + (with-open [r (io/reader body)] + (json/parse-stream r)) + body)))) + (deftest paging-test (testing "no paging params" - (is (= {:status 200 - :headers {} - :body {:limit nil - :offset nil - :paged? false - :params {}}} - (handler (ring.mock/request :get "/"))))) + (is (=? {:status 200 + :body {"limit" nil + "offset" nil + "paged?" false + "params" {}}} + (read-response (handler (ring.mock/request :get "/")))))) (testing "w/ paging params" - (is (= {:status 200 - :headers {} - :body {:limit 100 - :offset 200 - :paged? true - :params {:whatever "true"}}} - (handler (ring.mock/request :get "/" {:offset "200", :limit "100", :whatever "true"}))))) + (is (=? {:status 200 + :body {"limit" 100 + "offset" 200 + "paged?" true + "params" {"whatever" "true"}}} + (read-response (handler (ring.mock/request :get "/" {:offset "200", :limit "100", :whatever "true"})))))) + (testing "invalid params" - (is (schema= {:status (s/eq 400) - :headers s/Any - :body {:message #"Error parsing paging parameters.*" s/Keyword s/Any}} - (handler (ring.mock/request :get "/" {:offset "abc", :limit "100"})))))) + (is (=? {:status 400 + :headers (mw.security/security-headers) + :body {"message" #"Error parsing paging parameters.*"}} + (read-response (handler (ring.mock/request :get "/" {:offset "abc", :limit "100"}))))))) -- GitLab