blob: 897c9846d69d52b74880c19b039151e4a227cdff [file] [log] [blame]
// Copyright 2007-2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
// Since the net code is linked in as a lib, force the registration code to
// be a dependency, otherwise the linker is optimizing in out.
#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")
#include <vector>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "omaha/common/omaha_version.h"
#include "omaha/net/http_client.h"
#include "omaha/testing/unit_test.h"
namespace omaha {
// Test fixture, perhaps we need it later.
class HttpClientTest : public testing::Test {
protected:
HttpClientTest() {}
static void SetUpTestCase() {}
virtual void SetUp() {
http_client_.reset(
HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP));
ASSERT_TRUE(http_client_.get());
ASSERT_SUCCEEDED(http_client_->Initialize());
}
virtual void TearDown() {
http_client_.reset();
}
void GetUrl(const TCHAR* url, bool use_proxy);
scoped_ptr<HttpClient> http_client_;
};
CString BuildUserAgent() {
CString user_agent;
user_agent.Format(_T("HttpClientTest version %s"), omaha::GetVersionString());
return user_agent;
}
const TCHAR kTestUrlGet[] = _T("http://www.google.com/robots.txt");
const TCHAR kTestSecureUrlGet[] = _T("https://www.google.com/robots.txt");
// If using a proxy is specified, the function does WPAD detection to get the
// name of the proxy to be used. The request goes direct if the WPAD fails.
void HttpClientTest::GetUrl(const TCHAR* url, bool use_proxy) {
ASSERT_TRUE(url);
CString server, path;
int port = 0;
ASSERT_SUCCEEDED(http_client_->CrackUrl(url,
ICU_DECODE,
NULL,
&server,
&port,
&path,
NULL));
ASSERT_STREQ(server, _T("www.google.com"));
ASSERT_STREQ(path, _T("/robots.txt"));
HINTERNET session_handle = NULL;
ASSERT_SUCCEEDED(http_client_->Open(BuildUserAgent(),
HttpClient::kAccessTypeNoProxy,
NULL,
NULL,
&session_handle));
if (use_proxy) {
HttpClient::AutoProxyOptions autoproxy_options = {0};
autoproxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;
autoproxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
WINHTTP_AUTO_DETECT_TYPE_DNS_A;
autoproxy_options.auto_logon_if_challenged = true;
HttpClient::ProxyInfo proxy_info = {0};
http_client_->GetProxyForUrl(session_handle,
url,
&autoproxy_options,
&proxy_info);
if (proxy_info.proxy && wcslen(proxy_info.proxy)) {
proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
EXPECT_SUCCEEDED(http_client_->SetOption(session_handle,
WINHTTP_OPTION_PROXY,
&proxy_info,
sizeof(proxy_info)));
}
::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
}
HINTERNET connection_handle = NULL;
ASSERT_SUCCEEDED(http_client_->Connect(session_handle,
server,
port,
&connection_handle));
uint32 flags = port == 443 ? WINHTTP_FLAG_SECURE : 0;
HINTERNET request_handle = NULL;
ASSERT_SUCCEEDED(http_client_->OpenRequest(connection_handle,
_T("GET"),
path,
NULL, // HTTP 1.1
NULL, // Referrer.
NULL, // Default accept types.
flags,
&request_handle));
ASSERT_SUCCEEDED(http_client_->SendRequest(request_handle,
NULL, 0, NULL, 0, 0));
ASSERT_SUCCEEDED(http_client_->ReceiveResponse(request_handle));
CString content_type;
EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,
WINHTTP_QUERY_CONTENT_TYPE,
NULL,
&content_type,
NULL));
EXPECT_STREQ(content_type, _T("text/plain"));
CString server_header;
EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,
WINHTTP_QUERY_SERVER,
NULL,
&server_header,
NULL));
CString response;
DWORD size = 0;
do {
// Use ReadData to determine when a response has been completely read.
// Always allocate a buffer for ReadData even though QueryDataAvailable
// might return 0 bytes available.
ASSERT_SUCCEEDED(http_client_->QueryDataAvailable(request_handle, &size));
std::vector<uint8> buf(size + 1);
ASSERT_SUCCEEDED(http_client_->ReadData(request_handle,
&buf.front(),
buf.size(),
&size));
buf.resize(size);
if (size) {
response += CString(reinterpret_cast<char*>(&buf.front()), buf.size());
}
} while (size > 0);
// Compare a little bit of the body.
response.Truncate(10);
ASSERT_STREQ(response, _T("User-agent"));
ASSERT_SUCCEEDED(http_client_->Close(request_handle));
ASSERT_SUCCEEDED(http_client_->Close(connection_handle));
ASSERT_SUCCEEDED(http_client_->Close(session_handle));
}
TEST_F(HttpClientTest, Get) {
GetUrl(kTestUrlGet, false);
}
TEST_F(HttpClientTest, SecureGet) {
GetUrl(kTestSecureUrlGet, false);
}
TEST_F(HttpClientTest, ProxyGet) {
GetUrl(kTestUrlGet, true);
}
TEST_F(HttpClientTest, ProxySecureGet) {
GetUrl(kTestSecureUrlGet, true);
}
TEST_F(HttpClientTest, BuildRequestHeader) {
ASSERT_STREQ(HttpClient::BuildRequestHeader(_T("foo"), _T("bar")),
_T("foo: bar\r\n"));
}
TEST_F(HttpClientTest, GetStatusCodeClass) {
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_CONTINUE),
HttpClient::STATUS_CODE_INFORMATIONAL);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_OK),
HttpClient::STATUS_CODE_SUCCESSFUL);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_PARTIAL_CONTENT),
HttpClient::STATUS_CODE_SUCCESSFUL);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_AMBIGUOUS),
HttpClient::STATUS_CODE_REDIRECTION);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_REDIRECT),
HttpClient::STATUS_CODE_REDIRECTION);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_BAD_REQUEST),
HttpClient::STATUS_CODE_CLIENT_ERROR);
EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_SERVICE_UNAVAIL),
HttpClient::STATUS_CODE_SERVER_ERROR);
}
TEST_F(HttpClientTest, CrackUrl) {
CString scheme, server, path, query;
int port = 0;
ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host/path?query"),
0,
&scheme,
&server,
&port,
&path,
&query));
ASSERT_STREQ(scheme, _T("http"));
ASSERT_STREQ(server, _T("host"));
ASSERT_EQ(port, INTERNET_DEFAULT_HTTP_PORT);
ASSERT_STREQ(path, _T("/path"));
ASSERT_STREQ(query, _T("?query"));
ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host"),
0,
NULL,
NULL,
NULL,
&path,
&query));
ASSERT_STREQ(path, _T(""));
ASSERT_STREQ(query, _T(""));
}
} // namespace omaha