/root/doris/be/src/http/http_channel.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. 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 | | #include "http/http_channel.h" |
19 | | |
20 | | #include <event2/buffer.h> |
21 | | #include <event2/bufferevent.h> |
22 | | #include <event2/http.h> |
23 | | |
24 | | #include <algorithm> |
25 | | #include <sstream> |
26 | | #include <string> |
27 | | #include <vector> |
28 | | |
29 | | #include "common/logging.h" |
30 | | #include "common/status.h" |
31 | | #include "gutil/strings/split.h" |
32 | | #include "gutil/strings/strip.h" |
33 | | #include "http/http_headers.h" |
34 | | #include "http/http_request.h" |
35 | | #include "http/http_status.h" |
36 | | #include "util/slice.h" |
37 | | #include "util/zlib.h" |
38 | | |
39 | | namespace doris { |
40 | | |
41 | | // Send Unauthorized status with basic challenge |
42 | 1 | void HttpChannel::send_basic_challenge(HttpRequest* req, const std::string& realm) { |
43 | 1 | static std::string s_prompt_str = "Please provide your userid and password\n"; |
44 | 1 | std::stringstream ss; |
45 | 1 | ss << "Basic realm=\"" << realm << "\""; |
46 | 1 | req->add_output_header(HttpHeaders::WWW_AUTHENTICATE, ss.str().c_str()); |
47 | 1 | send_reply(req, HttpStatus::UNAUTHORIZED, s_prompt_str); |
48 | 1 | } |
49 | | |
50 | 2 | void HttpChannel::send_error(HttpRequest* request, HttpStatus status) { |
51 | 2 | evhttp_send_error(request->get_evhttp_request(), status, default_reason(status).c_str()); |
52 | 2 | } |
53 | | |
54 | 15 | void HttpChannel::send_reply(HttpRequest* request, HttpStatus status) { |
55 | 15 | evhttp_send_reply(request->get_evhttp_request(), status, default_reason(status).c_str(), |
56 | 15 | nullptr); |
57 | 15 | } |
58 | | |
59 | 21 | void HttpChannel::send_reply(HttpRequest* request, HttpStatus status, const std::string& content) { |
60 | 21 | auto evb = evbuffer_new(); |
61 | 21 | std::string compressed_content; |
62 | 21 | if (compress_content(request->header(HttpHeaders::ACCEPT_ENCODING), content, |
63 | 21 | &compressed_content)) { |
64 | 0 | request->add_output_header(HttpHeaders::CONTENT_ENCODING, "gzip"); |
65 | 0 | evbuffer_add(evb, compressed_content.c_str(), compressed_content.size()); |
66 | 21 | } else { |
67 | 21 | evbuffer_add(evb, content.c_str(), content.size()); |
68 | 21 | } |
69 | 21 | evhttp_send_reply(request->get_evhttp_request(), status, default_reason(status).c_str(), evb); |
70 | 21 | evbuffer_free(evb); |
71 | 21 | } |
72 | | |
73 | | void HttpChannel::send_file(HttpRequest* request, int fd, size_t off, size_t size, |
74 | 0 | bufferevent_rate_limit_group* rate_limit_group) { |
75 | 0 | auto evb = evbuffer_new(); |
76 | 0 | evbuffer_add_file(evb, fd, off, size); |
77 | 0 | auto* evhttp_request = request->get_evhttp_request(); |
78 | 0 | if (rate_limit_group) { |
79 | 0 | auto* evhttp_connection = evhttp_request_get_connection(evhttp_request); |
80 | 0 | auto* buffer_event = evhttp_connection_get_bufferevent(evhttp_connection); |
81 | 0 | bufferevent_add_to_rate_limit_group(buffer_event, rate_limit_group); |
82 | 0 | } |
83 | 0 | evhttp_send_reply(evhttp_request, HttpStatus::OK, default_reason(HttpStatus::OK).c_str(), evb); |
84 | 0 | evbuffer_free(evb); |
85 | 0 | } |
86 | | |
87 | | bool HttpChannel::compress_content(const std::string& accept_encoding, const std::string& input, |
88 | 26 | std::string* output) { |
89 | | // Don't bother compressing empty content. |
90 | 26 | if (input.empty()) { |
91 | 2 | return false; |
92 | 2 | } |
93 | | |
94 | | // Check if gzip compression is accepted by the caller. If so, compress the |
95 | | // content and replace the prerendered output. |
96 | 24 | bool is_compressed = false; |
97 | 24 | std::vector<string> encodings = strings::Split(accept_encoding, ","); |
98 | 25 | for (string& encoding : encodings) { |
99 | 25 | StripWhiteSpace(&encoding); |
100 | 25 | if (encoding == "gzip") { |
101 | 2 | std::ostringstream oss; |
102 | 2 | Status s = zlib::CompressLevel(Slice(input), 1, &oss); |
103 | 2 | if (s.ok()) { |
104 | 2 | *output = oss.str(); |
105 | 2 | is_compressed = true; |
106 | 2 | } else { |
107 | 0 | LOG(WARNING) << "Could not compress output: " << s.to_string(); |
108 | 0 | } |
109 | 2 | break; |
110 | 2 | } |
111 | 25 | } |
112 | 24 | return is_compressed; |
113 | 26 | } |
114 | | |
115 | | } // namespace doris |