Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(567)

Unified Diff: sync/internal_api/attachments/attachment_uploader_impl.cc

Issue 278263003: Add a minimal AttachmentUploaderImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Apply 2nd round of CR feedback from pavely. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sync/internal_api/attachments/attachment_uploader_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/internal_api/attachments/attachment_uploader_impl.cc
diff --git a/sync/internal_api/attachments/attachment_uploader_impl.cc b/sync/internal_api/attachments/attachment_uploader_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..25630dcaba8b2a71f79192b91921497bb17587bd
--- /dev/null
+++ b/sync/internal_api/attachments/attachment_uploader_impl.cc
@@ -0,0 +1,182 @@
+// Copyright 2014 The Chromium 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 "sync/internal_api/public/attachments/attachment_uploader_impl.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "sync/api/attachments/attachment.h"
+#include "sync/protocol/sync.pb.h"
+#include "url/gurl.h"
+
+namespace {
+
+const char kContentType[] = "application/octet-stream";
+
+} // namespace
+
+namespace syncer {
+
+// Encapsulates all the state associated with a single upload.
+class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
+ public base::NonThreadSafe {
+ public:
+ // Construct an UploadState.
+ //
+ // |owner| is a pointer to the object that will own (and must outlive!) this
+ // |UploadState.
+ UploadState(const GURL& upload_url,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter,
+ const Attachment& attachment,
+ const UploadCallback& user_callback,
+ AttachmentUploaderImpl* owner);
+
+ virtual ~UploadState();
+
+ // Add |user_callback| to the list of callbacks to be invoked when this upload
+ // completed.
+ void AddUserCallback(const UploadCallback& user_callback);
+
+ // Return the Attachment this object is uploading.
+ const Attachment& GetAttachment();
+
+ // URLFetcher implementation.
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ private:
+ typedef std::vector<UploadCallback> UploadCallbackList;
+
+ GURL upload_url_;
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter_;
+ Attachment attachment_;
+ UploadCallbackList user_callbacks_;
+ scoped_ptr<net::URLFetcher> fetcher_;
+ // Pointer to the AttachmentUploaderImpl that owns this object.
+ AttachmentUploaderImpl* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadState);
+};
+
+AttachmentUploaderImpl::UploadState::UploadState(
+ const GURL& upload_url,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter,
+ const Attachment& attachment,
+ const UploadCallback& user_callback,
+ AttachmentUploaderImpl* owner)
+ : upload_url_(upload_url),
+ url_request_context_getter_(url_request_context_getter),
+ attachment_(attachment),
+ user_callbacks_(1, user_callback),
+ owner_(owner) {
+ DCHECK(url_request_context_getter_);
+ DCHECK(upload_url_.is_valid());
+ DCHECK(owner_);
+ fetcher_.reset(
+ net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this));
+ fetcher_->SetRequestContext(url_request_context_getter_.get());
+ // TODO(maniscalco): Is there a better way? Copying the attachment data into
+ // a string feels wrong given how large attachments may be (several MBs). If
+ // we may end up switching from URLFetcher to URLRequest, this copy won't be
+ // necessary.
+ scoped_refptr<base::RefCountedMemory> memory = attachment.GetData();
+ const std::string upload_content(memory->front_as<char>(), memory->size());
+ fetcher_->SetUploadData(kContentType, upload_content);
+ // TODO(maniscalco): Add authentication support (bug 371516).
+ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DISABLE_CACHE);
+ // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and
+ // Content-length) on the request and include the content's MD5,
+ // AttachmentId's unique_id and the "sync birthday" (bug 371521).
+ fetcher_->Start();
+}
+
+AttachmentUploaderImpl::UploadState::~UploadState() {
+}
+
+void AttachmentUploaderImpl::UploadState::AddUserCallback(
+ const UploadCallback& user_callback) {
+ DCHECK(CalledOnValidThread());
+ user_callbacks_.push_back(user_callback);
+}
+
+const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() {
+ DCHECK(CalledOnValidThread());
+ return attachment_;
+}
+
+void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ DCHECK(CalledOnValidThread());
+ // TODO(maniscalco): Once the protocol is better defined, deal with the
+ // various HTTP response code we may encounter.
+ UploadResult result = UPLOAD_UNSPECIFIED_ERROR;
+ if (source->GetResponseCode() == net::HTTP_OK) {
+ result = UPLOAD_SUCCESS;
+ }
+ // TODO(maniscalco): Update the attachment id with server address information
+ // before passing it to the callback (bug 371522).
+ AttachmentId updated_id = attachment_.GetId();
+ UploadCallbackList::const_iterator iter = user_callbacks_.begin();
+ UploadCallbackList::const_iterator end = user_callbacks_.end();
+ for (; iter != end; ++iter) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(*iter, result, updated_id));
+ }
+ // Destroy this object and return immediately.
+ owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id());
+ return;
+}
+
+AttachmentUploaderImpl::AttachmentUploaderImpl(
+ const std::string& url_prefix,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter)
+ : url_prefix_(url_prefix),
+ url_request_context_getter_(url_request_context_getter) {
+ DCHECK(CalledOnValidThread());
+}
+
+AttachmentUploaderImpl::~AttachmentUploaderImpl() {
+ DCHECK(CalledOnValidThread());
+}
+
+void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment,
+ const UploadCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ const AttachmentId attachment_id = attachment.GetId();
+ const std::string unique_id = attachment_id.GetProto().unique_id();
+ DCHECK(!unique_id.empty());
+ StateMap::iterator iter = state_map_.find(unique_id);
+ if (iter == state_map_.end()) {
+ const GURL url = GetUploadURLForAttachmentId(attachment_id);
+ scoped_ptr<UploadState> upload_state(new UploadState(
+ url, url_request_context_getter_, attachment, callback, this));
+ state_map_.add(unique_id, upload_state.Pass());
+ } else {
+ DCHECK(
+ attachment.GetData()->Equals(iter->second->GetAttachment().GetData()));
+ // We already have an upload for this attachment. "Join" it.
+ iter->second->AddUserCallback(callback);
+ }
+}
+
+GURL AttachmentUploaderImpl::GetUploadURLForAttachmentId(
+ const AttachmentId& attachment_id) const {
+ return GURL(url_prefix_ + attachment_id.GetProto().unique_id());
+}
+
+void AttachmentUploaderImpl::DeleteUploadStateFor(const UniqueId& unique_id) {
+ state_map_.erase(unique_id);
+}
+
+} // namespace syncer
« no previous file with comments | « no previous file | sync/internal_api/attachments/attachment_uploader_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698