9

以下代码是否安全:

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);
...

问题发生在tryGetResponseon HTTPS请求中:

 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 中尝试)建立新连接而没有设置超时。

4

4 回答 4

3

不,一般来说这是不安全的。JVM 实现之间的行为可能会有所不同(想想 IBM J9 与 Oracle VM 与 Open JDK),并且在同一 VM 的版本之间发生更改,恕不另行通知。

原因是 API 规范不做任何保证。

如果您告诉我您正在使用哪个特定版本中的哪个具体实现,我可以查看源代码并尝试得出一些结论。但我强烈建议不要依赖你在那里找到的行为。

关于 HTTP S:SSL 似乎仍然存在一些错误。例如,OpenSSL 已经公开宣布,他们将在本周末披露一个安全漏洞。在某些错误情况下,针对该问题的错误修复可能会改变 HTTPS 连接的行为。我们在消息来源中发现的任何东西都可能在本周末变得毫无意义。如果没有,它可能会随着下一个安全修复程序而改变。

更新:

我试图找到与您在更新的问题中引用的 Java 版本相对应的来源。找到 Java 源代码不是什么大问题,但代码会很快进入本地部分。这本身就是一个很好的提示,答案不仅是特定于版本的,而且是特定于平台的(Linux、Windows、Mac 等)。您可以查看 Java 1.6 的 OpenJDK 源代码,例如Windows 的网络堆栈

注意:您很可能使用过 Sun JDK 1.6。OpenJDK 1.6 基于 Sun/Oracle JDK,但基于 JDK 1.7。Open JDK 1.6 是从 Sun/Oracle JDK 1.7 向后移植到 Java 1.6 的代码。因此,仍然可能存在一些小的差异,但在发生错误后对于连接的使用可能很重要。

于 2015-03-17T09:39:54.403 回答
2

对于规范getErrorStream

如果连接失败但服务器仍然发送了有用的数据,则返回错误流。典型的例子是当 HTTP 服务器响应 404 时,这将导致在连接中抛出 FileNotFoundException,但服务器发送了一个 HTML 帮助页面,其中包含有关如何操作的建议。此方法不会导致启动连接。如果连接未连接,或者服务器在连接时没有错误,或者服务器有错误但没有发送错误数据,则此方法将返回 null。这是默认设置。

返回:如果有错误流,如果没有错误、连接未连接或服务器未发送有用数据,则返回 null。

您还可以检查以消除任何疑问,因此让我们看一些方法:

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);
}

因此,它会缓存标头并在已知的情况下返回它们,即使可能在 a 之后IOException,它也不会传播异常,但如果之前没有成功获取标头,则可能返回 null。

于 2015-03-17T08:52:35.777 回答
2

特别是,在InterruptedIOException(例如,读取超时)调用方法的情况下是否安全getContentEncoding()?

你可以试试。将发生的最坏情况是另一种情况。例如,IOException.在某些情况下调用和读取错误页面的内容是完全安全的。IOException,FileNotFoundException,getErrorStream()

于 2015-03-17T08:53:52.320 回答
0
catch (IOException e) {
    if(conn != null) {
        conn.getContentEncoding();
        conn.getErrorStream();
        conn.whateverOtherMethodThere();
        ...
    }

公共类 InterruptedIOException 扩展 IOException

表示 I/O 操作已被中断。抛出 InterruptedIOException 以指示输入或输出传输已终止,因为执行它的线程被中断。字段 bytesTransferred 指示在中断发生之前成功传输了多少字节。

这意味着如果发生中断的异常,您将无法对 HttpUrlConnection 进行进一步处理。

再次通过 IOException,您无法捕获其他类型的异常,例如 IllegalArgumentException、非法线程状态异常等等。

更多详情http://download.java.net/jdk7/archive/b123/docs/api/java/net/HttpURLConnection.html#getRequestMethod%28%29

于 2014-01-22T15:54:05.410 回答