|
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