]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/src/http/common.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / src / http / common.cc
1 /*
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.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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
16 * under the License.
17 */
18 /*
19 * Copyright 2015 Cloudius Systems
20 */
21
22 #include <seastar/http/common.hh>
23 #include <seastar/core/iostream-impl.hh>
24
25 namespace seastar {
26
27 namespace httpd {
28
29 operation_type str2type(const sstring& type) {
30 if (type == "DELETE") {
31 return DELETE;
32 }
33 if (type == "POST") {
34 return POST;
35 }
36 if (type == "PUT") {
37 return PUT;
38 }
39 if (type == "HEAD") {
40 return HEAD;
41 }
42 if (type == "OPTIONS") {
43 return OPTIONS;
44 }
45 if (type == "TRACE") {
46 return TRACE;
47 }
48 if (type == "CONNECT") {
49 return CONNECT;
50 }
51 return GET;
52 }
53
54 sstring type2str(operation_type type) {
55 if (type == DELETE) {
56 return "DELETE";
57 }
58 if (type == POST) {
59 return "POST";
60 }
61 if (type == PUT) {
62 return "PUT";
63 }
64 if (type == HEAD) {
65 return "HEAD";
66 }
67 if (type == OPTIONS) {
68 return "OPTIONS";
69 }
70 if (type == TRACE) {
71 return "TRACE";
72 }
73 if (type == CONNECT) {
74 return "CONNECT";
75 }
76 return "GET";
77 }
78
79 }
80
81 namespace http {
82 namespace internal {
83
84 static constexpr size_t default_body_sink_buffer_size = 32000;
85
86 // Data sinks below are running "on top" of socket output stream and provide
87 // reliable and handy way of generating request bodies according to selected
88 // encoding type and content-length.
89 //
90 // Respectively, both .close() methods should not close the underlying stream,
91 // because the socket in question may continue being in use for keep-alive
92 // connections, and closing it would just break the keep-alive-ness
93
94 class http_chunked_data_sink_impl : public data_sink_impl {
95 output_stream<char>& _out;
96
97 future<> write_size(size_t s) {
98 auto req = format("{:x}\r\n", s);
99 return _out.write(req);
100 }
101 public:
102 http_chunked_data_sink_impl(output_stream<char>& out) : _out(out) {
103 }
104 virtual future<> put(net::packet data) override { abort(); }
105 using data_sink_impl::put;
106 virtual future<> put(temporary_buffer<char> buf) override {
107 if (buf.size() == 0) {
108 // size 0 buffer should be ignored, some server
109 // may consider it an end of message
110 return make_ready_future<>();
111 }
112 auto size = buf.size();
113 return write_size(size).then([this, buf = std::move(buf)] () mutable {
114 return _out.write(buf.get(), buf.size());
115 }).then([this] () mutable {
116 return _out.write("\r\n", 2);
117 });
118 }
119 virtual future<> close() override {
120 return make_ready_future<>();
121 }
122 };
123
124 class http_chunked_data_sink : public data_sink {
125 public:
126 http_chunked_data_sink(output_stream<char>& out)
127 : data_sink(std::make_unique<http_chunked_data_sink_impl>(
128 out)) {}
129 };
130
131 output_stream<char> make_http_chunked_output_stream(output_stream<char>& out) {
132 output_stream_options opts;
133 opts.trim_to_size = true;
134 return output_stream<char>(http_chunked_data_sink(out), default_body_sink_buffer_size, opts);
135 }
136
137 class http_content_length_data_sink_impl : public data_sink_impl {
138 output_stream<char>& _out;
139 const size_t _limit;
140 size_t& _bytes_written;
141
142 public:
143 http_content_length_data_sink_impl(output_stream<char>& out, size_t& len)
144 : _out(out)
145 , _limit(std::exchange(len, 0))
146 , _bytes_written(len)
147 {
148 }
149 virtual future<> put(net::packet data) override { abort(); }
150 using data_sink_impl::put;
151 virtual future<> put(temporary_buffer<char> buf) override {
152 if (buf.size() == 0 || _bytes_written == _limit) {
153 return make_ready_future<>();
154 }
155
156 auto size = buf.size();
157 if (_bytes_written + size > _limit) {
158 return make_exception_future<>(std::runtime_error(format("body conent length overflow: want {} limit {}", _bytes_written + buf.size(), _limit)));
159 }
160
161 return _out.write(buf.get(), size).then([this, size] {
162 _bytes_written += size;
163 });
164 }
165 virtual future<> close() override {
166 return make_ready_future<>();
167 }
168 };
169
170 class http_content_length_data_sink : public data_sink {
171 public:
172 http_content_length_data_sink(output_stream<char>& out, size_t& len)
173 : data_sink(std::make_unique<http_content_length_data_sink_impl>(out, len))
174 {
175 }
176 };
177
178 output_stream<char> make_http_content_length_output_stream(output_stream<char>& out, size_t& len) {
179 output_stream_options opts;
180 opts.trim_to_size = true;
181 return output_stream<char>(http_content_length_data_sink(out, len), default_body_sink_buffer_size, opts);
182 }
183
184 }
185 }
186
187 }
188