fix alowPatch

This commit is contained in:
Looly 2021-07-08 09:29:02 +08:00
parent 5c6e548db2
commit 96e88307f8
3 changed files with 55 additions and 46 deletions

View File

@ -13,8 +13,6 @@ import javax.net.ssl.SSLSocketFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.ProtocolException; import java.net.ProtocolException;
import java.net.Proxy; import java.net.Proxy;
@ -122,7 +120,7 @@ public class HttpConnection {
// 增加PATCH方法支持 // 增加PATCH方法支持
if (Method.PATCH.equals(method)) { if (Method.PATCH.equals(method)) {
allowPatch(); HttpGlobalConfig.allowPatch();
} }
} }
@ -546,23 +544,5 @@ public class HttpConnection {
private URLConnection openConnection() throws IOException { private URLConnection openConnection() throws IOException {
return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy); return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy);
} }
/**
* 增加支持的METHOD方法
* see: https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch
*
* @since 5.1.6
*/
private static void allowPatch() {
final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods");
if (null != methodsField) {
// 去除final修饰
ReflectUtil.setFieldValue(methodsField, "modifiers", methodsField.getModifiers() & ~Modifier.FINAL);
final String[] methods = {
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
};
ReflectUtil.setFieldValue(null, methodsField, methods);
}
}
// --------------------------------------------------------------- Private Method end // --------------------------------------------------------------- Private Method end
} }

View File

@ -1,13 +1,17 @@
package cn.hutool.http; package cn.hutool.http;
import java.io.Serializable; import cn.hutool.core.util.ReflectUtil;
import java.net.CookieManager;
import cn.hutool.http.cookie.GlobalCookieManager; import cn.hutool.http.cookie.GlobalCookieManager;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.CookieManager;
import java.net.HttpURLConnection;
/** /**
* HTTP 全局参数配置 * HTTP 全局参数配置
* *
* @author Looly * @author Looly
* @since 4.6.2 * @since 4.6.2
*/ */
@ -15,10 +19,11 @@ public class HttpGlobalConfig implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected static int timeout = -1; protected static int timeout = -1;
private static boolean isAllowPatch = false;
/** /**
* 获取全局默认的超时时长 * 获取全局默认的超时时长
* *
* @return 全局默认的超时时长 * @return 全局默认的超时时长
*/ */
public static int getTimeout() { public static int getTimeout() {
@ -27,16 +32,16 @@ public class HttpGlobalConfig implements Serializable {
/** /**
* 设置默认的连接和读取超时时长 * 设置默认的连接和读取超时时长
* *
* @param customTimeout 超时时长 * @param customTimeout 超时时长
*/ */
public static void setTimeout(int customTimeout) { synchronized public static void setTimeout(int customTimeout) {
timeout = customTimeout; timeout = customTimeout;
} }
/** /**
* 获取Cookie管理器用于自定义Cookie管理 * 获取Cookie管理器用于自定义Cookie管理
* *
* @return {@link CookieManager} * @return {@link CookieManager}
* @since 4.1.0 * @since 4.1.0
* @see GlobalCookieManager#getCookieManager() * @see GlobalCookieManager#getCookieManager()
@ -47,7 +52,7 @@ public class HttpGlobalConfig implements Serializable {
/** /**
* 自定义{@link CookieManager} * 自定义{@link CookieManager}
* *
* @param customCookieManager 自定义的{@link CookieManager} * @param customCookieManager 自定义的{@link CookieManager}
* @since 4.5.14 * @since 4.5.14
* @see GlobalCookieManager#setCookieManager(CookieManager) * @see GlobalCookieManager#setCookieManager(CookieManager)
@ -55,14 +60,37 @@ public class HttpGlobalConfig implements Serializable {
public static void setCookieManager(CookieManager customCookieManager) { public static void setCookieManager(CookieManager customCookieManager) {
GlobalCookieManager.setCookieManager(customCookieManager); GlobalCookieManager.setCookieManager(customCookieManager);
} }
/** /**
* 关闭Cookie * 关闭Cookie
* *
* @since 4.1.9 * @since 4.1.9
* @see GlobalCookieManager#setCookieManager(CookieManager) * @see GlobalCookieManager#setCookieManager(CookieManager)
*/ */
public static void closeCookie() { public static void closeCookie() {
GlobalCookieManager.setCookieManager(null); GlobalCookieManager.setCookieManager(null);
} }
/**
* 增加支持的METHOD方法<br>
* 此方法通过注入方式修改{@link HttpURLConnection}中的methods静态属性增加PATCH方法<br>
* see: https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch
*
* @since 5.7.4
*/
synchronized public static void allowPatch() {
if(isAllowPatch){
return;
}
final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods");
if (null != methodsField) {
// 去除final修饰
ReflectUtil.setFieldValue(methodsField, "modifiers", methodsField.getModifiers() & ~Modifier.FINAL);
final String[] methods = {
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
};
ReflectUtil.setFieldValue(null, methodsField, methods);
isAllowPatch = true;
}
}
} }

View File

@ -12,7 +12,7 @@ import java.util.zip.InflaterInputStream;
/** /**
* HTTP输入流此流用于包装Http请求响应内容的流用于解析各种压缩分段的响应流内容 * HTTP输入流此流用于包装Http请求响应内容的流用于解析各种压缩分段的响应流内容
* *
* @author Looly * @author Looly
* *
*/ */
@ -23,7 +23,7 @@ public class HttpInputStream extends InputStream {
/** /**
* 构造 * 构造
* *
* @param response 响应对象 * @param response 响应对象
*/ */
public HttpInputStream(HttpResponse response) { public HttpInputStream(HttpResponse response) {
@ -34,37 +34,38 @@ public class HttpInputStream extends InputStream {
public int read() throws IOException { public int read() throws IOException {
return this.in.read(); return this.in.read();
} }
@SuppressWarnings("NullableProblems")
@Override @Override
public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b, int off, int len) throws IOException {
return this.in.read(b, off, len); return this.in.read(b, off, len);
} }
@Override @Override
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
return this.in.skip(n); return this.in.skip(n);
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
return this.in.available(); return this.in.available();
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
this.in.close(); this.in.close();
} }
@Override @Override
public synchronized void mark(int readlimit) { public synchronized void mark(int readlimit) {
this.in.mark(readlimit); this.in.mark(readlimit);
} }
@Override @Override
public synchronized void reset() throws IOException { public synchronized void reset() throws IOException {
this.in.reset(); this.in.reset();
} }
@Override @Override
public boolean markSupported() { public boolean markSupported() {
return this.in.markSupported(); return this.in.markSupported();
@ -72,7 +73,7 @@ public class HttpInputStream extends InputStream {
/** /**
* 初始化流 * 初始化流
* *
* @param response 响应对象 * @param response 响应对象
*/ */
private void init(HttpResponse response) { private void init(HttpResponse response) {
@ -84,13 +85,13 @@ public class HttpInputStream extends InputStream {
} }
// 服务器无返回内容忽略之 // 服务器无返回内容忽略之
} }
// 在一些情况下返回的流为null此时提供状态码说明 // 在一些情况下返回的流为null此时提供状态码说明
if (null == this.in) { if (null == this.in) {
this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", response.status).getBytes()); this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", response.status).getBytes());
return; return;
} }
if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) { if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) {
// Accept-Encoding: gzip // Accept-Encoding: gzip
try { try {