Skip to content

Commit e57cf76

Browse files
committed
Merge branch 'master' of github.com:ztellman/aleph
2 parents 503a015 + 687cc84 commit e57cf76

File tree

13 files changed

+301
-182
lines changed

13 files changed

+301
-182
lines changed

examples/project.clj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
(defproject aleph.examples "0.4.2-alpha1"
2-
:dependencies [[aleph "0.4.2-alpha1"]
3-
[gloss "0.2.5"]
4-
[compojure "1.3.3"]
5-
[org.clojure/clojure "1.8.0"]
6-
[org.clojure/core.async "0.1.346.0-17112a-alpha"]]
1+
(defproject aleph.examples "0.4.6"
2+
:dependencies [[aleph "0.4.6"]
3+
[gloss "0.2.6"]
4+
[compojure "1.6.1"]
5+
[org.clojure/clojure "1.9.0"]
6+
[org.clojure/core.async "0.4.474"]]
77
:plugins [[lein-marginalia "0.9.0"]])

src/aleph/http.clj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
| `name-resolver` | specify the mechanism to resolve the address of the unresolved named address. When not set or equals to `:default`, JDK's built-in domain name lookup mechanism is used (blocking). Set to`:noop` not to resolve addresses or pass an instance of `io.netty.resolver.AddressResolverGroup` you need. Note, that if the appropriate connection-pool is created with dns-options shared DNS resolver would be used
118118
| `proxy-options` | a map to specify proxy settings. HTTP, SOCKS4 and SOCKS5 proxies are supported. Note, that when using proxy `connections-per-host` configuration is still applied to the target host disregarding tunneling settings. If you need to limit number of connections to the proxy itself use `total-connections` setting.
119119
| `response-executor` | optional `java.util.concurrent.Executor` that will execute response callbacks
120+
| `log-activity` | when set, logs all events on each channel (connection) with a log level given. Accepts either one of `:trace`, `:debug`, `:info`, `:warn`, `:error` or an instance of `io.netty.handler.logging.LogLevel`. Note, that this setting *does not* enforce any changes to the logging configuration (default configuration is `INFO`, so you won't see any `DEBUG` or `TRACE` level messages, unless configured explicitly)
120121
121122
Supported `proxy-options` are
122123
@@ -235,7 +236,8 @@
235236
| `pool-timeout` | timeout in milliseconds for the pool to generate a connection
236237
| `connection-timeout` | timeout in milliseconds for the connection to become established
237238
| `request-timeout` | timeout in milliseconds for the arrival of a response over the established connection
238-
| `read-timeout` | timeout in milliseconds for the response to be completed"
239+
| `read-timeout` | timeout in milliseconds for the response to be completed
240+
| `follow-redirects?` | whether to follow redirects, defaults to `true`; see `aleph.http.client-middleware/handle-redirects`"
239241
[{:keys [pool
240242
middleware
241243
pool-timeout
@@ -247,8 +249,7 @@
247249
:or {pool default-connection-pool
248250
response-executor default-response-executor
249251
middleware identity
250-
connection-timeout 6e4 ;; 60 seconds
251-
follow-redirects? true}
252+
connection-timeout 6e4} ;; 60 seconds
252253
:as req}]
253254

254255
(executor/with-executor response-executor

src/aleph/http/client.clj

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@
2424
HttpRequest
2525
HttpResponse
2626
HttpContent
27+
HttpUtil
28+
HttpHeaderNames
2729
LastHttpContent
2830
FullHttpResponse
2931
HttpObjectAggregator]
3032
[io.netty.channel
3133
Channel
3234
ChannelHandler ChannelHandlerContext
3335
ChannelPipeline]
36+
[io.netty.handler.stream ChunkedWriteHandler]
37+
[io.netty.handler.codec.http FullHttpRequest]
3438
[io.netty.handler.codec.http.websocketx
3539
CloseWebSocketFrame
3640
PingWebSocketFrame
@@ -51,6 +55,9 @@
5155
HttpProxyHandler
5256
Socks4ProxyHandler
5357
Socks5ProxyHandler]
58+
[io.netty.handler.logging
59+
LoggingHandler
60+
LogLevel]
5461
[java.util.concurrent.atomic
5562
AtomicInteger]
5663
[aleph.utils
@@ -171,7 +178,7 @@
171178

172179
(instance? HttpResponse msg)
173180
(let [rsp msg]
174-
(if (HttpHeaders/isTransferEncodingChunked rsp)
181+
(if (HttpUtil/isTransferEncodingChunked rsp)
175182
(let [s (netty/buffered-source (netty/channel ctx) #(alength ^bytes %) buffer-capacity)
176183
c (d/deferred)]
177184
(reset! stream s)
@@ -262,7 +269,7 @@
262269
;; * `curl` uses separate option `--proxytunnel` flag to switch tunneling on
263270
;; * `curl` uses CONNECT when sending request to HTTPS destination through HTTP proxy
264271
;;
265-
;; Explicitily setting `tunnel?` to false when it's expected to use CONNECT
272+
;; Explicitly setting `tunnel?` to false when it's expected to use CONNECT
266273
;; throws `IllegalArgumentException` to reduce the confusion
267274
(defn http-proxy-handler
268275
[^InetSocketAddress address
@@ -343,6 +350,21 @@
343350
(.remove (.pipeline ctx) this))
344351
(.fireUserEventTriggered ^ChannelHandlerContext ctx evt))))
345352

353+
(defn coerce-log-level [level]
354+
(if (instance? LogLevel level)
355+
level
356+
(let [netty-level (case level
357+
:trace LogLevel/TRACE
358+
:debug LogLevel/DEBUG
359+
:info LogLevel/INFO
360+
:warn LogLevel/WARN
361+
:error LogLevel/ERROR
362+
nil)]
363+
(when (nil? netty-level)
364+
(throw (IllegalArgumentException.
365+
(str "unknown log level given: " level))))
366+
netty-level)))
367+
346368
(defn pipeline-builder
347369
[response-stream
348370
{:keys
@@ -354,7 +376,8 @@
354376
raw-stream?
355377
proxy-options
356378
ssl?
357-
idle-timeout]
379+
idle-timeout
380+
log-activity]
358381
:or
359382
{pipeline-transform identity
360383
response-buffer-size 65536
@@ -365,7 +388,11 @@
365388
(fn [^ChannelPipeline pipeline]
366389
(let [handler (if raw-stream?
367390
(raw-client-handler response-stream response-buffer-size)
368-
(client-handler response-stream response-buffer-size))]
391+
(client-handler response-stream response-buffer-size))
392+
logger (when (some? log-activity)
393+
(LoggingHandler.
394+
"aleph-client"
395+
^LogLevel (coerce-log-level log-activity)))]
369396
(doto pipeline
370397
(.addLast "http-client"
371398
(HttpClientCodec.
@@ -374,6 +401,7 @@
374401
max-chunk-size
375402
false
376403
false))
404+
(.addLast "streamer" ^ChannelHandler (ChunkedWriteHandler.))
377405
(.addLast "handler" ^ChannelHandler handler)
378406
(http/attach-idle-handlers idle-timeout))
379407
(when (some? proxy-options)
@@ -388,6 +416,8 @@
388416
"pending-proxy-connection"
389417
^ChannelHandler
390418
(pending-proxy-connection-handler response-stream)))))
419+
(when (some? logger)
420+
(.addFirst pipeline "activity-logger" logger))
391421
(pipeline-transform pipeline))))
392422

393423
(defn close-connection [f]
@@ -448,20 +478,43 @@
448478
(assoc req :uri (:request-url req))
449479
req))]
450480
(when-not (.get (.headers req') "Host")
451-
(HttpHeaders/setHost req' (str host (when explicit-port? (str ":" port)))))
481+
(.set (.headers req') HttpHeaderNames/HOST (str host (when explicit-port? (str ":" port)))))
452482
(when-not (.get (.headers req') "Connection")
453-
(HttpHeaders/setKeepAlive req' keep-alive?))
483+
(HttpUtil/setKeepAlive req' keep-alive?))
454484
(when (and (non-tunnel-proxy? proxy-options')
455485
(get proxy-options :keep-alive? true)
456486
(not (.get (.headers req') "Proxy-Connection")))
457487
(.set (.headers req') "Proxy-Connection" "Keep-Alive"))
458488

459-
(let [body (if-let [parts (get req :multipart)]
460-
(let [boundary (multipart/boundary)
461-
content-type (str "multipart/form-data; boundary=" boundary)]
462-
(HttpHeaders/setHeader req' "Content-Type" content-type)
463-
(multipart/encode-body boundary parts))
464-
(get req :body))]
489+
(let [body (:body req)
490+
parts (:multipart req)
491+
multipart? (some? parts)
492+
[req' body] (cond
493+
;; RFC #7231 4.3.8. TRACE
494+
;; A client MUST NOT send a message body...
495+
(= :trace (:request-method req))
496+
(do
497+
(when (or (some? body) multipart?)
498+
(log/warn "TRACE request body was omitted"))
499+
[req' nil])
500+
501+
(not multipart?)
502+
[req' body]
503+
504+
:else
505+
(multipart/encode-request req' parts))]
506+
507+
(when-let [save-message (get req :aleph/save-request-message)]
508+
;; debug purpose only
509+
;; note, that req' is effectively mutable, so
510+
;; it will "capture" all changes made during "send-message"
511+
;; execution
512+
(reset! save-message req'))
513+
514+
(when-let [save-body (get req :aleph/save-request-body)]
515+
;; might be different in case we use :multipart
516+
(reset! save-body body))
517+
465518
(netty/safe-execute ch
466519
(http/send-message ch true ssl? req' body))))
467520

@@ -584,14 +637,14 @@
584637
#(when (.isOpen ch)
585638
(d/chain'
586639
(netty/wrap-future (.close handshaker ch (CloseWebSocketFrame.)))
587-
(fn [_] (netty/close ch))))))))
640+
(fn [_] (netty/close ctx))))))))
588641

589642
(instance? FullHttpResponse msg)
590643
(let [rsp ^FullHttpResponse msg]
591644
(throw
592645
(IllegalStateException.
593646
(str "unexpected HTTP response, status: "
594-
(.getStatus rsp)
647+
(.status rsp)
595648
", body: '"
596649
(bs/to-string (.content rsp))
597650
"'"))))

src/aleph/http/client_middleware.clj

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
(:refer-clojure :exclude [update])
55
(:require
66
[potemkin :as p]
7-
[clojure.stacktrace :refer [root-cause]]
87
[clojure.string :as str]
98
[clojure.walk :refer [prewalk]]
109
[manifold.deferred :as d]
@@ -666,7 +665,7 @@
666665
:else (>= (System/currentTimeMillis) (+ created max-age))))
667666

668667
(defprotocol CookieSpec
669-
"Implement rules for accepting and returing cookies"
668+
"Implement rules for accepting and returning cookies"
670669
(parse-cookie [this cookie-str])
671670
(write-cookies [this cookies])
672671
(match-cookie-origin? [this origin cookie]))
@@ -733,7 +732,9 @@
733732
([header]
734733
(decode-set-cookie-header default-cookie-spec header))
735734
([cookie-spec header]
736-
(netty-cookie->cookie (parse-cookie cookie-spec header))))
735+
(some->> header
736+
(parse-cookie cookie-spec)
737+
(netty-cookie->cookie))))
737738

738739
;; we might want to use here http/get-all helper,
739740
;; but it would result in circular dependencies
@@ -784,7 +785,7 @@
784785
(write-cookie-header cookies cookie-spec req)))
785786

786787
(defn wrap-cookies
787-
"Middleware that set 'Cookie' header based on the contentn of cookies passed
788+
"Middleware that set 'Cookie' header based on the content of cookies passed
788789
with the request or from cookies storage (when provided). Source for 'Cookie'
789790
header content by priorities:
790791
@@ -904,6 +905,34 @@
904905
(defmethod coerce-response-body :default [_ resp]
905906
resp)
906907

908+
(defn wrap-request-debug [req]
909+
(cond-> req
910+
(opt req :save-request)
911+
(assoc :aleph/save-request-message (atom nil))
912+
913+
(opt req :debug-body)
914+
(assoc :aleph/save-request-body (atom nil))))
915+
916+
(defn handle-response-debug [req rsp]
917+
(let [saved-message (get req :aleph/save-request-message)
918+
saved-body (get req :aleph/save-request-body)
919+
req' (dissoc req
920+
:aleph/save-request-body
921+
:aleph/save-request-message
922+
:save-request
923+
:save-request?
924+
:debug-body
925+
:debug-body?)]
926+
(cond-> rsp
927+
(some? saved-message)
928+
(assoc :aleph/netty-request @saved-message)
929+
930+
(some? saved-body)
931+
(assoc :aleph/request-body @saved-body)
932+
933+
(opt req :save-request)
934+
(assoc :aleph/request req'))))
935+
907936
(def default-middleware
908937
[wrap-method
909938
wrap-url
@@ -916,7 +945,8 @@
916945
wrap-accept
917946
wrap-accept-encoding
918947
wrap-content-type
919-
wrap-cookies])
948+
wrap-cookies
949+
wrap-request-debug])
920950

921951
(defn wrap-request
922952
"Returns a batteries-included HTTP request function corresponding to the given
@@ -936,7 +966,8 @@
936966

937967
;; coerce the response body
938968
(fn [{:keys [body] :as rsp}]
939-
(if body
940-
(d/future-with (or executor (ex/wait-pool))
941-
(coerce-response-body req' rsp))
942-
rsp)))))))))
969+
(let [rsp' (handle-response-debug req' rsp)]
970+
(if (nil? body)
971+
rsp'
972+
(d/future-with (or executor (ex/wait-pool))
973+
(coerce-response-body req' rsp'))))))))))))

0 commit comments

Comments
 (0)