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 "extensions/browser/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 "extensions/browser/api/web_request/form_data_parser.h"
11#include "extensions/browser/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.
28base::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
40namespace extensions {
41
42namespace subtle {
43
44void 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
54UploadDataPresenter::~UploadDataPresenter() {}
55
56RawDataPresenter::RawDataPresenter()
57  : success_(true),
58    list_(new base::ListValue) {
59}
60RawDataPresenter::~RawDataPresenter() {}
61
62void 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
78bool RawDataPresenter::Succeeded() {
79  return success_;
80}
81
82scoped_ptr<base::Value> RawDataPresenter::Result() {
83  if (!success_)
84    return scoped_ptr<base::Value>();
85
86  return list_.PassAs<base::Value>();
87}
88
89void RawDataPresenter::FeedNextBytes(const char* bytes, size_t size) {
90  subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
91                             BinaryValue::CreateWithCopiedBuffer(bytes, size),
92                             list_.get());
93}
94
95void 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
102ParsedDataPresenter::ParsedDataPresenter(const net::URLRequest& request)
103  : parser_(FormDataParser::Create(request)),
104    success_(parser_.get() != NULL),
105    dictionary_(success_ ? new base::DictionaryValue() : NULL) {
106}
107
108ParsedDataPresenter::~ParsedDataPresenter() {}
109
110void 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
131bool ParsedDataPresenter::Succeeded() {
132  if (success_ && !parser_->AllDataReadOK())
133    Abort();
134  return success_;
135}
136
137scoped_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
145scoped_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
150ParsedDataPresenter::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
156void ParsedDataPresenter::Abort() {
157  success_ = false;
158  dictionary_.reset();
159  parser_.reset();
160}
161
162}  // namespace extensions
163