| 611 | } |
| 612 | |
| 613 | void Webserver::SendResponse(struct sq_connection* connection, |
| 614 | const string& response_code_line, const string& content_type, const string& content, |
| 615 | const vector<string>& header_lines) { |
| 616 | // Buffer the output and send it in a single call to sq_write in order to avoid |
| 617 | // triggering an interaction between Nagle's algorithm and TCP delayed acks. |
| 618 | std::ostringstream oss; |
| 619 | oss << "HTTP/1.1 " << response_code_line << CRLF; |
| 620 | for (const auto& h : header_lines) { |
| 621 | oss << h << CRLF; |
| 622 | } |
| 623 | oss << "X-Frame-Options: " << FLAGS_webserver_x_frame_options << CRLF; |
| 624 | oss << "X-Content-Type-Options: nosniff" << CRLF; |
| 625 | oss << "Cache-Control: no-store" << CRLF; |
| 626 | if (!FLAGS_disable_content_security_policy_header) { |
| 627 | oss << "Content-Security-Policy: " << CSP_HEADER << CRLF; |
| 628 | } |
| 629 | |
| 630 | struct sq_request_info* request_info = sq_get_request_info(connection); |
| 631 | if (request_info->is_ssl) { |
| 632 | oss << "Strict-Transport-Security: max-age=31536000; includeSubDomains" << CRLF; |
| 633 | } |
| 634 | oss << "Content-Type: " << content_type << CRLF; |
| 635 | const char * accepted_encodings = sq_get_header(connection, "Accept-Encoding"); |
| 636 | |
| 637 | { |
| 638 | std::shared_lock<std::shared_mutex> l(compressed_buffer_mem_tracker_lock_); |
| 639 | |
| 640 | // Include vector's new memory allocations into 'compressed_buffer_mem_tracker_' |
| 641 | MemTrackerAllocator<uint8_t> vector_mem_tracker_allocator( |
| 642 | compressed_buffer_mem_tracker_); |
| 643 | vector<uint8_t> output(0, vector_mem_tracker_allocator); |
| 644 | |
| 645 | // If accepted, support responses with gzip compression |
| 646 | if (accepted_encodings != NULL && std::string_view(accepted_encodings).find("gzip") |
| 647 | != string::npos && CompressStringToBuffer(content, output).ok()) { |
| 648 | oss << "Content-Encoding: gzip" << CRLF; |
| 649 | oss << "Content-Length: " << output.size() << CRLF; |
| 650 | oss << CRLF; |
| 651 | // Interpret the data in the necessary form, do not reallocate |
| 652 | oss.write(reinterpret_cast<char*>(output.data()), output.size()); |
| 653 | } else { |
| 654 | oss << "Content-Length: " << content.size() << CRLF; |
| 655 | oss << CRLF; |
| 656 | oss.write(content.data(), content.size()); |
| 657 | } |
| 658 | } |
| 659 | string output_str = oss.str(); |
| 660 | |
| 661 | // Make sure to use sq_write for writing the output, as sq_printf truncates at 8kb |
| 662 | sq_write(connection, output_str.data(), output_str.size()); |
| 663 | } |
| 664 | |
| 665 | void Webserver::GetCommonJson(Document* document, const struct sq_connection* connection, |
| 666 | const WebRequest& req, const std::string& csrf_token) { |