3 Copyright (c) 2008, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
34 #include "libtorrent/socket.hpp"
35 #include "libtorrent/connection_queue.hpp"
36 #include "libtorrent/http_connection.hpp"
37 #include "setup_transfer.hpp"
40 #include <boost/optional.hpp>
42 using namespace libtorrent
;
45 connection_queue
cq(ios
);
47 int connect_handler_called
= 0;
48 int handler_called
= 0;
51 error_code g_error_code
;
52 char data_buffer
[4000];
54 void print_http_header(http_parser
const& p
)
56 std::cerr
<< " < " << p
.status_code() << " " << p
.message() << std::endl
;
58 for (std::map
<std::string
, std::string
>::const_iterator i
59 = p
.headers().begin(), end(p
.headers().end()); i
!= end
; ++i
)
61 std::cerr
<< " < " << i
->first
<< ": " << i
->second
<< std::endl
;
65 void http_connect_handler(http_connection
& c
)
67 ++connect_handler_called
;
68 TEST_CHECK(c
.socket().is_open());
69 std::cerr
<< "connected to: " << c
.socket().remote_endpoint() << std::endl
;
70 TEST_CHECK(c
.socket().remote_endpoint().address() == address::from_string("127.0.0.1"));
73 void http_handler(error_code
const& ec
, http_parser
const& parser
74 , char const* data
, int size
, http_connection
& c
)
80 if (parser
.header_finished())
82 http_status
= parser
.status_code();
83 if (http_status
== 200)
85 TEST_CHECK(memcmp(data
, data_buffer
, size
) == 0);
88 print_http_header(parser
);
95 connect_handler_called
= 0;
99 g_error_code
= error_code();
102 void run_test(std::string
const& url
, int size
, int status
, int connected
103 , boost::optional
<error_code
> ec
, proxy_settings
const& ps
)
107 std::cerr
<< " ===== TESTING: " << url
<< " =====" << std::endl
;
109 boost::shared_ptr
<http_connection
> h(new http_connection(ios
, cq
110 , &::http_handler
, true, &::http_connect_handler
));
111 h
->get(url
, seconds(5), 0, &ps
);
115 std::cerr
<< "connect_handler_called: " << connect_handler_called
<< std::endl
;
116 std::cerr
<< "handler_called: " << handler_called
<< std::endl
;
117 std::cerr
<< "status: " << http_status
<< std::endl
;
118 std::cerr
<< "size: " << data_size
<< std::endl
;
119 std::cerr
<< "error_code: " << g_error_code
.message() << std::endl
;
120 TEST_CHECK(connect_handler_called
== connected
);
121 TEST_CHECK(handler_called
== 1);
122 TEST_CHECK(data_size
== size
|| size
== -1);
123 TEST_CHECK(!ec
|| g_error_code
== *ec
);
124 TEST_CHECK(http_status
== status
|| status
== -1);
127 void run_suite(std::string
const& protocol
, proxy_settings
const& ps
)
129 if (ps
.type
!= proxy_settings::none
)
131 start_proxy(ps
.port
, ps
.type
);
133 char const* test_name
[] = {"no", "SOCKS4", "SOCKS5"
134 , "SOCKS5 password protected", "HTTP", "HTTP password protected"};
135 std::cout
<< "\n\n********************** using " << test_name
[ps
.type
]
136 << " proxy **********************\n" << std::endl
;
138 typedef boost::optional
<error_code
> err
;
139 // this requires the hosts file to be modified
140 // run_test(protocol + "://test.dns.ts:8001/test_file", 3216, 200, 1, error_code(), ps);
142 run_test(protocol
+ "://127.0.0.1:8001/relative/redirect", 3216, 200, 2, error_code(), ps
);
143 run_test(protocol
+ "://127.0.0.1:8001/redirect", 3216, 200, 2, error_code(), ps
);
144 run_test(protocol
+ "://127.0.0.1:8001/infinite_redirect", 0, 301, 6, error_code(), ps
);
145 run_test(protocol
+ "://127.0.0.1:8001/test_file", 3216, 200, 1, error_code(), ps
);
146 run_test(protocol
+ "://127.0.0.1:8001/test_file.gz", 3216, 200, 1, error_code(), ps
);
147 run_test(protocol
+ "://127.0.0.1:8001/non-existing-file", -1, 404, 1, err(), ps
);
148 // if we're going through an http proxy, we won't get the same error as if the hostname
150 if ((ps
.type
== proxy_settings::http
|| ps
.type
== proxy_settings::http_pw
) && protocol
!= "https")
151 run_test(protocol
+ "://non-existent-domain.se/non-existing-file", -1, 502, 1, err(), ps
);
153 run_test(protocol
+ "://non-existent-domain.se/non-existing-file", -1, -1, 0, err(), ps
);
155 if (ps
.type
!= proxy_settings::none
)
161 std::srand(std::time(0));
162 std::generate(data_buffer
, data_buffer
+ sizeof(data_buffer
), &std::rand
);
163 std::ofstream("test_file").write(data_buffer
, 3216);
164 std::system("gzip -9 -c test_file > test_file.gz");
167 ps
.hostname
= "127.0.0.1";
169 ps
.username
= "testuser";
170 ps
.password
= "testpass";
172 start_web_server(8001);
173 for (int i
= 0; i
< 5; ++i
)
175 ps
.type
= (proxy_settings::proxy_type
)i
;
176 run_suite("http", ps
);
178 stop_web_server(8001);
180 #ifdef TORRENT_USE_OPENSSL
181 start_web_server(8001, true);
182 for (int i
= 0; i
< 5; ++i
)
184 ps
.type
= (proxy_settings::proxy_type
)i
;
185 run_suite("https", ps
);
187 stop_web_server(8001);
190 std::remove("test_file");