aboutsummaryrefslogtreecommitdiffstats
path: root/vbench/src/vbench/http/http_client.h
blob: 4254c65983a2c0e55d09588d5f5b6e04e34ea6a1 (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.


#pragma once

#include "http_connection.h"
#include "http_connection_pool.h"
#include "http_result_handler.h"
#include <vbench/core/socket.h>

namespace vbench {

/**
 * This class handles sequential HTTP requests against a single
 * server.
 **/
class HttpClient
{
public:
    using CryptoEngine = vespalib::CryptoEngine;
private:
    static const size_t WRITE_SIZE = 2000;

    struct HeaderInfo {
        bool connectionCloseGiven;
        bool contentLengthGiven;
        bool chunkedEncodingGiven;
        bool keepAliveGiven;
        uint32_t status;
        uint32_t version;
        size_t contentLength;
        HeaderInfo() : connectionCloseGiven(false), contentLengthGiven(false),
                       chunkedEncodingGiven(false), keepAliveGiven(false),
                       status(0), version(0) {}
    };

    HttpConnection::UP _conn;
    string             _url;
    HttpResultHandler &_handler;
    HeaderInfo         _header;

    // scratch data used for parsing
    string              _line;
    std::vector<string> _split;

    HttpClient(HttpConnection::UP conn, const string &url, HttpResultHandler &handler)
        : _conn(std::move(conn)), _url(url), _handler(handler), _header() {}

    bool serverKeepAlive() const {
        return ((_header.version == 1 && !_header.connectionCloseGiven) ||
                (_header.version == 0 && _header.keepAliveGiven));
    }

    void writeRequest();
    bool readStatus();
    bool readHeaders();
    bool readContent(size_t len);
    bool readChunkSize(bool first, size_t &size);
    bool skipTrailers();
    bool readContent();
    bool perform(CryptoEngine &crypto);

public:
    ~HttpClient();
    static bool fetch(CryptoEngine &crypto, const ServerSpec &server, const string &url,
                      HttpResultHandler &handler)
    {
        HttpClient client(HttpConnection::UP(new HttpConnection(crypto, server)), url, handler);
        return client.perform(crypto);
    }
    static bool fetch(HttpConnectionPool &pool,
                      const ServerSpec &server, const string &url,
                      HttpResultHandler &handler)
    {
        HttpClient client(pool.getConnection(server), url, handler);
        if (client.perform(pool.crypto())) {
            if (client.serverKeepAlive()) {
                pool.putConnection(std::move(client._conn));
            }
            return true;
        }
        return false;
    }
};

} // namespace vbench