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(DictionaryValue * dictionary,const std::string & key)28 ListValue* GetOrCreateList(DictionaryValue* dictionary,
29 const std::string& key) {
30 ListValue* list = NULL;
31 if (!dictionary->GetList(key, &list)) {
32 list = new 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,Value * value,ListValue * list)44 void AppendKeyValuePair(const char* key, Value* value, ListValue* list) {
45 DictionaryValue* dictionary = new DictionaryValue;
46 dictionary->SetWithoutPathExpansion(key, value);
47 list->Append(dictionary);
48 }
49
50 } // namespace subtle
51
52 // Implementation of UploadDataPresenter.
53
~UploadDataPresenter()54 UploadDataPresenter::~UploadDataPresenter() {}
55
56 // Implementation of RawDataPresenter.
57
RawDataPresenter()58 RawDataPresenter::RawDataPresenter()
59 : success_(true),
60 list_(new base::ListValue) {
61 }
~RawDataPresenter()62 RawDataPresenter::~RawDataPresenter() {}
63
FeedNext(const net::UploadElementReader & reader)64 void RawDataPresenter::FeedNext(const net::UploadElementReader& reader) {
65 if (!success_)
66 return;
67
68 if (reader.AsBytesReader()) {
69 const net::UploadBytesElementReader* bytes_reader = reader.AsBytesReader();
70 FeedNextBytes(bytes_reader->bytes(), bytes_reader->length());
71 } else if (reader.AsFileReader()) {
72 // Insert the file path instead of the contents, which may be too large.
73 const net::UploadFileElementReader* file_reader = reader.AsFileReader();
74 FeedNextFile(file_reader->path().AsUTF8Unsafe());
75 } else {
76 NOTIMPLEMENTED();
77 }
78 }
79
Succeeded()80 bool RawDataPresenter::Succeeded() {
81 return success_;
82 }
83
Result()84 scoped_ptr<Value> RawDataPresenter::Result() {
85 if (!success_)
86 return scoped_ptr<Value>();
87
88 return list_.PassAs<Value>();
89 }
90
FeedNextBytes(const char * bytes,size_t size)91 void RawDataPresenter::FeedNextBytes(const char* bytes, size_t size) {
92 subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
93 BinaryValue::CreateWithCopiedBuffer(bytes, size),
94 list_.get());
95 }
96
FeedNextFile(const std::string & filename)97 void RawDataPresenter::FeedNextFile(const std::string& filename) {
98 // Insert the file path instead of the contents, which may be too large.
99 subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
100 new base::StringValue(filename),
101 list_.get());
102 }
103
104 // Implementation of ParsedDataPresenter.
105
ParsedDataPresenter(const net::URLRequest & request)106 ParsedDataPresenter::ParsedDataPresenter(const net::URLRequest& request)
107 : parser_(FormDataParser::Create(request)),
108 success_(parser_.get() != NULL),
109 dictionary_(success_ ? new DictionaryValue() : NULL) {
110 }
111
~ParsedDataPresenter()112 ParsedDataPresenter::~ParsedDataPresenter() {}
113
FeedNext(const net::UploadElementReader & reader)114 void ParsedDataPresenter::FeedNext(const net::UploadElementReader& reader) {
115 if (!success_)
116 return;
117
118 const net::UploadBytesElementReader* bytes_reader = reader.AsBytesReader();
119 if (!bytes_reader) {
120 return;
121 }
122 if (!parser_->SetSource(base::StringPiece(bytes_reader->bytes(),
123 bytes_reader->length()))) {
124 Abort();
125 return;
126 }
127
128 FormDataParser::Result result;
129 while (parser_->GetNextNameValue(&result)) {
130 GetOrCreateList(dictionary_.get(), result.name())->Append(
131 new StringValue(result.value()));
132 }
133 }
134
Succeeded()135 bool ParsedDataPresenter::Succeeded() {
136 if (success_ && !parser_->AllDataReadOK())
137 Abort();
138 return success_;
139 }
140
Result()141 scoped_ptr<Value> ParsedDataPresenter::Result() {
142 if (!success_)
143 return scoped_ptr<Value>();
144
145 return dictionary_.PassAs<Value>();
146 }
147
148 // static
CreateForTests()149 scoped_ptr<ParsedDataPresenter> ParsedDataPresenter::CreateForTests() {
150 const std::string form_type("application/x-www-form-urlencoded");
151 return scoped_ptr<ParsedDataPresenter>(new ParsedDataPresenter(form_type));
152 }
153
ParsedDataPresenter(const std::string & form_type)154 ParsedDataPresenter::ParsedDataPresenter(const std::string& form_type)
155 : parser_(FormDataParser::CreateFromContentTypeHeader(&form_type)),
156 success_(parser_.get() != NULL),
157 dictionary_(success_ ? new DictionaryValue() : NULL) {
158 }
159
Abort()160 void ParsedDataPresenter::Abort() {
161 success_ = false;
162 dictionary_.reset();
163 parser_.reset();
164 }
165
166 } // namespace extensions
167