aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/http/io/stream.h
blob: e0846ef107e2e4cc12bcc9c3470b4d1057fa9f66 (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#pragma once

#include "headers.h"

#include <util/stream/output.h>
#include <util/generic/maybe.h>
#include <util/generic/ptr.h>
#include <util/generic/string.h>
#include <util/generic/strbuf.h>
#include <util/generic/yexception.h>
#include <util/generic/array_ref.h>

class TSocket;

struct THttpException: public yexception {
};

struct THttpParseException: public THttpException {
};

struct THttpReadException: public THttpException {
};

/// Чтение ответа HTTP-сервера.
class THttpInput: public IInputStream {
public:
    THttpInput(IInputStream* slave);
    THttpInput(THttpInput&& httpInput);
    ~THttpInput() override;

    /*
     * parsed http headers
     */
    /// Возвращает контейнер с заголовками ответа HTTP-сервера.
    const THttpHeaders& Headers() const noexcept;

    /*
     * parsed http trailers
     */
    /// Возвращает контейнер (возможно пустой) с trailer'ами ответа HTTP-сервера.
    /// Поток должен быть вычитан полностью прежде чем trailer'ы будут доступны.
    /// Пока поток не вычитан до конца возвращается Nothing.
    /// https://tools.ietf.org/html/rfc7230#section-4.1.2
    const TMaybe<THttpHeaders>& Trailers() const noexcept;

    /*
     * first line - response or request
     */
    /// Возвращает первую строку ответа HTTP-сервера.
    /// @details Первая строка HTTP-сервера - строка состояния,
    /// содержащая три поля: версию HTTP, код состояния и описание.
    const TString& FirstLine() const noexcept;

    /*
     * connection can be keep-alive
     */
    /// Проверяет, не завершено ли соединение с сервером.
    /// @details Транзакция считается завершенной, если не передан заголовок
    /// "Connection: Keep Alive".
    bool IsKeepAlive() const noexcept;

    /*
     * output data can be encoded
     */
    /// Проверяет, поддерживается ли данный тип кодирования содержимого
    /// ответа HTTP-сервера.
    bool AcceptEncoding(const TString& coding) const;

    /// Пытается определить наилучший тип кодирования ответа HTTP-сервера.
    /// @details Если ответ сервера говорит о том, что поддерживаются
    /// любые типы кодирования, выбирается gzip. В противном случае
    /// из списка типов кодирования выбирается лучший из поддерживаемых сервером.
    TString BestCompressionScheme() const;
    TString BestCompressionScheme(TArrayRef<const TStringBuf> codings) const;

    /// Если заголовки содержат Content-Length, возвращает true и
    /// записывает значение из заголовка в value
    bool GetContentLength(ui64& value) const noexcept;

    /// Признак запакованности данных, - если выставлен, то Content-Length, при наличии в заголовках,
    /// показывает объём запакованных данных, а из THttpInput мы будем вычитывать уже распакованные.
    bool ContentEncoded() const noexcept;

    /// Returns true if Content-Length or Transfer-Encoding header received
    bool HasContent() const noexcept;

    bool HasExpect100Continue() const noexcept; 
 
private:
    size_t DoRead(void* buf, size_t len) override;
    size_t DoSkip(size_t len) override;

private:
    class TImpl;
    THolder<TImpl> Impl_;
};

/// Передача запроса HTTP-серверу.
class THttpOutput: public IOutputStream {
public:
    THttpOutput(IOutputStream* slave);
    THttpOutput(IOutputStream* slave, THttpInput* request);
    ~THttpOutput() override;

    /*
     * sent http headers
     */
    /// Возвращает контейнер с заголовками запроса к HTTP-серверу.
    const THttpHeaders& SentHeaders() const noexcept;

    /// Устанавливает режим, при котором сервер выдает ответ в упакованном виде.
    void EnableCompression(bool enable);
    void EnableCompression(TArrayRef<const TStringBuf> schemas);

    /// Устанавливает режим, при котором соединение с сервером не завершается
    /// после окончания транзакции.
    void EnableKeepAlive(bool enable);

    /// Устанавливает режим, при котором тело HTTP-запроса/ответа преобразуется в соответствии
    /// с заголовками Content-Encoding и Transfer-Encoding (включен по умолчанию)
    void EnableBodyEncoding(bool enable);

    /// Устанавливает режим, при котором тело HTTP-ответа сжимается кодеком
    /// указанным в Content-Encoding (включен по умолчанию)
    void EnableCompressionHeader(bool enable);

    /// Проверяет, производится ли выдача ответов в упакованном виде.
    bool IsCompressionEnabled() const noexcept;

    /// Проверяет, не завершается ли соединение с сервером после окончания транзакции.
    bool IsKeepAliveEnabled() const noexcept;

    /// Проверяет, преобразуется ли тело HTTP-запроса/ответа в соответствии
    /// с заголовками Content-Encoding и Transfer-Encoding
    bool IsBodyEncodingEnabled() const noexcept;

    /// Проверяет, сжимается ли тело HTTP-ответа кодеком
    /// указанным в Content-Encoding
    bool IsCompressionHeaderEnabled() const noexcept;

    /*
     * is this connection can be really keep-alive
     */
    /// Проверяет, можно ли установить режим, при котором соединение с сервером
    /// не завершается после окончания транзакции.
    bool CanBeKeepAlive() const noexcept;

    void SendContinue(); 
 
    /*
     * first line - response or request
     */
    /// Возвращает первую строку HTTP-запроса/ответа
    const TString& FirstLine() const noexcept;

    /// Возвращает размер отправленных данных (без заголовков, с учётом сжатия, без
    /// учёта chunked transfer encoding)
    size_t SentSize() const noexcept;

private:
    void DoWrite(const void* buf, size_t len) override;
    void DoFlush() override;
    void DoFinish() override;

private:
    class TImpl;
    THolder<TImpl> Impl_;
};

/// Возвращает код состояния из ответа сервера.
unsigned ParseHttpRetCode(const TStringBuf& ret);

/// Отправляет HTTP-серверу запрос с минимумом необходимых заголовков.
void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent = "YandexSomething/1.0", const TStringBuf& from = "webadmin@yandex.ru");

TArrayRef<const TStringBuf> SupportedCodings();

/// @}