summaryrefslogtreecommitdiff
path: root/libs/tdlib/td/tdnet
diff options
context:
space:
mode:
Diffstat (limited to 'libs/tdlib/td/tdnet')
-rw-r--r--libs/tdlib/td/tdnet/CMakeLists.txt54
-rw-r--r--libs/tdlib/td/tdnet/td/net/GetHostByNameActor.cpp48
-rw-r--r--libs/tdlib/td/tdnet/td/net/GetHostByNameActor.h35
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.cpp83
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.h28
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpConnectionBase.cpp153
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpConnectionBase.h164
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.cpp34
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.h25
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpFile.cpp25
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpFile.h49
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpHeaderCreator.h139
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpInboundConnection.cpp28
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpInboundConnection.h43
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.cpp23
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.h46
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpQuery.cpp70
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpQuery.h47
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpReader.cpp814
-rw-r--r--libs/tdlib/td/tdnet/td/net/HttpReader.h108
-rw-r--r--libs/tdlib/td/tdnet/td/net/NetStats.h145
-rw-r--r--libs/tdlib/td/tdnet/td/net/Socks5.cpp249
-rw-r--r--libs/tdlib/td/tdnet/td/net/Socks5.h71
-rw-r--r--libs/tdlib/td/tdnet/td/net/SslFd.cpp280
-rw-r--r--libs/tdlib/td/tdnet/td/net/SslFd.h109
-rw-r--r--libs/tdlib/td/tdnet/td/net/TcpListener.cpp62
-rw-r--r--libs/tdlib/td/tdnet/td/net/TcpListener.h35
-rw-r--r--libs/tdlib/td/tdnet/td/net/Wget.cpp126
-rw-r--r--libs/tdlib/td/tdnet/td/net/Wget.h48
29 files changed, 0 insertions, 3141 deletions
diff --git a/libs/tdlib/td/tdnet/CMakeLists.txt b/libs/tdlib/td/tdnet/CMakeLists.txt
deleted file mode 100644
index 823ed027d6..0000000000
--- a/libs/tdlib/td/tdnet/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
-
-if (NOT OPENSSL_FOUND)
- find_package(OpenSSL REQUIRED)
- find_package(ZLIB REQUIRED)
-endif()
-
-#SOURCE SETS
-set(TDNET_SOURCE
- td/net/GetHostByNameActor.cpp
- td/net/HttpChunkedByteFlow.cpp
- td/net/HttpConnectionBase.cpp
- td/net/HttpContentLengthByteFlow.cpp
- td/net/HttpFile.cpp
- td/net/HttpInboundConnection.cpp
- td/net/HttpOutboundConnection.cpp
- td/net/HttpQuery.cpp
- td/net/HttpReader.cpp
- td/net/Socks5.cpp
- td/net/SslFd.cpp
- td/net/TcpListener.cpp
- td/net/Wget.cpp
-
- td/net/GetHostByNameActor.h
- td/net/HttpChunkedByteFlow.h
- td/net/HttpConnectionBase.h
- td/net/HttpContentLengthByteFlow.h
- td/net/HttpFile.h
- td/net/HttpHeaderCreator.h
- td/net/HttpInboundConnection.h
- td/net/HttpOutboundConnection.h
- td/net/HttpQuery.h
- td/net/HttpReader.h
- td/net/NetStats.h
- td/net/Socks5.h
- td/net/SslFd.h
- td/net/TcpListener.h
- td/net/Wget.h
-)
-
-#RULES
-#LIBRARIES
-
-add_library(tdnet STATIC ${TDNET_SOURCE})
-target_include_directories(tdnet PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
-target_include_directories(tdnet SYSTEM PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
-target_link_libraries(tdnet PUBLIC tdutils tdactor ${OPENSSL_LIBRARIES} PRIVATE ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES})
-
-install(TARGETS tdnet EXPORT TdTargets
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
- RUNTIME DESTINATION bin
- INCLUDES DESTINATION include
-)
diff --git a/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.cpp b/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.cpp
deleted file mode 100644
index b6cdcca0f0..0000000000
--- a/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/GetHostByNameActor.h"
-
-#include "td/utils/logging.h"
-#include "td/utils/Time.h"
-
-namespace td {
-GetHostByNameActor::GetHostByNameActor(int32 ok_timeout, int32 error_timeout)
- : ok_timeout_(ok_timeout), error_timeout_(error_timeout) {
-}
-
-void GetHostByNameActor::run(std::string host, int port, td::Promise<td::IPAddress> promise) {
- auto r_ip = load_ip(std::move(host), port);
- promise.set_result(std::move(r_ip));
-}
-
-Result<td::IPAddress> GetHostByNameActor::load_ip(string host, int port) {
- auto &value = cache_.emplace(host, Value{{}, 0}).first->second;
- auto begin_time = td::Time::now();
- if (value.expire_at > begin_time) {
- auto ip = value.ip.clone();
- if (ip.is_ok()) {
- ip.ok_ref().set_port(port);
- CHECK(ip.ok().get_port() == port);
- }
- return ip;
- }
-
- td::IPAddress ip;
- auto status = ip.init_host_port(host, port);
- auto end_time = td::Time::now();
- LOG(WARNING) << "Init host = " << host << ", port = " << port << " in " << end_time - begin_time << " seconds to "
- << ip;
-
- if (status.is_ok()) {
- value = Value{ip, end_time + ok_timeout_};
- return ip;
- } else {
- value = Value{status.clone(), end_time + error_timeout_};
- return std::move(status);
- }
-}
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.h b/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.h
deleted file mode 100644
index b352a05d18..0000000000
--- a/libs/tdlib/td/tdnet/td/net/GetHostByNameActor.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-#include "td/actor/actor.h"
-#include "td/actor/PromiseFuture.h"
-
-#include "td/utils/port/IPAddress.h"
-#include "td/utils/Status.h"
-
-#include <unordered_map>
-
-namespace td {
-class GetHostByNameActor final : public td::Actor {
- public:
- explicit GetHostByNameActor(int32 ok_timeout = CACHE_TIME, int32 error_timeout = ERROR_CACHE_TIME);
- void run(std::string host, int port, td::Promise<td::IPAddress> promise);
-
- private:
- struct Value {
- Result<td::IPAddress> ip;
- double expire_at;
- };
- std::unordered_map<string, Value> cache_;
- static constexpr int32 CACHE_TIME = 60 * 29; // 29 minutes
- static constexpr int32 ERROR_CACHE_TIME = 60 * 5; // 5 minutes
-
- int32 ok_timeout_;
- int32 error_timeout_;
- Result<td::IPAddress> load_ip(string host, int port) TD_WARN_UNUSED_RESULT;
-};
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.cpp b/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.cpp
deleted file mode 100644
index 2edd225bfa..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpChunkedByteFlow.h"
-
-#include "td/utils/find_boundary.h"
-#include "td/utils/format.h"
-#include "td/utils/logging.h"
-#include "td/utils/misc.h"
-#include "td/utils/Status.h"
-
-namespace td {
-
-void HttpChunkedByteFlow::loop() {
- bool was_updated = false;
- size_t need_size;
- while (true) {
- if (state_ == ReadChunkLength) {
- bool ok = find_boundary(input_->clone(), "\r\n", len_);
- if (len_ > 10) {
- return finish(Status::Error(PSLICE() << "Too long length in chunked "
- << input_->cut_head(len_).move_as_buffer_slice().as_slice()));
- }
- if (!ok) {
- need_size = input_->size() + 1;
- break;
- }
- auto s_len = input_->cut_head(len_).move_as_buffer_slice();
- input_->advance(2);
- len_ = hex_to_integer<size_t>(s_len.as_slice());
- if (len_ > MAX_CHUNK_SIZE) {
- return finish(Status::Error(PSLICE() << "Invalid chunk size " << tag("size", len_)));
- }
- save_len_ = len_;
- state_ = ReadChunkContent;
- }
-
- auto size = input_->size();
- auto ready = min(len_, size);
- need_size = min(MIN_UPDATE_SIZE, len_ + 2);
- if (size < need_size) {
- break;
- }
- total_size_ += ready;
- uncommited_size_ += ready;
- if (total_size_ > MAX_SIZE) {
- return finish(Status::Error(PSLICE() << "Too big query " << tag("size", input_->size())));
- }
-
- output_.append(input_->cut_head(ready));
- len_ -= ready;
- if (uncommited_size_ >= MIN_UPDATE_SIZE) {
- uncommited_size_ = 0;
- was_updated = true;
- }
-
- if (len_ == 0) {
- if (input_->size() < 2) {
- need_size = 2;
- break;
- }
- input_->cut_head(2);
- total_size_ += 2;
- if (save_len_ == 0) {
- return finish(Status::OK());
- }
- state_ = ReadChunkLength;
- len_ = 0;
- }
- }
- if (was_updated) {
- on_output_updated();
- }
- if (!is_input_active_) {
- return finish(Status::Error("Unexpected end of stream"));
- }
- set_need_size(need_size);
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.h b/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.h
deleted file mode 100644
index 9c62c3368e..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpChunkedByteFlow.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/utils/ByteFlow.h"
-
-namespace td {
-
-class HttpChunkedByteFlow final : public ByteFlowBase {
- public:
- void loop() override;
-
- private:
- static constexpr int MAX_CHUNK_SIZE = 15 << 20; // some reasonable limit
- static constexpr int MAX_SIZE = 150 << 20; // some reasonable limit
- static constexpr size_t MIN_UPDATE_SIZE = 1 << 14;
- enum { ReadChunkLength, ReadChunkContent, OK } state_ = ReadChunkLength;
- size_t len_ = 0;
- size_t save_len_;
- size_t total_size_ = 0;
- size_t uncommited_size_ = 0;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.cpp b/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.cpp
deleted file mode 100644
index 087ee5b790..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpConnectionBase.h"
-
-#include "td/actor/actor.h"
-
-#include "td/net/HttpHeaderCreator.h"
-
-#include "td/utils/logging.h"
-#include "td/utils/misc.h"
-
-namespace td {
-namespace detail {
-
-HttpConnectionBase::HttpConnectionBase(State state, FdProxy fd, size_t max_post_size, size_t max_files,
- int32 idle_timeout)
- : state_(state)
- , stream_connection_(std::move(fd))
- , max_post_size_(max_post_size)
- , max_files_(max_files)
- , idle_timeout_(idle_timeout) {
- CHECK(state_ != State::Close);
-}
-
-void HttpConnectionBase::live_event() {
- if (idle_timeout_ != 0) {
- set_timeout_in(idle_timeout_);
- }
-}
-
-void HttpConnectionBase::start_up() {
- stream_connection_.get_fd().set_observer(this);
- subscribe(stream_connection_.get_fd());
- reader_.init(&stream_connection_.input_buffer(), max_post_size_, max_files_);
- if (state_ == State::Read) {
- current_query_ = make_unique<HttpQuery>();
- }
- live_event();
- yield();
-}
-void HttpConnectionBase::tear_down() {
- unsubscribe_before_close(stream_connection_.get_fd());
- stream_connection_.close();
-}
-
-void HttpConnectionBase::write_next(BufferSlice buffer) {
- CHECK(state_ == State::Write);
- stream_connection_.output_buffer().append(std::move(buffer));
- loop();
-}
-
-void HttpConnectionBase::write_ok() {
- CHECK(state_ == State::Write);
- current_query_ = make_unique<HttpQuery>();
- state_ = State::Read;
- live_event();
- loop();
-}
-
-void HttpConnectionBase::write_error(Status error) {
- CHECK(state_ == State::Write);
- LOG(WARNING) << "Close http connection: " << error;
- state_ = State::Close;
- loop();
-}
-
-void HttpConnectionBase::timeout_expired() {
- LOG(INFO) << "Idle timeout expired";
-
- if (stream_connection_.need_flush_write()) {
- on_error(Status::Error("Write timeout expired"));
- } else if (state_ == State::Read) {
- on_error(Status::Error("Read timeout expired"));
- }
-
- stop();
-}
-void HttpConnectionBase::loop() {
- if (can_read(stream_connection_)) {
- LOG(DEBUG) << "Can read from the connection";
- auto r = stream_connection_.flush_read();
- if (r.is_error()) {
- if (!begins_with(r.error().message(), "SSL error {336134278")) { // if error is not yet outputed
- LOG(INFO) << "flush_read error: " << r.error();
- }
- on_error(Status::Error(r.error().public_message()));
- return stop();
- }
- }
-
- // TODO: read_next even when state_ == State::Write
-
- bool want_read = false;
- if (state_ == State::Read) {
- auto res = reader_.read_next(current_query_.get());
- if (res.is_error()) {
- live_event();
- state_ = State::Write;
- LOG(INFO) << res.error();
- HttpHeaderCreator hc;
- hc.init_status_line(res.error().code());
- hc.set_content_size(0);
- stream_connection_.output_buffer().append(hc.finish().ok());
- close_after_write_ = true;
- on_error(Status::Error(res.error().public_message()));
- } else if (res.ok() == 0) {
- state_ = State::Write;
- LOG(INFO) << "Send query to handler";
- live_event();
- on_query(std::move(current_query_));
- } else {
- want_read = true;
- }
- }
-
- if (can_write(stream_connection_)) {
- LOG(DEBUG) << "Can write to the connection";
- auto r = stream_connection_.flush_write();
- if (r.is_error()) {
- LOG(INFO) << "flush_write error: " << r.error();
- on_error(Status::Error(r.error().public_message()));
- }
- if (close_after_write_ && !stream_connection_.need_flush_write()) {
- return stop();
- }
- }
-
- if (stream_connection_.get_fd().has_pending_error()) {
- auto pending_error = stream_connection_.get_pending_error();
- LOG(INFO) << pending_error;
- if (!close_after_write_) {
- on_error(Status::Error(pending_error.public_message()));
- }
- state_ = State::Close;
- }
- if (can_close(stream_connection_)) {
- LOG(INFO) << "Can close the connection";
- state_ = State::Close;
- }
- if (state_ == State::Close) {
- LOG_IF(INFO, stream_connection_.need_flush_write()) << "Close nonempty connection";
- LOG_IF(INFO, want_read &&
- (stream_connection_.input_buffer().size() > 0 || current_query_->type_ != HttpQuery::Type::EMPTY))
- << "Close connection while reading request/response";
- return stop();
- }
-}
-} // namespace detail
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.h b/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.h
deleted file mode 100644
index 1d420a3175..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpConnectionBase.h
+++ /dev/null
@@ -1,164 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/actor.h"
-
-#include "td/net/HttpQuery.h"
-#include "td/net/HttpReader.h"
-
-#include "td/utils/buffer.h"
-#include "td/utils/BufferedFd.h"
-#include "td/utils/port/Fd.h"
-#include "td/utils/Slice.h"
-#include "td/utils/Status.h"
-
-namespace td {
-
-class FdInterface {
- public:
- FdInterface() = default;
- FdInterface(const FdInterface &) = delete;
- FdInterface &operator=(const FdInterface &) = delete;
- FdInterface(FdInterface &&) = default;
- FdInterface &operator=(FdInterface &&) = default;
- virtual ~FdInterface() = default;
- virtual const Fd &get_fd() const = 0;
- virtual Fd &get_fd() = 0;
- virtual int32 get_flags() const = 0;
- virtual Status get_pending_error() TD_WARN_UNUSED_RESULT = 0;
-
- virtual Result<size_t> write(Slice slice) TD_WARN_UNUSED_RESULT = 0;
- virtual Result<size_t> read(MutableSlice slice) TD_WARN_UNUSED_RESULT = 0;
-
- virtual void close() = 0;
- virtual bool empty() const = 0;
-};
-
-template <class FdT>
-class FdToInterface : public FdInterface {
- public:
- FdToInterface() = default;
- explicit FdToInterface(FdT fd) : fd_(std::move(fd)) {
- }
-
- const Fd &get_fd() const final {
- return fd_.get_fd();
- }
- Fd &get_fd() final {
- return fd_.get_fd();
- }
- int32 get_flags() const final {
- return fd_.get_flags();
- }
- Status get_pending_error() final TD_WARN_UNUSED_RESULT {
- return fd_.get_pending_error();
- }
-
- Result<size_t> write(Slice slice) final TD_WARN_UNUSED_RESULT {
- return fd_.write(slice);
- }
- Result<size_t> read(MutableSlice slice) final TD_WARN_UNUSED_RESULT {
- return fd_.read(slice);
- }
-
- void close() final {
- fd_.close();
- }
- bool empty() const final {
- return fd_.empty();
- }
-
- private:
- FdT fd_;
-};
-
-template <class FdT>
-std::unique_ptr<FdInterface> make_fd_interface(FdT fd) {
- return make_unique<FdToInterface<FdT>>(std::move(fd));
-}
-
-class FdProxy {
- public:
- FdProxy() = default;
- explicit FdProxy(std::unique_ptr<FdInterface> fd) : fd_(std::move(fd)) {
- }
-
- const Fd &get_fd() const {
- return fd_->get_fd();
- }
- Fd &get_fd() {
- return fd_->get_fd();
- }
- int32 get_flags() const {
- return fd_->get_flags();
- }
- Status get_pending_error() TD_WARN_UNUSED_RESULT {
- return fd_->get_pending_error();
- }
-
- Result<size_t> write(Slice slice) TD_WARN_UNUSED_RESULT {
- return fd_->write(slice);
- }
- Result<size_t> read(MutableSlice slice) TD_WARN_UNUSED_RESULT {
- return fd_->read(slice);
- }
-
- void close() {
- fd_->close();
- }
- bool empty() const {
- return fd_->empty();
- }
-
- private:
- std::unique_ptr<FdInterface> fd_;
-};
-
-template <class FdT>
-FdProxy make_fd_proxy(FdT fd) {
- return FdProxy(make_fd_interface(std::move(fd)));
-}
-
-namespace detail {
-class HttpConnectionBase : public Actor {
- public:
- void write_next(BufferSlice buffer);
- void write_ok();
- void write_error(Status error);
-
- protected:
- enum class State { Read, Write, Close };
- template <class FdT>
- HttpConnectionBase(State state, FdT fd, size_t max_post_size, size_t max_files, int32 idle_timeout)
- : HttpConnectionBase(state, make_fd_proxy(std::move(fd)), max_post_size, max_files, idle_timeout) {
- }
- HttpConnectionBase(State state, FdProxy fd, size_t max_post_size, size_t max_files, int32 idle_timeout);
-
- private:
- using StreamConnection = BufferedFd<FdProxy>;
- State state_;
- StreamConnection stream_connection_;
- size_t max_post_size_;
- size_t max_files_;
- int32 idle_timeout_;
- HttpReader reader_;
- HttpQueryPtr current_query_;
- bool close_after_write_ = false;
-
- void live_event();
-
- void start_up() override;
- void tear_down() override;
- void timeout_expired() override;
- void loop() override;
-
- virtual void on_query(HttpQueryPtr) = 0;
- virtual void on_error(Status error) = 0;
-};
-} // namespace detail
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.cpp b/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.cpp
deleted file mode 100644
index ea299b3993..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpContentLengthByteFlow.h"
-
-#include "td/utils/Status.h"
-
-namespace td {
-
-void HttpContentLengthByteFlow::loop() {
- auto ready_size = input_->size();
- if (ready_size > len_) {
- ready_size = len_;
- }
- auto need_size = min(MIN_UPDATE_SIZE, len_);
- if (ready_size < need_size) {
- set_need_size(need_size);
- return;
- }
- output_.append(input_->cut_head(ready_size));
- len_ -= ready_size;
- if (len_ == 0) {
- return finish(Status::OK());
- }
- if (!is_input_active_) {
- return finish(Status::Error("Unexpected end of stream"));
- }
- on_output_updated();
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.h b/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.h
deleted file mode 100644
index 18f86abdb0..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpContentLengthByteFlow.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/utils/ByteFlow.h"
-
-namespace td {
-
-class HttpContentLengthByteFlow final : public ByteFlowBase {
- public:
- HttpContentLengthByteFlow() = default;
- explicit HttpContentLengthByteFlow(size_t len) : len_(len) {
- }
- void loop() override;
-
- private:
- static constexpr size_t MIN_UPDATE_SIZE = 1 << 14;
- size_t len_ = 0;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpFile.cpp b/libs/tdlib/td/tdnet/td/net/HttpFile.cpp
deleted file mode 100644
index b4f6e6d16b..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpFile.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpFile.h"
-
-#include "td/net/HttpReader.h"
-
-#include "td/utils/format.h"
-
-namespace td {
-
-HttpFile::~HttpFile() {
- if (!temp_file_name.empty()) {
- HttpReader::delete_temp_file(temp_file_name);
- }
-}
-
-StringBuilder &operator<<(StringBuilder &sb, const HttpFile &file) {
- return sb << tag("name", file.name) << tag("size", file.size);
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpFile.h b/libs/tdlib/td/tdnet/td/net/HttpFile.h
deleted file mode 100644
index 6f35843060..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpFile.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/utils/common.h"
-#include "td/utils/StringBuilder.h"
-
-namespace td {
-
-class HttpFile {
- public:
- string field_name;
- string name;
- string content_type;
- int64 size;
- string temp_file_name;
-
- HttpFile(string field_name, string name, string content_type, int64 size, string temp_file_name)
- : field_name(std::move(field_name))
- , name(std::move(name))
- , content_type(std::move(content_type))
- , size(size)
- , temp_file_name(std::move(temp_file_name)) {
- }
-
- HttpFile(const HttpFile &) = delete;
- HttpFile &operator=(const HttpFile &) = delete;
-
- HttpFile(HttpFile &&other)
- : field_name(std::move(other.field_name))
- , name(std::move(other.name))
- , content_type(std::move(other.content_type))
- , size(other.size)
- , temp_file_name(std::move(other.temp_file_name)) {
- other.temp_file_name.clear();
- }
-
- HttpFile &operator=(HttpFile &&) = delete;
-
- ~HttpFile();
-};
-
-StringBuilder &operator<<(StringBuilder &sb, const HttpFile &file);
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpHeaderCreator.h b/libs/tdlib/td/tdnet/td/net/HttpHeaderCreator.h
deleted file mode 100644
index d3e84e5dbf..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpHeaderCreator.h
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/utils/logging.h"
-#include "td/utils/Slice.h"
-#include "td/utils/Status.h"
-#include "td/utils/StringBuilder.h"
-
-namespace td {
-
-class HttpHeaderCreator {
- public:
- static constexpr size_t MAX_HEADER = 4096;
- HttpHeaderCreator() : sb_({header_, MAX_HEADER}) {
- }
- void init_ok() {
- sb_ = StringBuilder({header_, MAX_HEADER});
- sb_ << "HTTP/1.1 200 OK\r\n";
- }
- void init_get(Slice url) {
- sb_ = StringBuilder({header_, MAX_HEADER});
- sb_ << "GET " << url << " HTTP/1.1\r\n";
- }
- void init_post(Slice url) {
- sb_ = StringBuilder({header_, MAX_HEADER});
- sb_ << "POST " << url << " HTTP/1.1\r\n";
- }
- void init_error(int code, Slice reason) {
- sb_ = StringBuilder({header_, MAX_HEADER});
- sb_ << "HTTP/1.1 " << code << " " << reason << "\r\n";
- }
- void init_status_line(int http_status_code) {
- sb_ = StringBuilder({header_, MAX_HEADER});
- sb_ << "HTTP/1.1 " << http_status_code << " " << get_status_line(http_status_code) << "\r\n";
- }
- void add_header(Slice key, Slice value) {
- sb_ << key << ": " << value << "\r\n";
- }
- void set_content_type(Slice type) {
- add_header("Content-Type", type);
- }
- void set_content_size(size_t size) {
- add_header("Content-Length", to_string(size));
- }
- void set_keep_alive() {
- add_header("Connection", "keep-alive");
- }
-
- Result<Slice> finish(Slice content = {}) TD_WARN_UNUSED_RESULT {
- sb_ << "\r\n";
- if (!content.empty()) {
- sb_ << content;
- }
- if (sb_.is_error()) {
- return Status::Error("Too much headers");
- }
- return sb_.as_cslice();
- }
-
- private:
- static CSlice get_status_line(int http_status_code) {
- if (http_status_code == 200) {
- return CSlice("OK");
- }
- switch (http_status_code) {
- case 201:
- return CSlice("Created");
- case 202:
- return CSlice("Accepted");
- case 204:
- return CSlice("No Content");
- case 206:
- return CSlice("Partial Content");
- case 301:
- return CSlice("Moved Permanently");
- case 302:
- return CSlice("Found");
- case 303:
- return CSlice("See Other");
- case 304:
- return CSlice("Not Modified");
- case 307:
- return CSlice("Temporary Redirect");
- case 400:
- return CSlice("Bad Request");
- case 401:
- return CSlice("Unauthorized");
- case 403:
- return CSlice("Forbidden");
- case 404:
- return CSlice("Not Found");
- case 405:
- return CSlice("Method Not Allowed");
- case 406:
- return CSlice("Not Acceptable");
- case 408:
- return CSlice("Request Timeout");
- case 409:
- return CSlice("Conflict");
- case 411:
- return CSlice("Length Required");
- case 413:
- return CSlice("Request Entity Too Large");
- case 414:
- return CSlice("Request-URI Too Long");
- case 415:
- return CSlice("Unsupported Media Type");
- case 418:
- return CSlice("I'm a teapot");
- case 429:
- return CSlice("Too Many Requests");
- case 431:
- return CSlice("Request Header Fields Too Large");
- case 480:
- return CSlice("Temporarily Unavailable");
- case 501:
- return CSlice("Not Implemented");
- case 502:
- return CSlice("Bad Gateway");
- case 503:
- return CSlice("Service Unavailable");
- case 505:
- return CSlice("HTTP Version Not Supported");
- default:
- LOG_IF(ERROR, http_status_code != 500) << "Unsupported status code " << http_status_code << " returned";
- return CSlice("Internal Server Error");
- }
- }
-
- char header_[MAX_HEADER];
- StringBuilder sb_;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.cpp b/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.cpp
deleted file mode 100644
index 533cdd5407..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpInboundConnection.h"
-
-#include "td/utils/logging.h"
-
-namespace td {
-// HttpInboundConnection implementation
-HttpInboundConnection::HttpInboundConnection(SocketFd fd, size_t max_post_size, size_t max_files, int32 idle_timeout,
- ActorShared<Callback> callback)
- : HttpConnectionBase(State::Read, std::move(fd), max_post_size, max_files, idle_timeout)
- , callback_(std::move(callback)) {
-}
-
-void HttpInboundConnection::on_query(HttpQueryPtr query) {
- CHECK(!callback_.empty());
- send_closure(callback_, &Callback::handle, std::move(query), ActorOwn<HttpInboundConnection>(actor_id(this)));
-}
-
-void HttpInboundConnection::on_error(Status error) {
- // nothing to do
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.h b/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.h
deleted file mode 100644
index 013b024592..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpInboundConnection.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/actor.h"
-
-#include "td/net/HttpConnectionBase.h"
-#include "td/net/HttpQuery.h"
-
-#include "td/utils/port/SocketFd.h"
-#include "td/utils/Status.h"
-
-namespace td {
-
-class HttpInboundConnection final : public detail::HttpConnectionBase {
- public:
- class Callback : public Actor {
- public:
- virtual void handle(HttpQueryPtr query, ActorOwn<HttpInboundConnection> connection) = 0;
- };
- // Inherited interface
- // void write_next(BufferSlice buffer);
- // void write_ok();
- // void write_error(Status error);
-
- HttpInboundConnection(SocketFd fd, size_t max_post_size, size_t max_files, int32 idle_timeout,
- ActorShared<Callback> callback);
-
- private:
- void on_query(HttpQueryPtr query) override;
- void on_error(Status error) override;
- void hangup() override {
- callback_.release();
- stop();
- }
- ActorShared<Callback> callback_;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.cpp b/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.cpp
deleted file mode 100644
index f6efe7e07a..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpOutboundConnection.h"
-
-#include "td/utils/logging.h"
-
-namespace td {
-// HttpOutboundConnection implementation
-void HttpOutboundConnection::on_query(HttpQueryPtr query) {
- CHECK(!callback_.empty());
- send_closure(callback_, &Callback::handle, std::move(query));
-}
-
-void HttpOutboundConnection::on_error(Status error) {
- CHECK(!callback_.empty());
- send_closure(callback_, &Callback::on_connection_error, std::move(error));
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.h b/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.h
deleted file mode 100644
index d7496c59c4..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpOutboundConnection.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/actor.h"
-
-#include "td/net/HttpConnectionBase.h"
-#include "td/net/HttpQuery.h"
-
-#include "td/utils/Status.h"
-
-namespace td {
-
-class HttpOutboundConnection final : public detail::HttpConnectionBase {
- public:
- class Callback : public Actor {
- public:
- virtual void handle(HttpQueryPtr query) = 0;
- virtual void on_connection_error(Status error) = 0; // TODO rename to on_error
- };
- template <class FdT>
- HttpOutboundConnection(FdT fd, size_t max_post_size, size_t max_files, int32 idle_timeout,
- ActorShared<Callback> callback)
- : HttpConnectionBase(HttpConnectionBase::State::Write, std::move(fd), max_post_size, max_files, idle_timeout)
- , callback_(std::move(callback)) {
- }
- // Inherited interface
- // void write_next(BufferSlice buffer);
- // void write_ok();
- // void write_error(Status error);
-
- private:
- void on_query(HttpQueryPtr query) override;
- void on_error(Status error) override;
- void hangup() override {
- callback_.release();
- HttpConnectionBase::hangup();
- }
- ActorShared<Callback> callback_;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpQuery.cpp b/libs/tdlib/td/tdnet/td/net/HttpQuery.cpp
deleted file mode 100644
index b4af0eef3f..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpQuery.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpQuery.h"
-
-#include <algorithm>
-
-namespace td {
-
-Slice HttpQuery::header(Slice key) const {
- auto it = std::find_if(headers_.begin(), headers_.end(),
- [&key](const std::pair<MutableSlice, MutableSlice> &s) { return s.first == key; });
- return it == headers_.end() ? Slice() : it->second;
-}
-
-MutableSlice HttpQuery::arg(Slice key) const {
- auto it = std::find_if(args_.begin(), args_.end(),
- [&key](const std::pair<MutableSlice, MutableSlice> &s) { return s.first == key; });
- return it == args_.end() ? MutableSlice() : it->second;
-}
-
-std::vector<std::pair<string, string>> HttpQuery::string_args() const {
- std::vector<std::pair<string, string>> res;
- for (auto &it : args_) {
- res.push_back(std::make_pair(it.first.str(), it.second.str()));
- }
- return res;
-}
-
-StringBuilder &operator<<(StringBuilder &sb, const HttpQuery &q) {
- switch (q.type_) {
- case HttpQuery::Type::EMPTY:
- sb << "EMPTY";
- return sb;
- case HttpQuery::Type::GET:
- sb << "GET";
- break;
- case HttpQuery::Type::POST:
- sb << "POST";
- break;
- case HttpQuery::Type::RESPONSE:
- sb << "RESPONSE";
- break;
- }
- if (q.type_ == HttpQuery::Type::RESPONSE) {
- sb << ":" << q.code_ << ":" << q.reason_;
- } else {
- sb << ":" << q.url_path_;
- for (auto &key_value : q.args_) {
- sb << ":[" << key_value.first << ":" << key_value.second << "]";
- }
- }
- if (q.keep_alive_) {
- sb << ":keep-alive";
- }
- sb << "\n";
- for (auto &key_value : q.headers_) {
- sb << key_value.first << "=" << key_value.second << "\n";
- }
- sb << "BEGIN CONTENT\n";
- sb << q.content_;
- sb << "END CONTENT\n";
-
- return sb;
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpQuery.h b/libs/tdlib/td/tdnet/td/net/HttpQuery.h
deleted file mode 100644
index acab74ac66..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpQuery.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/net/HttpFile.h"
-
-#include "td/utils/buffer.h"
-#include "td/utils/common.h"
-#include "td/utils/Slice.h"
-#include "td/utils/StringBuilder.h"
-
-#include <utility>
-
-namespace td {
-
-class HttpQuery {
- public:
- enum class Type : int8 { EMPTY, GET, POST, RESPONSE };
-
- std::vector<BufferSlice> container_;
- Type type_;
- MutableSlice url_path_;
- std::vector<std::pair<MutableSlice, MutableSlice>> args_;
- int code_;
- MutableSlice reason_;
-
- bool keep_alive_;
- std::vector<std::pair<MutableSlice, MutableSlice>> headers_;
- std::vector<HttpFile> files_;
- MutableSlice content_;
-
- Slice header(Slice key) const;
-
- MutableSlice arg(Slice key) const;
-
- std::vector<std::pair<string, string>> string_args() const;
-};
-
-using HttpQueryPtr = std::unique_ptr<HttpQuery>;
-
-StringBuilder &operator<<(StringBuilder &sb, const HttpQuery &q);
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpReader.cpp b/libs/tdlib/td/tdnet/td/net/HttpReader.cpp
deleted file mode 100644
index 1cfa7666a7..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpReader.cpp
+++ /dev/null
@@ -1,814 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/HttpReader.h"
-
-#include "td/utils/filesystem.h"
-#include "td/utils/find_boundary.h"
-#include "td/utils/format.h"
-#include "td/utils/Gzip.h"
-#include "td/utils/HttpUrl.h"
-#include "td/utils/JsonBuilder.h"
-#include "td/utils/logging.h"
-#include "td/utils/misc.h"
-#include "td/utils/Parser.h"
-#include "td/utils/PathView.h"
-#include "td/utils/port/path.h"
-
-#include <cstring>
-
-namespace td {
-
-constexpr const char HttpReader::TEMP_DIRECTORY_PREFIX[];
-
-static size_t urldecode(Slice from, MutableSlice to, bool decode_plus_sign_as_space) {
- size_t to_i = 0;
- CHECK(to.size() >= from.size());
- for (size_t from_i = 0, n = from.size(); from_i < n; from_i++) {
- if (from[from_i] == '%' && from_i + 2 < n) {
- int high = hex_to_int(from[from_i + 1]);
- int low = hex_to_int(from[from_i + 2]);
- if (high < 16 && low < 16) {
- to[to_i++] = static_cast<char>(high * 16 + low);
- from_i += 2;
- continue;
- }
- }
- to[to_i++] = decode_plus_sign_as_space && from[from_i] == '+' ? ' ' : from[from_i];
- }
- return to_i;
-}
-
-static MutableSlice urldecode_inplace(MutableSlice str, bool decode_plus_sign_as_space) {
- size_t result_size = urldecode(str, str, decode_plus_sign_as_space);
- str.truncate(result_size);
- return str;
-}
-
-void HttpReader::init(ChainBufferReader *input, size_t max_post_size, size_t max_files) {
- input_ = input;
- state_ = ReadHeaders;
- headers_read_length_ = 0;
- content_length_ = 0;
- query_ = nullptr;
- max_post_size_ = max_post_size;
- max_files_ = max_files;
- total_parameters_length_ = 0;
- total_headers_length_ = 0;
-}
-
-Result<size_t> HttpReader::read_next(HttpQuery *query) {
- if (query_ != query) {
- CHECK(query_ == nullptr);
- query_ = query;
- }
- size_t need_size = input_->size() + 1;
- while (true) {
- if (state_ != ReadHeaders) {
- flow_source_.wakeup();
- if (flow_sink_.is_ready() && flow_sink_.status().is_error()) {
- return Status::Error(400, "Bad Request: " + flow_sink_.status().message().str());
- }
- need_size = flow_source_.get_need_size();
- if (need_size == 0) {
- need_size = input_->size() + 1;
- }
- }
- switch (state_) {
- case ReadHeaders: {
- auto result = split_header();
- if (result.is_error() || result.ok() != 0) {
- return result;
- }
- if (transfer_encoding_.empty() && content_length_ == 0) {
- break;
- }
-
- flow_source_ = ByteFlowSource(input_);
- ByteFlowInterface *source = &flow_source_;
- if (transfer_encoding_.empty()) {
- content_length_flow_ = HttpContentLengthByteFlow(content_length_);
- *source >> content_length_flow_;
- source = &content_length_flow_;
- } else if (transfer_encoding_ == "chunked") {
- chunked_flow_ = HttpChunkedByteFlow();
- *source >> chunked_flow_;
- source = &chunked_flow_;
- } else {
- LOG(ERROR) << "Unsupported " << tag("transfer-encoding", transfer_encoding_);
- return Status::Error(501, "Unimplemented: unsupported transfer-encoding");
- }
-
- if (content_encoding_.empty()) {
- } else if (content_encoding_ == "gzip" || content_encoding_ == "deflate") {
- gzip_flow_ = GzipByteFlow(Gzip::Decode);
- gzip_flow_.set_max_output_size(MAX_FILE_SIZE);
- *source >> gzip_flow_;
- source = &gzip_flow_;
- } else {
- LOG(ERROR) << "Unsupported " << tag("content-encoding", content_encoding_);
- return Status::Error(415, "Unsupported Media Type: unsupported content-encoding");
- }
-
- flow_sink_ = ByteFlowSink();
- *source >> flow_sink_;
- content_ = flow_sink_.get_output();
-
- if (content_length_ > MAX_CONTENT_SIZE) {
- return Status::Error(413, PSLICE() << "Request Entity Too Large: content length is " << content_length_);
- }
-
- if (std::strstr(content_type_lowercased_.c_str(), "multipart/form-data")) {
- state_ = ReadMultipartFormData;
-
- const char *p = std::strstr(content_type_lowercased_.c_str(), "boundary");
- if (p == nullptr) {
- return Status::Error(400, "Bad Request: boundary not found");
- }
- p += 8;
- ptrdiff_t offset = p - content_type_lowercased_.c_str();
- p = static_cast<const char *>(
- std::memchr(content_type_.begin() + offset, '=', content_type_.size() - offset));
- if (p == nullptr) {
- return Status::Error(400, "Bad Request: boundary value not found");
- }
- p++;
- const char *end_p = static_cast<const char *>(std::memchr(p, ';', content_type_.end() - p));
- if (end_p == nullptr) {
- end_p = content_type_.end();
- }
- if (*p == '"' && p + 1 < end_p && end_p[-1] == '"') {
- p++;
- end_p--;
- }
-
- Slice boundary(p, static_cast<size_t>(end_p - p));
- if (boundary.empty() || boundary.size() > MAX_BOUNDARY_LENGTH) {
- return Status::Error(400, "Bad Request: boundary too big or empty");
- }
-
- boundary_ = "\r\n--" + boundary.str();
- form_data_parse_state_ = SkipPrologue;
- form_data_read_length_ = 0;
- form_data_skipped_length_ = 0;
- } else if (std::strstr(content_type_lowercased_.c_str(), "application/x-www-form-urlencoded") ||
- std::strstr(content_type_lowercased_.c_str(), "application/json")) {
- state_ = ReadArgs;
- } else {
- form_data_skipped_length_ = 0;
- state_ = ReadContent;
- }
- continue;
- }
- case ReadContent: {
- if (content_->size() > max_post_size_) {
- state_ = ReadContentToFile;
- continue;
- }
- if (flow_sink_.is_ready()) {
- CHECK(query_->container_.size() == 1u);
- query_->container_.emplace_back(content_->cut_head(content_->size()).move_as_buffer_slice());
- query_->content_ = query_->container_.back().as_slice();
- break;
- }
-
- return need_size;
- }
- case ReadContentToFile: {
- // save content to a file
- if (temp_file_.empty()) {
- auto file = open_temp_file("file");
- if (file.is_error()) {
- return Status::Error(500, "Internal Server Error: can't create temporary file");
- }
- }
-
- auto size = content_->size();
- if (size) {
- TRY_STATUS(save_file_part(content_->cut_head(size).move_as_buffer_slice()));
- }
- if (flow_sink_.is_ready()) {
- query_->files_.emplace_back("file", "", content_type_.str(), file_size_, temp_file_name_);
- close_temp_file();
- break;
- }
-
- return need_size;
- }
- case ReadArgs: {
- auto size = content_->size();
- if (size > MAX_TOTAL_PARAMETERS_LENGTH - total_parameters_length_) {
- return Status::Error(413, "Request Entity Too Large: too much parameters");
- }
-
- if (flow_sink_.is_ready()) {
- query_->container_.emplace_back(content_->cut_head(size).move_as_buffer_slice());
- Status result;
- if (std::strstr(content_type_lowercased_.c_str(), "application/x-www-form-urlencoded")) {
- result = parse_parameters(query_->container_.back().as_slice());
- } else {
- result = parse_json_parameters(query_->container_.back().as_slice());
- }
- if (result.is_error()) {
- if (result.code() == 413) {
- return std::move(result);
- }
- LOG(INFO) << result.message();
- }
- query_->content_ = MutableSlice();
- break;
- }
-
- return need_size;
- }
- case ReadMultipartFormData: {
- TRY_RESULT(result, parse_multipart_form_data());
- if (result) {
- break;
- }
- return need_size;
- }
- default:
- UNREACHABLE();
- }
- break;
- }
-
- init(input_, max_post_size_, max_files_);
- return 0;
-}
-
-// returns Status on wrong request
-// returns true if parsing has finished
-// returns false if need more data
-Result<bool> HttpReader::parse_multipart_form_data() {
- while (true) {
- LOG(DEBUG) << "Parsing multipart form data in state " << form_data_parse_state_;
- switch (form_data_parse_state_) {
- case SkipPrologue:
- if (find_boundary(content_->clone(), {boundary_.c_str() + 2, boundary_.size() - 2}, form_data_read_length_)) {
- size_t to_skip = form_data_read_length_ + (boundary_.size() - 2);
- content_->advance(to_skip);
- form_data_skipped_length_ += to_skip;
- form_data_read_length_ = 0;
-
- form_data_parse_state_ = ReadPartHeaders;
- continue;
- }
-
- content_->advance(form_data_read_length_);
- form_data_skipped_length_ += form_data_read_length_;
- form_data_read_length_ = 0;
- return false;
- case ReadPartHeaders:
- if (find_boundary(content_->clone(), "\r\n\r\n", form_data_read_length_)) {
- total_headers_length_ += form_data_read_length_;
- if (total_headers_length_ > MAX_TOTAL_HEADERS_LENGTH) {
- return Status::Error(431, "Request Header Fields Too Large: total headers size exceeded");
- }
- if (form_data_read_length_ == 0) {
- // there is no headers at all
- return Status::Error(400, "Bad Request: headers in multipart/form-data are empty");
- }
-
- content_->advance(2); // "\r\n" after boundary
- auto headers = content_->cut_head(form_data_read_length_).move_as_buffer_slice();
- CHECK(headers.as_slice().size() == form_data_read_length_);
- LOG(DEBUG) << "Parse headers in multipart form data: \"" << headers.as_slice() << "\"";
- content_->advance(2);
-
- form_data_skipped_length_ += form_data_read_length_ + 4;
- form_data_read_length_ = 0;
-
- field_name_ = MutableSlice();
- file_field_name_.clear();
- field_content_type_ = "application/octet-stream";
- file_name_.clear();
- CHECK(temp_file_.empty());
- temp_file_name_.clear();
-
- Parser headers_parser(headers.as_slice());
- while (headers_parser.status().is_ok() && !headers_parser.data().empty()) {
- MutableSlice header_name = headers_parser.read_till(':');
- headers_parser.skip(':');
- char *header_value_begin = headers_parser.ptr();
- char *header_value_end;
- do {
- headers_parser.read_till('\r');
- header_value_end = headers_parser.ptr();
- headers_parser.skip('\r');
- headers_parser.skip('\n');
- } while (headers_parser.status().is_ok() &&
- (headers_parser.peek_char() == ' ' || headers_parser.peek_char() == '\t'));
-
- MutableSlice header_value(header_value_begin, header_value_end);
-
- header_name = trim(header_name);
- header_value = trim(header_value);
- to_lower_inplace(header_name);
-
- if (header_name == "content-disposition") {
- if (header_value.substr(0, 10) != "form-data;") {
- return Status::Error(400, "Bad Request: expected form-data content disposition");
- }
- header_value.remove_prefix(10);
- while (true) {
- header_value = trim(header_value);
- const char *key_end =
- static_cast<const char *>(std::memchr(header_value.data(), '=', header_value.size()));
- if (key_end == nullptr) {
- break;
- }
- size_t key_size = key_end - header_value.data();
- auto key = header_value.substr(0, key_size);
- key = trim(key);
-
- header_value.remove_prefix(key_size + 1);
- const char *value_end =
- static_cast<const char *>(std::memchr(header_value.data(), ';', header_value.size()));
- size_t value_size;
- if (value_end == nullptr) {
- value_size = header_value.size();
- } else {
- value_size = value_end - header_value.data();
- }
- auto value = header_value.substr(0, value_size);
- value = trim(value);
- if (value.size() > 1u && value[0] == '"' && value.back() == '"') {
- value = {value.data() + 1, value.size() - 2};
- }
- header_value.remove_prefix(value_size + (header_value.size() > value_size));
-
- if (key == "name") {
- field_name_ = value;
- } else if (key == "filename") {
- file_name_ = value.str();
- } else {
- // ignore unknown parts of header
- }
- }
- } else if (header_name == "content-type") {
- field_content_type_ = header_value.str();
- } else {
- // ignore unknown header
- }
- }
-
- if (headers_parser.status().is_error()) {
- return Status::Error(400, "Bad Request: can't parse form data headers");
- }
-
- if (field_name_.empty()) {
- return Status::Error(400, "Bad Request: field name in multipart/form-data not found");
- }
-
- if (!file_name_.empty()) {
- // file
- if (query_->files_.size() == max_files_) {
- return Status::Error(413, "Request Entity Too Large: too much files attached");
- }
- auto file = open_temp_file(file_name_);
- if (file.is_error()) {
- return Status::Error(500, "Internal Server Error: can't create temporary file");
- }
-
- // don't need to save headers for files
- file_field_name_ = field_name_.str();
- form_data_parse_state_ = ReadFile;
- } else {
- // save headers for query parameters. They contain header names
- query_->container_.push_back(std::move(headers));
- form_data_parse_state_ = ReadPartValue;
- }
-
- continue;
- }
-
- if (total_headers_length_ + form_data_read_length_ > MAX_TOTAL_HEADERS_LENGTH) {
- return Status::Error(431, "Request Header Fields Too Large: total headers size exceeded");
- }
- return false;
- case ReadPartValue:
- if (find_boundary(content_->clone(), boundary_, form_data_read_length_)) {
- if (total_parameters_length_ + form_data_read_length_ > MAX_TOTAL_PARAMETERS_LENGTH) {
- return Status::Error(413, "Request Entity Too Large: too much parameters in form data");
- }
-
- query_->container_.emplace_back(content_->cut_head(form_data_read_length_).move_as_buffer_slice());
- MutableSlice value = query_->container_.back().as_slice();
- content_->advance(boundary_.size());
- form_data_skipped_length_ += form_data_read_length_ + boundary_.size();
- form_data_read_length_ = 0;
-
- if (begins_with(field_content_type_, "application/x-www-form-urlencoded")) {
- // treat value as ordinary parameters
- auto result = parse_parameters(value);
- if (result.is_error()) {
- return std::move(result);
- }
- } else {
- total_parameters_length_ += form_data_read_length_;
- LOG(DEBUG) << "Get ordinary parameter in multipart form data: \"" << field_name_ << "\": \"" << value
- << "\"";
- query_->args_.emplace_back(field_name_, value);
- }
-
- form_data_parse_state_ = CheckForLastBoundary;
- continue;
- }
- CHECK(content_->size() < form_data_read_length_ + boundary_.size());
-
- if (total_parameters_length_ + form_data_read_length_ > MAX_TOTAL_PARAMETERS_LENGTH) {
- return Status::Error(413, "Request Entity Too Large: too much parameters in form data");
- }
- return false;
- case ReadFile: {
- if (find_boundary(content_->clone(), boundary_, form_data_read_length_)) {
- auto file_part = content_->cut_head(form_data_read_length_).move_as_buffer_slice();
- content_->advance(boundary_.size());
- form_data_skipped_length_ += form_data_read_length_ + boundary_.size();
- form_data_read_length_ = 0;
-
- TRY_STATUS(save_file_part(std::move(file_part)));
-
- query_->files_.emplace_back(file_field_name_, file_name_, field_content_type_, file_size_, temp_file_name_);
- close_temp_file();
-
- form_data_parse_state_ = CheckForLastBoundary;
- continue;
- }
-
- // TODO optimize?
- auto file_part = content_->cut_head(form_data_read_length_).move_as_buffer_slice();
- form_data_skipped_length_ += form_data_read_length_;
- form_data_read_length_ = 0;
- CHECK(content_->size() < boundary_.size());
-
- TRY_STATUS(save_file_part(std::move(file_part)));
- return false;
- }
- case CheckForLastBoundary: {
- if (content_->size() < 2) {
- // need more data
- return false;
- }
-
- auto range = content_->clone();
- char x[2];
- range.advance(2, {x, 2});
- if (x[0] == '-' && x[1] == '-') {
- content_->advance(2);
- form_data_skipped_length_ += 2;
- form_data_parse_state_ = SkipEpilogue;
- } else {
- form_data_parse_state_ = ReadPartHeaders;
- }
- continue;
- }
- case SkipEpilogue: {
- size_t size = content_->size();
- LOG(DEBUG) << "Skipping epilogue. Have " << size << " bytes";
- content_->advance(size);
- form_data_skipped_length_ += size;
- // TODO(now): check if form_data_skipped_length is too big
- return flow_sink_.is_ready();
- }
- default:
- UNREACHABLE();
- }
- break;
- }
-
- return true;
-}
-
-Result<size_t> HttpReader::split_header() {
- if (find_boundary(input_->clone(), "\r\n\r\n", headers_read_length_)) {
- query_->container_.clear();
- auto a = input_->cut_head(headers_read_length_ + 2);
- auto b = a.move_as_buffer_slice();
- query_->container_.emplace_back(std::move(b));
- // query_->container_.emplace_back(input_->cut_head(headers_read_length_ + 2).move_as_buffer_slice());
- CHECK(query_->container_.back().size() == headers_read_length_ + 2);
- input_->advance(2);
- total_headers_length_ = headers_read_length_;
- auto status = parse_head(query_->container_.back().as_slice());
- if (status.is_error()) {
- return std::move(status);
- }
- return 0;
- }
-
- if (input_->size() > MAX_TOTAL_HEADERS_LENGTH) {
- return Status::Error(431, "Request Header Fields Too Large: total headers size exceeded");
- }
- return input_->size() + 1;
-}
-
-void HttpReader::process_header(MutableSlice header_name, MutableSlice header_value) {
- header_name = trim(header_name);
- header_value = trim(header_value); // TODO need to remove "\r\n" from value
- to_lower_inplace(header_name);
- LOG(DEBUG) << "process_header [" << header_name << "=>" << header_value << "]";
- query_->headers_.emplace_back(header_name, header_value);
- // TODO: check if protocol is HTTP/1.1
- query_->keep_alive_ = true;
- if (header_name == "content-length") {
- content_length_ = to_integer<size_t>(header_value);
- } else if (header_name == "connection") {
- to_lower_inplace(header_value);
- if (header_value == "close") {
- query_->keep_alive_ = false;
- }
- } else if (header_name == "content-type") {
- content_type_ = header_value;
- content_type_lowercased_ = header_value.str();
- to_lower_inplace(content_type_lowercased_);
- } else if (header_name == "content-encoding") {
- to_lower_inplace(header_value);
- content_encoding_ = header_value;
- } else if (header_name == "transfer-encoding") {
- to_lower_inplace(header_value);
- transfer_encoding_ = header_value;
- }
-}
-
-Status HttpReader::parse_url(MutableSlice url) {
- size_t url_path_size = 0;
- while (url_path_size < url.size() && url[url_path_size] != '?' && url[url_path_size] != '#') {
- url_path_size++;
- }
-
- query_->url_path_ = urldecode_inplace({url.data(), url_path_size}, false);
-
- if (url_path_size == url.size() || url[url_path_size] != '?') {
- return Status::OK();
- }
- return parse_parameters(url.substr(url_path_size + 1));
-}
-
-Status HttpReader::parse_parameters(MutableSlice parameters) {
- total_parameters_length_ += parameters.size();
- if (total_parameters_length_ > MAX_TOTAL_PARAMETERS_LENGTH) {
- return Status::Error(413, "Request Entity Too Large: too much parameters");
- }
- LOG(DEBUG) << "Parse parameters: \"" << parameters << "\"";
-
- Parser parser(parameters);
- while (!parser.data().empty()) {
- auto key_value = parser.read_till_nofail('&');
- parser.skip_nofail('&');
- Parser kv_parser(key_value);
- auto key = urldecode_inplace(kv_parser.read_till_nofail('='), true);
- kv_parser.skip_nofail('=');
- auto value = urldecode_inplace(kv_parser.data(), true);
- query_->args_.emplace_back(key, value);
- }
-
- CHECK(parser.status().is_ok());
- return Status::OK();
-}
-
-Status HttpReader::parse_json_parameters(MutableSlice parameters) {
- if (parameters.empty()) {
- return Status::OK();
- }
-
- total_parameters_length_ += parameters.size();
- if (total_parameters_length_ > MAX_TOTAL_PARAMETERS_LENGTH) {
- return Status::Error(413, "Request Entity Too Large: too much parameters");
- }
- LOG(DEBUG) << "Parse json parameters: \"" << parameters << "\"";
-
- Parser parser(parameters);
- parser.skip_whitespaces();
- parser.skip('{');
- if (parser.status().is_error()) {
- return Status::Error(400, "Bad Request: json object expected");
- }
- while (true) {
- parser.skip_whitespaces();
- if (parser.try_skip('}')) {
- parser.skip_whitespaces();
- if (parser.empty()) {
- return Status::OK();
- }
- return Status::Error(400, "Bad Request: unexpected data after object end");
- }
- if (parser.empty()) {
- return Status::Error(400, "Bad Request: expected parameter name");
- }
- auto r_key = json_string_decode(parser);
- if (r_key.is_error()) {
- return Status::Error(400, string("Bad Request: can't parse parameter name: ") + r_key.error().message().c_str());
- }
- parser.skip_whitespaces();
- if (!parser.try_skip(':')) {
- return Status::Error(400, "Bad Request: can't parse object, ':' expected");
- }
- parser.skip_whitespaces();
- Result<MutableSlice> r_value;
- if (parser.peek_char() == '"') {
- r_value = json_string_decode(parser);
- } else {
- const int32 DEFAULT_MAX_DEPTH = 100;
- auto begin = parser.ptr();
- auto result = do_json_skip(parser, DEFAULT_MAX_DEPTH);
- if (result.is_ok()) {
- r_value = MutableSlice(begin, parser.ptr());
- } else {
- r_value = result.move_as_error();
- }
- }
- if (r_value.is_error()) {
- return Status::Error(400,
- string("Bad Request: can't parse parameter value: ") + r_value.error().message().c_str());
- }
- query_->args_.emplace_back(r_key.move_as_ok(), r_value.move_as_ok());
-
- parser.skip_whitespaces();
- if (parser.peek_char() != '}' && !parser.try_skip(',')) {
- return Status::Error(400, "Bad Request: expected next field or object end");
- }
- }
- UNREACHABLE();
- return Status::OK();
-}
-
-Status HttpReader::parse_head(MutableSlice head) {
- Parser parser(head);
-
- Slice type = parser.read_till(' ');
- parser.skip(' ');
- // GET POST HTTP/1.1
- if (type == "GET") {
- query_->type_ = HttpQuery::Type::GET;
- } else if (type == "POST") {
- query_->type_ = HttpQuery::Type::POST;
- } else if (type.size() >= 4 && type.substr(0, 4) == "HTTP") {
- if (type == "HTTP/1.1" || type == "HTTP/1.0") {
- query_->type_ = HttpQuery::Type::RESPONSE;
- } else {
- LOG(INFO) << "Unsupported HTTP version: " << type;
- return Status::Error(505, "HTTP Version Not Supported");
- }
- } else {
- LOG(INFO) << "Not Implemented " << tag("type", type) << tag("head", head);
- return Status::Error(501, "Not Implemented");
- }
-
- query_->args_.clear();
-
- if (query_->type_ == HttpQuery::Type::RESPONSE) {
- query_->code_ = to_integer<int32>(parser.read_till(' '));
- parser.skip(' ');
- query_->reason_ = parser.read_till('\r');
- } else {
- auto url_version = parser.read_till('\r');
- auto space_pos = url_version.rfind(' ');
- if (space_pos == static_cast<size_t>(-1)) {
- return Status::Error(400, "Bad Request: wrong request line");
- }
-
- TRY_STATUS(parse_url(url_version.substr(0, space_pos)));
-
- auto http_version = url_version.substr(space_pos + 1);
- if (http_version != "HTTP/1.1" && http_version != "HTTP/1.0") {
- LOG(WARNING) << "Unsupported HTTP version: " << http_version;
- return Status::Error(505, "HTTP Version Not Supported");
- }
- }
- parser.skip('\r');
- parser.skip('\n');
-
- content_length_ = 0;
- content_type_ = "application/octet-stream";
- content_type_lowercased_ = content_type_.str();
- transfer_encoding_ = "";
- content_encoding_ = "";
-
- query_->keep_alive_ = false;
- query_->headers_.clear();
- query_->files_.clear();
- query_->content_ = MutableSlice();
- while (parser.status().is_ok() && !parser.data().empty()) {
- MutableSlice header_name = parser.read_till(':');
- parser.skip(':');
- char *header_value_begin = parser.ptr();
- char *header_value_end;
- do {
- parser.read_till('\r');
- header_value_end = parser.ptr();
- parser.skip('\r');
- parser.skip('\n');
- } while (parser.status().is_ok() && (parser.peek_char() == ' ' || parser.peek_char() == '\t'));
-
- process_header(header_name, {header_value_begin, header_value_end});
- }
- return parser.status().is_ok() ? Status::OK() : Status::Error(400, "Bad Request");
-}
-
-Status HttpReader::open_temp_file(CSlice desired_file_name) {
- CHECK(temp_file_.empty());
-
- auto tmp_dir = get_temporary_dir();
- if (tmp_dir.empty()) {
- return Status::Error("Can't find temporary directory");
- }
-
- TRY_RESULT(dir, realpath(tmp_dir, true));
- CHECK(!dir.empty());
-
- auto first_try = try_open_temp_file(dir, desired_file_name);
- if (first_try.is_ok()) {
- return Status::OK();
- }
-
- // Creation of new file with desired name has failed. Trying to create unique directory for it
- TRY_RESULT(directory, mkdtemp(dir, TEMP_DIRECTORY_PREFIX));
- auto second_try = try_open_temp_file(directory, desired_file_name);
- if (second_try.is_ok()) {
- return Status::OK();
- }
- auto third_try = try_open_temp_file(directory, "file");
- if (third_try.is_ok()) {
- return Status::OK();
- }
-
- rmdir(directory).ignore();
- LOG(WARNING) << "Failed to create temporary file " << desired_file_name << ": " << second_try.error();
- return second_try.move_as_error();
-}
-
-Status HttpReader::try_open_temp_file(Slice directory_name, CSlice desired_file_name) {
- CHECK(temp_file_.empty());
- CHECK(!directory_name.empty());
-
- string file_name = clean_filename(desired_file_name);
- if (file_name.empty()) {
- file_name = "file";
- }
-
- temp_file_name_.clear();
- temp_file_name_.reserve(directory_name.size() + 1 + file_name.size());
- temp_file_name_.append(directory_name.data(), directory_name.size());
- if (temp_file_name_.back() != TD_DIR_SLASH) {
- temp_file_name_ += TD_DIR_SLASH;
- }
- temp_file_name_.append(file_name.data(), file_name.size());
-
- TRY_RESULT(opened_file, FileFd::open(temp_file_name_, FileFd::Write | FileFd::CreateNew, 0640));
-
- file_size_ = 0;
- temp_file_ = std::move(opened_file);
- LOG(DEBUG) << "Created temporary file " << temp_file_name_;
- return Status::OK();
-}
-
-Status HttpReader::save_file_part(BufferSlice &&file_part) {
- file_size_ += narrow_cast<int64>(file_part.size());
- if (file_size_ > MAX_FILE_SIZE) {
- string file_name = temp_file_name_;
- close_temp_file();
- delete_temp_file(file_name);
- return Status::Error(
- 413, PSLICE() << "Request Entity Too Large: file is too big to be uploaded " << tag("size", file_size_));
- }
-
- LOG(DEBUG) << "Save file part of size " << file_part.size() << " to file " << temp_file_name_;
- auto result_written = temp_file_.write(file_part.as_slice());
- if (result_written.is_error() || result_written.ok() != file_part.size()) {
- string file_name = temp_file_name_;
- close_temp_file();
- delete_temp_file(file_name);
- return Status::Error(500, "Internal server error: can't upload the file");
- }
- return Status::OK();
-}
-
-void HttpReader::close_temp_file() {
- LOG(DEBUG) << "Close temporary file " << temp_file_name_;
- CHECK(!temp_file_.empty());
- temp_file_.close();
- CHECK(temp_file_.empty());
- temp_file_name_.clear();
-}
-
-void HttpReader::delete_temp_file(CSlice file_name) {
- CHECK(!file_name.empty());
- LOG(DEBUG) << "Unlink temporary file " << file_name;
- unlink(file_name).ignore();
- PathView path_view(file_name);
- Slice parent = path_view.parent_dir();
- const size_t prefix_length = std::strlen(TEMP_DIRECTORY_PREFIX);
- if (parent.size() >= prefix_length + 7 &&
- parent.substr(parent.size() - prefix_length - 7, prefix_length) == TEMP_DIRECTORY_PREFIX) {
- LOG(DEBUG) << "Unlink temporary directory " << parent;
- rmdir(Slice(parent.data(), parent.size() - 1).str()).ignore();
- }
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/HttpReader.h b/libs/tdlib/td/tdnet/td/net/HttpReader.h
deleted file mode 100644
index 74067d1291..0000000000
--- a/libs/tdlib/td/tdnet/td/net/HttpReader.h
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/net/HttpChunkedByteFlow.h"
-#include "td/net/HttpContentLengthByteFlow.h"
-#include "td/net/HttpQuery.h"
-
-#include "td/utils/buffer.h"
-#include "td/utils/ByteFlow.h"
-#include "td/utils/common.h"
-#include "td/utils/GzipByteFlow.h"
-#include "td/utils/port/FileFd.h"
-#include "td/utils/Slice.h"
-#include "td/utils/Status.h"
-#include "td/utils/StringBuilder.h"
-
-#include <limits>
-
-namespace td {
-
-class HttpReader {
- public:
- void init(ChainBufferReader *input, size_t max_post_size = std::numeric_limits<size_t>::max(),
- size_t max_files = 100);
- Result<size_t> read_next(HttpQuery *query) TD_WARN_UNUSED_RESULT; // TODO move query to init
-
- HttpReader() = default;
- HttpReader(const HttpReader &other) = delete;
- HttpReader &operator=(const HttpReader &other) = delete;
- HttpReader(HttpReader &&other) = delete;
- HttpReader &operator=(HttpReader &&other) = delete;
- ~HttpReader() {
- if (!temp_file_.empty()) {
- temp_file_.close();
- }
- }
-
- static void delete_temp_file(CSlice file_name);
-
- private:
- size_t max_post_size_;
- size_t max_files_;
-
- enum { ReadHeaders, ReadContent, ReadContentToFile, ReadArgs, ReadMultipartFormData } state_;
- size_t headers_read_length_;
- size_t content_length_;
- ChainBufferReader *input_;
- ByteFlowSource flow_source_;
- HttpChunkedByteFlow chunked_flow_;
- GzipByteFlow gzip_flow_;
- HttpContentLengthByteFlow content_length_flow_;
- ByteFlowSink flow_sink_;
- ChainBufferReader *content_;
-
- HttpQuery *query_;
- Slice transfer_encoding_;
- Slice content_encoding_;
- Slice content_type_;
- string content_type_lowercased_;
- size_t total_parameters_length_;
- size_t total_headers_length_;
-
- string boundary_;
- size_t form_data_read_length_;
- size_t form_data_skipped_length_;
- enum {
- SkipPrologue,
- ReadPartHeaders,
- ReadPartValue,
- ReadFile,
- CheckForLastBoundary,
- SkipEpilogue
- } form_data_parse_state_;
- MutableSlice field_name_;
- string file_field_name_;
- string field_content_type_;
- string file_name_;
- FileFd temp_file_;
- string temp_file_name_;
- int64 file_size_;
-
- Result<size_t> split_header() TD_WARN_UNUSED_RESULT;
- void process_header(MutableSlice header_name, MutableSlice header_value);
- Result<bool> parse_multipart_form_data() TD_WARN_UNUSED_RESULT;
- Status parse_url(MutableSlice url) TD_WARN_UNUSED_RESULT;
- Status parse_parameters(MutableSlice parameters) TD_WARN_UNUSED_RESULT;
- Status parse_json_parameters(MutableSlice parameters) TD_WARN_UNUSED_RESULT;
- Status parse_head(MutableSlice head) TD_WARN_UNUSED_RESULT;
-
- Status open_temp_file(CSlice desired_file_name) TD_WARN_UNUSED_RESULT;
- Status try_open_temp_file(Slice directory_name, CSlice desired_file_name) TD_WARN_UNUSED_RESULT;
- Status save_file_part(BufferSlice &&file_part) TD_WARN_UNUSED_RESULT;
- void close_temp_file();
-
- static constexpr size_t MAX_CONTENT_SIZE = 150 << 20; // Some reasonable limit
- static constexpr size_t MAX_TOTAL_PARAMETERS_LENGTH = 1 << 16; // Some reasonable limit
- static constexpr size_t MAX_TOTAL_HEADERS_LENGTH = 1 << 18; // Some reasonable limit
- static constexpr size_t MAX_BOUNDARY_LENGTH = 70; // As defined by RFC1341
- static constexpr int64 MAX_FILE_SIZE = 1500 << 20; // Telegram server file size limit
- static constexpr const char TEMP_DIRECTORY_PREFIX[] = "tdlib-server-tmp";
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/NetStats.h b/libs/tdlib/td/tdnet/td/net/NetStats.h
deleted file mode 100644
index e67f9fbc93..0000000000
--- a/libs/tdlib/td/tdnet/td/net/NetStats.h
+++ /dev/null
@@ -1,145 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/SchedulerLocalStorage.h"
-
-#include "td/utils/common.h"
-#include "td/utils/format.h"
-#include "td/utils/logging.h"
-#include "td/utils/StringBuilder.h"
-#include "td/utils/Time.h"
-
-#include <atomic>
-#include <memory>
-
-namespace td {
-
-class NetStatsCallback {
- public:
- virtual void on_read(uint64 bytes) = 0;
- virtual void on_write(uint64 bytes) = 0;
- NetStatsCallback() = default;
- NetStatsCallback(const NetStatsCallback &) = delete;
- NetStatsCallback &operator=(const NetStatsCallback &) = delete;
- virtual ~NetStatsCallback() = default;
-};
-
-struct NetStatsData {
- uint64 read_size = 0;
- uint64 write_size = 0;
-
- uint64 count = 0;
- double duration = 0;
-};
-
-inline NetStatsData operator+(const NetStatsData &a, const NetStatsData &b) {
- NetStatsData res;
- res.read_size = a.read_size + b.read_size;
- res.write_size = a.write_size + b.write_size;
- res.count = a.count + b.count;
- res.duration = a.duration + b.duration;
- return res;
-}
-inline NetStatsData operator-(const NetStatsData &a, const NetStatsData &b) {
- NetStatsData res;
- CHECK(a.read_size >= b.read_size);
- res.read_size = a.read_size - b.read_size;
-
- CHECK(a.write_size >= b.write_size);
- res.write_size = a.write_size - b.write_size;
-
- CHECK(a.count >= b.count);
- res.count = a.count - b.count;
-
- CHECK(a.duration >= b.duration);
- res.duration = a.duration - b.duration;
-
- return res;
-}
-
-inline StringBuilder &operator<<(StringBuilder &sb, const NetStatsData &data) {
- return sb << tag("Rx size", format::as_size(data.read_size)) << tag("Tx size", format::as_size(data.write_size))
- << tag("count", data.count) << tag("duration", format::as_time(data.duration));
-}
-
-class NetStats {
- public:
- class Callback {
- public:
- virtual void on_stats_updated() = 0;
- Callback() = default;
- Callback(const Callback &) = delete;
- Callback &operator=(const Callback &) = delete;
- virtual ~Callback() = default;
- };
-
- std::shared_ptr<NetStatsCallback> get_callback() const {
- return impl_;
- }
-
- NetStatsData get_stats() const {
- return impl_->get_stats();
- }
-
- // do it before get_callback
- void set_callback(std::unique_ptr<Callback> callback) {
- impl_->set_callback(std::move(callback));
- }
-
- private:
- class Impl : public NetStatsCallback {
- public:
- NetStatsData get_stats() const {
- NetStatsData res;
- local_net_stats_.for_each([&](auto &stats) {
- res.read_size += stats.read_size.load(std::memory_order_relaxed);
- res.write_size += stats.write_size.load(std::memory_order_relaxed);
- });
- return res;
- }
- void set_callback(std::unique_ptr<Callback> callback) {
- callback_ = std::move(callback);
- }
-
- private:
- struct LocalNetStats {
- double last_update = 0;
- uint64 unsync_size = 0;
- std::atomic<uint64> read_size{0};
- std::atomic<uint64> write_size{0};
- };
- SchedulerLocalStorage<LocalNetStats> local_net_stats_;
- std::unique_ptr<Callback> callback_;
-
- void on_read(uint64 size) final {
- auto &stats = local_net_stats_.get();
- stats.read_size.fetch_add(size, std::memory_order_relaxed);
-
- on_change(stats, size);
- }
- void on_write(uint64 size) final {
- auto &stats = local_net_stats_.get();
- stats.write_size.fetch_add(size, std::memory_order_relaxed);
-
- on_change(stats, size);
- }
-
- void on_change(LocalNetStats &stats, uint64 size) {
- stats.unsync_size += size;
- auto now = Time::now_cached();
- if (stats.unsync_size > 10000 || now - stats.last_update > 5 * 60) {
- stats.unsync_size = 0;
- stats.last_update = now;
- callback_->on_stats_updated();
- }
- }
- };
- std::shared_ptr<Impl> impl_{std::make_shared<Impl>()};
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/Socks5.cpp b/libs/tdlib/td/tdnet/td/net/Socks5.cpp
deleted file mode 100644
index 02e1e067ea..0000000000
--- a/libs/tdlib/td/tdnet/td/net/Socks5.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/Socks5.h"
-
-#include "td/utils/format.h"
-#include "td/utils/logging.h"
-#include "td/utils/misc.h"
-#include "td/utils/port/Fd.h"
-#include "td/utils/Slice.h"
-
-namespace td {
-
-static int VERBOSITY_NAME(socks5) = VERBOSITY_NAME(DEBUG);
-
-Socks5::Socks5(SocketFd socket_fd, IPAddress ip_address, string username, string password,
- std::unique_ptr<Callback> callback, ActorShared<> parent)
- : fd_(std::move(socket_fd))
- , ip_address_(std::move(ip_address))
- , username_(std::move(username))
- , password_(std::move(password))
- , callback_(std::move(callback))
- , parent_(std::move(parent)) {
-}
-
-void Socks5::on_error(Status status) {
- CHECK(status.is_error());
- VLOG(socks5) << "Receive " << status;
- if (callback_) {
- callback_->set_result(std::move(status));
- callback_.reset();
- }
- stop();
-}
-
-void Socks5::tear_down() {
- VLOG(socks5) << "Finish to connect to proxy";
- unsubscribe(fd_.get_fd());
- fd_.get_fd().set_observer(nullptr);
- if (callback_) {
- callback_->set_result(std::move(fd_));
- callback_.reset();
- }
-}
-
-void Socks5::hangup() {
- on_error(Status::Error("Cancelled"));
-}
-
-void Socks5::start_up() {
- VLOG(socks5) << "Begin to connect to proxy";
- fd_.get_fd().set_observer(this);
- subscribe(fd_.get_fd());
- set_timeout_in(10);
- if (can_write(fd_)) {
- loop();
- }
-}
-
-void Socks5::send_greeting() {
- VLOG(socks5) << "Send greeting to proxy";
- CHECK(state_ == State::SendGreeting);
- state_ = State::WaitGreetingResponse;
-
- string greeting;
- greeting += '\x05';
- bool use_username = !username_.empty();
- char authentication_count = use_username ? '\x02' : '\x01';
- greeting += authentication_count;
- greeting += '\0';
- if (use_username) {
- greeting += '\x02';
- }
-
- fd_.output_buffer().append(greeting);
-}
-
-Status Socks5::wait_greeting_response() {
- auto &buf = fd_.input_buffer();
- VLOG(socks5) << "Receive greeting response of size " << buf.size();
- if (buf.size() < 2) {
- return Status::OK();
- }
- auto buffer_slice = buf.read_as_buffer_slice(2);
- auto slice = buffer_slice.as_slice();
- if (slice[0] != '\x05') {
- return Status::Error(PSLICE() << "Unsupported socks protocol version " << int(slice[0]));
- }
- auto authentication_method = slice[1];
- if (authentication_method == '\0') {
- state_ = State::SendIpAddress;
- send_ip_address();
- return Status::OK();
- }
- if (authentication_method == '\x02') {
- return send_username_password();
- }
- return Status::Error("Unsupported authentication mode");
-}
-
-Status Socks5::send_username_password() {
- VLOG(socks5) << "Send username and password";
- if (username_.size() >= 128) {
- return Status::Error("Username is too long");
- }
- if (password_.size() >= 128) {
- return Status::Error("Password is too long");
- }
-
- string request;
- request += '\x01';
- request += narrow_cast<char>(username_.size());
- request += username_;
- request += narrow_cast<char>(password_.size());
- request += password_;
- fd_.output_buffer().append(request);
- state_ = State::WaitPasswordResponse;
-
- return Status::OK();
-}
-
-Status Socks5::wait_password_response() {
- auto &buf = fd_.input_buffer();
- VLOG(socks5) << "Receive password response of size " << buf.size();
- if (buf.size() < 2) {
- return Status::OK();
- }
- auto buffer_slice = buf.read_as_buffer_slice(2);
- auto slice = buffer_slice.as_slice();
- if (slice[0] != '\x01') {
- return Status::Error(PSLICE() << "Unsupported socks subnegotiation protocol version " << int(slice[0]));
- }
- if (slice[1] != '\x00') {
- return Status::Error("Wrong username or password");
- }
-
- state_ = State::SendIpAddress;
- send_ip_address();
- return Status::OK();
-}
-
-void Socks5::send_ip_address() {
- VLOG(socks5) << "Send IP address";
- CHECK(state_ == State::SendIpAddress);
- callback_->on_connected();
- string request;
- request += '\x05';
- request += '\x01';
- request += '\x00';
- if (ip_address_.is_ipv4()) {
- request += '\x01';
- auto ipv4 = ip_address_.get_ipv4();
- request += static_cast<char>(ipv4 & 255);
- request += static_cast<char>((ipv4 >> 8) & 255);
- request += static_cast<char>((ipv4 >> 16) & 255);
- request += static_cast<char>((ipv4 >> 24) & 255);
- } else {
- request += '\x04';
- request += ip_address_.get_ipv6().str();
- }
- auto port = ip_address_.get_port();
- request += static_cast<char>((port >> 8) & 255);
- request += static_cast<char>(port & 255);
- fd_.output_buffer().append(request);
- state_ = State::WaitIpAddressResponse;
-}
-
-Status Socks5::wait_ip_address_response() {
- CHECK(state_ == State::WaitIpAddressResponse);
- auto it = fd_.input_buffer().clone();
- VLOG(socks5) << "Receive IP address response of size " << it.size();
- if (it.size() < 4) {
- return Status::OK();
- }
- char c;
- MutableSlice c_slice(&c, 1);
- it.advance(1, c_slice);
- if (c != '\x05') {
- return Status::Error("Invalid response");
- }
- it.advance(1, c_slice);
- if (c != '\0') {
- return Status::Error(PSLICE() << tag("code", c));
- }
- it.advance(1, c_slice);
- if (c != '\0') {
- return Status::Error("byte must be zero");
- }
- it.advance(1, c_slice);
- if (c == '\x01') {
- if (it.size() < 4) {
- return Status::OK();
- }
- it.advance(4);
- } else if (c == '\x04') {
- if (it.size() < 16) {
- return Status::OK();
- }
- it.advance(16);
- } else {
- return Status::Error("Invalid response");
- }
- if (it.size() < 2) {
- return Status::OK();
- }
- it.advance(2);
- stop();
- return Status::OK();
-}
-
-void Socks5::loop() {
- auto status = [&] {
- TRY_STATUS(fd_.flush_read());
- switch (state_) {
- case State::SendGreeting:
- send_greeting();
- break;
- case State::WaitGreetingResponse:
- TRY_STATUS(wait_greeting_response());
- break;
- case State::WaitPasswordResponse:
- TRY_STATUS(wait_password_response());
- break;
- case State::WaitIpAddressResponse:
- TRY_STATUS(wait_ip_address_response());
- break;
- case State::SendIpAddress:
- case State::Stop:
- UNREACHABLE();
- }
- TRY_STATUS(fd_.flush_write());
- return Status::OK();
- }();
- if (status.is_error()) {
- on_error(std::move(status));
- }
- if (can_close(fd_)) {
- on_error(Status::Error("Connection closed"));
- }
-}
-
-void Socks5::timeout_expired() {
- on_error(Status::Error("Timeout expired"));
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/Socks5.h b/libs/tdlib/td/tdnet/td/net/Socks5.h
deleted file mode 100644
index b67a33c282..0000000000
--- a/libs/tdlib/td/tdnet/td/net/Socks5.h
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/actor.h"
-#include "td/actor/PromiseFuture.h"
-
-#include "td/utils/BufferedFd.h"
-#include "td/utils/common.h"
-#include "td/utils/port/IPAddress.h"
-#include "td/utils/port/SocketFd.h"
-#include "td/utils/Status.h"
-
-namespace td {
-
-class Socks5 : public Actor {
- public:
- class Callback {
- public:
- Callback() = default;
- Callback(const Callback &) = delete;
- Callback &operator=(const Callback &) = delete;
- virtual ~Callback() = default;
-
- virtual void set_result(Result<SocketFd>) = 0;
- virtual void on_connected() = 0;
- };
-
- Socks5(SocketFd socket_fd, IPAddress ip_address, string username, string password, std::unique_ptr<Callback> callback,
- ActorShared<> parent);
-
- private:
- BufferedFd<SocketFd> fd_;
- IPAddress ip_address_;
- string username_;
- string password_;
- std::unique_ptr<Callback> callback_;
- ActorShared<> parent_;
-
- void on_error(Status status);
- void tear_down() override;
- void start_up() override;
- void hangup() override;
-
- enum class State {
- SendGreeting,
- WaitGreetingResponse,
- WaitPasswordResponse,
- SendIpAddress,
- WaitIpAddressResponse,
- Stop
- } state_ = State::SendGreeting;
-
- void send_greeting();
- Status wait_greeting_response();
- Status send_username_password();
-
- Status wait_password_response();
-
- void send_ip_address();
- Status wait_ip_address_response();
-
- void loop() override;
- void timeout_expired() override;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/SslFd.cpp b/libs/tdlib/td/tdnet/td/net/SslFd.cpp
deleted file mode 100644
index f6f7557235..0000000000
--- a/libs/tdlib/td/tdnet/td/net/SslFd.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/SslFd.h"
-
-#include "td/utils/logging.h"
-#include "td/utils/StackAllocator.h"
-#include "td/utils/StringBuilder.h"
-#include "td/utils/Time.h"
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-
-#include <map>
-#include <mutex>
-
-namespace td {
-
-#if !TD_WINDOWS
-static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
- if (!preverify_ok) {
- char buf[256];
- X509_NAME_oneline(X509_get_subject_name(X509_STORE_CTX_get_current_cert(ctx)), buf, 256);
-
- int err = X509_STORE_CTX_get_error(ctx);
- auto warning = PSTRING() << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err)
- << ":depth=" << X509_STORE_CTX_get_error_depth(ctx) << ":" << buf;
- double now = Time::now();
-
- static std::mutex warning_mutex;
- {
- std::lock_guard<std::mutex> lock(warning_mutex);
- static std::map<std::string, double> next_warning_time;
- double &next = next_warning_time[warning];
- if (next <= now) {
- next = now + 300; // one warning per 5 minutes
- LOG(WARNING) << warning;
- }
- }
- }
-
- return preverify_ok;
-}
-#endif
-
-namespace {
-
-Status create_openssl_error(int code, Slice message) {
- const int buf_size = 1 << 12;
- auto buf = StackAllocator::alloc(buf_size);
- StringBuilder sb(buf.as_slice());
-
- sb << message;
- while (unsigned long error_code = ERR_get_error()) {
- sb << "{" << error_code << ", " << ERR_error_string(error_code, nullptr) << "}";
- }
- LOG_IF(ERROR, sb.is_error()) << "OPENSSL error buffer overflow";
- return Status::Error(code, sb.as_cslice());
-}
-
-void openssl_clear_errors(Slice from) {
- if (ERR_peek_error() != 0) {
- LOG(ERROR) << from << ": " << create_openssl_error(0, "Unprocessed OPENSSL_ERROR");
- }
- errno = 0;
-}
-
-void do_ssl_shutdown(SSL *ssl_handle) {
- if (!SSL_is_init_finished(ssl_handle)) {
- return;
- }
- openssl_clear_errors("Before SSL_shutdown");
- SSL_set_quiet_shutdown(ssl_handle, 1);
- SSL_shutdown(ssl_handle);
- openssl_clear_errors("After SSL_shutdown");
-}
-
-} // namespace
-
-SslFd::SslFd(SocketFd &&fd, SSL *ssl_handle_, SSL_CTX *ssl_ctx_)
- : fd_(std::move(fd)), ssl_handle_(ssl_handle_), ssl_ctx_(ssl_ctx_) {
-}
-
-Result<SslFd> SslFd::init(SocketFd fd, CSlice host, CSlice cert_file, VerifyPeer verify_peer) {
-#if TD_WINDOWS
- return Status::Error("TODO");
-#else
- static bool init_openssl = [] {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- return OPENSSL_init_ssl(0, nullptr) != 0;
-#else
- OpenSSL_add_all_algorithms();
- SSL_load_error_strings();
- return OpenSSL_add_ssl_algorithms() != 0;
-#endif
- }();
- CHECK(init_openssl);
-
- openssl_clear_errors("Before SslFd::init");
- CHECK(!fd.empty());
-
- auto ssl_method =
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- TLS_client_method();
-#else
- SSLv23_client_method();
-#endif
- if (ssl_method == nullptr) {
- return create_openssl_error(-6, "Failed to create an SSL client method");
- }
-
- auto ssl_ctx = SSL_CTX_new(ssl_method);
- if (ssl_ctx == nullptr) {
- return create_openssl_error(-7, "Failed to create an SSL context");
- }
- auto ssl_ctx_guard = ScopeExit() + [&]() { SSL_CTX_free(ssl_ctx); };
- long options = 0;
-#ifdef SSL_OP_NO_SSLv2
- options |= SSL_OP_NO_SSLv2;
-#endif
-#ifdef SSL_OP_NO_SSLv3
- options |= SSL_OP_NO_SSLv3;
-#endif
- SSL_CTX_set_options(ssl_ctx, options);
- SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
-
- if (cert_file.empty()) {
- SSL_CTX_set_default_verify_paths(ssl_ctx);
- } else {
- if (SSL_CTX_load_verify_locations(ssl_ctx, cert_file.c_str(), nullptr) == 0) {
- return create_openssl_error(-8, "Failed to set custom cert file");
- }
- }
- if (VERIFY_PEER && verify_peer == VerifyPeer::On) {
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
-
- if (VERIFY_DEPTH != -1) {
- SSL_CTX_set_verify_depth(ssl_ctx, VERIFY_DEPTH);
- }
- } else {
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);
- }
-
- // TODO(now): cipher list
- string cipher_list;
- if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.empty() ? "DEFAULT" : cipher_list.c_str()) == 0) {
- return create_openssl_error(-9, PSLICE() << "Failed to set cipher list \"" << cipher_list << '"');
- }
-
- auto ssl_handle = SSL_new(ssl_ctx);
- if (ssl_handle == nullptr) {
- return create_openssl_error(-13, "Failed to create an SSL handle");
- }
- auto ssl_handle_guard = ScopeExit() + [&]() {
- do_ssl_shutdown(ssl_handle);
- SSL_free(ssl_handle);
- };
-
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
- X509_VERIFY_PARAM *param = SSL_get0_param(ssl_handle);
- /* Enable automatic hostname checks */
- // TODO: X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
- X509_VERIFY_PARAM_set_hostflags(param, 0);
- X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
-#else
-#warning DANGEROUS! HTTPS HOST WILL NOT BE CHECKED. INSTALL OPENSSL >= 1.0.2 OR IMPLEMENT HTTPS HOST CHECK MANUALLY
-#endif
-
- if (!SSL_set_fd(ssl_handle, fd.get_fd().get_native_fd())) {
- return create_openssl_error(-14, "Failed to set fd");
- }
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
- auto host_str = host.str();
- SSL_set_tlsext_host_name(ssl_handle, MutableCSlice(host_str).begin());
-#endif
- SSL_set_connect_state(ssl_handle);
-
- ssl_ctx_guard.dismiss();
- ssl_handle_guard.dismiss();
- return SslFd(std::move(fd), ssl_handle, ssl_ctx);
-#endif
-}
-
-Result<size_t> SslFd::process_ssl_error(int ret, int *mask) {
-#if TD_WINDOWS
- return Status::Error("TODO");
-#else
- auto openssl_errno = errno;
- int error = SSL_get_error(ssl_handle_, ret);
- LOG(INFO) << "SSL ERROR: " << ret << " " << error;
- switch (error) {
- case SSL_ERROR_NONE:
- LOG(ERROR) << "SSL_get_error returned no error";
- return 0;
- case SSL_ERROR_ZERO_RETURN:
- LOG(DEBUG) << "SSL_ERROR_ZERO_RETURN";
- fd_.get_fd().update_flags(Fd::Close);
- write_mask_ |= Fd::Error;
- *mask |= Fd::Error;
- return 0;
- case SSL_ERROR_WANT_READ:
- LOG(DEBUG) << "SSL_ERROR_WANT_READ";
- fd_.get_fd().clear_flags(Fd::Read);
- *mask |= Fd::Read;
- return 0;
- case SSL_ERROR_WANT_WRITE:
- LOG(DEBUG) << "SSL_ERROR_WANT_WRITE";
- fd_.get_fd().clear_flags(Fd::Write);
- *mask |= Fd::Write;
- return 0;
- case SSL_ERROR_WANT_CONNECT:
- case SSL_ERROR_WANT_ACCEPT:
- case SSL_ERROR_WANT_X509_LOOKUP:
- LOG(DEBUG) << "SSL_ERROR: CONNECT ACCEPT LOOKUP";
- fd_.get_fd().clear_flags(Fd::Write);
- *mask |= Fd::Write;
- return 0;
- case SSL_ERROR_SYSCALL:
- LOG(DEBUG) << "SSL_ERROR_SYSCALL";
- if (ERR_peek_error() == 0) {
- if (openssl_errno != 0) {
- CHECK(openssl_errno != EAGAIN);
- return Status::PosixError(openssl_errno, "SSL_ERROR_SYSCALL");
- } else {
- // Socket was closed from the other side, probably. Not an error
- fd_.get_fd().update_flags(Fd::Close);
- write_mask_ |= Fd::Error;
- *mask |= Fd::Error;
- return 0;
- }
- }
- /* fall through */
- default:
- LOG(DEBUG) << "SSL_ERROR Default";
- fd_.get_fd().update_flags(Fd::Close);
- write_mask_ |= Fd::Error;
- read_mask_ |= Fd::Error;
- return create_openssl_error(1, "SSL error ");
- }
-#endif
-}
-
-Result<size_t> SslFd::write(Slice slice) {
- openssl_clear_errors("Before SslFd::write");
- auto size = SSL_write(ssl_handle_, slice.data(), static_cast<int>(slice.size()));
- if (size <= 0) {
- return process_ssl_error(size, &write_mask_);
- }
- return size;
-}
-Result<size_t> SslFd::read(MutableSlice slice) {
- openssl_clear_errors("Before SslFd::read");
- auto size = SSL_read(ssl_handle_, slice.data(), static_cast<int>(slice.size()));
- if (size <= 0) {
- return process_ssl_error(size, &read_mask_);
- }
- return size;
-}
-
-void SslFd::close() {
- if (fd_.empty()) {
- CHECK(!ssl_handle_ && !ssl_ctx_);
- return;
- }
- CHECK(ssl_handle_ && ssl_ctx_);
- do_ssl_shutdown(ssl_handle_);
- SSL_free(ssl_handle_);
- ssl_handle_ = nullptr;
- SSL_CTX_free(ssl_ctx_);
- ssl_ctx_ = nullptr;
- fd_.close();
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/SslFd.h b/libs/tdlib/td/tdnet/td/net/SslFd.h
deleted file mode 100644
index c197b9c318..0000000000
--- a/libs/tdlib/td/tdnet/td/net/SslFd.h
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/utils/port/Fd.h"
-#include "td/utils/port/SocketFd.h"
-#include "td/utils/Slice.h"
-#include "td/utils/Status.h"
-
-#include <openssl/ssl.h> // TODO can we remove it from header and make target_link_libraries dependence PRIVATE?
-
-namespace td {
-
-class SslFd {
- public:
- enum class VerifyPeer { On, Off };
- static Result<SslFd> init(SocketFd fd, CSlice host, CSlice cert_file = CSlice(),
- VerifyPeer verify_peer = VerifyPeer::On) TD_WARN_UNUSED_RESULT;
-
- SslFd(const SslFd &other) = delete;
- SslFd &operator=(const SslFd &other) = delete;
- SslFd(SslFd &&other)
- : fd_(std::move(other.fd_))
- , write_mask_(other.write_mask_)
- , read_mask_(other.read_mask_)
- , ssl_handle_(other.ssl_handle_)
- , ssl_ctx_(other.ssl_ctx_) {
- other.ssl_handle_ = nullptr;
- other.ssl_ctx_ = nullptr;
- }
- SslFd &operator=(SslFd &&other) {
- close();
-
- fd_ = std::move(other.fd_);
- write_mask_ = other.write_mask_;
- read_mask_ = other.read_mask_;
- ssl_handle_ = other.ssl_handle_;
- ssl_ctx_ = other.ssl_ctx_;
-
- other.ssl_handle_ = nullptr;
- other.ssl_ctx_ = nullptr;
- return *this;
- }
-
- const Fd &get_fd() const {
- return fd_.get_fd();
- }
-
- Fd &get_fd() {
- return fd_.get_fd();
- }
-
- Status get_pending_error() TD_WARN_UNUSED_RESULT {
- return fd_.get_pending_error();
- }
-
- Result<size_t> write(Slice slice) TD_WARN_UNUSED_RESULT;
- Result<size_t> read(MutableSlice slice) TD_WARN_UNUSED_RESULT;
-
- void close();
-
- int32 get_flags() const {
- int32 res = 0;
- int32 fd_flags = fd_.get_flags();
- fd_flags &= ~Fd::Error;
- if (fd_flags & Fd::Close) {
- res |= Fd::Close;
- }
- write_mask_ &= ~fd_flags;
- read_mask_ &= ~fd_flags;
- if (write_mask_ == 0) {
- res |= Fd::Write;
- }
- if (read_mask_ == 0) {
- res |= Fd::Read;
- }
- return res;
- }
-
- bool empty() const {
- return fd_.empty();
- }
-
- ~SslFd() {
- close();
- }
-
- private:
- static constexpr bool VERIFY_PEER = true;
- static constexpr int VERIFY_DEPTH = 10;
-
- SocketFd fd_;
- mutable int write_mask_ = 0;
- mutable int read_mask_ = 0;
-
- // TODO unique_ptr
- SSL *ssl_handle_ = nullptr;
- SSL_CTX *ssl_ctx_ = nullptr;
-
- SslFd(SocketFd &&fd, SSL *ssl_handle_, SSL_CTX *ssl_ctx_);
-
- Result<size_t> process_ssl_error(int ret, int *mask) TD_WARN_UNUSED_RESULT;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/TcpListener.cpp b/libs/tdlib/td/tdnet/td/net/TcpListener.cpp
deleted file mode 100644
index 54531f9b60..0000000000
--- a/libs/tdlib/td/tdnet/td/net/TcpListener.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/TcpListener.h"
-
-#include "td/utils/logging.h"
-#include "td/utils/port/Fd.h"
-
-namespace td {
-// TcpListener implementation
-TcpListener::TcpListener(int port, ActorShared<Callback> callback) : port_(port), callback_(std::move(callback)) {
-}
-
-void TcpListener::hangup() {
- stop();
-}
-
-void TcpListener::start_up() {
- auto r_socket = ServerSocketFd::open(port_);
- if (r_socket.is_error()) {
- LOG(ERROR) << "Can't open server socket: " << r_socket.error();
- set_timeout_in(5);
- return;
- }
- server_fd_ = r_socket.move_as_ok();
- server_fd_.get_fd().set_observer(this);
- subscribe(server_fd_.get_fd());
-}
-
-void TcpListener::tear_down() {
- LOG(ERROR) << "TcpListener closed";
- if (!server_fd_.empty()) {
- unsubscribe_before_close(server_fd_.get_fd());
- server_fd_.close();
- }
-}
-
-void TcpListener::loop() {
- if (server_fd_.empty()) {
- start_up();
- }
- while (can_read(server_fd_)) {
- auto r_socket_fd = server_fd_.accept();
- if (r_socket_fd.is_error()) {
- if (r_socket_fd.error().code() != -1) {
- LOG(ERROR) << r_socket_fd.error();
- }
- continue;
- }
- send_closure(callback_, &Callback::accept, r_socket_fd.move_as_ok());
- }
-
- if (can_close(server_fd_)) {
- LOG(ERROR) << "HELLO!";
- stop();
- }
-}
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/TcpListener.h b/libs/tdlib/td/tdnet/td/net/TcpListener.h
deleted file mode 100644
index f2e61a2387..0000000000
--- a/libs/tdlib/td/tdnet/td/net/TcpListener.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/actor/actor.h"
-
-#include "td/utils/port/ServerSocketFd.h"
-#include "td/utils/port/SocketFd.h"
-
-namespace td {
-
-class TcpListener final : public Actor {
- public:
- class Callback : public Actor {
- public:
- virtual void accept(SocketFd fd) = 0;
- };
-
- TcpListener(int port, ActorShared<Callback> callback);
- void hangup() override;
-
- private:
- int port_;
- ServerSocketFd server_fd_;
- ActorShared<Callback> callback_;
- void start_up() override;
- void tear_down() override;
- void loop() override;
-};
-
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/Wget.cpp b/libs/tdlib/td/tdnet/td/net/Wget.cpp
deleted file mode 100644
index b30128be32..0000000000
--- a/libs/tdlib/td/tdnet/td/net/Wget.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#include "td/net/Wget.h"
-
-#include "td/net/HttpHeaderCreator.h"
-#include "td/net/HttpOutboundConnection.h"
-#include "td/net/SslFd.h"
-
-#include "td/utils/buffer.h"
-#include "td/utils/HttpUrl.h"
-#include "td/utils/logging.h"
-#include "td/utils/port/IPAddress.h"
-#include "td/utils/port/SocketFd.h"
-#include "td/utils/Slice.h"
-
-#include <limits>
-
-namespace td {
-Wget::Wget(Promise<HttpQueryPtr> promise, string url, std::vector<std::pair<string, string>> headers, int32 timeout_in,
- int32 ttl, SslFd::VerifyPeer verify_peer)
- : promise_(std::move(promise))
- , input_url_(std::move(url))
- , headers_(std::move(headers))
- , timeout_in_(timeout_in)
- , ttl_(ttl)
- , verify_peer_(verify_peer) {
-}
-
-Status Wget::try_init() {
- string input_url = input_url_;
- TRY_RESULT(url, parse_url(MutableSlice(input_url)));
-
- IPAddress addr;
- TRY_STATUS(addr.init_host_port(url.host_, url.port_));
-
- TRY_RESULT(fd, SocketFd::open(addr));
- if (url.protocol_ == HttpUrl::Protocol::HTTP) {
- connection_ =
- create_actor<HttpOutboundConnection>("Connect", std::move(fd), std::numeric_limits<std::size_t>::max(), 0, 0,
- ActorOwn<HttpOutboundConnection::Callback>(actor_id(this)));
- } else {
- TRY_RESULT(ssl_fd, SslFd::init(std::move(fd), url.host_, CSlice() /* certificate */, verify_peer_));
- connection_ =
- create_actor<HttpOutboundConnection>("Connect", std::move(ssl_fd), std::numeric_limits<std::size_t>::max(), 0,
- 0, ActorOwn<HttpOutboundConnection::Callback>(actor_id(this)));
- }
-
- HttpHeaderCreator hc;
- hc.init_get(url.query_);
- bool was_host = false;
- for (auto &header : headers_) {
- if (header.first == "Host") { // TODO: lowercase
- was_host = true;
- }
- hc.add_header(header.first, header.second);
- }
- if (!was_host) {
- hc.add_header("Host", url.host_);
- }
- hc.add_header("Accept-Encoding", "gzip, deflate");
-
- send_closure(connection_, &HttpOutboundConnection::write_next, BufferSlice(hc.finish().ok()));
- send_closure(connection_, &HttpOutboundConnection::write_ok);
- return Status::OK();
-}
-
-void Wget::loop() {
- if (connection_.empty()) {
- auto status = try_init();
- if (status.is_error()) {
- return on_error(std::move(status));
- }
- }
-}
-
-void Wget::handle(HttpQueryPtr result) {
- on_ok(std::move(result));
-}
-
-void Wget::on_connection_error(Status error) {
- on_error(std::move(error));
-}
-
-void Wget::on_ok(HttpQueryPtr http_query_ptr) {
- CHECK(promise_);
- if (http_query_ptr->code_ == 302 && ttl_ > 0) {
- LOG(DEBUG) << *http_query_ptr;
- input_url_ = http_query_ptr->header("location").str();
- LOG(DEBUG) << input_url_;
- ttl_--;
- connection_.reset();
- yield();
- } else if (http_query_ptr->code_ >= 200 && http_query_ptr->code_ < 300) {
- promise_.set_value(std::move(http_query_ptr));
- stop();
- } else {
- on_error(Status::Error(PSLICE() << "http error: " << http_query_ptr->code_));
- }
-}
-
-void Wget::on_error(Status error) {
- CHECK(error.is_error());
- CHECK(promise_);
- promise_.set_error(std::move(error));
- stop();
-}
-
-void Wget::start_up() {
- set_timeout_in(timeout_in_);
- loop();
-}
-
-void Wget::timeout_expired() {
- on_error(Status::Error("Timeout expired"));
-}
-
-void Wget::tear_down() {
- if (promise_) {
- on_error(Status::Error("Cancelled"));
- }
-}
-} // namespace td
diff --git a/libs/tdlib/td/tdnet/td/net/Wget.h b/libs/tdlib/td/tdnet/td/net/Wget.h
deleted file mode 100644
index cecb113c94..0000000000
--- a/libs/tdlib/td/tdnet/td/net/Wget.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-#pragma once
-
-#include "td/net/HttpOutboundConnection.h"
-#include "td/net/HttpQuery.h"
-#include "td/net/SslFd.h"
-
-#include "td/actor/PromiseFuture.h"
-
-#include "td/utils/common.h"
-#include "td/utils/Status.h"
-
-#include <utility>
-
-namespace td {
-
-class Wget : public HttpOutboundConnection::Callback {
- public:
- explicit Wget(Promise<HttpQueryPtr> promise, string url, std::vector<std::pair<string, string>> headers = {},
- int32 timeout_in = 10, int32 ttl = 3, SslFd::VerifyPeer verify_peer = SslFd::VerifyPeer::On);
-
- private:
- Status try_init();
- void loop() override;
- void handle(HttpQueryPtr result) override;
- void on_connection_error(Status error) override;
- void on_ok(HttpQueryPtr http_query_ptr);
- void on_error(Status error);
-
- void tear_down() override;
- void start_up() override;
- void timeout_expired() override;
-
- Promise<HttpQueryPtr> promise_;
- ActorOwn<HttpOutboundConnection> connection_;
- string input_url_;
- std::vector<std::pair<string, string>> headers_;
- int32 timeout_in_;
- int32 ttl_;
- SslFd::VerifyPeer verify_peer_;
-};
-
-} // namespace td