2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright 2015 Cloudius Systems
26 // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
28 // Distributed under the Boost Software License, Version 1.0. (See accompanying
29 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
31 #include <seastar/http/reply.hh>
32 #include <seastar/core/print.hh>
33 #include <seastar/http/httpd.hh>
34 #include <seastar/http/common.hh>
35 #include <seastar/http/response_parser.hh>
36 #include <seastar/core/loop.hh>
42 namespace status_strings
{
44 const sstring continue_
= "100 Continue";
45 const sstring switching_protocols
= "101 Switching Protocols";
46 const sstring ok
= "200 OK";
47 const sstring created
= "201 Created";
48 const sstring accepted
= "202 Accepted";
49 const sstring nonauthoritative_information
= "203 Non-Authoritative Information";
50 const sstring no_content
= "204 No Content";
51 const sstring reset_content
= "205 Reset Content";
52 const sstring partial_content
= "206 Partial Content";
53 const sstring multiple_choices
= "300 Multiple Choices";
54 const sstring moved_permanently
= "301 Moved Permanently";
55 const sstring moved_temporarily
= "302 Moved Temporarily";
56 const sstring see_other
= "303 See Other";
57 const sstring not_modified
= "304 Not Modified";
58 const sstring use_proxy
= "305 Use Proxy";
59 const sstring temporary_redirect
= "307 Temporary Redirect";
60 const sstring bad_request
= "400 Bad Request";
61 const sstring unauthorized
= "401 Unauthorized";
62 const sstring payment_required
= "402 Payment Required";
63 const sstring forbidden
= "403 Forbidden";
64 const sstring not_found
= "404 Not Found";
65 const sstring method_not_allowed
= "405 Method Not Allowed";
66 const sstring not_acceptable
= "406 Not Acceptable";
67 const sstring request_timeout
= "408 Request Timeout";
68 const sstring conflict
= "409 Conflict";
69 const sstring gone
= "410 Gone";
70 const sstring length_required
= "411 Length Required";
71 const sstring payload_too_large
= "413 Payload Too Large";
72 const sstring uri_too_long
= "414 URI Too Long";
73 const sstring unsupported_media_type
= "415 Unsupported Media Type";
74 const sstring expectation_failed
= "417 Expectation Failed";
75 const sstring unprocessable_entity
= "422 Unprocessable Entity";
76 const sstring upgrade_required
= "426 Upgrade Required";
77 const sstring too_many_requests
= "429 Too Many Requests";
78 const sstring internal_server_error
= "500 Internal Server Error";
79 const sstring not_implemented
= "501 Not Implemented";
80 const sstring bad_gateway
= "502 Bad Gateway";
81 const sstring service_unavailable
= "503 Service Unavailable";
82 const sstring gateway_timeout
= "504 Gateway Timeout";
83 const sstring http_version_not_supported
= "505 HTTP Version Not Supported";
84 const sstring insufficient_storage
= "507 Insufficient Storage";
86 static const sstring
& to_string(reply::status_type status
) {
88 case reply::status_type::continue_
:
90 case reply::status_type::switching_protocols
:
91 return switching_protocols
;
92 case reply::status_type::ok
:
94 case reply::status_type::created
:
96 case reply::status_type::accepted
:
98 case reply::status_type::nonauthoritative_information
:
99 return nonauthoritative_information
;
100 case reply::status_type::no_content
:
102 case reply::status_type::reset_content
:
103 return reset_content
;
104 case reply::status_type::partial_content
:
105 return partial_content
;
106 case reply::status_type::multiple_choices
:
107 return multiple_choices
;
108 case reply::status_type::moved_permanently
:
109 return moved_permanently
;
110 case reply::status_type::moved_temporarily
:
111 return moved_temporarily
;
112 case reply::status_type::see_other
:
114 case reply::status_type::not_modified
:
116 case reply::status_type::use_proxy
:
118 case reply::status_type::temporary_redirect
:
119 return temporary_redirect
;
120 case reply::status_type::bad_request
:
122 case reply::status_type::unauthorized
:
124 case reply::status_type::payment_required
:
125 return payment_required
;
126 case reply::status_type::forbidden
:
128 case reply::status_type::not_found
:
130 case reply::status_type::method_not_allowed
:
131 return method_not_allowed
;
132 case reply::status_type::not_acceptable
:
133 return not_acceptable
;
134 case reply::status_type::request_timeout
:
135 return request_timeout
;
136 case reply::status_type::conflict
:
138 case reply::status_type::gone
:
140 case reply::status_type::length_required
:
141 return length_required
;
142 case reply::status_type::payload_too_large
:
143 return payload_too_large
;
144 case reply::status_type::uri_too_long
:
146 case reply::status_type::unsupported_media_type
:
147 return unsupported_media_type
;
148 case reply::status_type::expectation_failed
:
149 return expectation_failed
;
150 case reply::status_type::unprocessable_entity
:
151 return unprocessable_entity
;
152 case reply::status_type::upgrade_required
:
153 return upgrade_required
;
154 case reply::status_type::too_many_requests
:
155 return too_many_requests
;
156 case reply::status_type::internal_server_error
:
157 return internal_server_error
;
158 case reply::status_type::not_implemented
:
159 return not_implemented
;
160 case reply::status_type::bad_gateway
:
162 case reply::status_type::service_unavailable
:
163 return service_unavailable
;
164 case reply::status_type::gateway_timeout
:
165 return gateway_timeout
;
166 case reply::status_type::http_version_not_supported
:
167 return http_version_not_supported
;
168 case reply::status_type::insufficient_storage
:
169 return insufficient_storage
;
171 return internal_server_error
;
174 } // namespace status_strings
176 std::ostream
& operator<<(std::ostream
& os
, reply::status_type st
) {
177 return os
<< status_strings::to_string(st
);
180 reply::reply(http_response
&& resp
)
181 : _status(static_cast<status_type
>(resp
._status_code
))
182 , _headers(std::move(resp
._headers
))
183 , _version(std::move(resp
._version
))
185 sstring length_header
= get_header("Content-Length");
186 content_length
= strtol(length_header
.c_str(), nullptr, 10);
189 sstring
reply::response_line() {
190 return "HTTP/" + _version
+ " " + status_strings::to_string(_status
) + "\r\n";
193 void reply::write_body(const sstring
& content_type
, noncopyable_function
<future
<>(output_stream
<char>&&)>&& body_writer
) {
194 set_content_type(content_type
);
195 _body_writer
= std::move(body_writer
);
198 void reply::write_body(const sstring
& content_type
, sstring content
) {
199 _content
= std::move(content
);
203 future
<> reply::write_reply_to_connection(httpd::connection
& con
) {
204 add_header("Transfer-Encoding", "chunked");
205 return con
.out().write(response_line()).then([this, &con
] () mutable {
206 return write_reply_headers(con
);
207 }).then([&con
] () mutable {
208 return con
.out().write("\r\n", 2);
209 }).then([this, &con
] () mutable {
210 return _body_writer(http::internal::make_http_chunked_output_stream(con
.out()));
215 future
<> reply::write_reply_headers(httpd::connection
& con
) {
216 return do_for_each(_headers
, [&con
](auto& h
) {
217 return con
.out().write(h
.first
+ ": " + h
.second
+ "\r\n");
222 } // namespace server