}
}
-CubemapStateProto Server::serialize()
+CubemapStateProto Server::serialize(unordered_map<const string *, size_t> *short_response_pool)
{
// We don't serialize anything queued, so empty the queues.
process_queued_data();
CubemapStateProto serialized;
for (const auto &fd_and_client : clients) {
- serialized.add_clients()->MergeFrom(fd_and_client.second.serialize());
+ serialized.add_clients()->MergeFrom(fd_and_client.second.serialize(short_response_pool));
}
for (unique_ptr<Stream> &stream : streams) {
serialized.add_streams()->MergeFrom(stream->serialize());
process_client(client_ptr);
}
-void Server::add_client_from_serialized(const ClientProto &client)
+void Server::add_client_from_serialized(const ClientProto &client, const vector<shared_ptr<const string>> &short_responses)
{
lock_guard<mutex> lock(mu);
Stream *stream;
} else {
stream = streams[stream_index].get();
}
- auto inserted = clients.insert(make_pair(client.sock(), Client(client, stream)));
+ auto inserted = clients.insert(make_pair(client.sock(), Client(client, short_responses, stream)));
assert(inserted.second == true); // Should not already exist.
Client *client_ptr = &inserted.first->second;
int ret;
do {
ret = write(client->sock,
- client->header_or_short_response.data() + client->header_or_short_response_bytes_sent,
- client->header_or_short_response.size() - client->header_or_short_response_bytes_sent);
+ client->header_or_short_response->data() + client->header_or_short_response_bytes_sent,
+ client->header_or_short_response->size() - client->header_or_short_response_bytes_sent);
} while (ret == -1 && errno == EINTR);
if (ret == -1 && errno == EAGAIN) {
}
client->header_or_short_response_bytes_sent += ret;
- assert(client->header_or_short_response_bytes_sent <= client->header_or_short_response.size());
+ assert(client->header_or_short_response_bytes_sent <= client->header_or_short_response->size());
- if (client->header_or_short_response_bytes_sent < client->header_or_short_response.size()) {
+ if (client->header_or_short_response_bytes_sent < client->header_or_short_response->size()) {
// We haven't sent all yet. Fine; go another round.
goto sending_header_or_short_response_again;
}
// We're done sending the header or error! Clear it to release some memory.
- client->header_or_short_response.clear();
+ client->header_or_short_response = nullptr;
+ client->header_or_short_response_holder.clear();
+ client->header_or_short_response_ref.reset();
if (client->state == Client::SENDING_SHORT_RESPONSE) {
if (more_requests(client)) {
void Server::construct_header(Client *client)
{
Stream *stream = client->stream;
- client->header_or_short_response = stream->http_header;
+ string response = stream->http_header;
if (client->stream_pos == Client::STREAM_POS_HEADER_ONLY) {
char buf[64];
snprintf(buf, sizeof(buf), "Content-length: %zu\r\n", stream->stream_header.size());
- client->header_or_short_response.append(buf);
+ response.append(buf);
} else if (client->stream_pos_end != Client::STREAM_POS_NO_END) {
char buf[64];
snprintf(buf, sizeof(buf), "Content-length: %zu\r\n", client->stream_pos_end - client->stream_pos);
- client->header_or_short_response.append(buf);
+ response.append(buf);
}
if (client->http_11) {
- assert(client->header_or_short_response.find("HTTP/1.0") == 0);
- client->header_or_short_response[7] = '1'; // Change to HTTP/1.1.
+ assert(response.find("HTTP/1.0") == 0);
+ response[7] = '1'; // Change to HTTP/1.1.
if (client->close_after_response) {
- client->header_or_short_response.append("Connection: close\r\n");
+ response.append("Connection: close\r\n");
}
} else {
assert(client->close_after_response);
}
if (stream->encoding == Stream::STREAM_ENCODING_RAW) {
- client->header_or_short_response.append("\r\n");
+ response.append("\r\n");
} else if (stream->encoding == Stream::STREAM_ENCODING_METACUBE) {
- client->header_or_short_response.append(
- "Content-encoding: metacube\r\n"
- "\r\n");
+ response.append("Content-encoding: metacube\r\n\r\n");
if (!stream->stream_header.empty()) {
metacube2_block_header hdr;
memcpy(hdr.sync, METACUBE2_SYNC, sizeof(hdr.sync));
hdr.size = htonl(stream->stream_header.size());
hdr.flags = htons(METACUBE_FLAGS_HEADER);
hdr.csum = htons(metacube2_compute_crc(&hdr));
- client->header_or_short_response.append(
- string(reinterpret_cast<char *>(&hdr), sizeof(hdr)));
+ response.append(string(reinterpret_cast<char *>(&hdr), sizeof(hdr)));
}
} else {
assert(false);
}
if (client->stream_pos == Client::STREAM_POS_HEADER_ONLY) {
client->state = Client::SENDING_SHORT_RESPONSE;
- client->header_or_short_response.append(stream->stream_header);
+ response.append(stream->stream_header);
} else {
client->state = Client::SENDING_HEADER;
if (client->stream_pos_end == Client::STREAM_POS_NO_END) { // Fragments don't contain stream headers.
- client->header_or_short_response.append(stream->stream_header);
+ response.append(stream->stream_header);
}
}
+ client->header_or_short_response_holder = move(response);
+ client->header_or_short_response = &client->header_or_short_response_holder;
+
// Switch states.
change_epoll_events(client, EPOLLOUT | EPOLLET | EPOLLRDHUP);
}
"HTTP/1.%d %d Error\r\nContent-type: text/plain\r\nContent-length: 30\r\n\r\nSomething went wrong. Sorry.\r\n",
client->http_11, error_code);
}
- client->header_or_short_response = error;
+ client->header_or_short_response_holder = error;
+ client->header_or_short_response = &client->header_or_short_response_holder;
// Switch states.
client->state = Client::SENDING_SHORT_RESPONSE;
map<string, string>::const_iterator ping_url_map_it = ping_url_map.find(client->url);
assert(ping_url_map_it != ping_url_map.end());
+ string response;
if (client->http_11) {
- client->header_or_short_response = "HTTP/1.1 204 No Content\r\n";
+ response = "HTTP/1.1 204 No Content\r\n";
if (client->close_after_response) {
- client->header_or_short_response.append("Connection: close\r\n");
+ response.append("Connection: close\r\n");
}
} else {
- client->header_or_short_response = "HTTP/1.0 204 No Content\r\n";
+ response = "HTTP/1.0 204 No Content\r\n";
assert(client->close_after_response);
}
if (!ping_url_map_it->second.empty()) {
- client->header_or_short_response.append("Access-Control-Allow-Origin: ");
- client->header_or_short_response.append(ping_url_map_it->second);
+ response.append("Access-Control-Allow-Origin: ");
+ response.append(ping_url_map_it->second);
+ response.append("\r\n");
}
- client->header_or_short_response.append("\r\n");
+ response.append("\r\n");
+
+ client->header_or_short_response_holder = move(response);
+ client->header_or_short_response = &client->header_or_short_response_holder;
// Switch states.
client->state = Client::SENDING_SHORT_RESPONSE;
client->state = Client::READING_REQUEST;
client->url.clear();
client->stream = NULL;
- client->header_or_short_response.clear();
+ client->header_or_short_response = nullptr;
+ client->header_or_short_response_holder.clear();
+ client->header_or_short_response_ref.reset();
client->header_or_short_response_bytes_sent = 0;
change_epoll_events(client, EPOLLIN | EPOLLET | EPOLLRDHUP); // No TLS handshake, so no EPOLLOUT needed.