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

Unified Diff: components/webrtc_log_uploader/webrtc_log_uploader.cc

Issue 14329020: Implementing uploading of a WebRTC diagnostic log. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed file added by mistake. Created 7 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
Index: components/webrtc_log_uploader/webrtc_log_uploader.cc
diff --git a/components/webrtc_log_uploader/webrtc_log_uploader.cc b/components/webrtc_log_uploader/webrtc_log_uploader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7c2e3fde997ab5bd621c194c9d2b50cb07de1512
--- /dev/null
+++ b/components/webrtc_log_uploader/webrtc_log_uploader.cc
@@ -0,0 +1,286 @@
+// Copyright 2013 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 "components/webrtc_log_uploader/webrtc_log_uploader.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/partial_circular_buffer.h"
+#include "base/shared_memory.h"
+#include "base/stringprintf.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/network_delegate.h"
+#include "net/proxy/proxy_config.h"
+#include "net/proxy/proxy_config_service.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "third_party/zlib/zlib.h"
+
+namespace components {
+
+namespace {
+
+const int kLogCountLimit = 5;
+const uint32 kIntermediateCompressionBufferBytes = 256 * 1024; // 256 KB
+
+const char kUploadURL[] = "https://clients2.google.com/cr/report";
+const char kUploadContentType[] = "multipart/form-data";
+const char kMultipartBoundary[] =
+ "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
+
+// Config getter that always returns direct settings.
+class ProxyConfigServiceDirect : public net::ProxyConfigService {
+ public:
+ // ProxyConfigService implementation.
+ virtual void AddObserver(Observer* observer) OVERRIDE {}
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {}
+ virtual ConfigAvailability GetLatestProxyConfig(
+ net::ProxyConfig* config) OVERRIDE {
+ *config = net::ProxyConfig::CreateDirect();
+ return CONFIG_VALID;
+ }
+};
+
+} // namespace
+
+class WebRtcLogURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ WebRtcLogURLRequestContextGetter() {}
+
+ // net::URLRequestContextGetter implementation.
+ virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ if (!url_request_context_) {
+ net::URLRequestContextBuilder builder;
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ builder.set_proxy_config_service(new ProxyConfigServiceDirect());
+#endif
+ url_request_context_.reset(builder.Build());
+ CHECK(url_request_context_.get());
+ }
+
+ return url_request_context_.get();
+ }
+
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetNetworkTaskRunner() const OVERRIDE {
+ return content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::IO);
+ }
+
+ private:
+ virtual ~WebRtcLogURLRequestContextGetter() {}
+
+ // NULL if not yet initialized. Otherwise, it is the URLRequestContext
+ // instance that was lazily created by GetURLRequestContext().
+ // Access only from the IO thread.
+ scoped_ptr<net::URLRequestContext> url_request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebRtcLogURLRequestContextGetter);
+};
+
+
+WebRtcLogUploader::WebRtcLogUploader()
+ : log_count_(0) {
+}
+
+WebRtcLogUploader::~WebRtcLogUploader() {
+}
+
+void WebRtcLogUploader::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+}
+
+void WebRtcLogUploader::OnURLFetchUploadProgress(
+ const net::URLFetcher* source, int64 current, int64 total) {
+}
+
+bool WebRtcLogUploader::ApplyForStartLogging() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (log_count_ < kLogCountLimit) {
+ ++log_count_;
+ return true;
+ }
+ return false;
+}
+
+void WebRtcLogUploader::UploadLog(scoped_ptr<base::SharedMemory> shared_memory,
+ uint32 length) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+
+ base::FilePath upload_file_path;
+ if (file_util::CreateTemporaryFile(&upload_file_path)) {
+ SetupMultipartFile(reinterpret_cast<uint8*>(shared_memory->memory()),
+ length, upload_file_path);
+
+ if (!request_context_getter_)
+ request_context_getter_ = new WebRtcLogURLRequestContextGetter();
+
+ std::string content_type = kUploadContentType;
+ content_type.append("; boundary=");
+ content_type.append(kMultipartBoundary);
+
+ net::URLFetcher* url_fetcher =
+ net::URLFetcher::Create(GURL(kUploadURL), net::URLFetcher::POST, this);
+ url_fetcher->SetRequestContext(request_context_getter_);
+ url_fetcher->SetUploadFilePath(
+ content_type, upload_file_path, 0, kuint64max,
+ content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::FILE));
+ url_fetcher->Start();
+ } else {
+ DLOG(ERROR) << "WebRtcLogUploader could not create temporary file: "
+ << upload_file_path.value();
+ }
+
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebRtcLogUploader::DecreaseLogCount, base::Unretained(this)));
+}
+
+void WebRtcLogUploader::SetupMultipartFile(
+ uint8* log_buffer, uint32 log_buffer_length,
+ const base::FilePath& upload_file_path) {
+ int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE;
+ bool created = false;
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ base::PlatformFile multipart_file =
+ CreatePlatformFile(upload_file_path, flags, &created, &error);
+ DCHECK(created);
+ DCHECK_EQ(error, base::PLATFORM_FILE_OK);
+
+ // TODO(grunell): Correct product name.
+ AddPairString(multipart_file, "prod", "Chrome");
+ // TODO(grunell): Correct version.
+ AddPairString(multipart_file, "ver", "0.0.1.1-dev-test");
+ AddPairString(multipart_file, "guid", "0");
+ AddPairString(multipart_file, "type", "log");
+
+ AddUrlChunks();
+
+ AddLogData(multipart_file, log_buffer, log_buffer_length);
+
+ std::string str = "--";
+ str.append(kMultipartBoundary);
+ str.append("--\r\n");
+ base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
+
+ DCHECK(base::ClosePlatformFile(multipart_file));
+}
+
+void WebRtcLogUploader::AddPairString(base::PlatformFile multipart_file,
+ const std::string& key,
+ const std::string& value) {
+ std::string str;
+ AddMultipartValueForUpload(key, value, kMultipartBoundary, "", &str);
+ base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
+}
+
+void WebRtcLogUploader::AddUrlChunks() {
+ // TODO(grunell): Implement.
+}
+
+void WebRtcLogUploader::AddLogData(base::PlatformFile multipart_file,
+ uint8* log_buffer,
+ uint32 log_buffer_length) {
+ std::string str = "--";
+ str.append(kMultipartBoundary);
+ str.append("\r\n");
+ str.append("Content-Disposition: form-data; name=\"log\"");
+ str.append("; filename=\"log.gz\"\r\n");
+ str.append("Content-Type: application/gzip\r\n\r\n");
+ base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
+
+ CompressLog(log_buffer, log_buffer_length, multipart_file);
+
+ std::string end_str = "\r\n";
+ base::WritePlatformFileAtCurrentPos(
+ multipart_file, end_str.c_str(), end_str.size());
+}
+
+// TODO(grunell): This is copied from cloud_print_helpers.cc. Break out to its
+// own file.
+void WebRtcLogUploader::AddMultipartValueForUpload(
+ const std::string& value_name, const std::string& value,
+ const std::string& mime_boundary, const std::string& content_type,
+ std::string* post_data) {
+ DCHECK(post_data);
+ // First line is the boundary
+ post_data->append("--" + mime_boundary + "\r\n");
+ // Next line is the Content-disposition
+ post_data->append(base::StringPrintf("Content-Disposition: form-data; "
+ "name=\"%s\"\r\n", value_name.c_str()));
+ if (!content_type.empty()) {
+ // If Content-type is specified, the next line is that
+ post_data->append(base::StringPrintf("Content-Type: %s\r\n",
+ content_type.c_str()));
+ }
+ // Leave an empty line and append the value.
+ post_data->append(base::StringPrintf("\r\n%s\r\n", value.c_str()));
+}
+
+void WebRtcLogUploader::CompressLog(uint8* input,
+ uint32 input_size,
+ base::PlatformFile output_file) {
+ base::PartialCircularBuffer read_pcb(input, input_size);
+
+ z_stream stream = {0};
+ int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ // windowBits = 15 is default, 16 is added to
+ // produce a gzip header + trailer.
+ 15 + 16,
+ 8, // memLevel = 8 is default.
+ Z_DEFAULT_STRATEGY);
+ DCHECK_EQ(Z_OK, result);
+
+ scoped_ptr<uint8[]> intermediate_buffer(
+ new uint8[kIntermediateCompressionBufferBytes]);
+ scoped_ptr<uint8[]> compressed(
+ new uint8[kIntermediateCompressionBufferBytes]);
+ memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferBytes);
+ memset(compressed.get(), 0, kIntermediateCompressionBufferBytes);
+
+ char* compressed_char_ptr = reinterpret_cast<char*>(&compressed.get()[0]);
+ uint32 read = 0;
+
+ do {
+ read = read_pcb.Read(intermediate_buffer.get(),
+ kIntermediateCompressionBufferBytes);
+ stream.next_in = &intermediate_buffer.get()[0];
+ stream.avail_in = read;
+ stream.next_out = &compressed.get()[0];
+ stream.avail_out = kIntermediateCompressionBufferBytes;
+ if (read != kIntermediateCompressionBufferBytes)
+ break;
+
+ result = deflate(&stream, Z_SYNC_FLUSH);
+ DCHECK_EQ(Z_OK, result);
+ DCHECK_LE(stream.avail_out, kIntermediateCompressionBufferBytes);
+ base::WritePlatformFileAtCurrentPos(
+ output_file, compressed_char_ptr,
+ kIntermediateCompressionBufferBytes - stream.avail_out);
+ } while (true);
+
+ result = deflate(&stream, Z_FINISH);
+ DCHECK(result == Z_STREAM_END);
+ DCHECK_LE(stream.avail_out, kIntermediateCompressionBufferBytes);
+ base::WritePlatformFileAtCurrentPos(
+ output_file, compressed_char_ptr,
+ kIntermediateCompressionBufferBytes - stream.avail_out);
+
+ result = deflateEnd(&stream);
+ DCHECK_EQ(Z_OK, result);
+}
+
+void WebRtcLogUploader::DecreaseLogCount() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ --log_count_;
+}
+
+} // namespace components

Powered by Google App Engine
This is Rietveld 408576698