aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/portal/portal.h
blob: a25c295c0832950ef0c09074a541d6d75af0b5e3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "listener.h"
#include "reactor.h"
#include "handle_manager.h"

#include <vespa/vespalib/net/crypto_engine.h>
#include <vespa/vespalib/net/crypto_socket.h>
#include <vespa/vespalib/stllike/string.h>

#include <map>
#include <memory>
#include <mutex>
#include <thread>

namespace vespalib {

namespace portal { class HttpConnection; }
namespace net { class ConnectionAuthContext; }

/**
 * Minimal HTTP server and connection establishment manager.
 **/
class Portal
{
public:
    using SP = std::shared_ptr<Portal>;

    class Token {
        friend class Portal;
    private:
        Portal &_portal;
        uint64_t _handle;
        Token(const Token &) = delete;
        Token &operator=(const Token &) = delete;
        Token(Token &&) = delete;
        Token &operator=(Token &&) = delete;
        Token(Portal &portal, uint64_t handle)
            : _portal(portal), _handle(handle) {}
        uint64_t handle() const { return _handle; }
    public:
        using UP = std::unique_ptr<Token>;
        ~Token();
    };

    class GetRequest {
        friend class Portal;
    private:
        portal::HttpConnection *_conn;
        GetRequest(portal::HttpConnection &conn) : _conn(&conn) {}
    public:
        GetRequest(const GetRequest &rhs) = delete;
        GetRequest &operator=(const GetRequest &rhs) = delete;
        GetRequest &operator=(GetRequest &&rhs) = delete;
        GetRequest(GetRequest &&rhs) noexcept : _conn(rhs._conn) {
            rhs._conn = nullptr;
        }
        bool active() const { return (_conn != nullptr); }
        const vespalib::string &get_header(const vespalib::string &name) const;
        const vespalib::string &get_host() const;
        const vespalib::string &get_uri() const;
        const vespalib::string &get_path() const;
        bool has_param(const vespalib::string &name) const;
        const vespalib::string &get_param(const vespalib::string &name) const;
        std::map<vespalib::string, vespalib::string> export_params() const;
        void respond_with_content(vespalib::stringref content_type,
                                  vespalib::stringref content);
        void respond_with_error(int code, vespalib::stringref msg);
        const net::ConnectionAuthContext &auth_context() const noexcept;
        ~GetRequest();
    };

    struct GetHandler {
        virtual void get(GetRequest request) = 0;
        virtual ~GetHandler();
    };

private:
    struct BindState {
        uint64_t handle;
        vespalib::string prefix;
        GetHandler *handler;
        BindState(uint64_t handle_in, vespalib::string prefix_in, GetHandler &handler_in) noexcept
            : handle(handle_in), prefix(std::move(prefix_in)), handler(&handler_in) {}
        bool operator<(const BindState &rhs) const {
            if (prefix.size() == rhs.prefix.size()) {
                return (handle > rhs.handle);
            }
            return (prefix.size() > rhs.prefix.size());
        }
    };

    CryptoEngine::SP       _crypto;
    portal::Reactor        _reactor;
    portal::HandleManager  _handle_manager;
    uint64_t               _conn_handle;
    portal::Listener::UP   _listener;
    std::mutex             _lock;
    std::vector<BindState> _bind_list;
    vespalib::string       _my_host;

    Token::UP make_token();
    void cancel_token(Token &token);

    portal::HandleGuard lookup_get_handler(const vespalib::string &uri, GetHandler *&handler);
    void evict_handle(uint64_t handle);

    void handle_accept(portal::HandleGuard guard, SocketHandle socket);
    void handle_http(portal::HttpConnection *conn);

    Portal(CryptoEngine::SP crypto, int port);
public:
    ~Portal();
    static SP create(CryptoEngine::SP crypto, int port);
    int listen_port() const { return _listener->listen_port(); }
    const vespalib::string &my_host() const { return _my_host; }
    Token::UP bind(const vespalib::string &path_prefix, GetHandler &handler);
};

} // namespace vespalib