以下代码是否安全:
try {
URL url = new URL(urlRequest);
conn = (HttpURLConnection)url.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
String encoding = conn.getContentEncoding();
return Utils.wrapCompressedStream(conn.getInputStream(), encoding);
} catch (IOException e) {
if(conn != null) {
conn.getContentEncoding();
conn.getErrorStream();
conn.whateverOtherMethodThere();
...
}
}
特别是,在InterruptedIOException(例如,读取超时)调用getContentEncoding()
之类的方法时是否安全?据我所知,此方法需要实时连接才能读取HTTP(S)标头。
更新(附加信息):
这个问题源于真实的系统体验。我相信,系统是在Oracle / Sun JVM 1.6上运行的。代码几乎相同:
...
} catch (IOException e) {
if(conn != null) {
try {
String response = tryGetResponse(conn);
...
问题发生在 HTTPS 请求的tryGetResponse
:
private static String tryGetResponse(HttpURLConnection conn) {
if(conn == null) return "(failed to get)";
InputStream in = null;
try {
InputStream err = conn.getErrorStream();
if (err != null) {
in = Utils.wrapCompressedStream(err, conn.getContentEncoding());
}
return Utils.inputStreamToString(in);
} catch (IOException e) {
return "(failed to get)";
} finally {
Utils.closeQuitely(in);
}
}
自发系统挂在getContentEncoding()
电话的套接字连接(或读取)上:
in = Utils.wrapCompressedStream(err, conn.getContentEncoding());
在初始代码中抛出SocketTimeoutException
之后。
因此,似乎getContentEncoding()
尝试(或在Java 6中尝试)建立新连接而不设置超时。
答案 0 :(得分:3)
没有。一般来说不安全。 JVM实现(认为IBM J9与Oracle VM与Open JDK之间)的行为可能不同,并且在不通知的情况下在同一VM的版本之间进行更改。
原因是API规范不做任何保证。
如果您告诉我您使用哪个特定版本的具体实现,我可以查看来源并尝试做出一些结论。但我强烈建议不要依赖你在那里找到的行为。
关于HTTP S :SSL似乎仍然存在一些漏洞。例如,OpenSSL已经发布了public announcement,他们将在本周末发布一个安全漏洞。修复此错误可能会在某些错误情况下更改HTTPS连接的行为。可能的是,无论我们在消息来源中找到什么,都会在本周末没有实际意义。如果没有,它可能会随着下一个安全修复程序而改变。
更新:
我已经尝试找到与您在更新的问题中引用的Java版本相对应的源代码。查找Java-Sources不是一个大问题,但代码很快就会进入本机部分。仅此一点就是一个很好的暗示,答案不仅仅是版本特定的,还有平台特定的(Linux,Windows,Mac等)。您可以查看Java 1.6的OpenJDK源代码,例如: for the network stack for Windows。
注意:您很可能使用过Sun JDK 1.6。 OpenJDK 1.6在Sun / Oracle JDK上,但在JDK 1.7上。 Open JDK 1.6是Sun / Oracle JDK 1.7 backportet到Java 1.6的代码形式。所以仍然可能存在一些小的差异,但在发生错误后对连接的使用仍然很重要。
答案 1 :(得分:2)
对于getErrorStream
spec说:
如果连接失败但服务器仍然发送了有用的数据,则返回错误流。典型示例是当HTTP服务器以404响应时,这将导致在连接中抛出FileNotFoundException,但服务器发送了一个HTML帮助页面,其中包含有关如何操作的建议。 此方法不会导致启动连接。如果未连接连接,或者连接时服务器没有错误,或者服务器出现错误但未发送错误数据,则此方法将返回null。这是默认值。
返回: 错误流(如果有),如果没有错误,则为null,连接未连接或服务器未发送任何有用数据。
您还可以检查source以消除疑虑,让我们看一些方法:
public InputStream getErrorStream() {
if (connected && responseCode >= 400) {
// Client Error 4xx and Server Error 5xx
if (errorStream != null) {
return errorStream;
} else if (inputStream != null) {
return inputStream;
}
}
return null;
}
可以安全地调用它(不会抛出任何异常),并且可以在某些errorStream
个案例中设置IOException
。来源中的评论为buffer the error stream if bytes < 4k and it can be buffered within 1 second
。
getContentEncoding
来自规范的行为是:
返回: URL引用的资源的内容编码,如果不知道则为null。
但是错误之后怎么办?让我们看看代码:
public String getContentEncoding() { //from the base class java.net.URLConnection
return getHeaderField("content-encoding");
}
public String getHeaderField(String name) {
try {
getInputStream();
} catch (IOException e) {} //ah exception is eaten
if (cachedHeaders != null) {
return cachedHeaders.findValue(name);
}
return responses.findValue(name);
}
因此,如果已知,它会缓存标头并返回它们,即使可能在IOException
之后,它也不会传播异常,但如果以前没有成功获得标头,则可能返回null。
答案 2 :(得分:2)
特别是,
等方法是否安全?InterruptedIOException
(例如,读取超时)调用getContentEncoding()?
你可以试试。最糟糕的情况是另一个IOException.
在IOException,
例如FileNotFoundException,
的几种情况下,调用getErrorStream()
并读取错误页面的内容是完全安全的。
答案 3 :(得分:0)
catch (IOException e) {
if(conn != null) {
conn.getContentEncoding();
conn.getErrorStream();
conn.whateverOtherMethodThere();
...
}
公共类InterruptedIOException 扩展IOException
表示I / O操作已中断。抛出InterruptedIOException以指示输入或输出传输已终止,因为执行它的线程已中断。 bytesTransferred字段表示在中断发生之前成功传输了多少字节。
这意味着如果发生中断的异常,则无法对HttpUrlConnection进行进一步处理。
再次通过IOException,您无法捕获其他类型的异常,例如IllegalArgumentException,illegalthreadstate异常等等。