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
16using base::BinaryValue;
17using base::DictionaryValue;
18using base::ListValue;
19using base::StringValue;
20using base::Value;
21
22namespace keys = extension_web_request_api_constants;
23
24namespace {
25
26// Takes |dictionary| of <string, list of strings> pairs, and gets the list
27// for |key|, creating it if necessary.
28ListValue* 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
40namespace extensions {
41
42namespace subtle {
43
44void 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
54UploadDataPresenter::~UploadDataPresenter() {}
55
56// Implementation of RawDataPresenter.
57
58RawDataPresenter::RawDataPresenter()
59  : success_(true),
60    list_(new base::ListValue) {
61}
62RawDataPresenter::~RawDataPresenter() {}
63
64void 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
80bool RawDataPresenter::Succeeded() {
81  return success_;
82}
83
84scoped_ptr<Value> RawDataPresenter::Result() {
85  if (!success_)
86    return scoped_ptr<Value>();
87
88  return list_.PassAs<Value>();
89}
90
91void RawDataPresenter::FeedNextBytes(const char* bytes, size_t size) {
92  subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
93                             BinaryValue::CreateWithCopiedBuffer(bytes, size),
94                             list_.get());
95}
96
97void 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                             Value::CreateStringValue(filename),
101                             list_.get());
102}
103
104// Implementation of ParsedDataPresenter.
105
106ParsedDataPresenter::ParsedDataPresenter(const net::URLRequest& request)
107  : parser_(FormDataParser::Create(request)),
108    success_(parser_.get() != NULL),
109    dictionary_(success_ ? new DictionaryValue() : NULL) {
110}
111
112ParsedDataPresenter::~ParsedDataPresenter() {}
113
114void 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
135bool ParsedDataPresenter::Succeeded() {
136  if (success_ && !parser_->AllDataReadOK())
137    Abort();
138  return success_;
139}
140
141scoped_ptr<Value> ParsedDataPresenter::Result() {
142  if (!success_)
143    return scoped_ptr<Value>();
144
145  return dictionary_.PassAs<Value>();
146}
147
148// static
149scoped_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
154ParsedDataPresenter::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
160void ParsedDataPresenter::Abort() {
161  success_ = false;
162  dictionary_.reset();
163  parser_.reset();
164}
165
166}  // namespace extensions
167