Skip to content

Instantly share code, notes, and snippets.

@coxchen
Last active July 12, 2016 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save coxchen/1c760d78ffb4d7654050918acb255582 to your computer and use it in GitHub Desktop.
Save coxchen/1c760d78ffb4d7654050918acb255582 to your computer and use it in GitHub Desktop.
(defmacro collect-all [collections]
(into [] (concat ['ALL] (for [c collections]
(if (and (sequential? c) (keyword? (first c)))
`(~'collect-one ~@c)
`(~'collect-one ~c))))))
(defn process-har [requests & {:keys [view-with selection] :or {view-with count selection [ALL]}}]
(->> (select-one [:log :entries] requests)
(select [ALL (selected? :request :url sz-api?)])
(transform [ALL :request :url] sz-api!)
(select selection)
(select (collect-all [:startedDateTime :time [:request :method] [:request :url] [:request :postData :text] [:response :status] :timings]))
(transform [ALL] drop-last)
(select (collect-all [(srange 0 2) (srange 2 5) (srange 5 7)]))
(transform [ALL] drop-last)
(transform [ALL (srange 0 1) FIRST] long-time?)
(transform [ALL (srange 2 3) FIRST] error-status?!)
(transform [ALL ALL] (comp html-view (partial clojure.string/join "\n")))
(view-with)))
(defn entry-> [paths]
(fn [entry]
((apply juxt (mapv (fn [path] #(get-in % (flatten (conj [] path)))) paths)) entry)))
(defn process-har [requests & {:keys [view-with filter-with] :or {view-with count filter-with identity}}]
(->> (get-in requests [:log :entries])
(filter (comp sz-api? first (entry-> [[:request :url]])))
(mapv #(update-in % [:request :url] sz-api!))
(filter filter-with)
(mapv (entry-> [:startedDateTime :time [:request :method] [:request :url] [:request :postData :text] [:response :status] :timings]))
(mapv (fn [entry] (-> []
(conj (->> entry (take 2) long-time? (clojure.string/join "\n") (html-view)))
(conj (->> entry (drop 2) (take 3) (clojure.string/join "\n") (html-view)))
(conj (->> entry (drop 5) error-status?! (clojure.string/join "\n") (html-view))))))
(view-with)))
#_(defmacro collect-all [& collections]
(->> (for [c collections]
(if (and (sequential? c) (keyword? (first c)))
`(~'collect-one ~@c)
`(~'collect-one ~c)))
(concat ['ALL])
(into [])))
(defmacro collect-all [& collections]
(loop [collect-ones ['ALL ] c (first collections) remaining (rest collections)]
(if (not c)
collect-ones
(let [target (if (and (sequential? c) (keyword? (first c)))
`(~'collect-one ~@c)
`(~'collect-one ~c))]
(recur (conj collect-ones target) (first remaining) (rest remaining))))))
; (macroexpand '(collect-all :startedDateTime :time [:request :method] [:request :url] [:request :postData :text] [:response :status] :timings))
; => [ALL (collect-one :startedDateTime) (collect-one :time) (collect-one :request :method) (collect-one :request :url) (collect-one :request :postData :text) (collect-one :response :status) (collect-one :timings)]
; (macroexpand '(collect-all (srange 0 2) (srange 2 5) (srange 5 7)))
; => [ALL (collect-one (srange 0 2)) (collect-one (srange 2 5)) (collect-one (srange 5 7))]
(= (macroexpand '(collect-all :startedDateTime :time [:request :method] [:request :url] [:request :postData :text] [:response :status] :timings))
'[ALL
(collect-one :startedDateTime)
(collect-one :time)
(collect-one :request :method)
(collect-one :request :url)
(collect-one :request :postData :text)
(collect-one :response :status)
(collect-one :timings)])
(defmacro functionize [macro]
`(fn [& args#] (eval (cons '~macro args#))))
(defmacro apply-macro [macro args]
`(apply (functionize ~macro) ~args))
(defn morph [shape structure]
(if (not (empty? shape))
(transform (apply-macro collect-all (vals shape))
(fn [ & all] (zipmap (vec (keys shape)) (drop-last all)))
structure)
structure))
(def sample
'({:startedDateTime "2016-06-29T03:58:45.467Z", :time 13.220071792602539, :request {:method "GET", :url "https://172.17.37.160:8443/wsg/index.jsp", :httpVersion "HTTP/1.1", :headers [{:name "Accept-Encoding", :value "gzip, deflate, sdch"} {:name "Host", :value "172.17.37.160:8443"} {:name "Accept-Language", :value "en-US,en;q=0.8"} {:name "User-Agent", :value "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"} {:name "Accept", :value "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"} {:name "Referer", :value "https://172.17.37.160:8443/wsg/login.jsp?_t=1467172724407"} {:name "Cookie", :value "JSESSIONID=EEC640432D585F45FF6FC32DCB15DD25"} {:name "Connection", :value "keep-alive"}], :queryString [], :cookies [{:name "JSESSIONID", :value "EEC640432D585F45FF6FC32DCB15DD25", :expires nil, :httpOnly false, :secure false}], :headersSize 475, :bodySize 0}, :response {:bodySize 2608, :content {:size 6376, :mimeType "text/html", :compression 3768}, :cookies [], :httpVersion "HTTP/1.1", :headers [{:name "Pragma", :value "no-cache"} {:name "Strict-Transport-Security", :value "max-age=31536000 ; includeSubDomains"} {:name "Content-Encoding", :value "gzip"} {:name "X-Content-Type-Options", :value "nosniff"} {:name "Server", :value "Apache-Coyote/1.1"} {:name "Date", :value "Wed, 29 Jun 2016 03:59:23 GMT"} {:name "X-Frame-Options", :value "SAMEORIGIN"} {:name "Content-Type", :value "text/html;charset=UTF-8"} {:name "Cache-Control", :value "no-cache, no-store, max-age=0, must-revalidate"} {:name "Transfer-Encoding", :value "chunked"} {:name "Vary", :value "Accept-Encoding"} {:name "X-XSS-Protection", :value "1; mode=block"} {:name "Expires", :value "0"}], :status 200, :redirectURL "", :statusText "OK", :headersSize 450}, :cache {}, :timings {:blocked 0.68599998485297, :dns -1, :connect -1, :send 0.48599997535347994, :wait 11.535000056028348, :receive 0.5130717763677399, :ssl -1}, :connection "295508", :pageref "page_1"} {:startedDateTime "2016-06-29T03:58:45.516Z", :time 0, :request {:method "GET", :url "https://172.17.37.160:8443/wsg/styles/font-awesome-4.6.3/css/font-awesome.min.css?v=3.5.0.0.852", :httpVersion "unknown", :headers [{:name "User-Agent", :value "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36"}], :queryString [{:name "v", :value "3.5.0.0.852"}], :cookies [], :headersSize -1, :bodySize 0}, :response {:bodySize 0, :content {:size 29063, :mimeType "text/css"}, :cookies [], :httpVersion "unknown", :headers [{:name "Date", :value "Wed, 29 Jun 2016 03:58:44 GMT"} {:name "Content-Encoding", :value "gzip"} {:name "Vary", :value "Accept-Encoding"} {:name "Last-Modified", :value "Wed, 22 Jun 2016 17:29:41 GMT"} {:name "Server", :value "Apache-Coyote/1.1"} {:name "ETag", :value "W/\"29063-1466616581000\""} {:name "Transfer-Encoding", :value "chunked"} {:name "Content-Type", :value "text/css"} {:name "Accept-Ranges", :value "bytes"}], :status 200, :redirectURL "", :statusText "OK", :headersSize -1}, :cache {}, :timings {:blocked -1, :dns -1, :connect -1, :send 0, :wait 0, :receive 0, :ssl -1}, :connection "295128", :pageref "page_1"}))
(morph
{:startTime :startedDateTime
:elapsed :time
:req-method [:request :method]
:req-url [:request :url]
:post-data [:request :postData :text]
:resp-status [:response :status]
:timings :timings}
sample)
; => ({:startTime "2016-06-29T03:58:45.467Z", :elapsed 13.220071792602539, :req-method "GET", :req-url "https://172.17.37.160:8443/wsg/index.jsp", :post-data nil, :resp-status 200, :timings {:blocked 0.68599998485297, :dns -1, :connect -1, :send 0.48599997535347994, :wait 11.535000056028348, :receive 0.5130717763677399, :ssl -1}} {:startTime "2016-06-29T03:58:45.516Z", :elapsed 0, :req-method "GET", :req-url "https://172.17.37.160:8443/wsg/styles/font-awesome-4.6.3/css/font-awesome.min.css?v=3.5.0.0.852", :post-data nil, :resp-status 200, :timings {:blocked -1, :dns -1, :connect -1, :send 0, :wait 0, :receive 0, :ssl -1}})
@coxchen
Copy link
Author

coxchen commented Jul 7, 2016

scg-52183-duplicate-requests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment