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

Side by Side 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: Clean up after self-review. 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
6
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"
17
18 namespace {
19
20 const char kContentType[] = "application/octet-stream";
21
22 } // namespace
23
24 namespace syncer {
25
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.
31 UploadState(const GURL& upload_url,
32 const scoped_refptr<net::URLRequestContextGetter>&
33 url_request_context_getter,
34 const Attachment& attachment,
35 const UploadCallback& user_callback);
36
37 virtual ~UploadState();
38
39 // Add |user_callback| to the list of callbacks to be invoked when this upload
40 // completed.
41 void AddUserCallback(const UploadCallback& user_callback);
42
43 // Return the Attachment this object is uploading.
44 const Attachment& GetAttachment();
45
46 // URLFetcher implementation.
47 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
48
49 private:
50 typedef std::vector<UploadCallback> UploadCallbackList;
51
52 GURL upload_url_;
53 const scoped_refptr<net::URLRequestContextGetter>&
54 url_request_context_getter_;
55 Attachment attachment_;
56 UploadCallbackList user_callbacks_;
57 scoped_ptr<net::URLFetcher> fetcher_;
58
59 DISALLOW_COPY_AND_ASSIGN(UploadState);
60 };
61
62 AttachmentUploaderImpl::UploadState::UploadState(
63 const GURL& upload_url,
64 const scoped_refptr<net::URLRequestContextGetter>&
65 url_request_context_getter,
66 const Attachment& attachment,
67 const UploadCallback& user_callback)
68 : upload_url_(upload_url),
69 url_request_context_getter_(url_request_context_getter),
70 attachment_(attachment),
71 user_callbacks_(1, user_callback) {
72 DCHECK(url_request_context_getter_);
73 DCHECK(upload_url_.is_valid());
74 fetcher_.reset(
75 net::URLFetcher::Create(upload_url_, net::URLFetcher::POST, this));
76 fetcher_->SetRequestContext(url_request_context_getter_.get());
77 // TODO(maniscalco): Is there a better way? Copying the attachment data into
78 // a string feels wrong given how large attachments may be (several MBs). If
79 // we may end up switching from URLFetcher to URLRequest, this copy won't be
80 // necessary.
81 scoped_refptr<base::RefCountedMemory> memory = attachment.GetData();
82 const std::string upload_content(memory->front_as<char>(), memory->size());
83 fetcher_->SetUploadData(kContentType, upload_content);
84 // TODO(maniscalco): Add authentication support (bug 371516).
85 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
86 net::LOAD_DO_NOT_SEND_COOKIES |
87 net::LOAD_DISABLE_CACHE);
88 // TODO(maniscalco): Set an appropriate headers (User-Agent, Content-type, and
89 // Content-length) on the request and include the content's MD5,
90 // AttachmentId's unique_id and the "sync birthday" (bug 371521).
91 fetcher_->Start();
92 }
93
94 AttachmentUploaderImpl::UploadState::~UploadState() {
95 }
96
97 void AttachmentUploaderImpl::UploadState::AddUserCallback(
98 const UploadCallback& user_callback) {
99 DCHECK(CalledOnValidThread());
100 user_callbacks_.push_back(user_callback);
101 }
102
103 const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() {
104 DCHECK(CalledOnValidThread());
105 return attachment_;
106 }
107
108 void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
109 const net::URLFetcher* source) {
110 DCHECK(CalledOnValidThread());
111 // TODO(maniscalco): Once the protocol is better defined, deal with the
112 // various HTTP response code we may encounter.
113 UploadResult result = UPLOAD_UNSPECIFIED_ERROR;
114 if (source->GetResponseCode() == net::HTTP_OK) {
115 result = UPLOAD_SUCCESS;
116 }
117 // TODO(maniscalco): Update the attachment id with server address information
118 // before passing it to the callback (bug 371522).
119 AttachmentId updated_id = attachment_.GetId();
120 UploadCallbackList::const_iterator iter = user_callbacks_.begin();
121 UploadCallbackList::const_iterator end = user_callbacks_.end();
122 for (; iter != end; ++iter) {
123 base::MessageLoop::current()->PostTask(
124 FROM_HERE, base::Bind(*iter, result, updated_id));
125 }
126 }
127
128 AttachmentUploaderImpl::AttachmentUploaderImpl(
129 const AttachmentServerURLBuilder& url_builder,
130 const scoped_refptr<net::URLRequestContextGetter>&
131 url_request_context_getter)
132 : url_builder_(url_builder),
133 url_request_context_getter_(url_request_context_getter) {
134 DCHECK(CalledOnValidThread());
135 }
136
137 AttachmentUploaderImpl::~AttachmentUploaderImpl() {
138 DCHECK(CalledOnValidThread());
139 }
140
141 void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment,
142 const UploadCallback& callback) {
143 DCHECK(CalledOnValidThread());
144 const AttachmentId attachment_id = attachment.GetId();
145 const std::string unique_id = attachment_id.GetProto().unique_id();
146 DCHECK(!unique_id.empty());
147 StateMap::iterator iter = state_map_.find(unique_id);
148 if (iter == state_map_.end()) {
149 const GURL url = url_builder_.BuildUploadURLFor(attachment_id);
150 scoped_ptr<UploadState> upload_state(new UploadState(
151 url, url_request_context_getter_, attachment, callback));
152 state_map_.add(unique_id, upload_state.Pass());
pavely 2014/05/14 18:38:31 You never remove entries from state_map_. What wil
maniscalco 2014/05/14 21:59:03 Good catch. Entries should be removed immediately
153 } else {
154 DCHECK(
155 attachment.GetData()->Equals(iter->second->GetAttachment().GetData()));
156 // We already have an upload for this attachment. "Join" it.
157 iter->second->AddUserCallback(callback);
158 }
159 }
160
161 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698