OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_network_transaction.h" | 5 #include "net/http/http_network_transaction.h" |
6 | 6 |
7 #include <math.h> // ceil | 7 #include <math.h> // ceil |
8 #include <stdarg.h> | 8 #include <stdarg.h> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
(...skipping 1694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1705 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | 1705 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); |
1706 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | 1706 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); |
1707 session_deps.net_log = log.bound().net_log(); | 1707 session_deps.net_log = log.bound().net_log(); |
1708 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | 1708 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
1709 | 1709 |
1710 // Since we have proxy, should try to establish tunnel. | 1710 // Since we have proxy, should try to establish tunnel. |
1711 MockWrite data_writes1[] = { | 1711 MockWrite data_writes1[] = { |
1712 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | 1712 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
1713 "Host: www.google.com\r\n" | 1713 "Host: www.google.com\r\n" |
1714 "Proxy-Connection: keep-alive\r\n\r\n"), | 1714 "Proxy-Connection: keep-alive\r\n\r\n"), |
1715 }; | |
1716 | 1715 |
1717 MockWrite data_writes2[] = { | |
1718 // After calling trans->RestartWithAuth(), this is the request we should | 1716 // After calling trans->RestartWithAuth(), this is the request we should |
1719 // be issuing -- the final header line contains the credentials. | 1717 // be issuing -- the final header line contains the credentials. |
1720 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | 1718 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
1721 "Host: www.google.com\r\n" | 1719 "Host: www.google.com\r\n" |
1722 "Proxy-Connection: keep-alive\r\n" | 1720 "Proxy-Connection: keep-alive\r\n" |
1723 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | 1721 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), |
1724 | 1722 |
1725 MockWrite("GET / HTTP/1.1\r\n" | 1723 MockWrite("GET / HTTP/1.1\r\n" |
1726 "Host: www.google.com\r\n" | 1724 "Host: www.google.com\r\n" |
1727 "Connection: keep-alive\r\n\r\n"), | 1725 "Connection: keep-alive\r\n\r\n"), |
1728 }; | 1726 }; |
1729 | 1727 |
1730 // The proxy responds to the connect with a 407, using a persistent | 1728 // The proxy responds to the connect with a 407, using a persistent |
1731 // connection. | 1729 // connection. |
1732 MockRead data_reads1[] = { | 1730 MockRead data_reads1[] = { |
1733 // No credentials. | 1731 // No credentials. |
1734 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | 1732 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), |
1735 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | 1733 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), |
1736 MockRead("Proxy-Connection: close\r\n\r\n"), | 1734 MockRead("Proxy-Connection: close\r\n\r\n"), |
1737 }; | |
1738 | 1735 |
1739 MockRead data_reads2[] = { | |
1740 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | 1736 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), |
1741 | 1737 |
1742 MockRead("HTTP/1.1 200 OK\r\n"), | 1738 MockRead("HTTP/1.1 200 OK\r\n"), |
1743 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | 1739 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), |
1744 MockRead("Content-Length: 5\r\n\r\n"), | 1740 MockRead("Content-Length: 5\r\n\r\n"), |
1745 MockRead(false, "hello"), | 1741 MockRead(false, "hello"), |
1746 }; | 1742 }; |
1747 | 1743 |
1748 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | 1744 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
1749 data_writes1, arraysize(data_writes1)); | 1745 data_writes1, arraysize(data_writes1)); |
1750 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1751 data_writes2, arraysize(data_writes2)); | |
1752 session_deps.socket_factory.AddSocketDataProvider(&data1); | 1746 session_deps.socket_factory.AddSocketDataProvider(&data1); |
1753 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1754 SSLSocketDataProvider ssl(true, OK); | 1747 SSLSocketDataProvider ssl(true, OK); |
1755 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | 1748 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
1756 | 1749 |
1757 TestOldCompletionCallback callback1; | 1750 TestOldCompletionCallback callback1; |
1758 | 1751 |
1759 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | 1752 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |
1760 | 1753 |
1761 int rv = trans->Start(&request, &callback1, log.bound()); | 1754 int rv = trans->Start(&request, &callback1, log.bound()); |
1762 EXPECT_EQ(ERR_IO_PENDING, rv); | 1755 EXPECT_EQ(ERR_IO_PENDING, rv); |
1763 | 1756 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1956 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | 1949 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
1957 | 1950 |
1958 std::string response_data; | 1951 std::string response_data; |
1959 rv = ReadTransaction(trans.get(), &response_data); | 1952 rv = ReadTransaction(trans.get(), &response_data); |
1960 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | 1953 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); |
1961 | 1954 |
1962 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. | 1955 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. |
1963 session->CloseAllConnections(); | 1956 session->CloseAllConnections(); |
1964 } | 1957 } |
1965 | 1958 |
1966 // Test the request-challenge-retry sequence for basic auth, over a connection | |
1967 // that requires a restart when setting up an SSL tunnel. | |
1968 TEST_F(HttpNetworkTransactionTest, BasicAuthHttpsProxyNoKeepAlive) { | |
1969 HttpRequestInfo request; | |
1970 request.method = "GET"; | |
1971 request.url = GURL("https://www.google.com/"); | |
1972 // when the no authentication data flag is set. | |
1973 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
1974 | |
1975 // Configure against https proxy server "myproxy:70". | |
1976 SessionDependencies session_deps( | |
1977 ProxyService::CreateFixed("https://myproxy:70")); | |
1978 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
1979 session_deps.net_log = log.bound().net_log(); | |
1980 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1981 | |
1982 // Since we have proxy, should try to establish tunnel. | |
1983 MockWrite data_writes1[] = { | |
1984 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1985 "Host: www.google.com\r\n" | |
1986 "Proxy-Connection: keep-alive\r\n\r\n"), | |
1987 }; | |
1988 | |
1989 MockWrite data_writes2[] = { | |
1990 // After calling trans->RestartWithAuth(), this is the request we should | |
1991 // be issuing -- the final header line contains the credentials. | |
1992 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1993 "Host: www.google.com\r\n" | |
1994 "Proxy-Connection: keep-alive\r\n" | |
1995 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1996 | |
1997 MockWrite("GET / HTTP/1.1\r\n" | |
1998 "Host: www.google.com\r\n" | |
1999 "Connection: keep-alive\r\n\r\n"), | |
2000 }; | |
2001 | |
2002 // The proxy responds to the connect with a 407, using a persistent | |
2003 // connection. | |
2004 MockRead data_reads1[] = { | |
2005 // No credentials. | |
2006 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
2007 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2008 MockRead("Proxy-Connection: close\r\n\r\n"), | |
2009 }; | |
2010 | |
2011 MockRead data_reads2[] = { | |
2012 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
2013 | |
2014 MockRead("HTTP/1.1 200 OK\r\n"), | |
2015 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2016 MockRead("Content-Length: 5\r\n\r\n"), | |
2017 MockRead(false, "hello"), | |
2018 }; | |
2019 | |
2020 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2021 data_writes1, arraysize(data_writes1)); | |
2022 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
2023 data_writes2, arraysize(data_writes2)); | |
2024 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2025 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
2026 SSLSocketDataProvider proxy(true, OK); | |
2027 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); | |
2028 SSLSocketDataProvider proxy2(true, OK); | |
2029 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy2); | |
2030 SSLSocketDataProvider server(true, OK); | |
2031 session_deps.socket_factory.AddSSLSocketDataProvider(&server); | |
2032 | |
2033 TestOldCompletionCallback callback1; | |
2034 | |
2035 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2036 | |
2037 int rv = trans->Start(&request, &callback1, log.bound()); | |
2038 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2039 | |
2040 rv = callback1.WaitForResult(); | |
2041 EXPECT_EQ(OK, rv); | |
2042 net::CapturingNetLog::EntryList entries; | |
2043 log.GetEntries(&entries); | |
2044 size_t pos = ExpectLogContainsSomewhere( | |
2045 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
2046 NetLog::PHASE_NONE); | |
2047 ExpectLogContainsSomewhere( | |
2048 entries, pos, | |
2049 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
2050 NetLog::PHASE_NONE); | |
2051 | |
2052 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2053 ASSERT_TRUE(response != NULL); | |
2054 ASSERT_FALSE(response->headers == NULL); | |
2055 EXPECT_EQ(407, response->headers->response_code()); | |
2056 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2057 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2058 | |
2059 TestOldCompletionCallback callback2; | |
2060 | |
2061 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback2); | |
2062 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2063 | |
2064 rv = callback2.WaitForResult(); | |
2065 EXPECT_EQ(OK, rv); | |
2066 | |
2067 response = trans->GetResponseInfo(); | |
2068 ASSERT_TRUE(response != NULL); | |
2069 | |
2070 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2071 EXPECT_EQ(200, response->headers->response_code()); | |
2072 EXPECT_EQ(5, response->headers->GetContentLength()); | |
2073 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2074 | |
2075 // The password prompt info should not be set. | |
2076 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
2077 | |
2078 trans.reset(); | |
2079 session->CloseAllConnections(); | |
2080 } | |
2081 | |
2082 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
2083 // proxy connection, when setting up an SSL tunnel. | |
2084 TEST_F(HttpNetworkTransactionTest, BasicAuthHttpsProxyKeepAlive) { | |
2085 HttpRequestInfo request; | |
2086 request.method = "GET"; | |
2087 request.url = GURL("https://www.google.com/"); | |
2088 // Ensure that proxy authentication is attempted even | |
2089 // when the no authentication data flag is set. | |
2090 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
2091 | |
2092 // Configure against https proxy server "myproxy:70". | |
2093 SessionDependencies session_deps( | |
2094 ProxyService::CreateFixed("https://myproxy:70")); | |
2095 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2096 session_deps.net_log = log.bound().net_log(); | |
2097 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2098 | |
2099 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2100 | |
2101 // Since we have proxy, should try to establish tunnel. | |
2102 MockWrite data_writes1[] = { | |
2103 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
2104 "Host: www.google.com\r\n" | |
2105 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2106 | |
2107 // After calling trans->RestartWithAuth(), this is the request we should | |
2108 // be issuing -- the final header line contains the credentials. | |
2109 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
2110 "Host: www.google.com\r\n" | |
2111 "Proxy-Connection: keep-alive\r\n" | |
2112 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), | |
2113 }; | |
2114 | |
2115 // The proxy responds to the connect with a 407, using a persistent | |
2116 // connection. | |
2117 MockRead data_reads1[] = { | |
2118 // No credentials. | |
2119 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
2120 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2121 MockRead("Content-Length: 10\r\n\r\n"), | |
2122 MockRead("0123456789"), | |
2123 | |
2124 // Wrong credentials (wrong password). | |
2125 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
2126 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2127 MockRead("Content-Length: 10\r\n\r\n"), | |
2128 // No response body because the test stops reading here. | |
2129 MockRead(false, ERR_UNEXPECTED), // Should not be reached. | |
2130 }; | |
2131 | |
2132 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2133 data_writes1, arraysize(data_writes1)); | |
2134 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2135 SSLSocketDataProvider ssl(true, OK); | |
2136 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2137 | |
2138 TestOldCompletionCallback callback1; | |
2139 | |
2140 int rv = trans->Start(&request, &callback1, log.bound()); | |
2141 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2142 | |
2143 rv = callback1.WaitForResult(); | |
2144 EXPECT_EQ(OK, rv); | |
2145 net::CapturingNetLog::EntryList entries; | |
2146 log.GetEntries(&entries); | |
2147 size_t pos = ExpectLogContainsSomewhere( | |
2148 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
2149 NetLog::PHASE_NONE); | |
2150 ExpectLogContainsSomewhere( | |
2151 entries, pos, | |
2152 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
2153 NetLog::PHASE_NONE); | |
2154 | |
2155 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2156 ASSERT_TRUE(response != NULL); | |
2157 ASSERT_FALSE(response->headers == NULL); | |
2158 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2159 EXPECT_EQ(407, response->headers->response_code()); | |
2160 EXPECT_EQ(10, response->headers->GetContentLength()); | |
2161 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2162 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2163 | |
2164 TestOldCompletionCallback callback2; | |
2165 | |
2166 // Wrong password (should be "bar"). | |
2167 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz), &callback2); | |
2168 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2169 | |
2170 rv = callback2.WaitForResult(); | |
2171 EXPECT_EQ(OK, rv); | |
2172 | |
2173 response = trans->GetResponseInfo(); | |
2174 ASSERT_TRUE(response != NULL); | |
2175 ASSERT_FALSE(response->headers == NULL); | |
2176 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2177 EXPECT_EQ(407, response->headers->response_code()); | |
2178 EXPECT_EQ(10, response->headers->GetContentLength()); | |
2179 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2180 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2181 | |
2182 // Flush the idle socket before the NetLog and HttpNetworkTransaction go | |
2183 // out of scope. | |
2184 session->CloseAllConnections(); | |
2185 } | |
2186 | |
2187 // Test the request-challenge-retry sequence for basic auth, through | |
2188 // a SPDY proxy over a single SPDY session. | |
2189 TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { | |
2190 HttpRequestInfo request; | |
2191 request.method = "GET"; | |
2192 request.url = GURL("https://www.google.com/"); | |
2193 // when the no authentication data flag is set. | |
2194 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
2195 | |
2196 // Configure against https proxy server "myproxy:70". | |
2197 SessionDependencies session_deps( | |
2198 ProxyService::CreateFixed("https://myproxy:70")); | |
2199 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2200 session_deps.net_log = log.bound().net_log(); | |
2201 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2202 | |
2203 // Since we have proxy, should try to establish tunnel. | |
2204 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); | |
2205 scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
2206 | |
2207 // After calling trans->RestartWithAuth(), this is the request we should | |
2208 // be issuing -- the final header line contains the credentials. | |
2209 const char* const kAuthCredentials[] = { | |
2210 "proxy-authorization", "Basic Zm9vOmJhcg==", | |
2211 }; | |
2212 scoped_ptr<spdy::SpdyFrame> connect2( | |
2213 ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); | |
2214 // fetch https://www.google.com/ via HTTP | |
2215 const char get[] = "GET / HTTP/1.1\r\n" | |
2216 "Host: www.google.com\r\n" | |
2217 "Connection: keep-alive\r\n\r\n"; | |
2218 scoped_ptr<spdy::SpdyFrame> wrapped_get( | |
2219 ConstructSpdyBodyFrame(3, get, strlen(get), false)); | |
2220 | |
2221 MockWrite spdy_writes[] = { | |
2222 CreateMockWrite(*req, 0, true), | |
2223 CreateMockWrite(*rst, 2, true), | |
2224 CreateMockWrite(*connect2, 3), | |
2225 CreateMockWrite(*wrapped_get, 5) | |
2226 }; | |
2227 | |
2228 // The proxy responds to the connect with a 407, using a persistent | |
2229 // connection. | |
2230 const char* const kAuthChallenge[] = { | |
2231 "status", "407 Proxy Authentication Required", | |
2232 "version", "HTTP/1.1", | |
2233 "proxy-authenticate", "Basic realm=\"MyRealm1\"", | |
2234 }; | |
2235 | |
2236 scoped_ptr<spdy::SpdyFrame> conn_auth_resp( | |
2237 ConstructSpdyControlFrame(NULL, | |
2238 0, | |
2239 false, | |
2240 1, | |
2241 LOWEST, | |
2242 spdy::SYN_REPLY, | |
2243 spdy::CONTROL_FLAG_NONE, | |
2244 kAuthChallenge, | |
2245 arraysize(kAuthChallenge))); | |
2246 | |
2247 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
2248 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
2249 "Content-Length: 5\r\n\r\n"; | |
2250 | |
2251 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
2252 ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); | |
2253 scoped_ptr<spdy::SpdyFrame> wrapped_body( | |
2254 ConstructSpdyBodyFrame(3, "hello", 5, false)); | |
2255 MockRead spdy_reads[] = { | |
2256 CreateMockRead(*conn_auth_resp, 1, true), | |
2257 CreateMockRead(*conn_resp, 4, true), | |
2258 CreateMockRead(*wrapped_get_resp, 5, true), | |
2259 CreateMockRead(*wrapped_body, 6, true), | |
2260 MockRead(false, ERR_IO_PENDING), | |
2261 }; | |
2262 | |
2263 scoped_refptr<OrderedSocketData> spdy_data( | |
2264 new OrderedSocketData( | |
2265 spdy_reads, arraysize(spdy_reads), | |
2266 spdy_writes, arraysize(spdy_writes))); | |
2267 session_deps.socket_factory.AddSocketDataProvider(spdy_data); | |
2268 // Negotiate SPDY to the proxy | |
2269 SSLSocketDataProvider proxy(true, OK); | |
2270 proxy.next_proto_status = SSLClientSocket::kNextProtoNegotiated; | |
2271 proxy.next_proto = "spdy/2"; | |
2272 proxy.was_npn_negotiated = true; | |
2273 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); | |
2274 // Vanilla SSL to the server | |
2275 SSLSocketDataProvider server(true, OK); | |
2276 session_deps.socket_factory.AddSSLSocketDataProvider(&server); | |
2277 | |
2278 TestOldCompletionCallback callback1; | |
2279 | |
2280 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2281 | |
2282 int rv = trans->Start(&request, &callback1, log.bound()); | |
2283 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2284 | |
2285 rv = callback1.WaitForResult(); | |
2286 EXPECT_EQ(OK, rv); | |
2287 net::CapturingNetLog::EntryList entries; | |
2288 log.GetEntries(&entries); | |
2289 size_t pos = ExpectLogContainsSomewhere( | |
2290 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
2291 NetLog::PHASE_NONE); | |
2292 ExpectLogContainsSomewhere( | |
2293 entries, pos, | |
2294 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
2295 NetLog::PHASE_NONE); | |
2296 | |
2297 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2298 ASSERT_TRUE(response != NULL); | |
2299 ASSERT_FALSE(response->headers == NULL); | |
2300 EXPECT_EQ(407, response->headers->response_code()); | |
2301 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2302 EXPECT_TRUE(response->auth_challenge.get() != NULL); | |
2303 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2304 | |
2305 TestOldCompletionCallback callback2; | |
2306 | |
2307 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback2); | |
2308 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2309 | |
2310 rv = callback2.WaitForResult(); | |
2311 EXPECT_EQ(OK, rv); | |
2312 | |
2313 response = trans->GetResponseInfo(); | |
2314 ASSERT_TRUE(response != NULL); | |
2315 | |
2316 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2317 EXPECT_EQ(200, response->headers->response_code()); | |
2318 EXPECT_EQ(5, response->headers->GetContentLength()); | |
2319 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2320 | |
2321 // The password prompt info should not be set. | |
2322 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
2323 | |
2324 trans.reset(); | |
2325 session->CloseAllConnections(); | |
2326 } | |
2327 | |
2328 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). | 1959 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). |
2329 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. | 1960 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. |
2330 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { | 1961 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { |
2331 HttpRequestInfo request; | 1962 HttpRequestInfo request; |
2332 request.method = "GET"; | 1963 request.method = "GET"; |
2333 request.url = GURL("http://www.google.com/"); | 1964 request.url = GURL("http://www.google.com/"); |
2334 request.load_flags = 0; | 1965 request.load_flags = 0; |
2335 | 1966 |
2336 // We are using a DIRECT connection (i.e. no proxy) for this session. | 1967 // We are using a DIRECT connection (i.e. no proxy) for this session. |
2337 SessionDependencies session_deps; | 1968 SessionDependencies session_deps; |
(...skipping 5384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7722 } | 7353 } |
7723 | 7354 |
7724 // GenerateAuthToken is a mighty big test. | 7355 // GenerateAuthToken is a mighty big test. |
7725 // It tests all permutation of GenerateAuthToken behavior: | 7356 // It tests all permutation of GenerateAuthToken behavior: |
7726 // - Synchronous and Asynchronous completion. | 7357 // - Synchronous and Asynchronous completion. |
7727 // - OK or error on completion. | 7358 // - OK or error on completion. |
7728 // - Direct connection, non-authenticating proxy, and authenticating proxy. | 7359 // - Direct connection, non-authenticating proxy, and authenticating proxy. |
7729 // - HTTP or HTTPS backend (to include proxy tunneling). | 7360 // - HTTP or HTTPS backend (to include proxy tunneling). |
7730 // - Non-authenticating and authenticating backend. | 7361 // - Non-authenticating and authenticating backend. |
7731 // | 7362 // |
7732 // In all, there are 44 reasonable permutations (for example, if there are | 7363 // In all, there are 44 reasonable permuations (for example, if there are |
7733 // problems generating an auth token for an authenticating proxy, we don't | 7364 // problems generating an auth token for an authenticating proxy, we don't |
7734 // need to test all permutations of the backend server). | 7365 // need to test all permutations of the backend server). |
7735 // | 7366 // |
7736 // The test proceeds by going over each of the configuration cases, and | 7367 // The test proceeds by going over each of the configuration cases, and |
7737 // potentially running up to three rounds in each of the tests. The TestConfig | 7368 // potentially running up to three rounds in each of the tests. The TestConfig |
7738 // specifies both the configuration for the test as well as the expectations | 7369 // specifies both the configuration for the test as well as the expectations |
7739 // for the results. | 7370 // for the results. |
7740 TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { | 7371 TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { |
7741 static const char kServer[] = "http://www.example.com"; | 7372 static const char kServer[] = "http://www.example.com"; |
7742 static const char kSecureServer[] = "https://www.example.com"; | 7373 static const char kSecureServer[] = "https://www.example.com"; |
(...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8543 // This test ensures that the URL passed into the proxy is upgraded | 8174 // This test ensures that the URL passed into the proxy is upgraded |
8544 // to https when doing an Alternate Protocol upgrade. | 8175 // to https when doing an Alternate Protocol upgrade. |
8545 HttpStreamFactory::set_use_alternate_protocols(true); | 8176 HttpStreamFactory::set_use_alternate_protocols(true); |
8546 HttpStreamFactory::set_next_protos( | 8177 HttpStreamFactory::set_next_protos( |
8547 MakeNextProtos( | 8178 MakeNextProtos( |
8548 "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL)); | 8179 "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL)); |
8549 | 8180 |
8550 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | 8181 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); |
8551 HttpAuthHandlerMock::Factory* auth_factory = | 8182 HttpAuthHandlerMock::Factory* auth_factory = |
8552 new HttpAuthHandlerMock::Factory(); | 8183 new HttpAuthHandlerMock::Factory(); |
8553 HttpAuthHandlerMock* auth_handler1 = new HttpAuthHandlerMock(); | 8184 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); |
8554 auth_factory->AddMockHandler(auth_handler1, HttpAuth::AUTH_PROXY); | 8185 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); |
8555 HttpAuthHandlerMock* auth_handler2 = new HttpAuthHandlerMock(); | |
8556 auth_factory->AddMockHandler(auth_handler2, HttpAuth::AUTH_PROXY); | |
8557 auth_factory->set_do_init_from_challenge(true); | 8186 auth_factory->set_do_init_from_challenge(true); |
8558 session_deps.http_auth_handler_factory.reset(auth_factory); | 8187 session_deps.http_auth_handler_factory.reset(auth_factory); |
8559 | 8188 |
8560 HttpRequestInfo request; | 8189 HttpRequestInfo request; |
8561 request.method = "GET"; | 8190 request.method = "GET"; |
8562 request.url = GURL("http://www.google.com"); | 8191 request.url = GURL("http://www.google.com"); |
8563 request.load_flags = 0; | 8192 request.load_flags = 0; |
8564 | 8193 |
8565 // First round goes unauthenticated through the proxy. | 8194 // First round goes unauthenticated through the proxy. |
8566 MockWrite data_writes_1[] = { | 8195 MockWrite data_writes_1[] = { |
(...skipping 11 matching lines...) Expand all Loading... |
8578 }; | 8207 }; |
8579 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), | 8208 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), |
8580 data_writes_1, arraysize(data_writes_1)); | 8209 data_writes_1, arraysize(data_writes_1)); |
8581 | 8210 |
8582 // Second round tries to tunnel to www.google.com due to the | 8211 // Second round tries to tunnel to www.google.com due to the |
8583 // Alternate-Protocol announcement in the first round. It fails due | 8212 // Alternate-Protocol announcement in the first round. It fails due |
8584 // to a proxy authentication challenge. | 8213 // to a proxy authentication challenge. |
8585 // After the failure, a tunnel is established to www.google.com using | 8214 // After the failure, a tunnel is established to www.google.com using |
8586 // Proxy-Authorization headers. There is then a SPDY request round. | 8215 // Proxy-Authorization headers. There is then a SPDY request round. |
8587 // | 8216 // |
| 8217 // NOTE: Despite the "Proxy-Connection: Close", these are done on the |
| 8218 // same MockTCPClientSocket since the underlying HttpNetworkClientSocket |
| 8219 // does a Disconnect and Connect on the same socket, rather than trying |
| 8220 // to obtain a new one. |
| 8221 // |
8588 // NOTE: Originally, the proxy response to the second CONNECT request | 8222 // NOTE: Originally, the proxy response to the second CONNECT request |
8589 // simply returned another 407 so the unit test could skip the SSL connection | 8223 // simply returned another 407 so the unit test could skip the SSL connection |
8590 // establishment and SPDY framing issues. Alas, the | 8224 // establishment and SPDY framing issues. Alas, the |
8591 // retry-http-when-alternate-protocol fails logic kicks in, which was more | 8225 // retry-http-when-alternate-protocol fails logic kicks in, which was more |
8592 // complicated to set up expectations for than the SPDY session. | 8226 // complicated to set up expectations for than the SPDY session. |
8593 | 8227 |
8594 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | 8228 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); |
8595 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | 8229 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); |
8596 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | 8230 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); |
8597 | 8231 |
8598 MockWrite data_writes_2[] = { | 8232 MockWrite data_writes_2[] = { |
8599 // First connection attempt without Proxy-Authorization. | 8233 // First connection attempt without Proxy-Authorization. |
8600 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | 8234 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
8601 "Host: www.google.com\r\n" | 8235 "Host: www.google.com\r\n" |
8602 "Proxy-Connection: keep-alive\r\n" | 8236 "Proxy-Connection: keep-alive\r\n" |
8603 "\r\n"), | 8237 "\r\n"), |
8604 }; | |
8605 | 8238 |
8606 MockWrite data_writes_3[] = { | |
8607 // Non-alternate protocol job that will run in parallel | |
8608 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
8609 "Host: www.google.com\r\n" | |
8610 "Proxy-Connection: keep-alive\r\n" | |
8611 "\r\n"), | |
8612 }; | |
8613 | |
8614 MockWrite data_writes_4[] = { | |
8615 // Second connection attempt with Proxy-Authorization. | 8239 // Second connection attempt with Proxy-Authorization. |
8616 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | 8240 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
8617 "Host: www.google.com\r\n" | 8241 "Host: www.google.com\r\n" |
8618 "Proxy-Connection: keep-alive\r\n" | 8242 "Proxy-Connection: keep-alive\r\n" |
8619 "Proxy-Authorization: auth_token\r\n" | 8243 "Proxy-Authorization: auth_token\r\n" |
8620 "\r\n"), | 8244 "\r\n"), |
8621 | 8245 |
8622 // SPDY request | 8246 // SPDY request |
8623 CreateMockWrite(*req), | 8247 CreateMockWrite(*req), |
8624 }; | 8248 }; |
8625 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" | 8249 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" |
8626 "Proxy-Authenticate: Mock\r\n" | 8250 "Proxy-Authenticate: Mock\r\n" |
8627 "Proxy-Connection: close\r\n" | 8251 "Proxy-Connection: close\r\n" |
8628 "Content-Length: 0\r\n" | |
8629 "\r\n"); | 8252 "\r\n"); |
8630 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | 8253 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; |
8631 MockRead data_reads_2[] = { | 8254 MockRead data_reads_2[] = { |
8632 // First connection attempt fails | 8255 // First connection attempt fails |
8633 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), | 8256 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), |
8634 MockRead(true, kRejectConnectResponse, | 8257 MockRead(true, kRejectConnectResponse, |
8635 arraysize(kRejectConnectResponse) - 1, 1), | 8258 arraysize(kRejectConnectResponse) - 1, 1), |
8636 }; | |
8637 | 8259 |
8638 // Hang forever so we can ensure the alt job wins | |
8639 MockRead data_reads_3[] = { | |
8640 MockRead(false, ERR_IO_PENDING), | |
8641 }; | |
8642 | |
8643 MockRead data_reads_4[] = { | |
8644 // Second connection attempt passes | 8260 // Second connection attempt passes |
8645 MockRead(true, kAcceptConnectResponse, | 8261 MockRead(true, kAcceptConnectResponse, |
8646 arraysize(kAcceptConnectResponse) -1, 1), | 8262 arraysize(kAcceptConnectResponse) -1, 4), |
8647 | 8263 |
8648 // SPDY response | 8264 // SPDY response |
8649 CreateMockRead(*resp.get(), 3), | 8265 CreateMockRead(*resp.get(), 6), |
8650 CreateMockRead(*data.get(), 3), | 8266 CreateMockRead(*data.get(), 6), |
8651 MockRead(true, 0, 0, 4), | 8267 MockRead(true, 0, 0, 6), |
8652 }; | 8268 }; |
8653 scoped_refptr<OrderedSocketData> data_2( | 8269 scoped_refptr<OrderedSocketData> data_2( |
8654 new OrderedSocketData(data_reads_2, arraysize(data_reads_2), | 8270 new OrderedSocketData(data_reads_2, arraysize(data_reads_2), |
8655 data_writes_2, arraysize(data_writes_2))); | 8271 data_writes_2, arraysize(data_writes_2))); |
8656 scoped_refptr<OrderedSocketData> data_3( | |
8657 new OrderedSocketData(data_reads_3, arraysize(data_reads_3), | |
8658 data_writes_3, arraysize(data_writes_3))); | |
8659 // Hang forever so we can ensure the alt job wins | |
8660 MockConnect conn_3(false, ERR_IO_PENDING); | |
8661 data_3->set_connect_data(conn_3); | |
8662 scoped_refptr<OrderedSocketData> data_4( | |
8663 new OrderedSocketData(data_reads_4, arraysize(data_reads_4), | |
8664 data_writes_4, arraysize(data_writes_4))); | |
8665 | 8272 |
8666 SSLSocketDataProvider ssl(true, OK); | 8273 SSLSocketDataProvider ssl(true, OK); |
8667 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; | 8274 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; |
8668 ssl.next_proto = "spdy/2"; | 8275 ssl.next_proto = "spdy/2"; |
8669 ssl.was_npn_negotiated = true; | 8276 ssl.was_npn_negotiated = true; |
8670 | 8277 |
8671 MockConnect never_finishing_connect(false, ERR_IO_PENDING); | 8278 MockConnect never_finishing_connect(false, ERR_IO_PENDING); |
8672 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | 8279 StaticSocketDataProvider hanging_non_alternate_protocol_socket( |
8673 NULL, 0, NULL, 0); | 8280 NULL, 0, NULL, 0); |
8674 hanging_non_alternate_protocol_socket.set_connect_data( | 8281 hanging_non_alternate_protocol_socket.set_connect_data( |
8675 never_finishing_connect); | 8282 never_finishing_connect); |
8676 | 8283 |
8677 session_deps.socket_factory.AddSocketDataProvider(&data_1); | 8284 session_deps.socket_factory.AddSocketDataProvider(&data_1); |
8678 session_deps.socket_factory.AddSocketDataProvider(data_2.get()); | 8285 session_deps.socket_factory.AddSocketDataProvider(data_2.get()); |
8679 session_deps.socket_factory.AddSocketDataProvider(data_3.get()); | |
8680 session_deps.socket_factory.AddSocketDataProvider(data_4.get()); | |
8681 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8682 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | 8286 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
8683 session_deps.socket_factory.AddSocketDataProvider( | 8287 session_deps.socket_factory.AddSocketDataProvider( |
8684 &hanging_non_alternate_protocol_socket); | 8288 &hanging_non_alternate_protocol_socket); |
8685 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | 8289 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
8686 | 8290 |
8687 // First round should work and provide the Alternate-Protocol state. | 8291 // First round should work and provide the Alternate-Protocol state. |
8688 TestOldCompletionCallback callback_1; | 8292 TestOldCompletionCallback callback_1; |
8689 scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session)); | 8293 scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session)); |
8690 int rv = trans_1->Start(&request, &callback_1, BoundNetLog()); | 8294 int rv = trans_1->Start(&request, &callback_1, BoundNetLog()); |
8691 EXPECT_EQ(ERR_IO_PENDING, rv); | 8295 EXPECT_EQ(ERR_IO_PENDING, rv); |
(...skipping 10 matching lines...) Expand all Loading... |
8702 ASSERT_FALSE(response->auth_challenge.get() == NULL); | 8306 ASSERT_FALSE(response->auth_challenge.get() == NULL); |
8703 | 8307 |
8704 // Restart with auth. Tunnel should work and response received. | 8308 // Restart with auth. Tunnel should work and response received. |
8705 TestOldCompletionCallback callback_3; | 8309 TestOldCompletionCallback callback_3; |
8706 rv = trans_2->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback_3); | 8310 rv = trans_2->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback_3); |
8707 EXPECT_EQ(ERR_IO_PENDING, rv); | 8311 EXPECT_EQ(ERR_IO_PENDING, rv); |
8708 EXPECT_EQ(OK, callback_3.WaitForResult()); | 8312 EXPECT_EQ(OK, callback_3.WaitForResult()); |
8709 | 8313 |
8710 // After all that work, these two lines (or actually, just the scheme) are | 8314 // After all that work, these two lines (or actually, just the scheme) are |
8711 // what this test is all about. Make sure it happens correctly. | 8315 // what this test is all about. Make sure it happens correctly. |
8712 const GURL& request_url = auth_handler2->request_url(); | 8316 const GURL& request_url = auth_handler->request_url(); |
8713 EXPECT_EQ("https", request_url.scheme()); | 8317 EXPECT_EQ("https", request_url.scheme()); |
8714 EXPECT_EQ("www.google.com", request_url.host()); | 8318 EXPECT_EQ("www.google.com", request_url.host()); |
8715 | 8319 |
8716 HttpStreamFactory::set_next_protos(std::vector<std::string>()); | 8320 HttpStreamFactory::set_next_protos(std::vector<std::string>()); |
8717 HttpStreamFactory::set_use_alternate_protocols(false); | 8321 HttpStreamFactory::set_use_alternate_protocols(false); |
8718 } | 8322 } |
8719 | 8323 |
8720 // Test that if we cancel the transaction as the connection is completing, that | 8324 // Test that if we cancel the transaction as the connection is completing, that |
8721 // everything tears down correctly. | 8325 // everything tears down correctly. |
8722 TEST_F(HttpNetworkTransactionTest, SimpleCancel) { | 8326 TEST_F(HttpNetworkTransactionTest, SimpleCancel) { |
(...skipping 1124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9847 session->spdy_session_pool()->HasSession(host_port_proxy_pair_b)); | 9451 session->spdy_session_pool()->HasSession(host_port_proxy_pair_b)); |
9848 | 9452 |
9849 HttpStreamFactory::set_next_protos(std::vector<std::string>()); | 9453 HttpStreamFactory::set_next_protos(std::vector<std::string>()); |
9850 ClientSocketPoolManager::set_max_sockets_per_pool(old_max_sockets_per_pool); | 9454 ClientSocketPoolManager::set_max_sockets_per_pool(old_max_sockets_per_pool); |
9851 ClientSocketPoolManager::set_max_sockets_per_proxy_server( | 9455 ClientSocketPoolManager::set_max_sockets_per_proxy_server( |
9852 old_max_sockets_per_proxy_server); | 9456 old_max_sockets_per_proxy_server); |
9853 ClientSocketPoolManager::set_max_sockets_per_group(old_max_sockets_per_group); | 9457 ClientSocketPoolManager::set_max_sockets_per_group(old_max_sockets_per_group); |
9854 } | 9458 } |
9855 | 9459 |
9856 } // namespace net | 9460 } // namespace net |
OLD | NEW |