有时,需要发送的消息体不方便用单个容器来描述。 例如,当实现 HTTP 中继功能时,一个健壮的实现需要单独呈现来自下游主机的可用 body 缓冲区。 这些缓冲区应该是固定大小的,否则会在将完整消息体转发到上游主机之前,产生不必要且低效的读取完整消息体的负担。
为了支持这些用例,提供了 body 类型 buffer_body。此 body 使用调用者提供的指针和大小,而不是拥有的容器。 要使用此 body,请实例化序列化器的一个实例,并在调用流写入函数之前,填写指针和大小字段。
此示例从子进程读取数据,并将输出作为 HTTP 响应发回。进程的输出在可用时立即发送。
/** Send the output of a child process as an HTTP response. The output of the child process comes from a @b SyncReadStream. Data will be sent continuously as it is produced, without the requirement that the entire process output is buffered before being sent. The response will use the chunked transfer encoding. @param input A stream to read the child process output from. @param output A stream to write the HTTP response to. @param ec Set to the error, if any occurred. */ template< class SyncReadStream, class SyncWriteStream> void send_cgi_response( SyncReadStream& input, SyncWriteStream& output, error_code& ec) { static_assert(is_sync_read_stream<SyncReadStream>::value, "SyncReadStream requirements not met"); static_assert(is_sync_write_stream<SyncWriteStream>::value, "SyncWriteStream requirements not met"); // Set up the response. We use the buffer_body type, // allowing serialization to use manually provided buffers. response<buffer_body> res; res.result(status::ok); res.version(11); res.set(field::server, "Beast"); res.set(field::transfer_encoding, "chunked"); // No data yet, but we set more = true to indicate // that it might be coming later. Otherwise the // serializer::is_done would return true right after // sending the header. res.body().data = nullptr; res.body().more = true; // Create the serializer. response_serializer<buffer_body, fields> sr{res}; // Send the header immediately. write_header(output, sr, ec); if(ec) return; // Alternate between reading from the child process // and sending all the process output until there // is no more output. do { // Read a buffer from the child process char buffer[2048]; auto bytes_transferred = input.read_some( boost::asio::buffer(buffer, sizeof(buffer)), ec); if(ec == boost::asio::error::eof) { ec = {}; // `nullptr` indicates there is no buffer res.body().data = nullptr; // `false` means no more data is coming res.body().more = false; } else { if(ec) return; // Point to our buffer with the bytes that // we received, and indicate that there may // be some more data coming res.body().data = buffer; res.body().size = bytes_transferred; res.body().more = true; } // Write everything in the body buffer write(output, sr, ec); // This error is returned by body_buffer during // serialization when it is done sending the data // provided and needs another buffer. if(ec == error::need_buffer) { ec = {}; continue; } if(ec) return; } while(! sr.is_done()); }