void FastCGITransport::sendResponseHeaders(IOBufQueue& queue, int code) { CHECK(!m_headersSent); m_headersSent = true; if (code != 200) { queue.append(s_status); queue.append(std::to_string(code)); auto reasonStr = getResponseInfo(); if (reasonStr.empty()) { reasonStr = HttpProtocol::GetReasonString(code); } queue.append(s_space); queue.append(reasonStr); queue.append(s_newline); } for (auto& header : m_responseHeaders) { for (auto& value : header.second) { queue.append(header.first); queue.append(s_colon); queue.append(value); queue.append(s_newline); } } queue.append(s_newline); }
TEST_F(BroadcastHandlerTest, OnCompleted) { // Test with EOF on the handler EXPECT_CALL(*decoder, decode(_, _, _, _)) .WillRepeatedly( Invoke([&](MockByteToMessageDecoder<std::string>::Context*, IOBufQueue& q, std::string& data, size_t&) { auto buf = q.move(); if (buf) { buf->coalesce(); data = buf->moveToFbString().toStdString(); return true; } return false; })); InSequence dummy; // Add a subscriber EXPECT_EQ(handler->subscribe(&subscriber0), 0); EXPECT_CALL(subscriber0, onNext("data1")).Times(1); // Push some data IOBufQueue q; q.append(IOBuf::copyBuffer("data1")); pipeline->read(q); q.clear(); // Add another subscriber EXPECT_EQ(handler->subscribe(&subscriber1), 1); EXPECT_CALL(subscriber0, onNext("data2")).Times(1); EXPECT_CALL(subscriber1, onNext("data2")).Times(1); // Push more data q.append(IOBuf::copyBuffer("data2")); pipeline->read(q); q.clear(); // Unsubscribe one of the subscribers handler->unsubscribe(0); EXPECT_CALL(subscriber1, onCompleted()).Times(1); EXPECT_CALL(*handler, close(_)) .WillOnce(InvokeWithoutArgs([this] { pipeline.reset(); return makeFuture(); })); // The handler should be deleted now handler->readEOF(nullptr); }
void FastCGITransport::sendResponseHeaders(IOBufQueue& queue) { CHECK(!m_headersSent); m_headersSent = true; for (auto header : m_responseHeaders) { for (auto value : header.second) { queue.append(header.first); queue.append(": "); queue.append(value); queue.append("\r\n"); } } queue.append("\r\n"); }
void helper<ProtocolReader, ProtocolWriter>::process_exn( const char* func, const string& msg, unique_ptr<ResponseChannel::Request> req, Cpp2RequestContext* ctx, EventBase* eb, int32_t protoSeqId) { ProtocolWriter oprot; if (req) { LOG(ERROR) << msg << " in function " << func; TApplicationException x(msg); IOBufQueue queue = helper_w<ProtocolWriter>::write_exn( func, &oprot, protoSeqId, nullptr, x); queue.append(THeader::transform( queue.move(), ctx->getHeader()->getWriteTransforms(), ctx->getHeader()->getMinCompressBytes())); auto queue_mw = makeMoveWrapper(move(queue)); auto req_mw = makeMoveWrapper(move(req)); eb->runInEventBaseThread([=]() mutable { (*req_mw)->sendReply(queue_mw->move()); }); } else { LOG(ERROR) << msg << " in oneway function " << func; } }
void FastCGITransport::sendResponseHeaders(IOBufQueue& queue, int code) { auto appender = [&](folly::StringPiece sp) mutable { queue.append(sp); }; if (code != 200) { auto info = getResponseInfo(); auto reason = !info.empty() ? info : HttpProtocol::GetReasonString(code); folly::format("Status: {} {}\r\n", code, reason)(appender); } for (auto& header : m_responseHeaders) { for (auto& value : header.second) { folly::format("{}: {}\r\n", header.first, value)(appender); } } queue.append("\r\n", 2); }
bool KVParser::parseKeyValueContent(Cursor& cursor, size_t& available, size_t& length, IOBufQueue& queue) { std::unique_ptr<IOBuf> buf; size_t len = cursor.cloneAtMost(buf, length); queue.append(std::move(buf)); assert(length >= len); length -= len; assert(available >= len); available -= len; return (length == 0); }
void FastCGITransport::sendImpl(const void *data, int size, int code, bool chunked) { IOBufQueue queue; if (!m_headersSent) { sendResponseHeaders(queue, code); } queue.append(IOBuf::copyBuffer(data, size)); folly::MoveWrapper<std::unique_ptr<IOBuf>> chain_wrapper(queue.move()); Callback* callback = m_callback; auto fn = [callback, chain_wrapper]() mutable { if (callback) { callback->onStdOut(std::move(*chain_wrapper)); } }; m_connection->getEventBase()->runInEventBaseThread(fn); }
void FastCGITransport::sendResponseHeaders(IOBufQueue& queue, int code) { CHECK(!m_headersSent); m_headersSent = true; if (code != 200) { queue.append(s_status); queue.append(std::to_string(code)); queue.append(s_newline); } for (auto& header : m_responseHeaders) { for (auto& value : header.second) { queue.append(header.first); queue.append(s_colon); queue.append(value); queue.append(s_newline); } } queue.append(s_newline); }
TEST(CommunicateSubprocessTest, Duplex2) { checkFdLeak([] { // Pipe 200,000 lines through sed const size_t numCopies = 100000; auto iobuf = IOBuf::copyBuffer("this is a test\nanother line\n"); IOBufQueue input; for (size_t n = 0; n < numCopies; ++n) { input.append(iobuf->clone()); } std::vector<std::string> cmd({ "sed", "-u", "-e", "s/a test/a successful test/", "-e", "/^another line/w/dev/stderr", }); auto options = Subprocess::pipeStdin().pipeStdout().pipeStderr().usePath(); Subprocess proc(cmd, options); auto out = proc.communicateIOBuf(std::move(input)); proc.waitChecked(); // Convert stdout and stderr to strings so we can call split() on them. fbstring stdoutStr; if (out.first.front()) { stdoutStr = out.first.move()->moveToFbString(); } fbstring stderrStr; if (out.second.front()) { stderrStr = out.second.move()->moveToFbString(); } // stdout should be a copy of stdin, with "a test" replaced by // "a successful test" std::vector<StringPiece> stdoutLines; split('\n', stdoutStr, stdoutLines); EXPECT_EQ(numCopies * 2 + 1, stdoutLines.size()); // Strip off the trailing empty line if (!stdoutLines.empty()) { EXPECT_EQ("", stdoutLines.back()); stdoutLines.pop_back(); } size_t linenum = 0; for (const auto& line : stdoutLines) { if ((linenum & 1) == 0) { EXPECT_EQ("this is a successful test", line); } else { EXPECT_EQ("another line", line); } ++linenum; } // stderr should only contain the lines containing "another line" std::vector<StringPiece> stderrLines; split('\n', stderrStr, stderrLines); EXPECT_EQ(numCopies + 1, stderrLines.size()); // Strip off the trailing empty line if (!stderrLines.empty()) { EXPECT_EQ("", stderrLines.back()); stderrLines.pop_back(); } for (const auto& line : stderrLines) { EXPECT_EQ("another line", line); } }); }
TEST_F(BroadcastHandlerTest, BufferedRead) { // Test with decoder that buffers data based on some local logic // before pushing to subscribers IOBufQueue bufQueue{IOBufQueue::cacheChainLength()}; EXPECT_CALL(*decoder, decode(_, _, _, _)) .WillRepeatedly( Invoke([&](MockByteToMessageDecoder<std::string>::Context*, IOBufQueue& q, std::string& data, size_t&) { bufQueue.append(q); if (bufQueue.chainLength() < 5) { return false; } auto buf = bufQueue.move(); buf->coalesce(); data = buf->moveToFbString().toStdString(); return true; })); InSequence dummy; // Add a subscriber EXPECT_EQ(handler->subscribe(&subscriber0), 0); EXPECT_CALL(subscriber0, onNext("data1")).Times(1); // Push some fragmented data IOBufQueue q; q.append(IOBuf::copyBuffer("da")); pipeline->read(q); q.clear(); q.append(IOBuf::copyBuffer("ta1")); pipeline->read(q); q.clear(); // Push more fragmented data. onNext shouldn't be called yet. q.append(IOBuf::copyBuffer("dat")); pipeline->read(q); q.clear(); q.append(IOBuf::copyBuffer("a")); pipeline->read(q); q.clear(); // Add another subscriber EXPECT_EQ(handler->subscribe(&subscriber1), 1); EXPECT_CALL(subscriber0, onNext("data3data4")).Times(1); EXPECT_CALL(subscriber1, onNext("data3data4")).Times(1); // Push rest of the fragmented data. The entire data should be pushed // to both subscribers. q.append(IOBuf::copyBuffer("3data4")); pipeline->read(q); q.clear(); EXPECT_CALL(subscriber0, onNext("data2")).Times(1); EXPECT_CALL(subscriber1, onNext("data2")).Times(1); // Push some unfragmented data q.append(IOBuf::copyBuffer("data2")); pipeline->read(q); q.clear(); EXPECT_CALL(*handler, close(_)) .WillOnce(InvokeWithoutArgs([this] { pipeline.reset(); return makeFuture(); })); // Unsubscribe all subscribers. The handler should be deleted now. handler->unsubscribe(0); handler->unsubscribe(1); }