blob: 2a7c777f07c7df228f8e1b236130b5713a4d65c9 [file] [log] [blame]
// Copyright 2015 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.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOAD_JOB_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOAD_JOB_IMPL_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "chrome/browser/chromeos/policy/upload_job.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "url/gurl.h"
namespace base {
class SequencedTaskRunner;
}
namespace net {
class HttpResponseHeaders;
}
namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
} // namespace network
namespace policy {
// This implementation of UploadJob uses the OAuth2TokenService to acquire
// access tokens for the device management (cloud-based policy) server scope and
// uses a SimpleURLLoader to upload data to the specified upload url.
class UploadJobImpl : public UploadJob, public OAuth2TokenService::Consumer {
public:
// UploadJobImpl uses a MimeBoundaryGenerator to generate strings which
// mark the boundaries between data segments.
class MimeBoundaryGenerator {
public:
virtual ~MimeBoundaryGenerator();
virtual std::string GenerateBoundary() const = 0;
private:
DISALLOW_ASSIGN(MimeBoundaryGenerator);
};
// An implemenation of the MimeBoundaryGenerator which uses random
// alpha-numeric characters to construct MIME boundaries.
class RandomMimeBoundaryGenerator : public MimeBoundaryGenerator {
public:
~RandomMimeBoundaryGenerator() override;
std::string GenerateBoundary() const override; // MimeBoundaryGenerator
};
// |task_runner| must belong to the same thread from which the constructor and
// all the public methods are called.
UploadJobImpl(
const GURL& upload_url,
const std::string& account_id,
OAuth2TokenService* token_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
Delegate* delegate,
std::unique_ptr<MimeBoundaryGenerator> boundary_generator,
net::NetworkTrafficAnnotationTag traffic_annotation,
scoped_refptr<base::SequencedTaskRunner> task_runner);
~UploadJobImpl() override;
// UploadJob:
void AddDataSegment(const std::string& name,
const std::string& filename,
const std::map<std::string, std::string>& header_entries,
std::unique_ptr<std::string> data) override;
void Start() override;
// Sets the retry delay to a shorter time to prevent browser tests from
// timing out.
static void SetRetryDelayForTesting(long retryDelayMs);
private:
// Indicates the current state of the UploadJobImpl.
// State transitions for successful upload:
// IDLE -> ACQUIRING_TOKEN -> PREPARING_CONTENT -> UPLOADING -> SUCCESS
// If error happens, state goes back to ACQUIRING_TOKEN.
// State transitions when error occurs once:
// IDLE -> ACQUIRING_TOKEN -> PREPARING_CONTENT -> UPLOADING ->
// -> ACQUIRING_TOKEN -> PREPARING_CONTENT -> UPLOADING -> SUCCESS
// State transitions when tried unsuccessfully kMaxRetries times:
// ... -> PREPARING_CONTENT -> UPLOADING -> ERROR
enum State {
IDLE, // Start() has not been called.
ACQUIRING_TOKEN, // Trying to acquire the access token.
PREPARING_CONTENT, // Currently encoding the content.
UPLOADING, // Upload started.
SUCCESS, // Upload successfully completed.
ERROR // Upload failed.
};
// OAuth2TokenService::Consumer:
void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) override;
void OnGetTokenFailure(const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) override;
// Called when the SimpleURLLoader is finished.
void OnURLLoadComplete(scoped_refptr<net::HttpResponseHeaders> headers);
void HandleError(ErrorCode errorCode);
// Requests an access token for the upload scope.
void RequestAccessToken();
// Dispatches POST request.
void StartUpload();
// Constructs the body of the POST request by concatenating the
// |data_segments_|, separated by appropriate content-disposition headers and
// a MIME boundary. Places the request body in |post_data_| and a copy of the
// MIME boundary in |mime_boundary_|. Returns true on success. If |post_data_|
// and |mime_boundary_| were set already, returns true immediately. In case of
// an error, clears |post_data_| and |mime_boundary_| and returns false.
bool SetUpMultipart();
// Assembles the request and starts the SimpleURLLoader. Fails if another
// upload is still in progress or the content was not successfully encoded.
void CreateAndStartURLLoader(const std::string& access_token);
// The URL to which the POST request should be directed.
const GURL upload_url_;
// The account ID that will be used for the access token fetch.
const std::string account_id_;
// The token service used to retrieve the access token.
OAuth2TokenService* const token_service_;
// This is used to initialize the network::SimpleURLLoader object.
const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// The delegate to be notified of events.
Delegate* const delegate_;
// An implementation of MimeBoundaryGenerator. This instance will be used to
// generate MIME boundaries when assembling the multipart request in
// SetUpMultipart().
std::unique_ptr<MimeBoundaryGenerator> boundary_generator_;
// Network traffic annotation set by the delegate describing what kind of data
// is uploaded.
net::NetworkTrafficAnnotationTag traffic_annotation_;
// Current state the uploader is in.
State state_;
// Contains the cached MIME boundary.
std::unique_ptr<std::string> mime_boundary_;
// Contains the cached, encoded post data.
std::unique_ptr<std::string> post_data_;
// Keeps track of the number of retries.
int retry_;
// The OAuth request to receive the access token.
std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
// The OAuth access token.
std::string access_token_;
// Helper to upload the data.
std::unique_ptr<network::SimpleURLLoader> url_loader_;
// The data chunks to be uploaded.
std::vector<std::unique_ptr<DataSegment>> data_segments_;
// TaskRunner used for scheduling retry attempts.
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::ThreadChecker thread_checker_;
// Should remain the last member so it will be destroyed first and
// invalidate all weak pointers.
base::WeakPtrFactory<UploadJobImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(UploadJobImpl);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_UPLOAD_JOB_IMPL_H_