|
821 | 821 | :local-address local-address
|
822 | 822 | :transport (netty/determine-transport transport epoll?)
|
823 | 823 | :name-resolver name-resolver
|
824 |
| - :connect-timeout connect-timeout})] |
825 |
| - |
826 |
| - (attach-on-close-handler ch-d on-closed) |
827 |
| - |
828 |
| - (d/chain' ch-d |
829 |
| - (fn setup-client |
830 |
| - [^Channel ch] |
831 |
| - (log/debug "Channel:" ch) |
832 |
| - |
833 |
| - ;; We know the SSL handshake must be complete because create-client wraps the |
834 |
| - ;; future with maybe-ssl-handshake-future, so we can get the negotiated |
835 |
| - ;; protocol, falling back to HTTP/1.1 by default. |
836 |
| - (let [pipeline (.pipeline ch) |
837 |
| - protocol (cond |
838 |
| - ssl? |
839 |
| - (or (-> pipeline |
840 |
| - ^SslHandler (.get ^Class SslHandler) |
841 |
| - (.applicationProtocol)) |
842 |
| - ApplicationProtocolNames/HTTP_1_1) ; Not using ALPN, HTTP/2 isn't allowed |
843 |
| - |
844 |
| - force-h2c? |
845 |
| - (do |
846 |
| - (log/info "Forcing HTTP/2 over cleartext. Be sure to do this only with servers you control.") |
847 |
| - ApplicationProtocolNames/HTTP_2) |
848 |
| - |
849 |
| - :else |
850 |
| - ApplicationProtocolNames/HTTP_1_1) ; Not using SSL, HTTP/2 isn't allowed unless h2c requested |
851 |
| - setup-opts (assoc opts |
852 |
| - :authority authority |
853 |
| - :ch ch |
854 |
| - :server? false |
855 |
| - :keep-alive? keep-alive? |
856 |
| - :keep-alive?' keep-alive?' |
857 |
| - :logger logger |
858 |
| - :non-tun-proxy? non-tun-proxy? |
859 |
| - :pipeline pipeline |
860 |
| - :pipeline-transform pipeline-transform |
861 |
| - :raw-stream? raw-stream? |
862 |
| - :remote-address remote-address |
863 |
| - :response-buffer-size response-buffer-size |
864 |
| - :ssl-context ssl-context |
865 |
| - :ssl? ssl?)] |
866 |
| - |
867 |
| - (log/debug (str "Using HTTP protocol: " protocol) |
868 |
| - {:authority authority |
869 |
| - :ssl? ssl? |
870 |
| - :force-h2c? force-h2c?}) |
871 |
| - |
872 |
| - ;; can't use ApnHandler, because we need to coordinate with Manifold code |
873 |
| - (let [http-req-handler |
874 |
| - (cond (.equals ApplicationProtocolNames/HTTP_1_1 protocol) |
875 |
| - (setup-http1-client setup-opts) |
876 |
| - |
877 |
| - (.equals ApplicationProtocolNames/HTTP_2 protocol) |
878 |
| - (do |
879 |
| - (http2/setup-conn-pipeline setup-opts) |
880 |
| - (http2-req-handler setup-opts)) |
881 |
| - |
882 |
| - :else |
883 |
| - (do |
884 |
| - (let [msg (str "Unknown protocol: " protocol) |
885 |
| - e (IllegalStateException. msg)] |
886 |
| - (log/error e msg) |
887 |
| - (netty/close ch) |
888 |
| - (throw e))))] |
889 |
| - |
890 |
| - ;; Both Netty and Aleph are set up, unpause the pipeline |
891 |
| - (when (.get pipeline "pause-handler") |
892 |
| - (log/debug "Unpausing pipeline") |
893 |
| - (.remove pipeline "pause-handler")) |
894 |
| - |
895 |
| - (fn http-req-fn |
896 |
| - [req] |
897 |
| - (log/trace "http-req-fn fired") |
898 |
| - (log/debug "client request:" (pr-str req)) |
899 |
| - |
900 |
| - ;; If :aleph/close is set in the req, closes the channel and |
901 |
| - ;; returns a deferred containing the result. |
902 |
| - (if (or (contains? req :aleph/close) |
903 |
| - (contains? req ::close)) |
904 |
| - (-> ch (netty/close) (netty/wrap-future)) |
905 |
| - |
906 |
| - (let [t0 (System/nanoTime) |
907 |
| - ;; I suspect the below is an error for http1 |
908 |
| - ;; since the shared handler might not match. |
909 |
| - ;; Should work for HTTP2, though |
910 |
| - raw-stream? (get req :raw-stream? raw-stream?)] |
911 |
| - |
912 |
| - (if (or (not (.isActive ch)) |
913 |
| - (not (.isOpen ch))) |
914 |
| - |
915 |
| - (d/error-deferred |
916 |
| - (ex-info "Channel is inactive/closed." |
917 |
| - {:req req |
918 |
| - :ch ch |
919 |
| - :open? (.isOpen ch) |
920 |
| - :active? (.isActive ch)})) |
921 |
| - |
922 |
| - (-> (http-req-handler req) |
923 |
| - (d/chain' (rsp-handler |
924 |
| - {:ch ch |
925 |
| - :keep-alive? keep-alive? ; why not keep-alive?' |
926 |
| - :raw-stream? raw-stream? |
927 |
| - :req req |
928 |
| - :response-buffer-size response-buffer-size |
929 |
| - :t0 t0}))))))))))))) |
| 824 | + :connect-timeout connect-timeout}) |
| 825 | + |
| 826 | + _ (attach-on-close-handler ch-d on-closed) |
| 827 | + |
| 828 | + close-ch! (atom (fn [])) |
| 829 | + result (d/deferred) |
| 830 | + |
| 831 | + conn (d/chain' ch-d |
| 832 | + (fn setup-client |
| 833 | + [^Channel ch] |
| 834 | + (log/debug "Channel:" ch) |
| 835 | + (reset! close-ch! (fn [] @(-> (netty/close ch) (netty/wrap-future)))) |
| 836 | + (if (realized? result) |
| 837 | + ;; Account for race condition between setting `close-ch!` and putting |
| 838 | + ;; `result` into error state for cancellation |
| 839 | + (@close-ch!) |
| 840 | + ;; We know the SSL handshake must be complete because create-client wraps the |
| 841 | + ;; future with maybe-ssl-handshake-future, so we can get the negotiated |
| 842 | + ;; protocol, falling back to HTTP/1.1 by default. |
| 843 | + (let [pipeline (.pipeline ch) |
| 844 | + protocol (cond |
| 845 | + ssl? |
| 846 | + (or (-> pipeline |
| 847 | + ^SslHandler (.get ^Class SslHandler) |
| 848 | + (.applicationProtocol)) |
| 849 | + ApplicationProtocolNames/HTTP_1_1) ; Not using ALPN, HTTP/2 isn't allowed |
| 850 | + |
| 851 | + force-h2c? |
| 852 | + (do |
| 853 | + (log/info "Forcing HTTP/2 over cleartext. Be sure to do this only with servers you control.") |
| 854 | + ApplicationProtocolNames/HTTP_2) |
| 855 | + |
| 856 | + :else |
| 857 | + ApplicationProtocolNames/HTTP_1_1) ; Not using SSL, HTTP/2 isn't allowed unless h2c requested |
| 858 | + setup-opts (assoc opts |
| 859 | + :authority authority |
| 860 | + :ch ch |
| 861 | + :server? false |
| 862 | + :keep-alive? keep-alive? |
| 863 | + :keep-alive?' keep-alive?' |
| 864 | + :logger logger |
| 865 | + :non-tun-proxy? non-tun-proxy? |
| 866 | + :pipeline pipeline |
| 867 | + :pipeline-transform pipeline-transform |
| 868 | + :raw-stream? raw-stream? |
| 869 | + :remote-address remote-address |
| 870 | + :response-buffer-size response-buffer-size |
| 871 | + :ssl-context ssl-context |
| 872 | + :ssl? ssl?)] |
| 873 | + |
| 874 | + (log/debug (str "Using HTTP protocol: " protocol) |
| 875 | + {:authority authority |
| 876 | + :ssl? ssl? |
| 877 | + :force-h2c? force-h2c?}) |
| 878 | + |
| 879 | + ;; can't use ApnHandler, because we need to coordinate with Manifold code |
| 880 | + (let [http-req-handler |
| 881 | + (cond (.equals ApplicationProtocolNames/HTTP_1_1 protocol) |
| 882 | + (setup-http1-client setup-opts) |
| 883 | + |
| 884 | + (.equals ApplicationProtocolNames/HTTP_2 protocol) |
| 885 | + (do |
| 886 | + (http2/setup-conn-pipeline setup-opts) |
| 887 | + (http2-req-handler setup-opts)) |
| 888 | + |
| 889 | + :else |
| 890 | + (do |
| 891 | + (let [msg (str "Unknown protocol: " protocol) |
| 892 | + e (IllegalStateException. msg)] |
| 893 | + (log/error e msg) |
| 894 | + (netty/close ch) |
| 895 | + (throw e))))] |
| 896 | + |
| 897 | + ;; Both Netty and Aleph are set up, unpause the pipeline |
| 898 | + (when (.get pipeline "pause-handler") |
| 899 | + (log/debug "Unpausing pipeline") |
| 900 | + (.remove pipeline "pause-handler")) |
| 901 | + |
| 902 | + (fn http-req-fn |
| 903 | + [req] |
| 904 | + (log/trace "http-req-fn fired") |
| 905 | + (log/debug "client request:" (pr-str req)) |
| 906 | + |
| 907 | + ;; If :aleph/close is set in the req, closes the channel and |
| 908 | + ;; returns a deferred containing the result. |
| 909 | + (if (or (contains? req :aleph/close) |
| 910 | + (contains? req ::close)) |
| 911 | + (-> ch (netty/close) (netty/wrap-future)) |
| 912 | + |
| 913 | + (let [t0 (System/nanoTime) |
| 914 | + ;; I suspect the below is an error for http1 |
| 915 | + ;; since the shared handler might not match. |
| 916 | + ;; Should work for HTTP2, though |
| 917 | + raw-stream? (get req :raw-stream? raw-stream?)] |
| 918 | + |
| 919 | + (if (or (not (.isActive ch)) |
| 920 | + (not (.isOpen ch))) |
| 921 | + |
| 922 | + (d/error-deferred |
| 923 | + (ex-info "Channel is inactive/closed." |
| 924 | + {:req req |
| 925 | + :ch ch |
| 926 | + :open? (.isOpen ch) |
| 927 | + :active? (.isActive ch)})) |
| 928 | + |
| 929 | + (-> (http-req-handler req) |
| 930 | + (d/chain' (rsp-handler |
| 931 | + {:ch ch |
| 932 | + :keep-alive? keep-alive? ; why not keep-alive?' |
| 933 | + :raw-stream? raw-stream? |
| 934 | + :req req |
| 935 | + :response-buffer-size response-buffer-size |
| 936 | + :t0 t0}))))))))))))] |
| 937 | + (d/connect conn result) |
| 938 | + (d/catch' result (fn [e] |
| 939 | + (log/trace e "Closing HTTP connection channel") |
| 940 | + (d/error! ch-d e) |
| 941 | + (@close-ch!) |
| 942 | + (d/error-deferred e))) |
| 943 | + result)) |
930 | 944 |
|
931 | 945 |
|
932 | 946 |
|
|
0 commit comments