7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " lldb/Host/JSONTransport.h"
10
- #include " lldb/Utility/IOObject.h"
11
10
#include " lldb/Utility/LLDBLog.h"
12
11
#include " lldb/Utility/Log.h"
13
- #include " lldb/Utility/SelectHelper.h"
14
12
#include " lldb/Utility/Status.h"
15
13
#include " lldb/lldb-forward.h"
16
14
#include " llvm/ADT/StringExtras.h"
17
15
#include " llvm/ADT/StringRef.h"
18
16
#include " llvm/Support/Error.h"
19
17
#include " llvm/Support/raw_ostream.h"
20
- #include < optional>
21
18
#include < string>
22
19
#include < utility>
23
20
24
21
using namespace llvm ;
25
22
using namespace lldb ;
26
23
using namespace lldb_private ;
27
24
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
-
86
25
JSONTransport::JSONTransport (IOObjectSP input, IOObjectSP output)
87
26
: m_input(std::move(input)), m_output(std::move(output)) {}
88
27
89
28
void JSONTransport::Log (llvm::StringRef message) {
90
29
LLDB_LOG (GetLog (LLDBLog::Host), " {0}" , message);
91
30
}
92
31
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 ());
97
76
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;
131
81
}
132
82
133
83
Error HTTPDelimitedJSONTransport::WriteImpl (const std::string &message) {
@@ -138,25 +88,29 @@ Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
138
88
139
89
std::string Output;
140
90
raw_string_ostream OS (Output);
141
- OS << kHeaderContentLength << message.length () << kHeaderSeparator << message;
91
+ OS << kHeaderContentLength << kHeaderFieldSeparator << ' ' << message.length ()
92
+ << kHeaderSeparator << kHeaderSeparator << message;
142
93
size_t num_bytes = Output.size ();
143
94
return m_output->Write (Output.data (), num_bytes).takeError ();
144
95
}
145
96
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;
160
114
}
161
115
162
116
Error JSONRPCTransport::WriteImpl (const std::string &message) {
0 commit comments