1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/web_request/upload_data_presenter.h"
6
7 #include "base/files/file_path.h"
8 #include "base/strings/string_util.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/api/web_request/form_data_parser.h"
11 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h"
12 #include "net/base/upload_bytes_element_reader.h"
13 #include "net/base/upload_file_element_reader.h"
14 #include "net/url_request/url_request.h"
15
16 using base::BinaryValue;
17 using base::DictionaryValue;
18 using base::ListValue;
19 using base::StringValue;
20 using base::Value;
21
22 namespace keys = extension_web_request_api_constants;
23
24 namespace {
25
26 // Takes |dictionary| of <string, list of strings> pairs, and gets the list
27 // for |key|, creating it if necessary.
GetOrCreateList(base::DictionaryValue * dictionary,const std::string & key)28 base::ListValue* GetOrCreateList(base::DictionaryValue* dictionary,
29 const std::string& key) {
30 base::ListValue* list = NULL;
31 if (!dictionary->GetList(key, &list)) {
32 list = new base::ListValue();
33 dictionary->SetWithoutPathExpansion(key, list);
34 }
35 return list;
36 }
37
38 } // namespace
39
40 namespace extensions {
41
42 namespace subtle {
43
AppendKeyValuePair(const char * key,base::Value * value,base::ListValue * list)44 void AppendKeyValuePair(const char* key,
45 base::Value* value,
46 base::ListValue* list) {
47 base::DictionaryValue* dictionary = new base::DictionaryValue;
48 dictionary->SetWithoutPathExpansion(key, value);
49 list->Append(dictionary);
50 }
51
52 } // namespace subtle
53
~UploadDataPresenter()54 UploadDataPresenter::~UploadDataPresenter() {}
55
RawDataPresenter()56 RawDataPresenter::RawDataPresenter()
57 : success_(true),
58 list_(new base::ListValue) {
59 }
~RawDataPresenter()60 RawDataPresenter::~RawDataPresenter() {}
61
FeedNext(const net::UploadElementReader & reader)62 void RawDataPresenter::FeedNext(const net::UploadElementReader& reader) {
63 if (!success_)
64 return;
65
66 if (reader.AsBytesReader()) {
67 const net::UploadBytesElementReader* bytes_reader = reader.AsBytesReader();
68 FeedNextBytes(bytes_reader->bytes(), bytes_reader->length());
69 } else if (reader.AsFileReader()) {
70 // Insert the file path instead of the contents, which may be too large.
71 const net::UploadFileElementReader* file_reader = reader.AsFileReader();
72 FeedNextFile(file_reader->path().AsUTF8Unsafe());
73 } else {
74 NOTIMPLEMENTED();
75 }
76 }
77
Succeeded()78 bool RawDataPresenter::Succeeded() {
79 return success_;
80 }
81
Result()82 scoped_ptr<base::Value> RawDataPresenter::Result() {
83 if (!success_)
84 return scoped_ptr<base::Value>();
85
86 return list_.PassAs<base::Value>();
87 }
88
FeedNextBytes(const char * bytes,size_t size)89 void RawDataPresenter::FeedNextBytes(const char* bytes, size_t size) {
90 subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
91 BinaryValue::CreateWithCopiedBuffer(bytes, size),
92 list_.get());
93 }
94
FeedNextFile(const std::string & filename)95 void RawDataPresenter::FeedNextFile(const std::string& filename) {
96 // Insert the file path instead of the contents, which may be too large.
97 subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
98 new base::StringValue(filename),
99 list_.get());
100 }
101
ParsedDataPresenter(const net::URLRequest & request)102 ParsedDataPresenter::ParsedDataPresenter(const net::URLRequest& request)
103 : parser_(FormDataParser::Create(request)),
104 success_(parser_.get() != NULL),
105 dictionary_(success_ ? new base::DictionaryValue() : NULL) {
106 }
107
~ParsedDataPresenter()108 ParsedDataPresenter::~ParsedDataPresenter() {}
109
FeedNext(const net::UploadElementReader & reader)110 void ParsedDataPresenter::FeedNext(const net::UploadElementReader& reader) {
111 if (!success_)
112 return;
113
114 const net::UploadBytesElementReader* bytes_reader = reader.AsBytesReader();
115 if (!bytes_reader) {
116 return;
117 }
118 if (!parser_->SetSource(base::StringPiece(bytes_reader->bytes(),
119 bytes_reader->length()))) {
120 Abort();
121 return;
122 }
123
124 FormDataParser::Result result;
125 while (parser_->GetNextNameValue(&result)) {
126 GetOrCreateList(dictionary_.get(), result.name())->Append(
127 new base::StringValue(result.value()));
128 }
129 }
130
Succeeded()131 bool ParsedDataPresenter::Succeeded() {
132 if (success_ && !parser_->AllDataReadOK())
133 Abort();
134 return success_;
135 }
136
Result()137 scoped_ptr<base::Value> ParsedDataPresenter::Result() {
138 if (!success_)
139 return scoped_ptr<base::Value>();
140
141 return dictionary_.PassAs<base::Value>();
142 }
143
144 // static
CreateForTests()145 scoped_ptr<ParsedDataPresenter> ParsedDataPresenter::CreateForTests() {
146 const std::string form_type("application/x-www-form-urlencoded");
147 return scoped_ptr<ParsedDataPresenter>(new ParsedDataPresenter(form_type));
148 }
149
ParsedDataPresenter(const std::string & form_type)150 ParsedDataPresenter::ParsedDataPresenter(const std::string& form_type)
151 : parser_(FormDataParser::CreateFromContentTypeHeader(&form_type)),
152 success_(parser_.get() != NULL),
153 dictionary_(success_ ? new base::DictionaryValue() : NULL) {
154 }
155
Abort()156 void ParsedDataPresenter::Abort() {
157 success_ = false;
158 dictionary_.reset();
159 parser_.reset();
160 }
161
162 } // namespace extensions
163