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"
18+ #include " llvm/ADT/FunctionExtras.h"
1719#include " llvm/ADT/StringRef.h"
1820#include " llvm/Support/Error.h"
1921#include " llvm/Support/FormatVariadic.h"
2022#include " llvm/Support/JSON.h"
21- #include < chrono >
23+ #include < string >
2224#include < system_error>
25+ #include < vector>
2326
2427namespace lldb_private {
2528
@@ -28,27 +31,33 @@ class TransportEOFError : public llvm::ErrorInfo<TransportEOFError> {
2831 static char ID;
2932
3033 TransportEOFError () = default ;
31-
32- void log (llvm::raw_ostream &OS) const override {
33- OS << " transport end of file reached" ;
34- }
34+ void log (llvm::raw_ostream &OS) const override { OS << " transport EOF" ; }
3535 std::error_code convertToErrorCode () const override {
36- return llvm::inconvertibleErrorCode ( );
36+ return std::make_error_code (std::errc::io_error );
3737 }
3838};
3939
40- class TransportTimeoutError : public llvm ::ErrorInfo<TransportTimeoutError> {
40+ class TransportUnhandledContentsError
41+ : public llvm::ErrorInfo<TransportUnhandledContentsError> {
4142public:
4243 static char ID;
4344
44- TransportTimeoutError () = default ;
45+ explicit TransportUnhandledContentsError (std::string unhandled_contents)
46+ : m_unhandled_contents(unhandled_contents) {}
4547
4648 void log (llvm::raw_ostream &OS) const override {
47- OS << " transport operation timed out " ;
49+ OS << " transport EOF with unhandled contents " << m_unhandled_contents ;
4850 }
4951 std::error_code convertToErrorCode () const override {
50- return std::make_error_code (std::errc::timed_out );
52+ return std::make_error_code (std::errc::bad_message );
5153 }
54+
55+ const std::string &getUnhandledContents () const {
56+ return m_unhandled_contents;
57+ }
58+
59+ private:
60+ std::string m_unhandled_contents;
5261};
5362
5463class TransportInvalidError : public llvm ::ErrorInfo<TransportInvalidError> {
@@ -68,6 +77,11 @@ class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> {
6877// / A transport class that uses JSON for communication.
6978class JSONTransport {
7079public:
80+ using ReadHandleUP = MainLoopBase::ReadHandleUP;
81+ template <typename T>
82+ using Callback =
83+ llvm::unique_function<void (MainLoopBase &, const llvm::Expected<T>)>;
84+
7185 JSONTransport (lldb::IOObjectSP input, lldb::IOObjectSP output);
7286 virtual ~JSONTransport () = default ;
7387
@@ -83,24 +97,69 @@ class JSONTransport {
8397 return WriteImpl (message);
8498 }
8599
86- // / Reads the next message from the input stream .
100+ // / Registers the transport with the MainLoop .
87101 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);
102+ llvm::Expected<ReadHandleUP> RegisterReadObject (MainLoopBase &loop,
103+ Callback<T> callback) {
104+ Status error;
105+ ReadHandleUP handle = loop.RegisterReadObject (
106+ m_input,
107+ [&](MainLoopBase &loop) {
108+ char buffer[kReadBufferSize ];
109+ size_t len = sizeof (buffer);
110+ if (llvm::Error error = m_input->Read (buffer, len).takeError ()) {
111+ callback (loop, std::move (error));
112+ return ;
113+ }
114+
115+ if (len)
116+ m_buffer.append (std::string (buffer, len));
117+
118+ // If the buffer has contents, try parsing any pending messages.
119+ if (!m_buffer.empty ()) {
120+ llvm::Expected<std::vector<std::string>> messages = Parse ();
121+ if (llvm::Error error = messages.takeError ()) {
122+ callback (loop, std::move (error));
123+ return ;
124+ }
125+
126+ for (const auto &message : *messages)
127+ if constexpr (std::is_same<T, std::string>::value)
128+ callback (loop, message);
129+ else
130+ callback (loop, llvm::json::parse<T>(message));
131+ }
132+
133+ // On EOF, notify the callback after the remaining messages were
134+ // handled.
135+ if (len == 0 ) {
136+ if (m_buffer.empty ())
137+ callback (loop, llvm::make_error<TransportEOFError>());
138+ else
139+ callback (loop, llvm::make_error<TransportUnhandledContentsError>(
140+ m_buffer));
141+ }
142+ },
143+ error);
144+ if (error.Fail ())
145+ return error.takeError ();
146+ return handle;
93147 }
94148
95149protected:
150+ template <typename ... Ts> inline auto Logv (const char *Fmt, Ts &&...Vals) {
151+ Log (llvm::formatv (Fmt, std::forward<Ts>(Vals)...).str ());
152+ }
96153 virtual void Log (llvm::StringRef message);
97154
98155 virtual llvm::Error WriteImpl (const std::string &message) = 0;
99- virtual llvm::Expected<std::string>
100- ReadImpl (const std::chrono::microseconds &timeout) = 0 ;
156+ virtual llvm::Expected<std::vector<std::string>> Parse () = 0;
101157
102158 lldb::IOObjectSP m_input;
103159 lldb::IOObjectSP m_output;
160+ std::string m_buffer;
161+
162+ static constexpr size_t kReadBufferSize = 1024 ;
104163};
105164
106165// / A transport class for JSON with a HTTP header.
@@ -111,14 +170,13 @@ class HTTPDelimitedJSONTransport : public JSONTransport {
111170 virtual ~HTTPDelimitedJSONTransport () = default ;
112171
113172protected:
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 " ;
173+ llvm::Error WriteImpl (const std::string &message) override ;
174+ llvm::Expected<std::vector<std::string>> Parse () override ;
175+
176+ static constexpr llvm::StringLiteral kHeaderContentLength = " Content-Length" ;
177+ static constexpr llvm::StringLiteral kHeaderFieldSeparator = " :" ;
178+ static constexpr llvm::StringLiteral kHeaderSeparator = " \r\n " ;
179+ static constexpr llvm::StringLiteral kEndOfHeader = " \r\n\r\n " ;
122180};
123181
124182// / A transport class for JSON RPC.
@@ -129,9 +187,8 @@ class JSONRPCTransport : public JSONTransport {
129187 virtual ~JSONRPCTransport () = default ;
130188
131189protected:
132- virtual llvm::Error WriteImpl (const std::string &message) override ;
133- virtual llvm::Expected<std::string>
134- ReadImpl (const std::chrono::microseconds &timeout) override ;
190+ llvm::Error WriteImpl (const std::string &message) override ;
191+ llvm::Expected<std::vector<std::string>> Parse () override ;
135192
136193 static constexpr llvm::StringLiteral kMessageSeparator = " \n " ;
137194};
0 commit comments