聊聊jdk http的HeaderFilter

本文主要研究一下jdk http的HeaderFilter。

FilterFactory

java.net.http/jdk/internal/net/http/FilterFactory.java

class FilterFactory {// Strictly-ordered list of filters.final LinkedList<Class<? extends HeaderFilter>> filterClasses = new LinkedList<>();public void addFilter(Class<? extends HeaderFilter> type) {filterClasses.add(type);}LinkedList<HeaderFilter> getFilterChain() {LinkedList<HeaderFilter> l = new LinkedList<>();for (Class<? extends HeaderFilter> clazz : filterClasses) {try {// Requires a public no arg constructor.HeaderFilter headerFilter = clazz.getConstructor().newInstance();l.add(headerFilter);} catch (ReflectiveOperationException e) {throw new InternalError(e);}}return l;}
}
復制代碼
  • 提供了addFilter及getFilterChain方法,前者添加filter class,后者使用反射實例化filter。

HttpClientImpl

java.net.http/jdk/internal/net/http/HttpClientImpl.java

    private HttpClientImpl(HttpClientBuilderImpl builder,SingleFacadeFactory facadeFactory) {id = CLIENT_IDS.incrementAndGet();dbgTag = "HttpClientImpl(" + id +")";if (builder.sslContext == null) {try {sslContext = SSLContext.getDefault();} catch (NoSuchAlgorithmException ex) {throw new InternalError(ex);}} else {sslContext = builder.sslContext;}Executor ex = builder.executor;if (ex == null) {ex = Executors.newCachedThreadPool(new DefaultThreadFactory(id));isDefaultExecutor = true;} else {isDefaultExecutor = false;}delegatingExecutor = new DelegatingExecutor(this::isSelectorThread, ex);facadeRef = new WeakReference<>(facadeFactory.createFacade(this));client2 = new Http2ClientImpl(this);cookieHandler = builder.cookieHandler;connectTimeout = builder.connectTimeout;followRedirects = builder.followRedirects == null ?Redirect.NEVER : builder.followRedirects;this.userProxySelector = Optional.ofNullable(builder.proxy);this.proxySelector = userProxySelector.orElseGet(HttpClientImpl::getDefaultProxySelector);if (debug.on())debug.log("proxySelector is %s (user-supplied=%s)",this.proxySelector, userProxySelector.isPresent());authenticator = builder.authenticator;if (builder.version == null) {version = HttpClient.Version.HTTP_2;} else {version = builder.version;}if (builder.sslParams == null) {sslParams = getDefaultParams(sslContext);} else {sslParams = builder.sslParams;}connections = new ConnectionPool(id);connections.start();timeouts = new TreeSet<>();try {selmgr = new SelectorManager(this);} catch (IOException e) {// unlikelythrow new InternalError(e);}selmgr.setDaemon(true);filters = new FilterFactory();initFilters();assert facadeRef.get() != null;}private void initFilters() {addFilter(AuthenticationFilter.class);addFilter(RedirectFilter.class);if (this.cookieHandler != null) {addFilter(CookieFilter.class);}}private void addFilter(Class<? extends HeaderFilter> f) {filters.addFilter(f);}final LinkedList<HeaderFilter> filterChain() {return filters.getFilterChain();}
復制代碼
  • HttpClientImpl的構造器創建了FilterFactory,并調用addFilter添加默認的filter
  • filterChain方法則調用了FilterFactory的getFilterChain()方法,使用反射實例化這些filter

MultiExchange

java.net.http/jdk/internal/net/http/MultiExchange.java

    /*** MultiExchange with one final response.*/MultiExchange(HttpRequest userRequest,HttpRequestImpl requestImpl,HttpClientImpl client,HttpResponse.BodyHandler<T> responseHandler,PushPromiseHandler<T> pushPromiseHandler,AccessControlContext acc) {this.previous = null;this.userRequest = userRequest;this.request = requestImpl;this.currentreq = request;this.previousreq = null;this.client = client;this.filters = client.filterChain();this.acc = acc;this.executor = client.theExecutor();this.responseHandler = responseHandler;if (pushPromiseHandler != null) {Executor executor = acc == null? this.executor.delegate(): new PrivilegedExecutor(this.executor.delegate(), acc);this.pushGroup = new PushGroup<>(pushPromiseHandler, request, executor);} else {pushGroup = null;}this.exchange = new Exchange<>(request, this);}private CompletableFuture<Response> responseAsyncImpl() {CompletableFuture<Response> cf;if (attempts.incrementAndGet() > max_attempts) {cf = failedFuture(new IOException("Too many retries", retryCause));} else {if (currentreq.timeout().isPresent()) {responseTimerEvent = ResponseTimerEvent.of(this);client.registerTimer(responseTimerEvent);}try {// 1. apply request filters// if currentreq == previousreq the filters have already// been applied once. Applying them a second time might// cause some headers values to be added twice: for// instance, the same cookie might be added again.if (currentreq != previousreq) {requestFilters(currentreq);}} catch (IOException e) {return failedFuture(e);}Exchange<T> exch = getExchange();// 2. get responsecf = exch.responseAsync().thenCompose((Response response) -> {HttpRequestImpl newrequest;try {// 3. apply response filtersnewrequest = responseFilters(response);} catch (IOException e) {return failedFuture(e);}// 4. check filter result and repeat or continueif (newrequest == null) {if (attempts.get() > 1) {Log.logError("Succeeded on attempt: " + attempts);}return completedFuture(response);} else {this.response =new HttpResponseImpl<>(currentreq, response, this.response, null, exch);Exchange<T> oldExch = exch;return exch.ignoreBody().handle((r,t) -> {previousreq = currentreq;currentreq = newrequest;expiredOnce = false;setExchange(new Exchange<>(currentreq, this, acc));return responseAsyncImpl();}).thenCompose(Function.identity());} }).handle((response, ex) -> {// 5. handle errors and cancel any timer setcancelTimer();if (ex == null) {assert response != null;return completedFuture(response);}// all exceptions thrown are handled hereCompletableFuture<Response> errorCF = getExceptionalCF(ex);if (errorCF == null) {return responseAsyncImpl();} else {return errorCF;} }).thenCompose(Function.identity());}return cf;}private void requestFilters(HttpRequestImpl r) throws IOException {Log.logTrace("Applying request filters");for (HeaderFilter filter : filters) {Log.logTrace("Applying {0}", filter);filter.request(r, this);}Log.logTrace("All filters applied");}private HttpRequestImpl responseFilters(Response response) throws IOException{Log.logTrace("Applying response filters");Iterator<HeaderFilter> reverseItr = filters.descendingIterator();while (reverseItr.hasNext()) {HeaderFilter filter = reverseItr.next();Log.logTrace("Applying {0}", filter);HttpRequestImpl newreq = filter.response(response);if (newreq != null) {Log.logTrace("New request: stopping filters");return newreq;}}Log.logTrace("All filters applied");return null;}
復制代碼
  • MultiExchange在構造器里頭調用了client.filterChain(),完成filters的初始化
  • 在responseAsyncImpl方法里頭,執行請求之前調用requestFilters,得到response之后調用responseFilters
  • requestFilters是按順序執行,而responseFilters則取的是descendingIterator,逆序執行

HeaderFilter

java.net.http/jdk/internal/net/http/HeaderFilter.java

/*** A header filter that can examine or modify, typically system headers for* requests before they are sent, and responses before they are returned to the* user. Some ability to resend requests is provided.*/
interface HeaderFilter {void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException;/*** Returns null if response ok to be given to user.  Non null is a request* that must be resent and its response given to user. If impl throws an* exception that is returned to user instead.*/HttpRequestImpl response(Response r) throws IOException;
}
復制代碼
  • 可以看到HeaderFilter接口定義了request以及response方法
  • 對于response方法,如果對header處理沒問題就返回null,有異常拋異常,需要重新發送的則會返回HttpRequestImpl
  • HeaderFilter有三個實現類,分別是AuthenticationFilter、RedirectFilter、CookieFilter

AuthenticationFilter

java.net.http/jdk/internal/net/http/AuthenticationFilter.java

    @Overridepublic void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException {// use preemptive authentication if an entry exists.Cache cache = getCache(e);this.exchange = e;// Proxyif (exchange.proxyauth == null) {URI proxyURI = getProxyURI(r);if (proxyURI != null) {CacheEntry ca = cache.get(proxyURI, true);if (ca != null) {exchange.proxyauth = new AuthInfo(true, ca.scheme, null, ca);addBasicCredentials(r, true, ca.value);}}}// Serverif (exchange.serverauth == null) {CacheEntry ca = cache.get(r.uri(), false);if (ca != null) {exchange.serverauth = new AuthInfo(true, ca.scheme, null, ca);addBasicCredentials(r, false, ca.value);}}}// TODO: refactor into per auth scheme classprivate static void addBasicCredentials(HttpRequestImpl r,boolean proxy,PasswordAuthentication pw) {String hdrname = proxy ? "Proxy-Authorization" : "Authorization";StringBuilder sb = new StringBuilder(128);sb.append(pw.getUserName()).append(':').append(pw.getPassword());String s = encoder.encodeToString(sb.toString().getBytes(ISO_8859_1));String value = "Basic " + s;if (proxy) {if (r.isConnect()) {if (!Utils.PROXY_TUNNEL_FILTER.test(hdrname, value)) {Log.logError("{0} disabled", hdrname);return;}} else if (r.proxy() != null) {if (!Utils.PROXY_FILTER.test(hdrname, value)) {Log.logError("{0} disabled", hdrname);return;}}}r.setSystemHeader(hdrname, value);}@Overridepublic HttpRequestImpl response(Response r) throws IOException {Cache cache = getCache(exchange);int status = r.statusCode();HttpHeaders hdrs = r.headers();HttpRequestImpl req = r.request();if (status != UNAUTHORIZED && status != PROXY_UNAUTHORIZED) {// check if any authentication succeeded for first timeif (exchange.serverauth != null && !exchange.serverauth.fromcache) {AuthInfo au = exchange.serverauth;cache.store(au.scheme, req.uri(), false, au.credentials);}if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) {AuthInfo au = exchange.proxyauth;URI proxyURI = getProxyURI(req);if (proxyURI != null) {cache.store(au.scheme, proxyURI, true, au.credentials);}}return null;}//......}
復制代碼
  • 可以用于添加basic authentication的header

RedirectFilter

java.net.http/jdk/internal/net/http/RedirectFilter.java

    @Overridepublic synchronized void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException {this.request = r;this.client = e.client();this.policy = client.followRedirects();this.method = r.method();this.uri = r.uri();this.exchange = e;}@Overridepublic synchronized HttpRequestImpl response(Response r) throws IOException {return handleResponse(r);}/*** Checks to see if a new request is needed and returns it.* Null means response is ok to return to user.*/private HttpRequestImpl handleResponse(Response r) {int rcode = r.statusCode();if (rcode == 200 || policy == HttpClient.Redirect.NEVER) {return null;}if (rcode == HTTP_NOT_MODIFIED)return null;if (rcode >= 300 && rcode <= 399) {URI redir = getRedirectedURI(r.headers());String newMethod = redirectedMethod(rcode, method);Log.logTrace("response code: {0}, redirected URI: {1}", rcode, redir);if (canRedirect(redir) && ++exchange.numberOfRedirects < max_redirects) {Log.logTrace("redirect to: {0} with method: {1}", redir, newMethod);return HttpRequestImpl.newInstanceForRedirection(redir, newMethod, request);} else {Log.logTrace("not redirecting");return null;}}return null;}
復制代碼
  • 主要用于處理3xx跳轉,這個時候滿足條件的話會返回新的HttpRequestImpl實例

CookieFilter

java.net.http/jdk/internal/net/http/CookieFilter.java

    @Overridepublic void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException {HttpClientImpl client = e.client();Optional<CookieHandler> cookieHandlerOpt = client.cookieHandler();if (cookieHandlerOpt.isPresent()) {CookieHandler cookieHandler = cookieHandlerOpt.get();Map<String,List<String>> userheaders = r.getUserHeaders().map();Map<String,List<String>> cookies = cookieHandler.get(r.uri(), userheaders);// add the returned cookiesHttpHeadersBuilder systemHeadersBuilder = r.getSystemHeadersBuilder();if (cookies.isEmpty()) {Log.logTrace("Request: no cookie to add for {0}", r.uri());} else {Log.logTrace("Request: adding cookies for {0}", r.uri());}for (Map.Entry<String,List<String>> entry : cookies.entrySet()) {final String hdrname = entry.getKey();if (!hdrname.equalsIgnoreCase("Cookie")&& !hdrname.equalsIgnoreCase("Cookie2"))continue;List<String> values = entry.getValue();if (values == null || values.isEmpty()) continue;for (String val : values) {if (Utils.isValidValue(val)) {systemHeadersBuilder.addHeader(hdrname, val);}}}} else {Log.logTrace("Request: No cookie manager found for {0}", r.uri());}}@Overridepublic HttpRequestImpl response(Response r) throws IOException {HttpHeaders hdrs = r.headers();HttpRequestImpl request = r.request();Exchange<?> e = r.exchange;Log.logTrace("Response: processing cookies for {0}", request.uri());Optional<CookieHandler> cookieHandlerOpt = e.client().cookieHandler();if (cookieHandlerOpt.isPresent()) {CookieHandler cookieHandler = cookieHandlerOpt.get();Log.logTrace("Response: parsing cookies from {0}", hdrs.map());cookieHandler.put(request.uri(), hdrs.map());} else {Log.logTrace("Response: No cookie manager found for {0}",request.uri());}return null;}
復制代碼
  • 用于請求以及響應的cookie相關的處理

小結

  • FilterFactory使用了簡單的責任鏈模式,getFilterChain方法使用反射實例化各種filter
  • HeaderFilter定義了request及response兩個方法,分別作用于請求前及獲得響應之后
  • HeaderFilter有三個實現類,分別是AuthenticationFilter、RedirectFilter、CookieFilter
  • MultiExchange在responseAsyncImpl方法里頭,執行請求之前調用requestFilters,得到response之后調用responseFilters。其中requestFilters是按順序執行,而responseFilters則取的是descendingIterator,逆序執行

doc

  • java.net.http javadoc

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389592.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389592.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389592.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

旋轉變換(一)旋轉矩陣

1. 簡介 計算機圖形學中的應用非常廣泛的變換是一種稱為仿射變換的特殊變換&#xff0c;在仿射變換中的基本變換包括平移、旋轉、縮放、剪切這幾種。本文以及接下來的幾篇文章重點介紹一下關于旋轉的變換&#xff0c;包括二維旋轉變換、三維旋轉變換以及它的一些表達方式&#…

數據預處理 泰坦尼克號_了解泰坦尼克號數據集的數據預處理

數據預處理 泰坦尼克號什么是數據預處理&#xff1f; (What is Data Pre-Processing?) We know from my last blog that data preprocessing is a data mining technique that involves transforming raw data into an understandable format. Real-world data is often incom…

Pytorch中DNN入門思想及實現

DNN全連接層&#xff08;線性層&#xff09; 計算公式&#xff1a; y w * x b W和b是參與訓練的參數 W的維度決定了隱含層輸出的維度&#xff0c;一般稱為隱單元個數&#xff08;hidden size&#xff09; b是偏差值&#xff08;本文沒考慮&#xff09; 舉例&#xff1a; 輸…

IDEA去除mapper.xml文件中的sql語句的背景色

2019獨角獸企業重金招聘Python工程師標準>>> IDEA版本 2017.3 mapper.xml文件中的sql語句&#xff0c;總是黃色一大片&#xff0c;看起來不舒服。 按如下設置進行設置即可 此時設置完還有點背景色 再進行一個設置 Ok,完美解決 轉載于:https://my.oschina.net/u/3939…

vc6.0 繪制散點圖_vc有關散點圖的一切

vc6.0 繪制散點圖Scatterplots are one of the most popular visualization techniques in the world. Its purposes are recognizing clusters and correlations in ‘pairs’ of variables. There are many variations of scatter plots. We will look at some of them.散點圖…

sudo配置臨時取得root權限

sudo配置臨時取得root權限系統中的普通用戶有時需要root權限執行某種操作&#xff0c;要是使用su - root的話必須要知道root的密碼&#xff0c;這是不安全的&#xff0c;所以有了sudo&#xff0c;root可以對/etc/sudoers做一定的配置&#xff0c;讓普通用戶在不切換到root的情況…

Pytorch中RNN入門思想及實現

RNN循環神經網絡 整體思想&#xff1a; 將整個序列劃分成多個時間步&#xff0c;將每一個時間步的信息依次輸入模型&#xff0c;同時將模型輸出的結果傳給下一個時間步&#xff0c;也就是說后面的結果受前面輸入的影響。 RNN的實現公式&#xff1a; 個人思路&#xff1a; 首…

小扎不哭!FB又陷數據泄露風波,9000萬用戶受影響

對小扎來說&#xff0c;又是多災多難的一個月。 繼不久前Twitter曝出修補了一個可能造成數以百萬計用戶私密消息被共享給第三方開發人員的漏洞&#xff0c;連累Facebook股價跟著短線跳水之后&#xff0c;9月28日&#xff0c;Facebook又雙叒叕曝出因安全漏洞遭到黑客攻擊&#…

在衡量歐洲的政治意識形態時,調查規模的微小變化可能會很重要

(Related post: On a scale from 1 to 10, how much do the numbers used in survey scales really matter?)(相關文章&#xff1a; 從1到10的量表&#xff0c;調查量表中使用的數字到底有多重要&#xff1f; ) At Pew Research Center, survey questions about respondents’…

Pytorch中CNN入門思想及實現

CNN卷積神經網絡 基礎概念&#xff1a; 以卷積操作為基礎的網絡結構&#xff0c;每個卷積核可以看成一個特征提取器。 思想&#xff1a; 每次觀察數據的一部分&#xff0c;如圖&#xff0c;在整個矩陣中只觀察黃色部分33的矩陣&#xff0c;將這【33】矩陣(點乘)權重得到特…

java常用設計模式一:單例模式

1、餓漢式 package singleton.demo;/*** author Administrator* date 2019/01/07*/ public class Singleton {//在調用getInstance方法前&#xff0c;實例已經創建好private static Singleton instance new Singleton();//私有構造&#xff0c;防止被實例化private Singleton(…

SDUT-2121_數據結構實驗之鏈表六:有序鏈表的建立

數據結構實驗之鏈表六&#xff1a;有序鏈表的建立 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 輸入N個無序的整數&#xff0c;建立一個有序鏈表&#xff0c;鏈表中的結點按照數值非降序排列&#xff0c;輸出該有序鏈表。 Input 第一行輸入整數個數N&…

事件映射 消息映射_映射幻影收費站

事件映射 消息映射When I was a child, I had a voracious appetite for books. I was constantly visiting the library and picking new volumes to read, but one I always came back to was The Phantom Tollbooth, written by Norton Juster and illustrated by Jules Fei…

前端代碼調試常用

轉載于:https://www.cnblogs.com/tabCtrlShift/p/9076752.html

Pytorch中BN層入門思想及實現

批歸一化層-BN層&#xff08;Batch Normalization&#xff09; 作用及影響&#xff1a; 直接作用&#xff1a;對輸入BN層的張量進行數值歸一化&#xff0c;使其成為均值為零&#xff0c;方差為一的張量。 帶來影響&#xff1a; 1.使得網絡更加穩定&#xff0c;結果不容易受到…

JDK源碼學習筆記——TreeMap及紅黑樹

找了幾個分析比較到位的&#xff0c;不再重復寫了…… Java 集合系列12之 TreeMap詳細介紹(源碼解析)和使用示例 【Java集合源碼剖析】TreeMap源碼剖析 java源碼分析之TreeMap基礎篇 關于紅黑樹&#xff1a; Java數據結構和算法&#xff08;十一&#xff09;——紅黑樹 【數據結…

匿名內部類和匿名類_匿名schanonymous

匿名內部類和匿名類Everybody loves a fad. You can pinpoint someone’s generation better than carbon dating by asking them what their favorite toys and gadgets were as a kid. Tamagotchi and pogs? You were born around 1988, weren’t you? Coleco Electronic Q…

Pytorch框架中SGD&Adam優化器以及BP反向傳播入門思想及實現

因為這章內容比較多&#xff0c;分開來敘述&#xff0c;前面先講理論后面是講代碼。最重要的是代碼部分&#xff0c;結合代碼去理解思想。 SGD優化器 思想&#xff1a; 根據梯度&#xff0c;控制調整權重的幅度 公式&#xff1a; 權重(新) 權重(舊) - 學習率 梯度 Adam…

朱曄和你聊Spring系列S1E3:Spring咖啡罐里的豆子

標題中的咖啡罐指的是Spring容器&#xff0c;容器里裝的當然就是被稱作Bean的豆子。本文我們會以一個最基本的例子來熟悉Spring的容器管理和擴展點。閱讀PDF版本 為什么要讓容器來管理對象&#xff1f; 首先我們來聊聊這個問題&#xff0c;為什么我們要用Spring來管理對象&…

ab實驗置信度_為什么您的Ab測試需要置信區間

ab實驗置信度by Alos Bissuel, Vincent Grosbois and Benjamin HeymannAlosBissuel&#xff0c;Vincent Grosbois和Benjamin Heymann撰寫 The recent media debate on COVID-19 drugs is a unique occasion to discuss why decision making in an uncertain environment is a …