77// ===----------------------------------------------------------------------===//
88
99#include " lldb/Host/JSONTransport.h"
10- #include " lldb/Utility/IOObject.h"
1110#include " lldb/Utility/LLDBLog.h"
1211#include " lldb/Utility/Log.h"
13- #include " lldb/Utility/SelectHelper.h"
1412#include " lldb/Utility/Status.h"
1513#include " lldb/lldb-forward.h"
1614#include " llvm/ADT/StringExtras.h"
1715#include " llvm/ADT/StringRef.h"
1816#include " llvm/Support/Error.h"
1917#include " llvm/Support/raw_ostream.h"
20- #include < optional>
2118#include < string>
2219#include < utility>
2320
2421using namespace llvm ;
2522using namespace lldb ;
2623using namespace lldb_private ;
2724
28- // / ReadFull attempts to read the specified number of bytes. If EOF is
29- // / encountered, an empty string is returned.
30- static Expected<std::string>
31- ReadFull (IOObject &descriptor, size_t length,
32- std::optional<std::chrono::microseconds> timeout = std::nullopt ) {
33- if (!descriptor.IsValid ())
34- return llvm::make_error<TransportInvalidError>();
35-
36- bool timeout_supported = true ;
37- // FIXME: SelectHelper does not work with NativeFile on Win32.
38- #if _WIN32
39- timeout_supported = descriptor.GetFdType () == IOObject::eFDTypeSocket;
40- #endif
41-
42- if (timeout && timeout_supported) {
43- SelectHelper sh;
44- sh.SetTimeout (*timeout);
45- sh.FDSetRead (
46- reinterpret_cast <lldb::socket_t >(descriptor.GetWaitableHandle ()));
47- Status status = sh.Select ();
48- if (status.Fail ()) {
49- // Convert timeouts into a specific error.
50- if (status.GetType () == lldb::eErrorTypePOSIX &&
51- status.GetError () == ETIMEDOUT)
52- return make_error<TransportTimeoutError>();
53- return status.takeError ();
54- }
55- }
56-
57- std::string data;
58- data.resize (length);
59- Status status = descriptor.Read (data.data (), length);
60- if (status.Fail ())
61- return status.takeError ();
62-
63- // Read returns '' on EOF.
64- if (length == 0 )
65- return make_error<TransportEOFError>();
66-
67- // Return the actual number of bytes read.
68- return data.substr (0 , length);
69- }
70-
71- static Expected<std::string>
72- ReadUntil (IOObject &descriptor, StringRef delimiter,
73- std::optional<std::chrono::microseconds> timeout = std::nullopt ) {
74- std::string buffer;
75- buffer.reserve (delimiter.size () + 1 );
76- while (!llvm::StringRef (buffer).ends_with (delimiter)) {
77- Expected<std::string> next =
78- ReadFull (descriptor, buffer.empty () ? delimiter.size () : 1 , timeout);
79- if (auto Err = next.takeError ())
80- return std::move (Err);
81- buffer += *next;
82- }
83- return buffer.substr (0 , buffer.size () - delimiter.size ());
84- }
85-
8625JSONTransport::JSONTransport (IOObjectSP input, IOObjectSP output)
8726 : m_input(std::move(input)), m_output(std::move(output)) {}
8827
8928void JSONTransport::Log (llvm::StringRef message) {
9029 LLDB_LOG (GetLog (LLDBLog::Host), " {0}" , message);
9130}
9231
93- Expected<std::string>
94- HTTPDelimitedJSONTransport::ReadImpl (const std::chrono::microseconds &timeout) {
95- if (!m_input || !m_input->IsValid ())
96- return llvm::make_error<TransportInvalidError>();
32+ Expected<std::vector<std::string>> HTTPDelimitedJSONTransport::Parse () {
33+ if (m_buffer.empty ())
34+ return std::vector<std::string>{};
35+
36+ std::vector<std::string> messages;
37+ llvm::StringRef buf = m_buffer;
38+ size_t content_length = 0 , end_of_last_message = 0 , cursor = 0 ;
39+ do {
40+ auto idx = buf.find (kHeaderSeparator , cursor);
41+ if (idx == StringRef::npos)
42+ break ;
43+
44+ auto header = buf.slice (cursor, idx);
45+ cursor = idx + kHeaderSeparator .size ();
46+
47+ // An empty line separates the headers from the message body.
48+ if (header.empty ()) {
49+ // Not enough data, wait for the next chunk to arrive.
50+ if (content_length + cursor > buf.size ())
51+ break ;
52+
53+ std::string body = buf.substr (cursor, content_length).str ();
54+ end_of_last_message = cursor + content_length;
55+ cursor += content_length;
56+ Log (llvm::formatv (" --> {0}" , body).str ());
57+ messages.push_back (body);
58+ content_length = 0 ;
59+ continue ;
60+ }
61+
62+ // HTTP Headers are `<field-name>: [<field-value>]`.
63+ if (!header.contains (kHeaderFieldSeparator ))
64+ return make_error<StringError>(" malformed content header" ,
65+ inconvertibleErrorCode ());
66+
67+ auto [name, value] = header.split (kHeaderFieldSeparator );
68+ if (name.lower () == kHeaderContentLength .lower ()) {
69+ value = value.trim ();
70+ if (value.trim ().consumeInteger (10 , content_length))
71+ return make_error<StringError>(
72+ formatv (" invalid content length: {0}" , value).str (),
73+ inconvertibleErrorCode ());
74+ }
75+ } while (cursor < buf.size ());
9776
98- IOObject *input = m_input.get ();
99- Expected<std::string> message_header =
100- ReadFull (*input, kHeaderContentLength .size (), timeout);
101- if (!message_header)
102- return message_header.takeError ();
103- if (*message_header != kHeaderContentLength )
104- return createStringError (formatv (" expected '{0}' and got '{1}'" ,
105- kHeaderContentLength , *message_header)
106- .str ());
107-
108- Expected<std::string> raw_length = ReadUntil (*input, kHeaderSeparator );
109- if (!raw_length)
110- return handleErrors (raw_length.takeError (),
111- [&](const TransportEOFError &E) -> llvm::Error {
112- return createStringError (
113- " unexpected EOF while reading header separator" );
114- });
115-
116- size_t length;
117- if (!to_integer (*raw_length, length))
118- return createStringError (
119- formatv (" invalid content length {0}" , *raw_length).str ());
120-
121- Expected<std::string> raw_json = ReadFull (*input, length);
122- if (!raw_json)
123- return handleErrors (
124- raw_json.takeError (), [&](const TransportEOFError &E) -> llvm::Error {
125- return createStringError (" unexpected EOF while reading JSON" );
126- });
127-
128- Log (llvm::formatv (" --> {0}" , *raw_json).str ());
129-
130- return raw_json;
77+ // Store the remainder of the buffer for the next read callback.
78+ m_buffer = buf.substr (end_of_last_message);
79+
80+ return messages;
13181}
13282
13383Error HTTPDelimitedJSONTransport::WriteImpl (const std::string &message) {
@@ -138,25 +88,29 @@ Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
13888
13989 std::string Output;
14090 raw_string_ostream OS (Output);
141- OS << kHeaderContentLength << message.length () << kHeaderSeparator << message;
91+ OS << kHeaderContentLength << kHeaderFieldSeparator << ' ' << message.length ()
92+ << kHeaderSeparator << kHeaderSeparator << message;
14293 size_t num_bytes = Output.size ();
14394 return m_output->Write (Output.data (), num_bytes).takeError ();
14495}
14596
146- Expected<std::string>
147- JSONRPCTransport::ReadImpl (const std::chrono::microseconds &timeout) {
148- if (!m_input || !m_input->IsValid ())
149- return make_error<TransportInvalidError>();
150-
151- IOObject *input = m_input.get ();
152- Expected<std::string> raw_json =
153- ReadUntil (*input, kMessageSeparator , timeout);
154- if (!raw_json)
155- return raw_json.takeError ();
156-
157- Log (llvm::formatv (" --> {0}" , *raw_json).str ());
158-
159- return *raw_json;
97+ Expected<std::vector<std::string>> JSONRPCTransport::Parse () {
98+ std::vector<std::string> messages;
99+ StringRef buf = m_buffer;
100+ do {
101+ size_t idx = buf.find (kMessageSeparator );
102+ if (idx == StringRef::npos)
103+ break ;
104+ std::string raw_json = buf.substr (0 , idx).str ();
105+ buf = buf.substr (idx + 1 );
106+ Log (llvm::formatv (" --> {0}" , raw_json).str ());
107+ messages.push_back (raw_json);
108+ } while (!buf.empty ());
109+
110+ // Store the remainder of the buffer for the next read callback.
111+ m_buffer = buf.str ();
112+
113+ return messages;
160114}
161115
162116Error JSONRPCTransport::WriteImpl (const std::string &message) {
0 commit comments