Index: chrome/browser/webrtc_log_upload_manager.cc |
diff --git a/chrome/browser/webrtc_log_upload_manager.cc b/chrome/browser/webrtc_log_upload_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..45c134c972c92a731baafeffa1817529b9837051 |
--- /dev/null |
+++ b/chrome/browser/webrtc_log_upload_manager.cc |
@@ -0,0 +1,282 @@ |
+// Copyright (c) 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 "chrome/browser/webrtc_log_upload_manager.h" |
+/* |
+#if defined(USE_SYSTEM_LIBBZ2) |
+#include <bzlib.h> |
+#else |
+#include "third_party/bzip2/bzlib.h" |
+#endif |
+*/ |
+//#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/logging.h" |
+#include "base/prefs/pref_service.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/common/cloud_print/cloud_print_helpers.h" |
+#include "chrome/common/pref_names.h" |
+//#include "content/common/partial_circular_buffer.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "googleurl/src/gurl.h" |
+//#include "net/base/file_stream.h" |
+#include "net/proxy/proxy_config_service.h" |
+#include "net/url_request/url_fetcher.h" |
+#include "net/url_request/url_request_context_builder.h" |
+ |
+namespace { |
+ |
+const uint32 kIntermediateCompressionBufferSize = 0.5 * 1024 * 1024; // 0.5 MB |
+ |
+const char kTempUploadFile[] = "/tmp/chromium-webrtc-log-upload"; |
+const char kUploadURL[] = "https://clients2.google.com/cr/report"; |
+const char kUploadContentType[] = "multipart/form-data"; |
+const char kMultipartBoundary[] = |
+ "----**--yradnuoBgoLtrapitluMklaTelgooG--**----"; |
+ |
+const uint32 kFileCopyBufferSize = 128 * 1024; // 128 KB |
+ |
+// 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); |
+}; |
+ |
+ |
+WebRtcLogUploadManager::WebRtcLogUploadManager() |
+ : multipart_file_(base::kInvalidPlatformFileValue) { |
+} |
+ |
+WebRtcLogUploadManager::~WebRtcLogUploadManager() { |
+} |
+ |
+void WebRtcLogUploadManager::OnURLFetchComplete( |
+ const net::URLFetcher* source) { |
+ std::vector<net::URLFetcher*>::iterator it; |
+ for (it = url_fetchers_.begin(); it != url_fetchers_.end(); ++it) { |
+ if (*it == source) { |
+ url_fetchers_.erase(it); |
+ break; |
+ } |
+ } |
+ delete source; |
+} |
+ |
+void WebRtcLogUploadManager::OnURLFetchUploadProgress( |
+ const net::URLFetcher* source, int64 current, int64 total) { |
+} |
+ |
+void WebRtcLogUploadManager::UploadLog(base::PlatformFile log_file) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
+/* |
+ DCHECK(shared_memory); |
+ DCHECK(shared_memory->memory()); |
+ |
+ scoped_ptr<base::SharedMemory> scoped_shared_memory(shared_memory); |
+ |
+ uint8 compressed[length]; |
+ uint32 compressed_size = sizeof(compressed); //content::kWebRtcLogSize; |
+ ReadAndCompressLog(reinterpret_cast<uint8*>(scoped_shared_memory->memory()), |
+ length, compressed, &compressed_size); |
+*/ |
+ SetupUpload(log_file); |
+ |
+ 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, base::FilePath(kTempUploadFile), |
+ content::BrowserThread::GetMessageLoopProxyForThread( |
+ content::BrowserThread::FILE)); |
+ url_fetcher->Start(); |
+ url_fetchers_.push_back(url_fetcher); |
+} |
+ |
+/* |
+void WebRtcLogUploadManager::ReadAndCompressLog(uint8* input, |
+ uint32 input_size, |
+ uint8* output, |
+ uint32* output_size) { |
+ content::PartialCircularBuffer read_pcb(input, input_size); |
+ |
+ bz_stream stream = {0}; |
+ int result = BZ2_bzCompressInit(&stream, 6, 0, 0); |
+ DCHECK(result == BZ_OK); |
+ |
+ scoped_ptr<uint8[]> intermediate_buffer( |
+ new uint8[kIntermediateCompressionBufferSize]); |
+ memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferSize); |
+ uint32 read = read_pcb.Read(intermediate_buffer.get(), |
+ kIntermediateCompressionBufferSize); |
+ stream.next_in = reinterpret_cast<char*>(&intermediate_buffer.get()[0]); |
+ stream.avail_in = read; |
+ |
+ while (read == kIntermediateCompressionBufferSize) { |
+ stream.next_out = |
+ reinterpret_cast<char*>(&((output)[stream.total_out_lo32])); |
+ stream.avail_out = *output_size - stream.total_out_lo32; |
+ result = BZ2_bzCompress(&stream, BZ_RUN); |
+ DCHECK(result == BZ_OK); |
+ read = read_pcb.Read(intermediate_buffer.get(), |
+ kIntermediateCompressionBufferSize); |
+ } |
+ |
+ stream.avail_in = read; |
+ do { |
+ stream.next_out = |
+ reinterpret_cast<char*>(&((output)[stream.total_out_lo32])); |
+ stream.avail_out = *output_size - stream.total_out_lo32; |
+ result = BZ2_bzCompress(&stream, BZ_FINISH); |
+ } while (result == BZ_FINISH_OK); |
+ DCHECK(result == BZ_STREAM_END); |
+ |
+ result = BZ2_bzCompressEnd(&stream); |
+ DCHECK(result == BZ_OK); |
+ |
+ *output_size = stream.total_out_lo32; |
+} |
+*/ |
+ |
+void WebRtcLogUploadManager::SetupUpload(base::PlatformFile log_file) { |
+ /* |
+ file_stream_.reset(new net::FileStream(NULL)); |
+ int open_flags = base::PLATFORM_FILE_CREATE_ALWAYS | |
+ base::PLATFORM_FILE_WRITE; |
+ file_stream_->OpenSync(base::FilePath(kTempUploadFile), |
+ open_flags); |
+ */ |
+ |
+ int flags = base::PLATFORM_FILE_CREATE_ALWAYS | |
+ base::PLATFORM_FILE_WRITE /*| |
+ base::PLATFORM_FILE_DELETE_ON_CLOSE*/; |
+ bool created = false; |
+ base::PlatformFileError error = base::PLATFORM_FILE_OK; |
+ multipart_file_ = |
+ CreatePlatformFile(base::FilePath(kTempUploadFile), flags, |
+ &created, &error); |
+ DCHECK(created); |
+ DCHECK(error == base::PLATFORM_FILE_OK); |
+ |
+ // TODO(grunell): Correct product name. |
+ AddPairString("prod", "Chrome"); |
+ // TODO(grunell): Correct version. |
+ AddPairString("ver", "0.0.1.1-dev-test"); |
+ AddPairString("type", "log"); |
+ |
+ AddUrlChunks(); |
+ |
+ AddLogData(log_file); |
+ |
+ std::stringstream ss; |
+ ss << "--" << kMultipartBoundary << "--" << "\r\n"; |
+ base::WritePlatformFileAtCurrentPos( |
+ multipart_file_, ss.str().data(), ss.str().size()); |
+ |
+ // TODO(grunell): Close file? |
+} |
+ |
+void WebRtcLogUploadManager::AddPairString(const std::string& key, |
+ const std::string& value) { |
+ // TODO(grunell): Break out the function in cloud print. |
+ std::string str; |
+ cloud_print::AddMultipartValueForUpload( |
+ key, value, kMultipartBoundary, "", &str); |
+// file_stream_->WriteSync(str.c_str(), str.size()); |
+ base::WritePlatformFileAtCurrentPos(multipart_file_, str.c_str(), str.size()); |
+} |
+ |
+void WebRtcLogUploadManager::AddUrlChunks() { |
+ // TODO(grunell): Implement. |
+} |
+ |
+void WebRtcLogUploadManager::AddLogData(base::PlatformFile log_file) { |
+ std::stringstream ss; |
+ ss << "--" << kMultipartBoundary << "\r\n"; |
+ ss << "Content-Disposition: form-data; name=\"log\""; |
+ ss << "; filename=\"log.bz2\"" << "\r\n"; |
+ ss << "Content-Type: application/x-bzip" << "\r\n"; |
+ ss << "\r\n"; |
+// file_stream_->WriteSync(ss.str().data(), ss.str().size()); |
+ base::WritePlatformFileAtCurrentPos( |
+ multipart_file_, ss.str().data(), ss.str().size()); |
+ |
+// file_stream_->WriteSync(reinterpret_cast<const char*>(log_data), |
+// log_data_size); |
+ // Copy the log file contents |
+ char buffer[kFileCopyBufferSize] = {0}; |
+ int read = 0; |
+ int written = 0; |
+ int acc_written = 0; |
+ do { |
+ read = base::ReadPlatformFileAtCurrentPos(log_file, &buffer[0], |
+ sizeof(buffer)); |
+ DCHECK_GE(read, 0); |
+ written = base::WritePlatformFileAtCurrentPos(multipart_file_, &buffer[0], |
+ read); |
+ DCHECK_GE(written, 0); |
+ DCHECK_EQ(read, written); |
+ acc_written += written; |
+ } while (read > 0); |
+ |
+ LOG(ERROR) << "TOTAL WRITTEN = " << acc_written; |
+ |
+ std::string end_str = "\r\n"; |
+// file_stream_->WriteSync(end_str.c_str(), end_str.size()); |
+ base::WritePlatformFileAtCurrentPos( |
+ multipart_file_, end_str.c_str(), end_str.size()); |
+} |