14#include "llvm/ADT/SmallString.h"
15#include "llvm/Support/Error.h"
17#include <system_error>
23llvm::json::Object encodeError(llvm::Error E) {
28 if (llvm::Error Unhandled = llvm::handleErrors(
34 Message =
"Request cancelled because the document was modified";
38 Message =
"Request cancelled";
41 return llvm::Error::success();
43 [&](
const LSPError &L) -> llvm::Error {
46 return llvm::Error::success();
48 Message = llvm::toString(std::move(Unhandled));
50 return llvm::json::Object{
51 {
"message", std::move(Message)},
52 {
"code", int64_t(Code)},
56llvm::Error decodeError(
const llvm::json::Object &O) {
57 llvm::StringRef Msg = O.getString(
"message").value_or(
"Unspecified error");
58 if (
auto Code = O.getInteger(
"code"))
59 return llvm::make_error<LSPError>(Msg.str(),
ErrorCode(*Code));
60 return error(Msg.str());
65 JSONTransport(std::FILE *In, llvm::raw_ostream &Out,
67 : In(In), Out(Out), InMirror(InMirror ? *InMirror : llvm::nulls()),
68 Pretty(Pretty), Style(Style) {}
70 void notify(llvm::StringRef
Method, llvm::json::Value Params)
override {
71 sendMessage(llvm::json::Object{
74 {
"params", std::move(Params)},
77 void call(llvm::StringRef
Method, llvm::json::Value Params,
78 llvm::json::Value ID)
override {
79 sendMessage(llvm::json::Object{
81 {
"id", std::move(ID)},
83 {
"params", std::move(Params)},
86 void reply(llvm::json::Value ID,
87 llvm::Expected<llvm::json::Value> Result)
override {
89 sendMessage(llvm::json::Object{
91 {
"id", std::move(ID)},
92 {
"result", std::move(*Result)},
95 sendMessage(llvm::json::Object{
97 {
"id", std::move(ID)},
98 {
"error", encodeError(Result.takeError())},
103 llvm::Error loop(MessageHandler &Handler)
override {
107 return error(std::make_error_code(std::errc::operation_canceled),
108 "Got signal, shutting down");
110 return llvm::errorCodeToError(llvm::errnoAsErrorCode());
111 if (readRawMessage(JSON)) {
112 ThreadCrashReporter ScopedReporter([&JSON]() {
113 auto &OS = llvm::errs();
114 OS <<
"Signalled while processing message:\n";
117 if (
auto Doc = llvm::json::parse(JSON)) {
118 vlog(Pretty ?
"<<< {0:2}\n" :
"<<< {0}\n", *Doc);
119 if (!handleMessage(std::move(*Doc), Handler))
120 return llvm::Error::success();
123 vlog(
"<<< {0}\n", JSON);
124 elog(
"JSON parse error: {0}", llvm::toString(Doc.takeError()));
128 return llvm::errorCodeToError(std::make_error_code(std::errc::io_error));
133 bool handleMessage(llvm::json::Value Message, MessageHandler &Handler);
135 void sendMessage(llvm::json::Value Message) {
136 OutputBuffer.clear();
137 llvm::raw_svector_ostream OS(OutputBuffer);
138 OS << llvm::formatv(Pretty ?
"{0:2}" :
"{0}", Message);
139 Out <<
"Content-Length: " << OutputBuffer.size() <<
"\r\n\r\n"
142 vlog(
">>> {0}\n", OutputBuffer);
146 bool readRawMessage(std::string &JSON) {
148 : readStandardMessage(JSON);
150 bool readDelimitedMessage(std::string &JSON);
151 bool readStandardMessage(std::string &JSON);
153 llvm::SmallVector<char, 0> OutputBuffer;
155 llvm::raw_ostream &Out;
156 llvm::raw_ostream &InMirror;
161bool JSONTransport::handleMessage(llvm::json::Value Message,
162 MessageHandler &Handler) {
164 auto *
Object = Message.getAsObject();
166 Object->getString(
"jsonrpc") != std::optional<llvm::StringRef>(
"2.0")) {
167 elog(
"Not a JSON-RPC 2.0 message: {0:2}", Message);
171 std::optional<llvm::json::Value> ID;
172 if (
auto *I =
Object->get(
"id"))
177 elog(
"No method and no response ID: {0:2}", Message);
180 if (
auto *Err =
Object->getObject(
"error"))
181 return Handler.onReply(std::move(*ID), decodeError(*Err));
183 llvm::json::Value Result =
nullptr;
184 if (
auto *R =
Object->get(
"result"))
185 Result = std::move(*R);
186 return Handler.onReply(std::move(*ID), std::move(Result));
189 llvm::json::Value Params =
nullptr;
190 if (
auto *P =
Object->get(
"params"))
191 Params = std::move(*P);
194 return Handler.onCall(*Method, std::move(Params), std::move(*ID));
195 return Handler.onNotify(*Method, std::move(Params));
200bool readLine(std::FILE *In, llvm::SmallVectorImpl<char> &Out) {
203 static constexpr int BufSize = 128;
207 Out.resize_for_overwrite(Size + BufSize);
210 nullptr, [&] {
return std::fgets(&Out[Size], BufSize, In); }))
215 size_t Read = std::strlen(&Out[Size]);
216 if (
Read > 0 && Out[Size +
Read - 1] ==
'\n') {
217 Out.resize(Size +
Read);
227bool JSONTransport::readStandardMessage(std::string &JSON) {
230 unsigned long long ContentLength = 0;
231 llvm::SmallString<128> Line;
233 if (feof(In) || ferror(In) || !readLine(In, Line))
237 llvm::StringRef LineRef = Line;
242 if (LineRef.starts_with(
"#"))
246 if (LineRef.consume_front(
"Content-Length: ")) {
247 if (ContentLength != 0) {
248 elog(
"Warning: Duplicate Content-Length header received. "
249 "The previous value for this message ({0}) was ignored.",
252 llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
258 if (LineRef.trim().empty())
265 if (ContentLength > 1 << 30) {
266 elog(
"Refusing to read message with long Content-Length: {0}. "
267 "Expect protocol errors",
271 if (ContentLength == 0) {
272 log(
"Warning: Missing Content-Length header, or zero-length message.");
276 JSON.resize(ContentLength);
277 for (
size_t Pos = 0, Read; Pos < ContentLength; Pos +=
Read) {
280 return std::fread(&JSON[Pos], 1, ContentLength - Pos, In);
283 elog(
"Input was aborted. Read only {0} bytes of expected {1}.", Pos,
287 InMirror << llvm::StringRef(&JSON[Pos], Read);
300bool JSONTransport::readDelimitedMessage(std::string &JSON) {
302 llvm::SmallString<128> Line;
303 while (readLine(In, Line)) {
305 auto LineRef = Line.str().trim();
306 if (LineRef.starts_with(
"#"))
310 if (LineRef.rtrim() ==
"---")
319 elog(
"Input error while reading message!");
328 llvm::raw_ostream &Out,
329 llvm::raw_ostream *InMirror,
332 return std::make_unique<JSONTransport>(In, Out, InMirror, Pretty, Style);
void elog(const char *Fmt, Ts &&... Vals)
Conventional error when no result is returned due to cancellation.
void log(Logger::Level L, const char *Fmt, Ts &&... Vals)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Ret retryAfterSignalUnlessShutdown(const std::enable_if_t< true, Ret > &Fail, const Fun &F)
Retry an operation if it gets interrupted by a signal.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
std::unique_ptr< Transport > newJSONTransport(std::FILE *In, llvm::raw_ostream &Out, llvm::raw_ostream *InMirror, bool Pretty, JSONStreamStyle Style)
bool shutdownRequested()
Checks whether requestShutdown() was called.
void elog(const char *Fmt, Ts &&... Vals)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//