<commit_before>(ns puppetlabs.services.legacy-routes.legacy-routes-core
  (:require [clojure.string :as str]
            [clojure.tools.logging :as log]
            [puppetlabs.comidi :as comidi]
            [ring.util.codec :as ring-codec]
            [ring.util.response :as ring-response]
            [compojure.route :as route]
            [clojure.tools.logging :as log]
            [clojure.string :as string]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; v3 => v4 header translation support functions

; TODO: Improve the naive parsing here with a real library like
; https://github.com/ToBeReplaced/http-accept-headers
(defn- map-accept-header
  "Convert Accept: raw, s media types to Accept: binary.  NOTE: This method does
  not conform to RFC-2616 Accept: header specification.

  The split on `,` is naive, the method should take into account `;` parameters
  and such to be RFC compliant, but puppet agent does not use this format so
  implementing the full spec is unnecessary."
  [request]
  (if-let [accept (get-in request [:headers "accept"])]
    (let [vals (map str/lower-case (str/split accept #"\s*,\s*"))]
      (assoc-in request [:headers "accept"]
        (->> vals
          (replace {"raw" "binary", "s" "binary"})
          (distinct)
          (str/join ", "))))
    request))

(defn- respond-with-content-type-text-plain
  "Return a new ring handler with a ring middleware wrapped around `handler`
  that unconditionally adds the Content-Type: text/plain header to the
  response."
  [handler]
  (fn [request]
    (ring-response/content-type (handler request) "text/plain")))

(defn- add-query-param
  "Given a query string, add the given key and value to it. If the given
  query string is empty or nil then the resulting string will be the single
  KEY=VALUE expression."
  [query-str key value]
  {:pre [(or (string? query-str) (nil? query-str))
         (or (string? key) (keyword? key))
         (string? value)]
   :post [(string? %)]}
  (let [param-pairs (if (str/blank? query-str)
                      {}
                      (ring-codec/form-decode query-str))]
    (ring-codec/form-encode (assoc param-pairs key value))))

(defn- add-source-permissions-param
  "Add the source_permissions header to the request. This is needed since
  this was considered a default in Puppet 3.x and is now turned off by default
  in Puppet 4.x. See SERVER-684."
  [handler]
  (fn [request]
    (let [{:keys [query-string]} request
          updated-request (assoc request :query-string
                            (add-query-param
                              query-string :source_permissions "use"))]
      (handler updated-request))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Handler wrapper

(defn request-compatibility-wrapper
  "Given a Puppet 3.x request, convert it to a Puppet 4.x request."
  [handler mount-point api-version request]
  (let [{{environment :environment} :params
         uri :uri
         query-string               :query-string} request
        path-info (str "/" (-> (string/split uri #"/" 3) (nth 2)))]
    (let [compat-request
          (-> request
              (map-accept-header)
              (assoc :path-info    (str "/" api-version path-info)
                     :context      mount-point
                     :uri          (str mount-point "/" api-version path-info)
                     :query-string (if environment
                                     (add-query-param query-string
                                       :environment environment)
                                     query-string))
              (dissoc :params :route-params))]
      (handler compat-request))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Routing

(defn v2_0-routes
  "Creates the compojure routes to handle the 3.X master's '/v2.0' routes."
  [request-handler]
  (comidi/routes
    (comidi/GET "/environments" request<commit_msg>(MAINT) Fixed whitespace<commit_after>(ns puppetlabs.services.legacy-routes.legacy-routes-core
  (:require [clojure.string :as str]
            [clojure.tools.logging :as log]
            [puppetlabs.comidi :as comidi]
            [ring.util.codec :as ring-codec]
            [ring.util.response :as ring-response]
            [compojure.route :as route]
            [clojure.tools.logging :as log]
            [clojure.string :as string]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; v3 => v4 header translation support functions

; TODO: Improve the naive parsing here with a real library like
; https://github.com/ToBeReplaced/http-accept-headers
(defn- map-accept-header
  "Convert Accept: raw, s media types to Accept: binary.  NOTE: This method does
  not conform to RFC-2616 Accept: header specification.

  The split on `,` is naive, the method should take into account `;` parameters
  and such to be RFC compliant, but puppet agent does not use this format so
  implementing the full spec is unnecessary."
  [request]
  (if-let [accept (get-in request [:headers "accept"])]
    (let [vals (map str/lower-case (str/split accept #"\s*,\s*"))]
      (assoc-in request [:headers "accept"]
        (->> vals
          (replace {"raw" "binary", "s" "binary"})
          (distinct)
          (str/join ", "))))
    request))

(defn- respond-with-content-type-text-plain
  "Return a new ring handler with a ring middleware wrapped around `handler`
  that unconditionally adds the Content-Type: text/plain header to the
  response."
  [handler]
  (fn [request]
    (ring-response/content-type (handler request) "text/plain")))

(defn- add-query-param
  "Given a query string, add the given key and value to it. If the given
  query string is empty or nil then the resulting string will be the single
  KEY=VALUE expression."
  [query-str key value]
  {:pre [(or (string? query-str) (nil? query-str))
         (or (string? key) (keyword? key))
         (string? value)]
   :post [(string? %)]}
  (let [param-pairs (if (str/blank? query-str)
                      {}
                      (ring-codec/form-decode query-str))]
    (ring-codec/form-encode (assoc param-pairs key value))))

(defn- add-source-permissions-param
  "Add the source_permissions header to the request. This is needed since
  this was considered a default in Puppet 3.x and is now turned off by default
  in Puppet 4.x. See SERVER-684."
  [handler]
  (fn [request]
    (let [{:keys [query-string]} request
          updated-request (assoc request :query-string
                            (add-query-param
                              query-string :source_permissions "use"))]
      (handler updated-request))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Handler wrapper

(defn request-compatibility-wrapper
  "Given a Puppet 3.x request, convert it to a Puppet 4.x request."
  [handler mount-point api-version request]
  (let [{{environment :environment} :params
         uri :uri
         query-string :query-string} request
        path-info (str "/" (-> (string/split uri #"/" 3) (nth 2)))]
    (let [compat-request
          (-> request
              (map-accept-header)
              (assoc :path-info (str "/" api-version path-info)
                     :context mount-point
                     :uri (str mount-point "/" api-version path-info)
                     :query-string (if environment
                                     (add-query-param query-string
                                       :environment environment)
                                     query-string))
              (dissoc :params :route-params))]
      (handler compat-request))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Routing

(defn v2_0-routes
  "Creates the compojure routes to handle the 3.X master's '/v2.0' routes."
  [request-handler]
  (comidi/routes
    (comidi/GET "/environments" request
{'fraction_non_alphanumeric': 0.17041479260369816, 'fraction_numerical': 0.004997501249375313, 'mean_word_length': 2.465367965367965, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6720056', 'n_tokens_mistral': 2511, 'n_tokens_neox': 2317, 'n_words': 711}