Revert 275293 "Add authentication support to AttachmentUploaderI..."
[chromium-blink-merge.git] / sync / internal_api / attachments / attachment_uploader_impl.cc
blob25630dcaba8b2a71f79192b91921497bb17587bd
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/threading/non_thread_safe.h"
10 #include "net/base/load_flags.h"
11 #include "net/http/http_status_code.h"
12 #include "net/url_request/url_fetcher.h"
13 #include "net/url_request/url_fetcher_delegate.h"
14 #include "sync/api/attachments/attachment.h"
15 #include "sync/protocol/sync.pb.h"
16 #include "url/gurl.h"
18 namespace {
20 const char kContentType[] = "application/octet-stream";
22 } // namespace
24 namespace syncer {
26 // Encapsulates all the state associated with a single upload.
27 class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
28 public base::NonThreadSafe {
29 public:
30 // Construct an UploadState.
32 // |owner| is a pointer to the object that will own (and must outlive!) this
33 // |UploadState.
34 UploadState(const GURL& upload_url,
35 const scoped_refptr<net::URLRequestContextGetter>&
36 url_request_context_getter,
37 const Attachment& attachment,
38 const UploadCallback& user_callback,
39 AttachmentUploaderImpl* owner);
41 virtual ~UploadState();
43 // Add |user_callback| to the list of callbacks to be invoked when this upload
44 // completed.
45 void AddUserCallback(const UploadCallback& user_callback);
47 // Return the Attachment this object is uploading.
48 const Attachment& GetAttachment();
50 // URLFetcher implementation.
51 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
53 private:
54 typedef std::vector<UploadCallback> UploadCallbackList;
56 GURL upload_url_;
57 const scoped_refptr<net::URLRequestContextGetter>&
58 url_request_context_getter_;
59 Attachment attachment_;
60 UploadCallbackList user_callbacks_;
61 scoped_ptr<net::URLFetcher> fetcher_;
62 // Pointer to the AttachmentUploaderImpl that owns this object.
63 AttachmentUploaderImpl* owner_;
65 DISALLOW_COPY_AND_ASSIGN(UploadState);
68 AttachmentUploaderImpl::UploadState::UploadState(
69 const GURL& upload_url,
70 const scoped_refptr<net::URLRequestContextGetter>&
71 url_request_context_getter,
72 const Attachment& attachment,
73 const UploadCallback& user_callback,
74 AttachmentUploaderImpl* owner)
75 : upload_url_(upload_url),
76 url_request_context_getter_(url_request_context_getter),
77 attachment_(attachment),
78 user_callbacks_(1, user_callback),
79 owner_(owner) {
80 DCHECK(url_request_context_getter_);
81 DCHECK(upload_url_.is_valid());
82 DCHECK(owner_);
83 fetcher_.reset(
84 net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this));
85 fetcher_->SetRequestContext(url_request_context_getter_.get());
86 // TODO(maniscalco): Is there a better way? Copying the attachment data into
87 // a string feels wrong given how large attachments may be (several MBs). If
88 // we may end up switching from URLFetcher to URLRequest, this copy won't be
89 // necessary.
90 scoped_refptr<base::RefCountedMemory> memory = attachment.GetData();
91 const std::string upload_content(memory->front_as<char>(), memory->size());
92 fetcher_->SetUploadData(kContentType, upload_content);
93 // TODO(maniscalco): Add authentication support (bug 371516).
94 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
95 net::LOAD_DO_NOT_SEND_COOKIES |
96 net::LOAD_DISABLE_CACHE);
97 // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and
98 // Content-length) on the request and include the content's MD5,
99 // AttachmentId's unique_id and the "sync birthday" (bug 371521).
100 fetcher_->Start();
103 AttachmentUploaderImpl::UploadState::~UploadState() {
106 void AttachmentUploaderImpl::UploadState::AddUserCallback(
107 const UploadCallback& user_callback) {
108 DCHECK(CalledOnValidThread());
109 user_callbacks_.push_back(user_callback);
112 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() {
113 DCHECK(CalledOnValidThread());
114 return attachment_;
117 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
118 const net::URLFetcher* source) {
119 DCHECK(CalledOnValidThread());
120 // TODO(maniscalco): Once the protocol is better defined, deal with the
121 // various HTTP response code we may encounter.
122 UploadResult result = UPLOAD_UNSPECIFIED_ERROR;
123 if (source->GetResponseCode() == net::HTTP_OK) {
124 result = UPLOAD_SUCCESS;
126 // TODO(maniscalco): Update the attachment id with server address information
127 // before passing it to the callback (bug 371522).
128 AttachmentId updated_id = attachment_.GetId();
129 UploadCallbackList::const_iterator iter = user_callbacks_.begin();
130 UploadCallbackList::const_iterator end = user_callbacks_.end();
131 for (; iter != end; ++iter) {
132 base::MessageLoop::current()->PostTask(
133 FROM_HERE, base::Bind(*iter, result, updated_id));
135 // Destroy this object and return immediately.
136 owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id());
137 return;
140 AttachmentUploaderImpl::AttachmentUploaderImpl(
141 const std::string& url_prefix,
142 const scoped_refptr<net::URLRequestContextGetter>&
143 url_request_context_getter)
144 : url_prefix_(url_prefix),
145 url_request_context_getter_(url_request_context_getter) {
146 DCHECK(CalledOnValidThread());
149 AttachmentUploaderImpl::~AttachmentUploaderImpl() {
150 DCHECK(CalledOnValidThread());
153 void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment,
154 const UploadCallback& callback) {
155 DCHECK(CalledOnValidThread());
156 const AttachmentId attachment_id = attachment.GetId();
157 const std::string unique_id = attachment_id.GetProto().unique_id();
158 DCHECK(!unique_id.empty());
159 StateMap::iterator iter = state_map_.find(unique_id);
160 if (iter == state_map_.end()) {
161 const GURL url = GetUploadURLForAttachmentId(attachment_id);
162 scoped_ptr<UploadState> upload_state(new UploadState(
163 url, url_request_context_getter_, attachment, callback, this));
164 state_map_.add(unique_id, upload_state.Pass());
165 } else {
166 DCHECK(
167 attachment.GetData()->Equals(iter->second->GetAttachment().GetData()));
168 // We already have an upload for this attachment. "Join" it.
169 iter->second->AddUserCallback(callback);
173 GURL AttachmentUploaderImpl::GetUploadURLForAttachmentId(
174 const AttachmentId& attachment_id) const {
175 return GURL(url_prefix_ + attachment_id.GetProto().unique_id());
178 void AttachmentUploaderImpl::DeleteUploadStateFor(const UniqueId& unique_id) {
179 state_map_.erase(unique_id);
182 } // namespace syncer