]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/src/http/file_handler.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / src / http / file_handler.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/file_handler.hh>
23 #include <seastar/core/seastar.hh>
24 #include <algorithm>
25 #include <iostream>
26 #include <seastar/core/reactor.hh>
27 #include <seastar/core/fstream.hh>
28 #include <seastar/core/shared_ptr.hh>
29 #include <seastar/core/app-template.hh>
30 #include <seastar/http/exception.hh>
31
32 namespace seastar {
33
34 namespace httpd {
35
36 directory_handler::directory_handler(const sstring& doc_root,
37 file_transformer* transformer)
38 : file_interaction_handler(transformer), doc_root(doc_root) {
39 }
40
41 future<std::unique_ptr<reply>> directory_handler::handle(const sstring& path,
42 std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
43 sstring full_path = doc_root + req->param["path"];
44 auto h = this;
45 return engine().file_type(full_path).then(
46 [h, full_path, req = std::move(req), rep = std::move(rep)](auto val) mutable {
47 if (val) {
48 if (val.value() == directory_entry_type::directory) {
49 if (h->redirect_if_needed(*req.get(), *rep.get())) {
50 return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
51 }
52 full_path += "/index.html";
53 }
54 return h->read(full_path, std::move(req), std::move(rep));
55 }
56 rep->set_status(reply::status_type::not_found).done();
57 return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
58
59 });
60 }
61
62 file_interaction_handler::~file_interaction_handler() {
63 delete transformer;
64 }
65
66 sstring file_interaction_handler::get_extension(const sstring& file) {
67 size_t last_slash_pos = file.find_last_of('/');
68 size_t last_dot_pos = file.find_last_of('.');
69 sstring extension;
70 if (last_dot_pos != sstring::npos && last_dot_pos > last_slash_pos) {
71 extension = file.substr(last_dot_pos + 1);
72 }
73 // normalize file extension for mime type
74 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
75 return extension;
76 }
77
78 output_stream<char> file_interaction_handler::get_stream(std::unique_ptr<request> req,
79 const sstring& extension, output_stream<char>&& s) {
80 if (transformer) {
81 return transformer->transform(std::move(req), extension, std::move(s));
82 }
83 return std::move(s);
84 }
85
86 future<std::unique_ptr<reply>> file_interaction_handler::read(
87 sstring file_name, std::unique_ptr<request> req,
88 std::unique_ptr<reply> rep) {
89 sstring extension = get_extension(file_name);
90 rep->write_body(extension, [req = std::move(req), extension, file_name, this] (output_stream<char>&& s) mutable {
91 return do_with(output_stream<char>(get_stream(std::move(req), extension, std::move(s))),
92 [file_name] (output_stream<char>& os) {
93 return open_file_dma(file_name, open_flags::ro).then([&os] (file f) {
94 return do_with(input_stream<char>(make_file_input_stream(std::move(f))), [&os](input_stream<char>& is) {
95 return copy(is, os).then([&os] {
96 return os.close();
97 }).then([&is] {
98 return is.close();
99 });
100 });
101 });
102 });
103 });
104 return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
105 }
106
107 bool file_interaction_handler::redirect_if_needed(const request& req,
108 reply& rep) const {
109 if (req._url.length() == 0 || req._url.back() != '/') {
110 rep.set_status(reply::status_type::moved_permanently);
111 rep._headers["Location"] = req.get_url() + "/";
112 rep.done();
113 return true;
114 }
115 return false;
116 }
117
118 future<std::unique_ptr<reply>> file_handler::handle(const sstring& path,
119 std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
120 if (force_path && redirect_if_needed(*req.get(), *rep.get())) {
121 return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
122 }
123 return read(file, std::move(req), std::move(rep));
124 }
125
126 }
127
128 }