1// Copyright 2015 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <libwebserv/response_impl.h>
16
17#include <algorithm>
18
19#include <base/json/json_writer.h>
20#include <base/logging.h>
21#include <base/values.h>
22#include <brillo/http/http_request.h>
23#include <brillo/mime_utils.h>
24#include <brillo/streams/memory_stream.h>
25#include <brillo/strings/string_utils.h>
26#include <libwebserv/dbus_protocol_handler.h>
27
28namespace libwebserv {
29
30ResponseImpl::ResponseImpl(DBusProtocolHandler* handler,
31                           const std::string& request_id)
32    : handler_{handler}, request_id_{request_id} {
33}
34
35ResponseImpl::~ResponseImpl() {
36  if (!reply_sent_) {
37    ReplyWithError(brillo::http::status_code::InternalServerError,
38                   "Internal server error");
39  }
40}
41
42void ResponseImpl::AddHeader(const std::string& header_name,
43                             const std::string& value) {
44  headers_.emplace(header_name, value);
45}
46
47void ResponseImpl::AddHeaders(
48    const std::vector<std::pair<std::string, std::string>>& headers) {
49  headers_.insert(headers.begin(), headers.end());
50}
51
52void ResponseImpl::Reply(int status_code,
53                         brillo::StreamPtr data_stream,
54                         const std::string& mime_type) {
55  CHECK(data_stream);
56  status_code_ = status_code;
57  data_stream_ = std::move(data_stream);
58  AddHeader(brillo::http::response_header::kContentType, mime_type);
59  SendResponse();
60}
61
62void ResponseImpl::ReplyWithText(int status_code,
63                                 const std::string& text,
64                                 const std::string& mime_type) {
65  Reply(status_code, brillo::MemoryStream::OpenCopyOf(text, nullptr),
66        mime_type);
67}
68
69void ResponseImpl::ReplyWithJson(int status_code, const base::Value* json) {
70  std::string text;
71  base::JSONWriter::WriteWithOptions(
72      *json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &text);
73  std::string mime_type = brillo::mime::AppendParameter(
74      brillo::mime::application::kJson,
75      brillo::mime::parameters::kCharset,
76      "utf-8");
77  ReplyWithText(status_code, text, mime_type);
78}
79
80void ResponseImpl::ReplyWithJson(
81    int status_code, const std::map<std::string, std::string>& json) {
82  base::DictionaryValue json_value;
83  for (const auto& pair : json) {
84    json_value.SetString(pair.first, pair.second);
85  }
86  ReplyWithJson(status_code, &json_value);
87}
88
89void ResponseImpl::Redirect(int status_code, const std::string& redirect_url) {
90  AddHeader(brillo::http::response_header::kLocation, redirect_url);
91  ReplyWithError(status_code, "");
92}
93
94void ResponseImpl::ReplyWithError(int status_code,
95                                  const std::string& error_text) {
96  status_code_ = status_code;
97  data_stream_ = brillo::MemoryStream::OpenCopyOf(error_text, nullptr);
98  SendResponse();
99}
100
101void ResponseImpl::ReplyWithErrorNotFound() {
102  ReplyWithError(brillo::http::status_code::NotFound, "Not Found");
103}
104
105void ResponseImpl::SendResponse() {
106  CHECK(!reply_sent_) << "Response already sent";
107  reply_sent_ = true;
108  handler_->CompleteRequest(request_id_, status_code_, headers_,
109                            std::move(data_stream_));
110}
111
112}  // namespace libwebserv
113