blob: 3924505748b9ab0505221317d0789021b57b2216 [file] [log] [blame]
Chris Sosa45d9f102014-03-24 11:18:54 -07001// Copyright 2014 The Chromium OS 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 "buffet/http_utils.h"
6
7#include <algorithm>
Alex Vakulenkob3aac252014-05-07 17:35:24 -07008
Chris Sosa45d9f102014-03-24 11:18:54 -07009#include <base/json/json_reader.h>
10#include <base/json/json_writer.h>
Alex Vakulenkob3aac252014-05-07 17:35:24 -070011#include <base/values.h>
Chris Sosa45d9f102014-03-24 11:18:54 -070012
Alex Vakulenkob645cc92014-04-15 11:34:35 -070013#include "buffet/data_encoding.h"
Alex Vakulenkoc30f8212014-07-22 07:27:22 -070014#include "buffet/error_codes.h"
15#include "buffet/mime_utils.h"
Chris Sosa45d9f102014-03-24 11:18:54 -070016
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070017namespace buffet {
Chris Sosa45d9f102014-03-24 11:18:54 -070018namespace http {
19
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070020std::unique_ptr<Response> Get(const std::string& url,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070021 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070022 std::shared_ptr<Transport> transport,
23 ErrorPtr* error) {
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070024 return SendRequest(request_type::kGet, url, nullptr, 0, nullptr,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070025 headers, transport, error);
Chris Sosa45d9f102014-03-24 11:18:54 -070026}
27
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070028std::string GetAsString(const std::string& url,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070029 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070030 std::shared_ptr<Transport> transport,
31 ErrorPtr* error) {
32 auto resp = Get(url, headers, transport, error);
Chris Sosa45d9f102014-03-24 11:18:54 -070033 return resp ? resp->GetDataAsString() : std::string();
34}
35
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070036std::unique_ptr<Response> Head(const std::string& url,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070037 std::shared_ptr<Transport> transport,
38 ErrorPtr* error) {
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070039 Request request(url, request_type::kHead, transport);
Alex Vakulenkob3aac252014-05-07 17:35:24 -070040 return request.GetResponse(error);
Chris Sosa45d9f102014-03-24 11:18:54 -070041}
42
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070043std::unique_ptr<Response> PostText(const std::string& url,
44 const char* data,
45 const char* mime_type,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070046 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070047 std::shared_ptr<Transport> transport,
48 ErrorPtr* error) {
Chris Sosa45d9f102014-03-24 11:18:54 -070049 if (mime_type == nullptr) {
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070050 mime_type = mime::application::kWwwFormUrlEncoded;
Chris Sosa45d9f102014-03-24 11:18:54 -070051 }
52
Alex Vakulenkob3aac252014-05-07 17:35:24 -070053 return PostBinary(url, data, strlen(data), mime_type, headers, transport,
54 error);
Chris Sosa45d9f102014-03-24 11:18:54 -070055}
56
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070057std::unique_ptr<Response> SendRequest(const char * method,
58 const std::string& url,
59 const void* data,
Alex Vakulenkob645cc92014-04-15 11:34:35 -070060 size_t data_size,
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070061 const char* mime_type,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070062 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070063 std::shared_ptr<Transport> transport,
64 ErrorPtr* error) {
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070065 Request request(url, method, transport);
Alex Vakulenkob645cc92014-04-15 11:34:35 -070066 request.AddHeaders(headers);
67 if (data_size > 0) {
68 if (mime_type == nullptr) {
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070069 mime_type = mime::application::kOctet_stream;
Alex Vakulenkob645cc92014-04-15 11:34:35 -070070 }
71 request.SetContentType(mime_type);
Alex Vakulenkob3aac252014-05-07 17:35:24 -070072 if (!request.AddRequestBody(data, data_size, error))
73 return std::unique_ptr<Response>();
Chris Sosa45d9f102014-03-24 11:18:54 -070074 }
Alex Vakulenkob3aac252014-05-07 17:35:24 -070075 return request.GetResponse(error);
Chris Sosa45d9f102014-03-24 11:18:54 -070076}
77
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070078std::unique_ptr<Response> PostBinary(const std::string & url, const void* data,
79 size_t data_size, const char* mime_type,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070080 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070081 std::shared_ptr<Transport> transport,
82 ErrorPtr* error) {
Alex Vakulenkob645cc92014-04-15 11:34:35 -070083 return SendRequest(request_type::kPost, url,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070084 data, data_size, mime_type, headers, transport, error);
Chris Sosa45d9f102014-03-24 11:18:54 -070085}
86
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070087std::unique_ptr<Response> PostFormData(const std::string& url,
88 const FormFieldList& data,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070089 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070090 std::shared_ptr<Transport> transport,
91 ErrorPtr* error) {
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070092 std::string encoded_data = data_encoding::WebParamsEncode(data);
Alex Vakulenkob645cc92014-04-15 11:34:35 -070093 return PostBinary(url, encoded_data.c_str(), encoded_data.size(),
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070094 mime::application::kWwwFormUrlEncoded,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070095 headers, transport, error);
Alex Vakulenkob645cc92014-04-15 11:34:35 -070096}
97
98
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070099std::unique_ptr<Response> PostJson(const std::string& url,
100 const base::Value* json,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700101 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700102 std::shared_ptr<Transport> transport,
103 ErrorPtr* error) {
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700104 std::string data;
105 if (json)
106 base::JSONWriter::Write(json, &data);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700107 std::string mime_type = mime::AppendParameter(mime::application::kJson,
108 mime::parameters::kCharset,
109 "utf-8");
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700110 return PostBinary(url, data.c_str(), data.size(),
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700111 mime_type.c_str(), headers, transport, error);
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700112}
113
Alex Vakulenkob8ba5952014-04-17 11:35:56 -0700114std::unique_ptr<Response> PatchJson(const std::string& url,
115 const base::Value* json,
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700116 const HeaderList& headers,
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700117 std::shared_ptr<Transport> transport,
118 ErrorPtr* error) {
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700119 std::string data;
120 if (json)
121 base::JSONWriter::Write(json, &data);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700122 std::string mime_type = mime::AppendParameter(mime::application::kJson,
123 mime::parameters::kCharset,
124 "utf-8");
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700125 return SendRequest(request_type::kPatch, url, data.c_str(), data.size(),
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700126 mime_type.c_str(), headers, transport, error);
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700127}
128
129std::unique_ptr<base::DictionaryValue> ParseJsonResponse(
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700130 const Response* response, int* status_code, ErrorPtr* error) {
131 if (!response)
132 return std::unique_ptr<base::DictionaryValue>();
Alex Vakulenkob645cc92014-04-15 11:34:35 -0700133
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700134 if (status_code)
135 *status_code = response->GetStatusCode();
136
137 // Make sure we have a correct content type. Do not try to parse
138 // binary files, or HTML output. Limit to application/json and text/plain.
139 auto content_type = mime::RemoveParameters(response->GetContentType());
140 if (content_type != mime::application::kJson &&
141 content_type != mime::text::kPlain) {
Alex Vakulenkoc30f8212014-07-22 07:27:22 -0700142 Error::AddTo(error, errors::json::kDomain, "non_json_content_type",
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700143 "Unexpected response content type: " + content_type);
144 return std::unique_ptr<base::DictionaryValue>();
Chris Sosa45d9f102014-03-24 11:18:54 -0700145 }
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700146
147 std::string json = response->GetDataAsString();
148 std::string error_message;
149 base::Value* value = base::JSONReader::ReadAndReturnError(
150 json, base::JSON_PARSE_RFC, nullptr, &error_message);
151 if (!value) {
Alex Vakulenkoc30f8212014-07-22 07:27:22 -0700152 Error::AddTo(error, errors::json::kDomain, errors::json::kParseError,
153 error_message);
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700154 return std::unique_ptr<base::DictionaryValue>();
155 }
156 base::DictionaryValue* dict_value = nullptr;
157 if (!value->GetAsDictionary(&dict_value)) {
158 delete value;
Alex Vakulenkoc30f8212014-07-22 07:27:22 -0700159 Error::AddTo(error, errors::json::kDomain, errors::json::kObjectExpected,
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700160 "Response is not a valid JSON object");
161 return std::unique_ptr<base::DictionaryValue>();
162 }
163 return std::unique_ptr<base::DictionaryValue>(dict_value);
Chris Sosa45d9f102014-03-24 11:18:54 -0700164}
165
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700166} // namespace http
Alex Vakulenkoaf23b322014-05-08 16:25:45 -0700167} // namespace buffet