forked from hzane/libhttpsvr
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp_response_writer.cc
More file actions
201 lines (183 loc) · 7.63 KB
/
http_response_writer.cc
File metadata and controls
201 lines (183 loc) · 7.63 KB
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include "../libhttpsvr/precomp.h"
#include "../libhttpsvr/common_defs.h"
#include "../libhttpsvr/tpio_defs.h"
#include "../libhttpsvr/http_headers.h"
#include "../libhttpsvr/http_chunks.h"
#include "../libhttpsvr/http_server.h"
#include "../libhttpsvr/http_response_writer.h"
#include "../libhttpsvr/http_session.h"
#include "../libhttpsvr/http_apis.h"
#include "../libhttpsvr/http_env.h"
auto http_response_writer_new( http_server server, http_request req)->http_response_writer {
auto r = std::make_shared<http_response_writer_t>();
r->_chunks = std::make_shared<http_chunks_t>();
r->_headers = std::make_shared<http_headers_t>();
r->_rid = req->RequestId;
return std::move(r);
}
/*
auto http_response_writer_cancel( http_response_writer writer, http_server server) ->void {
auto tpio = server->_tpio;
auto q = server->_queue;
auto rid = writer->_rid;
http_cancel_http_request( tpio, q, rid, [writer](http_id, uint32_t) {} );
}
*/
auto http_response_cancel( http_server server, http_id id) ->void {
http_cancel_http_request( server->_tpio, server->_queue, id, []( http_id, uint32_t ) {} );
}
auto http_send_response_body_context_new( const uint8_t*data, uintptr_t len)->tpio_context* {
auto dl = sizeof( http_data_chunk ) + len;
auto ctx = _tpio_context_create( dl );
auto dc = (http_data_chunk*)ctx->buffer;
auto buffer = ctx->buffer + sizeof( *dc );
dc->DataChunkType = HttpDataChunkFromMemory;
dc->FromMemory.BufferLength = (uint32_t)len;
dc->FromMemory.pBuffer = buffer;
memcpy_s( buffer, len, data, len );
return ctx;
}
auto http_send_response_header_context_new( http_stream_writer writer ) ->tpio_context* {
auto rl = sizeof( HTTP_RESPONSE );
auto rsnl = writer->_reason.size();
auto hl = _http_headers_alloc_size( writer->_headers );
auto ctx = _tpio_context_create(rl + rsnl + hl);
auto ptr = ctx->buffer;
auto presp = ptr;
auto preason = presp + rl;
auto phstart = preason + rsnl;
ZeroMemory( ptr, rl + rsnl +hl );
auto resp = (http_response)presp;
resp->Version = writer->_version;
resp->StatusCode = writer->_status_code;
memcpy_s( preason, rsnl, writer->_reason.c_str(), rsnl );
resp->pReason = (char*)preason;
_http_response_headers_write( &resp->Headers, phstart, hl, writer->_headers );
return ctx;
}
auto http_send_response_context_new( http_response_writer writer )->tpio_context* {
auto rl = sizeof( HTTP_RESPONSE );
if ( writer->_chunks &&writer->_chunks->size() == 1 && writer->_response_complete
&& !writer->_headers->has( HttpHeaderContentLength ) ) {
auto ds = _http_chunks_data_size( writer->_chunks ) - sizeof( http_data_chunk ) * writer->_chunks->size();
writer->_headers->set( HttpHeaderContentLength, tpio_string_i( ds ) );
}
if ( !writer->_headers->has( HttpHeaderContentType ) ) {
writer->_headers->set( HttpHeaderContentType, http_env_default_content_type() );
}
auto rsnl = writer->_status_reason.size();
auto hl = _http_headers_alloc_size( writer->_headers );
auto datalen = _http_chunks_data_size( writer->_chunks );
auto ctx = _tpio_context_create( rl + rsnl + hl + datalen );
auto ptr = ctx->buffer;
auto presp = ptr;
auto preason = presp + rl;
auto phstart = preason + rsnl;
auto pchunks = phstart + hl;
auto resp = (http_response)presp;
ZeroMemory( presp, rl );
resp->Version = writer->_version;
resp->StatusCode = writer->_status_code;
memcpy_s( preason, rsnl, writer->_status_reason.c_str(), rsnl );
resp->ReasonLength = (uint16_t)rsnl;
resp->pReason = (char*)preason;
_http_response_headers_write( &resp->Headers, phstart, hl, writer->_headers );
auto pc = (http_data_chunk*)pchunks;
resp->EntityChunkCount = (uint16_t)writer->_chunks->size();
resp->pEntityChunks = resp->EntityChunkCount ? pc : nullptr;
_http_chunks_write( pchunks, datalen, writer->_chunks );
assert( pchunks + datalen == ptr + ctx->size );
return ctx;
}
auto http_response_writer_hijack(http_response_writer writer)->void {
assert(writer->_is_hijacked);
writer->_is_hijacked = true;
}
auto _http_chunks_write( uint8_t*buf, uintptr_t buflen, http_chunks chunks )->void {
auto end = buf + buflen;
std::for_each( chunks->cbegin(), chunks->cend(), [&buf, end](http_data_chunk const&c) {
assert(c.DataChunkType == HttpDataChunkFromMemory);
auto dc = (http_data_chunk*)buf;
auto buffer = buf + sizeof( *dc );
dc->DataChunkType = c.DataChunkType;
dc->FromMemory.BufferLength = c.FromMemory.BufferLength;
dc->FromMemory.pBuffer = buffer;
memcpy_s( buffer, end - buffer, c.FromMemory.pBuffer, c.FromMemory.BufferLength );
buf = buffer + c.FromMemory.BufferLength;
} );
}
auto _http_response_headers_write( http_response_headers*dest, uint8_t*header_start, uintptr_t hlen, http_headers headers )->void {
if ( !headers ) {
return;
}
dest->pTrailers = nullptr;
dest->TrailerCount = 0;
dest->UnknownHeaderCount = (uint16_t)headers->_unknown_headers.size();
auto punh = (decltype( dest->pUnknownHeaders ))header_start;
dest->pUnknownHeaders = dest->UnknownHeaderCount ? punh : nullptr;
auto &uh = headers->_unknown_headers;
auto punv = (uint8_t*)(punh + dest->UnknownHeaderCount);
std::for_each( uh.cbegin(), uh.cend(), [&punh, &punv]( std::pair<tpio_string, tpio_string>const&h ) {
punh->NameLength = (uint16_t)h.first.size();
punh->RawValueLength = (uint16_t)h.second.size();
memcpy_s( punv, punh->NameLength, h.first.c_str(), h.first.size() );
punh->pName = (char*)punv;
punv += punh->NameLength;
memcpy_s( punv, punh->RawValueLength, h.second.c_str(), h.second.size() );
punh->pRawValue = (char*)punv;
punv += punh->RawValueLength;
++punh;
} );
for ( auto i = 0; i < HttpHeaderResponseMaximum; ++i ) {
auto &kh = dest->KnownHeaders[i];
auto v = headers->get( i );
if ( !v.empty() ) {
kh.RawValueLength = (uint16_t)v.size();
memcpy_s( punv, kh.RawValueLength, v.c_str(), v.size() );
punv += v.size();
} else {
kh.pRawValue = nullptr;
kh.RawValueLength = 0;
}
}
}
auto http_response_writer_write( http_response_writer writer, uint8_t* data, uintptr_t size )->void {
auto c = http_chunk_memory_copy(data, size);
writer->_chunks->push_back( c );
}
auto http_response_writer_status_code( http_response_writer writer, uint32_t status_code )->void {
writer->_status_code = status_code;
}
auto http_response_writer_status_reason( http_response_writer writer, tpio_string const&reason )->void {
writer->_status_reason = reason;
}
auto _http_headers_alloc_size( http_headers headers )->uintptr_t {
if ( !headers ) {
return 0;
}
auto uz = headers->_unknown_headers.size();
auto kz = headers->_known_headers.size();
auto uhz = sizeof(http_unknown_header)* uz;
uintptr_t uxz = 0;
std::for_each( headers->_unknown_headers.cbegin(), headers->_unknown_headers.cend(), [&uxz]( const std::pair<tpio_string, tpio_string>&h ) {
uxz += h.first.size();
uxz += h.second.size();
} );
uintptr_t kxz = 0;
std::for_each( headers->_known_headers.cbegin(), headers->_known_headers.cend(), [&kxz]( const std::pair<uintptr_t, tpio_string>&h ) {
kxz += h.second.size();
} );
return uhz + uxz + kxz;
}
auto _http_chunks_data_size( http_chunks chunks )->uintptr_t {
if ( !chunks ) {
return 0;
}
uint32_t rtn = 0;
std::for_each( chunks->cbegin(), chunks->cend(), [&rtn](const http_data_chunk&c) {
assert( c.DataChunkType == HttpDataChunkFromMemory );
rtn += sizeof( http_data_chunk );
rtn += c.FromMemory.BufferLength;
} );
return rtn;
}