1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/http_request.h" 18 19 #include <string> 20 21 #include <base/bind.h> 22 #include <base/strings/string_number_conversions.h> 23 #include <base/strings/stringprintf.h> 24 25 #include "shill/async_connection.h" 26 #include "shill/connection.h" 27 #include "shill/dns_client.h" 28 #include "shill/error.h" 29 #include "shill/event_dispatcher.h" 30 #include "shill/http_url.h" 31 #include "shill/logging.h" 32 #include "shill/net/ip_address.h" 33 #include "shill/net/sockets.h" 34 35 using base::Bind; 36 using base::Callback; 37 using base::StringPrintf; 38 using std::string; 39 40 namespace shill { 41 42 namespace Logging { 43 static auto kModuleLogScope = ScopeLogger::kHTTP; 44 static string ObjectID(Connection* c) { return c->interface_name(); } 45 } 46 47 const int HTTPRequest::kConnectTimeoutSeconds = 10; 48 const int HTTPRequest::kDNSTimeoutSeconds = 5; 49 const int HTTPRequest::kInputTimeoutSeconds = 10; 50 51 const char HTTPRequest::kHTTPRequestTemplate[] = 52 "GET %s HTTP/1.1\r\n" 53 "Host: %s:%d\r\n" 54 "Connection: Close\r\n\r\n"; 55 56 HTTPRequest::HTTPRequest(ConnectionRefPtr connection, 57 EventDispatcher* dispatcher, 58 Sockets* sockets) 59 : connection_(connection), 60 dispatcher_(dispatcher), 61 sockets_(sockets), 62 weak_ptr_factory_(this), 63 connect_completion_callback_( 64 Bind(&HTTPRequest::OnConnectCompletion, 65 weak_ptr_factory_.GetWeakPtr())), 66 dns_client_callback_(Bind(&HTTPRequest::GetDNSResult, 67 weak_ptr_factory_.GetWeakPtr())), 68 read_server_callback_(Bind(&HTTPRequest::ReadFromServer, 69 weak_ptr_factory_.GetWeakPtr())), 70 write_server_callback_(Bind(&HTTPRequest::WriteToServer, 71 weak_ptr_factory_.GetWeakPtr())), 72 dns_client_( 73 new DNSClient(connection->IsIPv6() ? IPAddress::kFamilyIPv6 74 : IPAddress::kFamilyIPv4, 75 connection->interface_name(), 76 connection->dns_servers(), 77 kDNSTimeoutSeconds * 1000, 78 dispatcher, 79 dns_client_callback_)), 80 server_async_connection_( 81 new AsyncConnection(connection_->interface_name(), 82 dispatcher_, sockets, 83 connect_completion_callback_)), 84 server_port_(-1), 85 server_socket_(-1), 86 timeout_result_(kResultUnknown), 87 is_running_(false) { } 88 89 HTTPRequest::~HTTPRequest() { 90 Stop(); 91 } 92 93 HTTPRequest::Result HTTPRequest::Start( 94 const HTTPURL& url, 95 const Callback<void(const ByteString&)>& read_event_callback, 96 const Callback<void(Result, const ByteString&)>& result_callback) { 97 SLOG(connection_.get(), 3) << "In " << __func__; 98 99 DCHECK(!is_running_); 100 101 is_running_ = true; 102 request_data_ = ByteString(StringPrintf(kHTTPRequestTemplate, 103 url.path().c_str(), 104 url.host().c_str(), 105 url.port()), false); 106 server_hostname_ = url.host(); 107 server_port_ = url.port(); 108 connection_->RequestRouting(); 109 110 IPAddress addr(IPAddress::kFamilyIPv4); 111 if (connection_->IsIPv6()) { 112 addr.set_family(IPAddress::kFamilyIPv6); 113 } 114 if (addr.SetAddressFromString(server_hostname_)) { 115 if (!ConnectServer(addr, server_port_)) { 116 LOG(ERROR) << "Connect to " 117 << server_hostname_ 118 << " failed synchronously"; 119 return kResultConnectionFailure; 120 } 121 } else { 122 SLOG(connection_.get(), 3) << "Looking up host: " << server_hostname_; 123 Error error; 124 if (!dns_client_->Start(server_hostname_, &error)) { 125 LOG(ERROR) << "Failed to start DNS client: " << error.message(); 126 Stop(); 127 return kResultDNSFailure; 128 } 129 } 130 131 // Only install callbacks after connection succeeds in starting. 132 read_event_callback_ = read_event_callback; 133 result_callback_ = result_callback; 134 135 return kResultInProgress; 136 } 137 138 void HTTPRequest::Stop() { 139 SLOG(connection_.get(), 3) << "In " << __func__ << "; running is " 140 << is_running_; 141 142 if (!is_running_) { 143 return; 144 } 145 146 // Clear IO handlers first so that closing the socket doesn't cause 147 // events to fire. 148 write_server_handler_.reset(); 149 read_server_handler_.reset(); 150 151 connection_->ReleaseRouting(); 152 dns_client_->Stop(); 153 is_running_ = false; 154 result_callback_.Reset(); 155 read_event_callback_.Reset(); 156 request_data_.Clear(); 157 response_data_.Clear(); 158 server_async_connection_->Stop(); 159 server_hostname_.clear(); 160 server_port_ = -1; 161 if (server_socket_ != -1) { 162 sockets_->Close(server_socket_); 163 server_socket_ = -1; 164 } 165 timeout_closure_.Cancel(); 166 timeout_result_ = kResultUnknown; 167 } 168 169 bool HTTPRequest::ConnectServer(const IPAddress& address, int port) { 170 SLOG(connection_.get(), 3) << "In " << __func__; 171 if (!server_async_connection_->Start(address, port)) { 172 LOG(ERROR) << "Could not create socket to connect to server at " 173 << address.ToString(); 174 SendStatus(kResultConnectionFailure); 175 return false; 176 } 177 // Start a connection timeout only if we didn't synchronously connect. 178 if (server_socket_ == -1) { 179 StartIdleTimeout(kConnectTimeoutSeconds, kResultConnectionTimeout); 180 } 181 return true; 182 } 183 184 // DNSClient callback that fires when the DNS request completes. 185 void HTTPRequest::GetDNSResult(const Error& error, const IPAddress& address) { 186 SLOG(connection_.get(), 3) << "In " << __func__; 187 if (!error.IsSuccess()) { 188 LOG(ERROR) << "Could not resolve hostname " 189 << server_hostname_ 190 << ": " 191 << error.message(); 192 if (error.message() == DNSClient::kErrorTimedOut) { 193 SendStatus(kResultDNSTimeout); 194 } else { 195 SendStatus(kResultDNSFailure); 196 } 197 return; 198 } 199 ConnectServer(address, server_port_); 200 } 201 202 // AsyncConnection callback routine which fires when the asynchronous Connect() 203 // to the remote server completes (or fails). 204 void HTTPRequest::OnConnectCompletion(bool success, int fd) { 205 SLOG(connection_.get(), 3) << "In " << __func__; 206 if (!success) { 207 LOG(ERROR) << "Socket connection delayed failure to " 208 << server_hostname_ 209 << ": " 210 << server_async_connection_->error(); 211 // |this| could be freed as a result of calling SendStatus(). 212 SendStatus(kResultConnectionFailure); 213 return; 214 } 215 server_socket_ = fd; 216 write_server_handler_.reset( 217 dispatcher_->CreateReadyHandler(server_socket_, 218 IOHandler::kModeOutput, 219 write_server_callback_)); 220 StartIdleTimeout(kInputTimeoutSeconds, kResultRequestTimeout); 221 } 222 223 void HTTPRequest::OnServerReadError(const string& /*error_msg*/) { 224 SendStatus(kResultResponseFailure); 225 } 226 227 // IOInputHandler callback which fires when data has been read from the 228 // server. 229 void HTTPRequest::ReadFromServer(InputData* data) { 230 SLOG(connection_.get(), 3) << "In " << __func__ << " length " << data->len; 231 if (data->len == 0) { 232 SendStatus(kResultSuccess); 233 return; 234 } 235 236 response_data_.Append(ByteString(data->buf, data->len)); 237 StartIdleTimeout(kInputTimeoutSeconds, kResultResponseTimeout); 238 if (!read_event_callback_.is_null()) { 239 read_event_callback_.Run(response_data_); 240 } 241 } 242 243 void HTTPRequest::SendStatus(Result result) { 244 // Save copies on the stack, since Stop() will remove them. 245 Callback<void(Result, const ByteString&)> result_callback = result_callback_; 246 const ByteString response_data(response_data_); 247 Stop(); 248 249 // Call the callback last, since it may delete us and |this| may no longer 250 // be valid. 251 if (!result_callback.is_null()) { 252 result_callback.Run(result, response_data); 253 } 254 } 255 256 // Start a timeout for "the next event". 257 void HTTPRequest::StartIdleTimeout(int timeout_seconds, Result timeout_result) { 258 timeout_result_ = timeout_result; 259 timeout_closure_.Reset( 260 Bind(&HTTPRequest::TimeoutTask, weak_ptr_factory_.GetWeakPtr())); 261 dispatcher_->PostDelayedTask(timeout_closure_.callback(), 262 timeout_seconds * 1000); 263 } 264 265 void HTTPRequest::TimeoutTask() { 266 LOG(ERROR) << "Connection with " 267 << server_hostname_ 268 << " timed out"; 269 SendStatus(timeout_result_); 270 } 271 272 // Output ReadyHandler callback which fires when the server socket is 273 // ready for data to be sent to it. 274 void HTTPRequest::WriteToServer(int fd) { 275 CHECK_EQ(server_socket_, fd); 276 int ret = sockets_->Send(fd, request_data_.GetConstData(), 277 request_data_.GetLength(), 0); 278 CHECK(ret < 0 || static_cast<size_t>(ret) <= request_data_.GetLength()); 279 280 SLOG(connection_.get(), 3) << "In " << __func__ << " wrote " << ret << " of " 281 << request_data_.GetLength(); 282 283 if (ret < 0) { 284 LOG(ERROR) << "Client write failed to " 285 << server_hostname_; 286 SendStatus(kResultRequestFailure); 287 return; 288 } 289 290 request_data_ = ByteString(request_data_.GetConstData() + ret, 291 request_data_.GetLength() - ret); 292 293 if (request_data_.IsEmpty()) { 294 write_server_handler_->Stop(); 295 read_server_handler_.reset(dispatcher_->CreateInputHandler( 296 server_socket_, 297 read_server_callback_, 298 Bind(&HTTPRequest::OnServerReadError, weak_ptr_factory_.GetWeakPtr()))); 299 StartIdleTimeout(kInputTimeoutSeconds, kResultResponseTimeout); 300 } else { 301 StartIdleTimeout(kInputTimeoutSeconds, kResultRequestTimeout); 302 } 303 } 304 305 } // namespace shill 306