1313#ifndef LLDB_HOST_JSONTRANSPORT_H
1414#define LLDB_HOST_JSONTRANSPORT_H
1515
16+ #include " lldb/Host/MainLoopBase.h"
1617#include " lldb/lldb-forward.h"
1718#include " llvm/ADT/StringRef.h"
1819#include " llvm/Support/Error.h"
1920#include " llvm/Support/FormatVariadic.h"
2021#include " llvm/Support/JSON.h"
21- #include < chrono >
22+ #include < string >
2223#include < system_error>
24+ #include < vector>
2325
2426namespace lldb_private {
2527
@@ -28,27 +30,33 @@ class TransportEOFError : public llvm::ErrorInfo<TransportEOFError> {
2830 static char ID;
2931
3032 TransportEOFError () = default ;
31-
32- void log (llvm::raw_ostream &OS) const override {
33- OS << " transport end of file reached" ;
34- }
33+ void log (llvm::raw_ostream &OS) const override { OS << " transport EOF" ; }
3534 std::error_code convertToErrorCode () const override {
36- return llvm::inconvertibleErrorCode ( );
35+ return std::make_error_code (std::errc::io_error );
3736 }
3837};
3938
40- class TransportTimeoutError : public llvm ::ErrorInfo<TransportTimeoutError> {
39+ class TransportUnhandledContentsError
40+ : public llvm::ErrorInfo<TransportUnhandledContentsError> {
4141public:
4242 static char ID;
4343
44- TransportTimeoutError () = default ;
44+ explicit TransportUnhandledContentsError (std::string unhandled_contents)
45+ : m_unhandled_contents(unhandled_contents) {}
4546
4647 void log (llvm::raw_ostream &OS) const override {
47- OS << " transport operation timed out " ;
48+ OS << " transport EOF with unhandled contents " << m_unhandled_contents ;
4849 }
4950 std::error_code convertToErrorCode () const override {
50- return std::make_error_code (std::errc::timed_out );
51+ return std::make_error_code (std::errc::bad_message );
5152 }
53+
54+ const std::string &getUnhandledContents () const {
55+ return m_unhandled_contents;
56+ }
57+
58+ private:
59+ std::string m_unhandled_contents;
5260};
5361
5462class TransportInvalidError : public llvm ::ErrorInfo<TransportInvalidError> {
@@ -68,6 +76,10 @@ class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> {
6876// / A transport class that uses JSON for communication.
6977class JSONTransport {
7078public:
79+ using ReadHandleUP = MainLoopBase::ReadHandleUP;
80+ template <typename T>
81+ using Callback = std::function<void (MainLoopBase &, const llvm::Expected<T>)>;
82+
7183 JSONTransport (lldb::IOObjectSP input, lldb::IOObjectSP output);
7284 virtual ~JSONTransport () = default ;
7385
@@ -83,24 +95,69 @@ class JSONTransport {
8395 return WriteImpl (message);
8496 }
8597
86- // / Reads the next message from the input stream .
98+ // / Registers the transport with the MainLoop .
8799 template <typename T>
88- llvm::Expected<T> Read (const std::chrono::microseconds &timeout) {
89- llvm::Expected<std::string> message = ReadImpl (timeout);
90- if (!message)
91- return message.takeError ();
92- return llvm::json::parse<T>(/* JSON=*/ *message);
100+ llvm::Expected<ReadHandleUP> RegisterReadObject (MainLoopBase &loop,
101+ Callback<T> callback) {
102+ Status error;
103+ ReadHandleUP handle = loop.RegisterReadObject (
104+ m_input,
105+ [&](MainLoopBase &loop) {
106+ char buffer[kReadBufferSize ];
107+ size_t len = sizeof (buffer);
108+ if (llvm::Error error = m_input->Read (buffer, len).takeError ()) {
109+ callback (loop, std::move (error));
110+ return ;
111+ }
112+
113+ if (len)
114+ m_buffer.append (std::string (buffer, len));
115+
116+ // If the buffer has contents, try parsing any pending messages.
117+ if (!m_buffer.empty ()) {
118+ llvm::Expected<std::vector<std::string>> messages = Parse ();
119+ if (llvm::Error error = messages.takeError ()) {
120+ callback (loop, std::move (error));
121+ return ;
122+ }
123+
124+ for (const auto &message : *messages)
125+ if constexpr (std::is_same<T, std::string>::value)
126+ callback (loop, message);
127+ else
128+ callback (loop, llvm::json::parse<T>(message));
129+ }
130+
131+ // On EOF, notify the callback after the remaining messages were
132+ // handled.
133+ if (len == 0 ) {
134+ if (m_buffer.empty ())
135+ callback (loop, llvm::make_error<TransportEOFError>());
136+ else
137+ callback (loop, llvm::make_error<TransportUnhandledContentsError>(
138+ m_buffer));
139+ }
140+ },
141+ error);
142+ if (error.Fail ())
143+ return error.takeError ();
144+ return handle;
93145 }
94146
95147protected:
148+ template <typename ... Ts> inline auto Logv (const char *Fmt, Ts &&...Vals) {
149+ Log (llvm::formatv (Fmt, std::forward<Ts>(Vals)...).str ());
150+ }
96151 virtual void Log (llvm::StringRef message);
97152
98153 virtual llvm::Error WriteImpl (const std::string &message) = 0;
99- virtual llvm::Expected<std::string>
100- ReadImpl (const std::chrono::microseconds &timeout) = 0 ;
154+ virtual llvm::Expected<std::vector<std::string>> Parse () = 0;
101155
102156 lldb::IOObjectSP m_input;
103157 lldb::IOObjectSP m_output;
158+ std::string m_buffer;
159+
160+ static constexpr size_t kReadBufferSize = 1024 ;
104161};
105162
106163// / A transport class for JSON with a HTTP header.
@@ -111,14 +168,13 @@ class HTTPDelimitedJSONTransport : public JSONTransport {
111168 virtual ~HTTPDelimitedJSONTransport () = default ;
112169
113170protected:
114- virtual llvm::Error WriteImpl (const std::string &message) override ;
115- virtual llvm::Expected<std::string>
116- ReadImpl (const std::chrono::microseconds &timeout) override ;
117-
118- // FIXME: Support any header.
119- static constexpr llvm::StringLiteral kHeaderContentLength =
120- " Content-Length: " ;
121- static constexpr llvm::StringLiteral kHeaderSeparator = " \r\n\r\n " ;
171+ llvm::Error WriteImpl (const std::string &message) override ;
172+ llvm::Expected<std::vector<std::string>> Parse () override ;
173+
174+ static constexpr llvm::StringLiteral kHeaderContentLength = " Content-Length" ;
175+ static constexpr llvm::StringLiteral kHeaderFieldSeparator = " :" ;
176+ static constexpr llvm::StringLiteral kHeaderSeparator = " \r\n " ;
177+ static constexpr llvm::StringLiteral kEndOfHeader = " \r\n\r\n " ;
122178};
123179
124180// / A transport class for JSON RPC.
@@ -129,9 +185,8 @@ class JSONRPCTransport : public JSONTransport {
129185 virtual ~JSONRPCTransport () = default ;
130186
131187protected:
132- virtual llvm::Error WriteImpl (const std::string &message) override ;
133- virtual llvm::Expected<std::string>
134- ReadImpl (const std::chrono::microseconds &timeout) override ;
188+ llvm::Error WriteImpl (const std::string &message) override ;
189+ llvm::Expected<std::vector<std::string>> Parse () override ;
135190
136191 static constexpr llvm::StringLiteral kMessageSeparator = " \n " ;
137192};
0 commit comments