聊聊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.mzph.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 …