// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include #include #include "libcef/common/net/http_header_utils.h" #include "libcef/common/net/upload_data.h" #include "libcef/common/request_impl.h" #include "libcef/common/task_runner_impl.h" #include "base/logging.h" #include "components/navigation_interception/navigation_params.h" #include "content/public/browser/resource_request_info.h" #include "content/public/common/resource_type.h" #include "net/base/elements_upload_data_stream.h" #include "net/base/upload_data_stream.h" #include "net/base/upload_element_reader.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_file_element_reader.h" #include "net/http/http_request_headers.h" #include "net/url_request/url_request.h" #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" namespace { // A subclass of net::UploadBytesElementReader that keeps the associated // UploadElement alive until the request completes. class BytesElementReader : public net::UploadBytesElementReader { public: explicit BytesElementReader(scoped_ptr element) : net::UploadBytesElementReader(element->bytes(), element->bytes_length()), element_(element.Pass()) { DCHECK_EQ(net::UploadElement::TYPE_BYTES, element_->type()); } private: scoped_ptr element_; DISALLOW_COPY_AND_ASSIGN(BytesElementReader); }; base::TaskRunner* GetFileTaskRunner() { scoped_refptr task_runner = CefTaskRunnerImpl::GetTaskRunner(TID_FILE); DCHECK(task_runner.get()); return task_runner.get(); } // A subclass of net::UploadFileElementReader that keeps the associated // UploadElement alive until the request completes. class FileElementReader : public net::UploadFileElementReader { public: explicit FileElementReader(scoped_ptr element) : net::UploadFileElementReader( GetFileTaskRunner(), element->file_path(), element->file_range_offset(), element->file_range_length(), element->expected_file_modification_time()), element_(element.Pass()) { DCHECK_EQ(net::UploadElement::TYPE_FILE, element_->type()); } private: scoped_ptr element_; DISALLOW_COPY_AND_ASSIGN(FileElementReader); }; } // namespace #define CHECK_READONLY_RETURN(val) \ if (read_only_) { \ NOTREACHED() << "object is read only"; \ return val; \ } #define CHECK_READONLY_RETURN_VOID() \ if (read_only_) { \ NOTREACHED() << "object is read only"; \ return; \ } // CefRequest ----------------------------------------------------------------- // static CefRefPtr CefRequest::Create() { CefRefPtr request(new CefRequestImpl()); return request; } // CefRequestImpl ------------------------------------------------------------- CefRequestImpl::CefRequestImpl() : read_only_(false), track_changes_(false) { base::AutoLock lock_scope(lock_); Reset(); } bool CefRequestImpl::IsReadOnly() { base::AutoLock lock_scope(lock_); return read_only_; } CefString CefRequestImpl::GetURL() { base::AutoLock lock_scope(lock_); return url_; } void CefRequestImpl::SetURL(const CefString& url) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); if (url_ != url) { url_ = url; Changed(kChangedUrl); } } CefString CefRequestImpl::GetMethod() { base::AutoLock lock_scope(lock_); return method_; } void CefRequestImpl::SetMethod(const CefString& method) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); if (method_ != method) { method_ = method; Changed(kChangedMethod); } } CefRefPtr CefRequestImpl::GetPostData() { base::AutoLock lock_scope(lock_); return postdata_; } void CefRequestImpl::SetPostData(CefRefPtr postData) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); postdata_ = postData; Changed(kChangedPostData); } void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) { base::AutoLock lock_scope(lock_); headerMap = headermap_; } void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); headermap_ = headerMap; Changed(kChangedHeaderMap); } void CefRequestImpl::Set(const CefString& url, const CefString& method, CefRefPtr postData, const HeaderMap& headerMap) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); if (url_ != url) { url_ = url; Changed(kChangedUrl); } if (method_ != method) { method_ = method; Changed(kChangedMethod); } postdata_ = postData; headermap_ = headerMap; Changed(kChangedPostData | kChangedHeaderMap); } int CefRequestImpl::GetFlags() { base::AutoLock lock_scope(lock_); return flags_; } void CefRequestImpl::SetFlags(int flags) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); if (flags_ != flags) { flags_ = flags; Changed(kChangedFlags); } } CefString CefRequestImpl::GetFirstPartyForCookies() { base::AutoLock lock_scope(lock_); return first_party_for_cookies_; } void CefRequestImpl::SetFirstPartyForCookies(const CefString& url) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); if (first_party_for_cookies_ != url) { first_party_for_cookies_ = url; Changed(kChangedFirstPartyForCookies); } } CefRequestImpl::ResourceType CefRequestImpl::GetResourceType() { base::AutoLock lock_scope(lock_); return resource_type_; } CefRequestImpl::TransitionType CefRequestImpl::GetTransitionType() { base::AutoLock lock_scope(lock_); return transition_type_; } uint64 CefRequestImpl::GetIdentifier() { base::AutoLock lock_scope(lock_); return identifier_; } void CefRequestImpl::Set(net::URLRequest* request) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); Reset(); url_ = request->url().spec(); method_ = request->method(); first_party_for_cookies_ = request->first_party_for_cookies().spec(); identifier_ = request->identifier(); net::HttpRequestHeaders headers = request->extra_request_headers(); // URLRequest::SetReferrer ensures that we do not send username and password // fields in the referrer. GURL referrer(request->referrer()); // Strip Referer from request_info_.extra_headers to prevent, e.g., plugins // from overriding headers that are controlled using other means. Otherwise a // plugin could set a referrer although sending the referrer is inhibited. headers.RemoveHeader(net::HttpRequestHeaders::kReferer); // Our consumer should have made sure that this is a safe referrer. See for // instance WebCore::FrameLoader::HideReferrer. if (referrer.is_valid()) headers.SetHeader(net::HttpRequestHeaders::kReferer, referrer.spec()); // Transfer request headers GetHeaderMap(headers, headermap_); // Transfer post data, if any const net::UploadDataStream* data = request->get_upload(); if (data) { postdata_ = CefPostData::Create(); static_cast(postdata_.get())->Set(*data); } const content::ResourceRequestInfo* info = content::ResourceRequestInfo::ForRequest(request); if (info) { resource_type_ = static_cast(info->GetResourceType()); transition_type_ = static_cast(info->GetPageTransition()); } } void CefRequestImpl::Get(net::URLRequest* request, bool changed_only) const { base::AutoLock lock_scope(lock_); if (ShouldSet(kChangedMethod, changed_only)) request->set_method(method_); if (!first_party_for_cookies_.empty() && ShouldSet(kChangedFirstPartyForCookies, changed_only)) { request->set_first_party_for_cookies( GURL(std::string(first_party_for_cookies_))); } if (ShouldSet(kChangedHeaderMap, changed_only)) { CefString referrerStr; referrerStr.FromASCII(net::HttpRequestHeaders::kReferer); HeaderMap headerMap = headermap_; HeaderMap::iterator it = headerMap.find(referrerStr); if (it == headerMap.end()) { request->SetReferrer(std::string()); } else { request->SetReferrer(it->second); headerMap.erase(it); } net::HttpRequestHeaders headers; headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headerMap)); request->SetExtraRequestHeaders(headers); } if (ShouldSet(kChangedPostData, changed_only)) { if (postdata_.get()) { request->set_upload(make_scoped_ptr( static_cast(postdata_.get())->Get())); } else if (request->get_upload()) { request->set_upload(scoped_ptr()); } } } void CefRequestImpl::Set( const navigation_interception::NavigationParams& params, bool is_main_frame) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); Reset(); url_ = params.url().spec(); method_ = params.is_post() ? "POST" : "GET"; const content::Referrer& sanitized_referrer = content::Referrer::SanitizeForRequest(params.url(), params.referrer()); if (!sanitized_referrer.url.is_empty()) { headermap_.insert(std::make_pair( CefString("Referrer"), sanitized_referrer.url.spec())); } resource_type_ = is_main_frame ? RT_MAIN_FRAME : RT_SUB_FRAME; transition_type_ = static_cast(params.transition_type()); } void CefRequestImpl::Set(const blink::WebURLRequest& request) { DCHECK(!request.isNull()); base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); Reset(); url_ = request.url().spec().utf16(); method_ = request.httpMethod(); const blink::WebHTTPBody& body = request.httpBody(); if (!body.isNull()) { postdata_ = new CefPostDataImpl(); static_cast(postdata_.get())->Set(body); } GetHeaderMap(request, headermap_); if (request.cachePolicy() == blink::WebURLRequest::ReloadIgnoringCacheData) flags_ |= UR_FLAG_SKIP_CACHE; if (request.allowStoredCredentials()) flags_ |= UR_FLAG_ALLOW_CACHED_CREDENTIALS; if (request.reportUploadProgress()) flags_ |= UR_FLAG_REPORT_UPLOAD_PROGRESS; first_party_for_cookies_ = request.firstPartyForCookies().spec().utf16(); } void CefRequestImpl::Get(blink::WebURLRequest& request, bool changed_only) const { request.initialize(); base::AutoLock lock_scope(lock_); if (ShouldSet(kChangedUrl, changed_only)) { GURL gurl = GURL(url_.ToString()); request.setURL(blink::WebURL(gurl)); } if (ShouldSet(kChangedMethod, changed_only)) { std::string method(method_); request.setHTTPMethod(blink::WebString::fromUTF8(method.c_str())); } if (ShouldSet(kChangedPostData, changed_only)) { blink::WebHTTPBody body; if (postdata_.get()) { body.initialize(); static_cast(postdata_.get())->Get(body); request.setHTTPBody(body); } } if (ShouldSet(kChangedHeaderMap, changed_only)) SetHeaderMap(headermap_, request); if (ShouldSet(kChangedFlags, changed_only)) { request.setCachePolicy((flags_ & UR_FLAG_SKIP_CACHE) ? blink::WebURLRequest::ReloadIgnoringCacheData : blink::WebURLRequest::UseProtocolCachePolicy); #define SETBOOLFLAG(obj, flags, method, FLAG) \ obj.method((flags & (FLAG)) == (FLAG)) SETBOOLFLAG(request, flags_, setAllowStoredCredentials, UR_FLAG_ALLOW_CACHED_CREDENTIALS); SETBOOLFLAG(request, flags_, setReportUploadProgress, UR_FLAG_REPORT_UPLOAD_PROGRESS); } if (!first_party_for_cookies_.empty() && ShouldSet(kChangedFirstPartyForCookies, changed_only)) { GURL gurl = GURL(first_party_for_cookies_.ToString()); request.setFirstPartyForCookies(blink::WebURL(gurl)); } } void CefRequestImpl::SetReadOnly(bool read_only) { base::AutoLock lock_scope(lock_); if (read_only_ == read_only) return; read_only_ = read_only; if (postdata_.get()) static_cast(postdata_.get())->SetReadOnly(read_only); } void CefRequestImpl::SetTrackChanges(bool track_changes) { base::AutoLock lock_scope(lock_); if (track_changes_ == track_changes) return; track_changes_ = track_changes; changes_ = kChangedNone; if (postdata_.get()) { static_cast(postdata_.get())-> SetTrackChanges(track_changes); } } uint8 CefRequestImpl::GetChanges() const { base::AutoLock lock_scope(lock_); uint8 changes = changes_; if (postdata_.get() && static_cast(postdata_.get())->HasChanges()) { changes |= kChangedPostData; } return changes; } // static void CefRequestImpl::GetHeaderMap(const net::HttpRequestHeaders& headers, HeaderMap& map) { if (headers.IsEmpty()) return; net::HttpRequestHeaders::Iterator it(headers); do { map.insert(std::make_pair(it.name(), it.value())); } while (it.GetNext()); } // static void CefRequestImpl::GetHeaderMap(const blink::WebURLRequest& request, HeaderMap& map) { class HeaderVisitor : public blink::WebHTTPHeaderVisitor { public: explicit HeaderVisitor(HeaderMap* map) : map_(map) {} void visitHeader(const blink::WebString& name, const blink::WebString& value) override { map_->insert(std::make_pair(base::string16(name), base::string16(value))); } private: HeaderMap* map_; }; HeaderVisitor visitor(&map); request.visitHTTPHeaderFields(&visitor); } // static void CefRequestImpl::SetHeaderMap(const HeaderMap& map, blink::WebURLRequest& request) { HeaderMap::const_iterator it = map.begin(); for (; it != map.end(); ++it) request.setHTTPHeaderField(base::string16(it->first), base::string16(it->second)); } void CefRequestImpl::Changed(uint8 changes) { lock_.AssertAcquired(); if (track_changes_) changes_ |= changes; } bool CefRequestImpl::ShouldSet(uint8 changes, bool changed_only) const { lock_.AssertAcquired(); // Always change if changes are not being tracked. if (!track_changes_) return true; // Always change if changed-only was not requested. if (!changed_only) return true; // Change if the |changes| bit flag has been set. if ((changes_ & changes) == changes) return true; if ((changes & kChangedPostData) == kChangedPostData) { // Change if the post data object was modified directly. if (postdata_.get() && static_cast(postdata_.get())->HasChanges()) { return true; } } return false; } void CefRequestImpl::Reset() { lock_.AssertAcquired(); DCHECK(!read_only_); url_.clear(); method_ = "GET"; postdata_ = NULL; headermap_.clear(); resource_type_ = RT_SUB_RESOURCE; transition_type_ = TT_EXPLICIT; identifier_ = 0U; flags_ = UR_FLAG_NONE; first_party_for_cookies_.clear(); changes_ = kChangedNone; } // CefPostData ---------------------------------------------------------------- // static CefRefPtr CefPostData::Create() { CefRefPtr postdata(new CefPostDataImpl()); return postdata; } // CefPostDataImpl ------------------------------------------------------------ CefPostDataImpl::CefPostDataImpl() : read_only_(false), track_changes_(false), has_changes_(false) { } bool CefPostDataImpl::IsReadOnly() { base::AutoLock lock_scope(lock_); return read_only_; } size_t CefPostDataImpl::GetElementCount() { base::AutoLock lock_scope(lock_); return elements_.size(); } void CefPostDataImpl::GetElements(ElementVector& elements) { base::AutoLock lock_scope(lock_); elements = elements_; } bool CefPostDataImpl::RemoveElement(CefRefPtr element) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN(false); ElementVector::iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { if (it->get() == element.get()) { elements_.erase(it); Changed(); return true; } } return false; } bool CefPostDataImpl::AddElement(CefRefPtr element) { bool found = false; base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN(false); // check that the element isn't already in the list before adding ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { if (it->get() == element.get()) { found = true; break; } } if (!found) { elements_.push_back(element); Changed(); } return !found; } void CefPostDataImpl::RemoveElements() { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); elements_.clear(); Changed(); } void CefPostDataImpl::Set(const net::UploadData& data) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } CefRefPtr postelem; const ScopedVector& elements = data.elements(); ScopedVector::const_iterator it = elements.begin(); for (; it != elements.end(); ++it) { postelem = CefPostDataElement::Create(); static_cast(postelem.get())->Set(**it); AddElement(postelem); } } void CefPostDataImpl::Set(const net::UploadDataStream& data_stream) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } CefRefPtr postelem; const ScopedVector* elements = data_stream.GetElementReaders(); if (elements) { ScopedVector::const_iterator it = elements->begin(); for (; it != elements->end(); ++it) { postelem = CefPostDataElement::Create(); static_cast(postelem.get())->Set(**it); if (postelem->GetType() != PDE_TYPE_EMPTY) AddElement(postelem); } } } void CefPostDataImpl::Get(net::UploadData& data) const { base::AutoLock lock_scope(lock_); ScopedVector data_elements; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { net::UploadElement* element = new net::UploadElement(); static_cast(it->get())->Get(*element); data_elements.push_back(element); } data.swap_elements(&data_elements); } net::UploadDataStream* CefPostDataImpl::Get() const { base::AutoLock lock_scope(lock_); ScopedVector element_readers; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { element_readers.push_back( static_cast(it->get())->Get()); } return new net::ElementsUploadDataStream(element_readers.Pass(), 0); } void CefPostDataImpl::Set(const blink::WebHTTPBody& data) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } CefRefPtr postelem; blink::WebHTTPBody::Element element; size_t size = data.elementCount(); for (size_t i = 0; i < size; ++i) { if (data.elementAt(i, element)) { postelem = CefPostDataElement::Create(); static_cast(postelem.get())->Set(element); AddElement(postelem); } } } void CefPostDataImpl::Get(blink::WebHTTPBody& data) const { base::AutoLock lock_scope(lock_); blink::WebHTTPBody::Element element; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { static_cast(it->get())->Get(element); if (element.type == blink::WebHTTPBody::Element::TypeData) { data.appendData(element.data); } else if (element.type == blink::WebHTTPBody::Element::TypeFile) { data.appendFile(element.filePath); } else { NOTREACHED(); } } } void CefPostDataImpl::SetReadOnly(bool read_only) { base::AutoLock lock_scope(lock_); if (read_only_ == read_only) return; read_only_ = read_only; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { static_cast(it->get())->SetReadOnly(read_only); } } void CefPostDataImpl::SetTrackChanges(bool track_changes) { base::AutoLock lock_scope(lock_); if (track_changes_ == track_changes) return; track_changes_ = track_changes; has_changes_ = false; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { static_cast(it->get())-> SetTrackChanges(track_changes); } } bool CefPostDataImpl::HasChanges() const { base::AutoLock lock_scope(lock_); if (has_changes_) return true; ElementVector::const_iterator it = elements_.begin(); for (; it != elements_.end(); ++it) { if (static_cast(it->get())->HasChanges()) return true; } return false; } void CefPostDataImpl::Changed() { lock_.AssertAcquired(); if (track_changes_ && !has_changes_) has_changes_ = true; } // CefPostDataElement --------------------------------------------------------- // static CefRefPtr CefPostDataElement::Create() { CefRefPtr element(new CefPostDataElementImpl()); return element; } // CefPostDataElementImpl ----------------------------------------------------- CefPostDataElementImpl::CefPostDataElementImpl() : type_(PDE_TYPE_EMPTY), read_only_(false), track_changes_(false), has_changes_(false) { memset(&data_, 0, sizeof(data_)); } CefPostDataElementImpl::~CefPostDataElementImpl() { Cleanup(); } bool CefPostDataElementImpl::IsReadOnly() { base::AutoLock lock_scope(lock_); return read_only_; } void CefPostDataElementImpl::SetToEmpty() { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); Cleanup(); Changed(); } void CefPostDataElementImpl::SetToFile(const CefString& fileName) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); // Clear any data currently in the element Cleanup(); // Assign the new data type_ = PDE_TYPE_FILE; cef_string_copy(fileName.c_str(), fileName.length(), &data_.filename); Changed(); } void CefPostDataElementImpl::SetToBytes(size_t size, const void* bytes) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); // Clear any data currently in the element Cleanup(); // Assign the new data void* data = malloc(size); DCHECK(data != NULL); if (data == NULL) return; memcpy(data, bytes, size); type_ = PDE_TYPE_BYTES; data_.bytes.bytes = data; data_.bytes.size = size; Changed(); } CefPostDataElement::Type CefPostDataElementImpl::GetType() { base::AutoLock lock_scope(lock_); return type_; } CefString CefPostDataElementImpl::GetFile() { base::AutoLock lock_scope(lock_); DCHECK(type_ == PDE_TYPE_FILE); CefString filename; if (type_ == PDE_TYPE_FILE) filename.FromString(data_.filename.str, data_.filename.length, false); return filename; } size_t CefPostDataElementImpl::GetBytesCount() { base::AutoLock lock_scope(lock_); DCHECK(type_ == PDE_TYPE_BYTES); size_t size = 0; if (type_ == PDE_TYPE_BYTES) size = data_.bytes.size; return size; } size_t CefPostDataElementImpl::GetBytes(size_t size, void* bytes) { base::AutoLock lock_scope(lock_); DCHECK(type_ == PDE_TYPE_BYTES); size_t rv = 0; if (type_ == PDE_TYPE_BYTES) { rv = (size < data_.bytes.size ? size : data_.bytes.size); memcpy(bytes, data_.bytes.bytes, rv); } return rv; } void CefPostDataElementImpl::Set(const net::UploadElement& element) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } if (element.type() == net::UploadElement::TYPE_BYTES) { SetToBytes(element.bytes_length(), element.bytes()); } else if (element.type() == net::UploadElement::TYPE_FILE) { SetToFile(element.file_path().value()); } else { NOTREACHED(); } } void CefPostDataElementImpl::Set( const net::UploadElementReader& element_reader) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } const net::UploadBytesElementReader* bytes_reader = element_reader.AsBytesReader(); if (bytes_reader) { SetToBytes(bytes_reader->length(), bytes_reader->bytes()); return; } const net::UploadFileElementReader* file_reader = element_reader.AsFileReader(); if (file_reader) { SetToFile(file_reader->path().value()); return; } // Chunked uploads cannot currently be represented. SetToEmpty(); } void CefPostDataElementImpl::Get(net::UploadElement& element) const { base::AutoLock lock_scope(lock_); if (type_ == PDE_TYPE_BYTES) { element.SetToBytes(static_cast(data_.bytes.bytes), data_.bytes.size); } else if (type_ == PDE_TYPE_FILE) { base::FilePath path = base::FilePath(CefString(&data_.filename)); element.SetToFilePath(path); } else { NOTREACHED(); } } net::UploadElementReader* CefPostDataElementImpl::Get() const { base::AutoLock lock_scope(lock_); if (type_ == PDE_TYPE_BYTES) { net::UploadElement* element = new net::UploadElement(); element->SetToBytes(static_cast(data_.bytes.bytes), data_.bytes.size); return new BytesElementReader(make_scoped_ptr(element)); } else if (type_ == PDE_TYPE_FILE) { net::UploadElement* element = new net::UploadElement(); base::FilePath path = base::FilePath(CefString(&data_.filename)); element->SetToFilePath(path); return new FileElementReader(make_scoped_ptr(element)); } else { NOTREACHED(); return NULL; } } void CefPostDataElementImpl::Set(const blink::WebHTTPBody::Element& element) { { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); } if (element.type == blink::WebHTTPBody::Element::TypeData) { SetToBytes(element.data.size(), static_cast(element.data.data())); } else if (element.type == blink::WebHTTPBody::Element::TypeFile) { SetToFile(base::string16(element.filePath)); } else { NOTREACHED(); } } void CefPostDataElementImpl::Get(blink::WebHTTPBody::Element& element) const { base::AutoLock lock_scope(lock_); if (type_ == PDE_TYPE_BYTES) { element.type = blink::WebHTTPBody::Element::TypeData; element.data.assign( static_cast(data_.bytes.bytes), data_.bytes.size); } else if (type_ == PDE_TYPE_FILE) { element.type = blink::WebHTTPBody::Element::TypeFile; element.filePath.assign(base::string16(CefString(&data_.filename))); } else { NOTREACHED(); } } void CefPostDataElementImpl::SetReadOnly(bool read_only) { base::AutoLock lock_scope(lock_); if (read_only_ == read_only) return; read_only_ = read_only; } void CefPostDataElementImpl::SetTrackChanges(bool track_changes) { base::AutoLock lock_scope(lock_); if (track_changes_ == track_changes) return; track_changes_ = track_changes; has_changes_ = false; } bool CefPostDataElementImpl::HasChanges() const { base::AutoLock lock_scope(lock_); return has_changes_; } void CefPostDataElementImpl::Changed() { lock_.AssertAcquired(); if (track_changes_ && !has_changes_) has_changes_ = true; } void CefPostDataElementImpl::Cleanup() { if (type_ == PDE_TYPE_EMPTY) return; if (type_ == PDE_TYPE_BYTES) free(data_.bytes.bytes); else if (type_ == PDE_TYPE_FILE) cef_string_clear(&data_.filename); type_ = PDE_TYPE_EMPTY; memset(&data_, 0, sizeof(data_)); }