| /* |
| * Copyright 2012 Google Inc. All Rights Reserved. |
| * |
| * 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. |
| */ |
| |
| #include "net/dial/dial_service.h" |
| |
| #include "base/bind.h" |
| #include "base/debug/trace_event.h" |
| #include "base/string_piece.h" |
| #include "base/stringprintf.h" |
| #include "net/base/net_errors.h" |
| #include "net/server/http_server_request_info.h" |
| #include "net/url_request/url_request.h" |
| |
| namespace net { |
| |
| namespace { |
| const char* kUdpServerAgent = "Cobalt/2.0 UPnP/1.1"; |
| } // namespace |
| |
| DialService::DialService() { |
| http_server_ = new DialHttpServer(this); |
| udp_server_.reset(new DialUdpServer(http_server_->location_url(), |
| kUdpServerAgent)); |
| |
| // Compute HTTP local address and cache it. |
| IPEndPoint addr; |
| if (http_server_->GetLocalAddress(&addr) == net::OK) { |
| http_host_address_ = addr.ToString(); |
| } else { |
| DLOG(WARNING) << "Could not start Dial Server"; |
| } |
| } |
| |
| DialService::~DialService() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| Terminate(); |
| } |
| |
| const std::string& DialService::http_host_address() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return http_host_address_; |
| } |
| |
| void DialService::Terminate() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| // Note that we may not have the last ref to http_server_, so we can't control |
| // where it gets destroyed. Ensure we stop it on the right thread. |
| if (http_server_) { |
| http_server_->Stop(); |
| } |
| http_server_ = NULL; |
| udp_server_.reset(); |
| } |
| |
| void DialService::Register(const scoped_refptr<DialServiceHandler>& handler) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| TRACE_EVENT0("net::dial", __FUNCTION__); |
| DCHECK(handler); |
| const std::string& path = handler->service_name(); |
| if (!path.empty()) { |
| handlers_[path] = handler; |
| } |
| } |
| |
| void DialService::Deregister(const scoped_refptr<DialServiceHandler>& handler) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| TRACE_EVENT0("net::dial", __FUNCTION__); |
| DCHECK(handler); |
| for (ServiceHandlerMap::iterator it = handlers_.begin(); |
| it != handlers_.end(); ++it) { |
| if (it->second == handler) { |
| handlers_.erase(it); |
| break; |
| } |
| } |
| } |
| |
| scoped_refptr<DialServiceHandler> DialService::GetHandler( |
| const std::string& request_path, |
| std::string* handler_path) { |
| // This function should only be called by DialHttpServer, to find a handler |
| // to respond to an incoming request. |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| DCHECK(handler_path != NULL); |
| TRACE_EVENT0("net::dial", __FUNCTION__); |
| |
| VLOG(1) << "Requesting Handler for path: " << request_path; |
| base::StringPiece path(request_path); |
| |
| // remove '/apps/' |
| const base::StringPiece kUrlPrefix("/apps/"); |
| if (!path.starts_with(kUrlPrefix)) { |
| return NULL; |
| } |
| path = path.substr(kUrlPrefix.size()); |
| |
| // find the next '/', and extract the portion in between. |
| size_t pos = path.find_first_of('/'); |
| std::string service_path = path.substr(0, pos).as_string(); |
| |
| // sanity check further, then extract the data. |
| DCHECK_EQ(std::string::npos, service_path.find('/')); |
| ServiceHandlerMap::const_iterator it = handlers_.find(service_path); |
| if (it == handlers_.end()) { |
| return NULL; |
| } |
| DCHECK(it->second); |
| |
| // for the remaining portion, extract it out as the handler path. |
| *handler_path = path.substr(pos).as_string(); |
| |
| // If the |handler_path| is empty, that means the request is "/apps/Foo", the |
| // semantic equivalent of "/apps/Foo/". If we keep the |handler_path| empty, |
| // somehow the JS does not catch it. So for now forcing it to "/" instead. |
| if (handler_path->empty()) { |
| *handler_path = std::string("/"); |
| } |
| |
| DCHECK_EQ('/', handler_path->at(0)); |
| |
| return it->second; |
| } |
| |
| DialServiceProxy::DialServiceProxy( |
| const base::WeakPtr<DialService>& dial_service) |
| : dial_service_(dial_service) { |
| host_address_ = dial_service_->http_host_address(); |
| // Remember the message loop we were constructed on. We'll post all our tasks |
| // there, to ensure thread safety when accessing dial_service_. |
| message_loop_proxy_ = base::MessageLoopProxy::current(); |
| } |
| |
| DialServiceProxy::~DialServiceProxy() {} |
| |
| void DialServiceProxy::Register( |
| const scoped_refptr<DialServiceHandler>& handler) { |
| message_loop_proxy_->PostTask( |
| FROM_HERE, base::Bind(&DialServiceProxy::OnRegister, this, handler)); |
| } |
| |
| void DialServiceProxy::Deregister( |
| const scoped_refptr<DialServiceHandler>& handler) { |
| message_loop_proxy_->PostTask( |
| FROM_HERE, base::Bind(&DialServiceProxy::OnDeregister, this, handler)); |
| } |
| |
| void DialServiceProxy::OnRegister( |
| const scoped_refptr<DialServiceHandler>& handler) { |
| if (dial_service_) { |
| dial_service_->Register(handler); |
| } |
| } |
| |
| void DialServiceProxy::OnDeregister( |
| const scoped_refptr<DialServiceHandler>& handler) { |
| if (dial_service_) { |
| dial_service_->Deregister(handler); |
| } |
| } |
| |
| } // namespace net |