Index: chrome/browser/extensions/api/web_request/upload_data_presenter.cc |
diff --git a/chrome/browser/extensions/api/web_request/upload_data_presenter.cc b/chrome/browser/extensions/api/web_request/upload_data_presenter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b11b5cc23b20d8381d3d943365b8bc1beeefb61e |
--- /dev/null |
+++ b/chrome/browser/extensions/api/web_request/upload_data_presenter.cc |
@@ -0,0 +1,187 @@ |
+// Copyright (c) 2012 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/extensions/api/web_request/upload_data_presenter.h" |
+ |
+#include "base/file_path.h" |
+#include "base/string_util.h" |
+#include "base/values.h" |
+#include "chrome/browser/extensions/api/web_request/form_data_parser.h" |
+#include "net/url_request/url_request.h" |
+ |
+using base::BinaryValue; |
+using base::DictionaryValue; |
+using base::ListValue; |
+using base::StringValue; |
+using base::Value; |
+ |
+namespace { |
+ |
+// Takes |dictionary| of <string, list of strings> pairs, and gets the list |
+// for |key|, creating it if necessary. |
+ListValue* GetOrCreateList(DictionaryValue* dictionary, |
+ const std::string& key) { |
+ ListValue* list = NULL; |
+ if (!dictionary->GetList(key, &list)) { |
+ list = new ListValue(); |
+ dictionary->Set(key, list); |
+ } |
+ return list; |
+} |
+ |
+} // namespace |
+ |
+namespace extensions { |
+ |
+// Implementation of UploadDataPresenter. |
+ |
+UploadDataPresenter::~UploadDataPresenter() {} |
+ |
+// Implementation of ChunkedErrorPresenter. |
+ |
+ChunkedErrorPresenter::ChunkedErrorPresenter(const net::URLRequest* request) |
+ : chunks_found_(IsTransferEncodingChunked(request)) { |
+} |
+ |
+ChunkedErrorPresenter::~ChunkedErrorPresenter() {} |
+ |
+// static |
+bool ChunkedErrorPresenter::IsTransferEncodingChunked( |
+ const net::URLRequest* request){ |
+ std::string transfer_encoding; |
+ if (!request->extra_request_headers().GetHeader( |
+ net::HttpRequestHeaders::kTransferEncoding, &transfer_encoding)) { |
+ return false; |
+ } |
+ return base::strcasecmp(transfer_encoding.c_str(), "chunked") == 0; |
+} |
+ |
+void ChunkedErrorPresenter::FeedNext(const net::UploadData::Element& element) { |
+ if (chunks_found_) |
+ return; // We already found a reason to report an error. |
+ |
+ if (element.type() == net::UploadData::TYPE_CHUNK) |
+ chunks_found_ = true; |
+} |
+ |
+bool ChunkedErrorPresenter::Succeeded() { |
+ return chunks_found_; |
+} |
+ |
+scoped_ptr<Value> ChunkedErrorPresenter::Result() { |
+ if (!chunks_found_) |
+ return scoped_ptr<Value>(); |
+ |
+ scoped_ptr<StringValue> error_string(new StringValue( |
+ "Not supported: data is uploaded chunked.")); |
+ return error_string.PassAs<Value>(); |
+} |
+ |
+// Implementation of RawDataPresenter. |
+ |
+RawDataPresenter::RawDataPresenter() |
+ : success_(true), |
+ list_(new base::ListValue) { |
+} |
+RawDataPresenter::~RawDataPresenter() {} |
+ |
+void RawDataPresenter::FeedNext(const net::UploadData::Element& element) { |
+ if (!success_) |
+ return; |
+ |
+ switch (element.type()) { |
+ case net::UploadData::TYPE_BYTES: |
+ FeedNextBytes(element.bytes()); |
+ break; |
+ case net::UploadData::TYPE_CHUNK: |
+ Abort(); // Chunks are not supported (yet). |
+ break; |
+ case net::UploadData::TYPE_FILE: |
+ // Insert the file path instead of the contents, which may be too large. |
+ FeedNextFile(element.file_path().AsUTF8Unsafe()); |
+ break; |
+ case net::UploadData::TYPE_BLOB: |
+ // TYPE_BLOB is silently ignored. |
+ break; |
+ } |
+} |
+ |
+bool RawDataPresenter::Succeeded() { |
+ return success_; |
+} |
+ |
+scoped_ptr<Value> RawDataPresenter::Result() { |
+ if (!success_) |
+ return scoped_ptr<Value>(); |
+ |
+ return list_.PassAs<Value>(); |
+} |
+ |
+void RawDataPresenter::Abort() { |
+ success_ = false; |
+ list_.reset(); |
+} |
+ |
+void RawDataPresenter::FeedNextBytes(const std::vector<char>& bytes) { |
+ list_->Append( |
+ BinaryValue::CreateWithCopiedBuffer(&(bytes[0]), bytes.size())); |
+} |
+ |
+void RawDataPresenter::FeedNextFile(const std::string& filename) { |
+ // Insert the file path instead of the contents, which may be too large. |
+ list_->Append(Value::CreateStringValue(filename)); |
+} |
+ |
+// Implementation of ParsedDataPresenter. |
+ |
+ParsedDataPresenter::ParsedDataPresenter(const net::URLRequest* request) |
+ : parser_(FormDataParser::Create(request)), |
+ success_(parser_.get() != NULL), |
+ dictionary_(success_ ? new DictionaryValue() : NULL) { |
+} |
+ |
+ParsedDataPresenter::~ParsedDataPresenter() {} |
+ |
+void ParsedDataPresenter::FeedNext(const net::UploadData::Element& element) { |
+ if (!success_) |
+ return; |
+ |
+ if (element.type() != net::UploadData::TYPE_BYTES) { |
+ if (element.type() != net::UploadData::TYPE_FILE) { |
+ Abort(); // We do not handle blobs nor chunks. |
+ } |
+ return; // But we just ignore files. |
+ } |
+ if (!parser_->SetSource(&(element.bytes()))) { |
+ Abort(); |
+ return; |
+ } |
+ |
+ FormDataParser::Result result; |
+ while (parser_->GetNextNameValue(&result)) { |
+ GetOrCreateList(dictionary_.get(), result.name())->Append( |
+ new StringValue(result.value())); |
+ } |
+} |
+ |
+bool ParsedDataPresenter::Succeeded() { |
+ if (success_ && !parser_->AllDataReadOK()) |
+ Abort(); |
+ return success_; |
+} |
+ |
+scoped_ptr<Value> ParsedDataPresenter::Result() { |
+ if (success_) |
+ return dictionary_.PassAs<Value>(); |
+ else |
+ return scoped_ptr<Value>(); |
+} |
+ |
+void ParsedDataPresenter::Abort() { |
+ success_ = false; |
+ dictionary_.reset(); |
+ parser_.reset(); |
+} |
+ |
+} // namespace extensions |