1313#ifndef LLDB_HOST_JSONTRANSPORT_H
1414#define LLDB_HOST_JSONTRANSPORT_H
1515
16+ #include " lldb/Host/MainLoopBase.h"
17+ #include " lldb/Utility/IOObject.h"
18+ #include " lldb/Utility/Status.h"
1619#include " lldb/lldb-forward.h"
1720#include " llvm/ADT/StringRef.h"
1821#include " llvm/Support/Error.h"
1922#include " llvm/Support/FormatVariadic.h"
2023#include " llvm/Support/JSON.h"
21- #include < chrono >
24+ #include < string >
2225#include < system_error>
26+ #include < vector>
2327
2428namespace lldb_private {
2529
@@ -28,27 +32,26 @@ class TransportEOFError : public llvm::ErrorInfo<TransportEOFError> {
2832 static char ID;
2933
3034 TransportEOFError () = default ;
31-
32- void log (llvm::raw_ostream &OS) const override {
33- OS << " transport end of file reached" ;
34- }
35- std::error_code convertToErrorCode () const override {
36- return llvm::inconvertibleErrorCode ();
37- }
35+ void log (llvm::raw_ostream &OS) const override ;
36+ std::error_code convertToErrorCode () const override ;
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) ;
4545
46- void log (llvm::raw_ostream &OS) const override {
47- OS << " transport operation timed out " ;
48- }
49- std::error_code convertToErrorCode () const override {
50- return std::make_error_code (std::errc::timed_out) ;
46+ void log (llvm::raw_ostream &OS) const override ;
47+ std::error_code convertToErrorCode () const override ;
48+
49+ const std::string & getUnhandledContents () const {
50+ return m_unhandled_contents ;
5151 }
52+
53+ private:
54+ std::string m_unhandled_contents;
5255};
5356
5457class TransportInvalidError : public llvm ::ErrorInfo<TransportInvalidError> {
@@ -57,17 +60,17 @@ class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> {
5760
5861 TransportInvalidError () = default ;
5962
60- void log (llvm::raw_ostream &OS) const override {
61- OS << " transport IO object invalid" ;
62- }
63- std::error_code convertToErrorCode () const override {
64- return std::make_error_code (std::errc::not_connected);
65- }
63+ void log (llvm::raw_ostream &OS) const override ;
64+ std::error_code convertToErrorCode () const override ;
6665};
6766
6867// / A transport class that uses JSON for communication.
6968class JSONTransport {
7069public:
70+ using ReadHandleUP = MainLoopBase::ReadHandleUP;
71+ template <typename T>
72+ using Callback = std::function<void (MainLoopBase &, const llvm::Expected<T>)>;
73+
7174 JSONTransport (lldb::IOObjectSP input, lldb::IOObjectSP output);
7275 virtual ~JSONTransport () = default ;
7376
@@ -83,24 +86,68 @@ class JSONTransport {
8386 return WriteImpl (message);
8487 }
8588
86- // / Reads the next message from the input stream .
89+ // / Registers the transport with the MainLoop .
8790 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);
91+ llvm::Expected<ReadHandleUP> RegisterReadObject (MainLoopBase &loop,
92+ Callback<T> read_cb) {
93+ Status error;
94+ ReadHandleUP handle = loop.RegisterReadObject (
95+ m_input,
96+ [read_cb, this ](MainLoopBase &loop) {
97+ char buf[kReadBufferSize ];
98+ size_t num_bytes = sizeof (buf);
99+ if (llvm::Error error = m_input->Read (buf, num_bytes).takeError ()) {
100+ read_cb (loop, std::move (error));
101+ return ;
102+ }
103+ if (num_bytes)
104+ m_buffer.append (std::string (buf, num_bytes));
105+
106+ // If the buffer has contents, try parsing any pending messages.
107+ if (!m_buffer.empty ()) {
108+ llvm::Expected<std::vector<std::string>> messages = Parse ();
109+ if (llvm::Error error = messages.takeError ()) {
110+ read_cb (loop, std::move (error));
111+ return ;
112+ }
113+
114+ for (const auto &message : *messages)
115+ if constexpr (std::is_same<T, std::string>::value)
116+ read_cb (loop, message);
117+ else
118+ read_cb (loop, llvm::json::parse<T>(message));
119+ }
120+
121+ // On EOF, notify the callback after the remaining messages were
122+ // handled.
123+ if (num_bytes == 0 ) {
124+ if (m_buffer.empty ())
125+ read_cb (loop, llvm::make_error<TransportEOFError>());
126+ else
127+ read_cb (loop, llvm::make_error<TransportUnhandledContentsError>(
128+ std::string (m_buffer)));
129+ }
130+ },
131+ error);
132+ if (error.Fail ())
133+ return error.takeError ();
134+ return handle;
93135 }
94136
95137protected:
138+ template <typename ... Ts> inline auto Logv (const char *Fmt, Ts &&...Vals) {
139+ Log (llvm::formatv (Fmt, std::forward<Ts>(Vals)...).str ());
140+ }
96141 virtual void Log (llvm::StringRef message);
97142
98143 virtual llvm::Error WriteImpl (const std::string &message) = 0;
99- virtual llvm::Expected<std::string>
100- ReadImpl (const std::chrono::microseconds &timeout) = 0 ;
144+ virtual llvm::Expected<std::vector<std::string>> Parse () = 0;
145+
146+ static constexpr size_t kReadBufferSize = 1024 ;
101147
102148 lldb::IOObjectSP m_input;
103149 lldb::IOObjectSP m_output;
150+ llvm::SmallString<kReadBufferSize > m_buffer;
104151};
105152
106153// / A transport class for JSON with a HTTP header.
@@ -111,14 +158,13 @@ class HTTPDelimitedJSONTransport : public JSONTransport {
111158 virtual ~HTTPDelimitedJSONTransport () = default ;
112159
113160protected:
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 " ;
161+ llvm::Error WriteImpl (const std::string &message) override ;
162+ llvm::Expected<std::vector<std::string>> Parse () override ;
163+
164+ static constexpr llvm::StringLiteral kHeaderContentLength = " Content-Length" ;
165+ static constexpr llvm::StringLiteral kHeaderFieldSeparator = " :" ;
166+ static constexpr llvm::StringLiteral kHeaderSeparator = " \r\n " ;
167+ static constexpr llvm::StringLiteral kEndOfHeader = " \r\n\r\n " ;
122168};
123169
124170// / A transport class for JSON RPC.
@@ -129,9 +175,8 @@ class JSONRPCTransport : public JSONTransport {
129175 virtual ~JSONRPCTransport () = default ;
130176
131177protected:
132- virtual llvm::Error WriteImpl (const std::string &message) override ;
133- virtual llvm::Expected<std::string>
134- ReadImpl (const std::chrono::microseconds &timeout) override ;
178+ llvm::Error WriteImpl (const std::string &message) override ;
179+ llvm::Expected<std::vector<std::string>> Parse () override ;
135180
136181 static constexpr llvm::StringLiteral kMessageSeparator = " \n " ;
137182};
0 commit comments