line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#pragma once |
2
|
|
|
|
|
|
|
#include "Response.h" |
3
|
|
|
|
|
|
|
#include |
4
|
|
|
|
|
|
|
#include |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
namespace panda { namespace protocol { namespace http { |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
struct Request : Message, AllocatedObject { |
10
|
|
|
|
|
|
|
enum class Method {unspecified, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT}; |
11
|
|
|
|
|
|
|
enum class EncType {MULTIPART, URLENCODED, disabled}; |
12
|
|
|
|
|
|
|
enum class FormStreaming { none, started, file, done }; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
static inline string method_str(Request::Method rm) noexcept { |
15
|
|
|
|
|
|
|
using Method = Request::Method; |
16
|
|
|
|
|
|
|
switch (rm) { |
17
|
|
|
|
|
|
|
case Method::unspecified : return "[unspecified]"; |
18
|
|
|
|
|
|
|
case Method::OPTIONS : return "OPTIONS"; |
19
|
|
|
|
|
|
|
case Method::GET : return "GET"; |
20
|
|
|
|
|
|
|
case Method::HEAD : return "HEAD"; |
21
|
|
|
|
|
|
|
case Method::POST : return "POST"; |
22
|
|
|
|
|
|
|
case Method::PUT : return "PUT"; |
23
|
|
|
|
|
|
|
case Method::DELETE : return "DELETE"; |
24
|
|
|
|
|
|
|
case Method::TRACE : return "TRACE"; |
25
|
|
|
|
|
|
|
case Method::CONNECT : return "CONNECT"; |
26
|
|
|
|
|
|
|
default: return "[UNKNOWN]"; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
struct Builder; template struct BuilderImpl; |
31
|
|
|
|
|
|
|
using Cookies = Fields; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
struct NamedString { |
34
|
|
|
|
|
|
|
string value; |
35
|
|
|
|
|
|
|
string name; |
36
|
|
|
|
|
|
|
string content_type; |
37
|
|
|
|
|
|
|
}; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
struct Form: string_multimap { |
40
|
|
|
|
|
|
|
|
41
|
0
|
|
|
|
|
|
Form(EncType enc_type = EncType::disabled) noexcept :_enc_type(enc_type){} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
void enc_type (const EncType value) noexcept { _enc_type = value; } |
44
|
|
|
|
|
|
|
EncType enc_type () const noexcept { return _enc_type; } |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
operator bool () const noexcept { return _enc_type != EncType::disabled; } |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
void add(const string& key, const string& value, const string& filename = "", const string content_type = "") { |
49
|
|
|
|
|
|
|
insert({key, NamedString{value, filename, content_type}}); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
private: |
53
|
|
|
|
|
|
|
const URI* to_body (Body& body, uri::URI &uri, const URISP original_uri, const string& boundary) const noexcept; |
54
|
|
|
|
|
|
|
void to_uri (URI& uri, const URISP original_uri) const ; |
55
|
|
|
|
|
|
|
EncType _enc_type = EncType::MULTIPART; |
56
|
|
|
|
|
|
|
friend struct Request; |
57
|
|
|
|
|
|
|
}; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
URISP uri; |
61
|
|
|
|
|
|
|
Cookies cookies; |
62
|
|
|
|
|
|
|
Form form; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
compression::storage_t compression_prefs = Compression::IDENTITY; |
65
|
|
|
|
|
|
|
|
66
|
0
|
0
|
|
|
|
|
Request () {} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Request (Method method, const URISP& uri, Headers&& header = Headers(), Body&& body = Body(), bool chunked = false, int http_version = 0) : |
69
|
|
|
|
|
|
|
Message(std::move(header), std::move(body), chunked, http_version), uri(uri), _method(method) |
70
|
|
|
|
|
|
|
{ |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
bool expects_continue () const; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
std::vector to_vector () const; |
76
|
|
|
|
|
|
|
string to_string () const { return Message::to_string(to_vector()); } |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
virtual ResponseSP new_response () const { return make_iptr(); } |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
template |
82
|
|
|
|
|
|
|
void allow_compression (PrefN... prefn) { |
83
|
|
|
|
|
|
|
return _allow_compression(prefn...); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Method method() const noexcept; |
87
|
|
|
|
|
|
|
Method method_raw() const noexcept { return _method; } |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
void method_raw(Method value) noexcept { _method = value; } |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
std::uint8_t allowed_compression (bool inverse = false) const noexcept; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
void form_stream() { |
94
|
|
|
|
|
|
|
if (_form_streaming == FormStreaming::none) { |
95
|
|
|
|
|
|
|
_form_streaming = FormStreaming::started; |
96
|
|
|
|
|
|
|
form._enc_type = EncType::MULTIPART; |
97
|
|
|
|
|
|
|
_form_boundary = _generate_boundary(); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
else if (_form_streaming != FormStreaming::started) { |
100
|
|
|
|
|
|
|
throw "invalid state for form streaming"; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
bool form_streaming() noexcept { return _form_streaming == FormStreaming::started; } |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
wrapped_chunk form_finish(); |
107
|
|
|
|
|
|
|
wrapped_chunk form_field(const string& name, const string& content, const string& filename = "", const string& mime_type = ""); |
108
|
|
|
|
|
|
|
wrapped_chunk form_file(const string& name, const string filename = "", const string& mime_type = "application/octet-stream"); |
109
|
|
|
|
|
|
|
wrapped_chunk form_data(const string& data); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
protected: |
112
|
|
|
|
|
|
|
struct SerializationContext: Message::SerializationContext { |
113
|
|
|
|
|
|
|
const URI* uri; |
114
|
|
|
|
|
|
|
}; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
string form_trailer(const string& boundary) const noexcept { |
117
|
|
|
|
|
|
|
auto sz = boundary.size() + 6; |
118
|
|
|
|
|
|
|
string r(sz); |
119
|
|
|
|
|
|
|
r += "--"; |
120
|
|
|
|
|
|
|
r += boundary; |
121
|
|
|
|
|
|
|
r += "--\r\n"; |
122
|
|
|
|
|
|
|
return r; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Method _method = Method::unspecified; |
126
|
|
|
|
|
|
|
FormStreaming _form_streaming = FormStreaming::none; |
127
|
|
|
|
|
|
|
string _form_boundary; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
template |
130
|
|
|
|
|
|
|
void _allow_compression (Compression::Type p, PrefN... prefn) { |
131
|
|
|
|
|
|
|
compression::pack(this->compression_prefs, p); |
132
|
|
|
|
|
|
|
return _allow_compression(prefn...); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
void _allow_compression () {} |
135
|
|
|
|
|
|
|
void form_file_finalize(string& out) noexcept; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
~Request () {} // restrict stack allocation |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
private: |
140
|
|
|
|
|
|
|
friend struct RequestParser; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
static Method deduce_method (bool has_form, EncType form_enc, Method _method) noexcept; |
143
|
|
|
|
|
|
|
string _http_header (SerializationContext &ctx) const; |
144
|
|
|
|
|
|
|
static string _generate_boundary() noexcept; |
145
|
|
|
|
|
|
|
}; |
146
|
|
|
|
|
|
|
using RequestSP = iptr; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
template |
149
|
|
|
|
|
|
|
struct Request::BuilderImpl : Message::Builder { |
150
|
|
|
|
|
|
|
using Message::Builder::Builder; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
T& method (Request::Method method) { |
153
|
|
|
|
|
|
|
this->_message->method_raw(method); |
154
|
|
|
|
|
|
|
return this->self(); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
T& uri (const string& uri) { |
158
|
|
|
|
|
|
|
this->_message->uri = new URI(uri); |
159
|
|
|
|
|
|
|
return this->self(); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
T& uri (const URISP& uri) { |
163
|
|
|
|
|
|
|
this->_message->uri = uri; |
164
|
|
|
|
|
|
|
return this->self(); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
T& cookie (const string& name, const string& value) { |
168
|
|
|
|
|
|
|
this->_message->cookies.add(name, value); |
169
|
|
|
|
|
|
|
return this->self(); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
template |
173
|
|
|
|
|
|
|
T& allow_compression(PrefN... prefn) { |
174
|
|
|
|
|
|
|
this->_message->allow_compression(prefn...); |
175
|
|
|
|
|
|
|
return this->self(); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
template |
179
|
|
|
|
|
|
|
T& form(Form&& form) { |
180
|
|
|
|
|
|
|
this->_message->form = std::forward |
181
|
|
|
|
|
|
|
return this->self(); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
T& form_stream() { |
185
|
|
|
|
|
|
|
this->_message->form_stream(); |
186
|
|
|
|
|
|
|
return this->self(); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
}; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
struct Request::Builder : Request::BuilderImpl { |
191
|
|
|
|
|
|
|
Builder () : BuilderImpl(new Request()) {} |
192
|
|
|
|
|
|
|
}; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
}}} |