blob: 84d70cb928b7ec03180875c6d1f9ae4c94bb3845 [file] [log] [blame]
Alex Vakulenko9cd5e272014-04-25 17:26:11 -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_transport_fake.h"
6
7#include <base/json/json_writer.h>
Alex Vakulenkof8545912014-04-30 12:25:19 -07008#include <base/logging.h>
Alex Vakulenko9cd5e272014-04-25 17:26:11 -07009
10#include "buffet/http_connection_fake.h"
11#include "buffet/http_request.h"
12#include "buffet/mime_utils.h"
13#include "buffet/url_utils.h"
14
15using namespace chromeos;
16using namespace chromeos::http::fake;
17
18Transport::Transport() {
19 VLOG(1) << "fake::Transport created";
20}
21
22Transport::~Transport() {
23 VLOG(1) << "fake::Transport destroyed";
24}
25
26std::unique_ptr<http::Connection> Transport::CreateConnection(
27 std::shared_ptr<http::Transport> transport,
28 const std::string& url,
29 const std::string& method,
30 const HeaderList& headers,
31 const std::string& user_agent,
32 const std::string& referer,
33 std::string* error_msg) {
34 HeaderList headers_copy = headers;
35 if (!user_agent.empty()) {
36 headers_copy.push_back(std::make_pair(http::request_header::kUserAgent,
37 user_agent));
38 }
39 if (!referer.empty()) {
40 headers_copy.push_back(std::make_pair(http::request_header::kReferer,
41 referer));
42 }
43 std::unique_ptr<http::Connection> connection(
44 new http::fake::Connection(url, method, transport));
45 CHECK(connection) << "Unable to create Connection object";
46 if (!connection->SendHeaders(headers_copy)) {
47 connection.reset();
48 if (error_msg)
49 *error_msg = "Failed to send request headers";
50 }
51 return connection;
52}
53
54static inline std::string GetHandlerMapKey(const std::string& url,
55 const std::string& method) {
56 return method + ":" + url;
57}
58
59void Transport::AddHandler(const std::string& url, const std::string& method,
60 const HandlerCallback& handler) {
61 handlers_.insert(std::make_pair(GetHandlerMapKey(url, method), handler));
62}
63
64Transport::HandlerCallback Transport::GetHandler(
65 const std::string& url, const std::string& method) const {
66 // First try the exact combination of URL/Method
67 auto p = handlers_.find(GetHandlerMapKey(url, method));
68 if (p != handlers_.end())
69 return p->second;
70 // If not found, try URL/*
71 p = handlers_.find(GetHandlerMapKey(url, "*"));
72 if (p != handlers_.end())
73 return p->second;
74 // If still not found, try */method
75 p = handlers_.find(GetHandlerMapKey("*", method));
76 if (p != handlers_.end())
77 return p->second;
78 // Finally, try */*
79 p = handlers_.find(GetHandlerMapKey("*", "*"));
80 return (p != handlers_.end()) ? p->second : HandlerCallback();
81}
82
83void ServerRequestResponseBase::AddData(const void* data, size_t data_size) {
84 auto bytes = reinterpret_cast<const unsigned char*>(data);
85 data_.insert(data_.end(), bytes, bytes + data_size);
86}
87
88std::string ServerRequestResponseBase::GetDataAsString() const {
89 if (data_.empty())
90 return std::string();
91 auto chars = reinterpret_cast<const char*>(data_.data());
92 return std::string(chars, data_.size());
93}
94
95void ServerRequestResponseBase::AddHeaders(const HeaderList& headers) {
96 for (auto&& pair : headers) {
97 if (pair.second.empty())
98 headers_.erase(pair.first);
99 else
100 headers_.insert(pair);
101 }
102}
103
104std::string ServerRequestResponseBase::GetHeader(
105 const std::string& header_name) const {
106 auto p = headers_.find(header_name);
107 return p != headers_.end() ? p->second : std::string();
108}
109
110ServerRequest::ServerRequest(const std::string& url,
111 const std::string& method) : method_(method) {
112 auto params = url::GetQueryStringParameters(url);
113 url_ = url::RemoveQueryString(url, true);
114 form_fields_.insert(params.begin(), params.end());
115}
116
117std::string ServerRequest::GetFormField(const std::string& field_name) const {
118 if (!form_fields_parsed_) {
119 std::string mime_type = mime::RemoveParameters(
120 GetHeader(request_header::kContentType));
121 if (mime_type == mime::application::kWwwFormUrlEncoded &&
122 !GetData().empty()) {
123 auto fields = data_encoding::WebParamsDecode(GetDataAsString());
124 form_fields_.insert(fields.begin(), fields.end());
125 }
126 form_fields_parsed_ = true;
127 }
128 auto p = form_fields_.find(field_name);
129 return p != form_fields_.end() ? p->second : std::string();
130}
131
132void ServerResponse::Reply(int status_code, const void* data, size_t data_size,
133 const char* mime_type) {
134 data_.clear();
135 status_code_ = status_code;
136 AddData(data, data_size);
137 AddHeaders({
138 {response_header::kContentLength, std::to_string(data_size)},
139 {response_header::kContentType, mime_type}
140 });
141}
142
143void ServerResponse::ReplyText(int status_code, const std::string& text,
144 const char* mime_type) {
145 Reply(status_code, text.data(), text.size(), mime_type);
146}
147
148void ServerResponse::ReplyJson(int status_code, const base::Value* json) {
149 std::string text;
150 base::JSONWriter::WriteWithOptions(json,
151 base::JSONWriter::OPTIONS_PRETTY_PRINT,
152 &text);
153 ReplyText(status_code, text, mime::application::kJson);
154}
155
156std::string ServerResponse::GetStatusText() const {
157 static std::vector<std::pair<int, const char*>> status_text_map = {
158 {100, "Continue"},
159 {101, "Switching Protocols"},
160 {102, "Processing"},
161 {200, "OK"},
162 {201, "Created"},
163 {202, "Accepted"},
164 {203, "Non-Authoritative Information"},
165 {204, "No Content"},
166 {205, "Reset Content"},
167 {206, "Partial Content"},
168 {207, "Multi-Status"},
169 {208, "Already Reported"},
170 {226, "IM Used"},
171 {300, "Multiple Choices"},
172 {301, "Moved Permanently"},
173 {302, "Found"},
174 {303, "See Other"},
175 {304, "Not Modified"},
176 {305, "Use Proxy"},
177 {306, "Switch Proxy"},
178 {307, "Temporary Redirect"},
179 {308, "Permanent Redirect"},
180 {400, "Bad Request"},
181 {401, "Unauthorized"},
182 {402, "Payment Required"},
183 {403, "Forbidden"},
184 {404, "Not Found"},
185 {405, "Method Not Allowed"},
186 {406, "Not Acceptable"},
187 {407, "Proxy Authentication Required"},
188 {408, "Request Timeout"},
189 {409, "Conflict"},
190 {410, "Gone"},
191 {411, "Length Required"},
192 {412, "Precondition Failed"},
193 {413, "Request Entity Too Large"},
194 {414, "Request - URI Too Long"},
195 {415, "Unsupported Media Type"},
196 {429, "Too Many Requests"},
197 {431, "Request Header Fields Too Large"},
198 {500, "Internal Server Error"},
199 {501, "Not Implemented"},
200 {502, "Bad Gateway"},
201 {503, "Service Unavailable"},
202 {504, "Gateway Timeout"},
203 {505, "HTTP Version Not Supported"},
204 };
205
206 for (auto&& pair : status_text_map) {
207 if (pair.first == status_code_)
208 return pair.second;
209 }
210 return std::string();
211}