2017-02-07 18:28:20 +08:00
|
|
|
//===--- JSONRPCDispatcher.cpp - Main JSON parser entry point -------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "JSONRPCDispatcher.h"
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
#include "JSONExpr.h"
|
2017-02-07 18:28:20 +08:00
|
|
|
#include "ProtocolHandlers.h"
|
2017-11-02 17:21:51 +08:00
|
|
|
#include "Trace.h"
|
2017-02-07 18:28:20 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2017-11-07 22:45:31 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-02-07 18:28:20 +08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2017-05-16 23:23:55 +08:00
|
|
|
#include <istream>
|
|
|
|
|
2017-02-07 18:28:20 +08:00
|
|
|
using namespace clang;
|
|
|
|
using namespace clangd;
|
|
|
|
|
2017-12-13 20:51:22 +08:00
|
|
|
namespace {
|
|
|
|
static Key<std::unique_ptr<trace::Span>> RequestSpan;
|
|
|
|
static Key<json::Expr> RequestID;
|
|
|
|
static Key<JSONOutput *> RequestOut;
|
|
|
|
} // namespace
|
|
|
|
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
void JSONOutput::writeMessage(const json::Expr &Message) {
|
|
|
|
std::string S;
|
|
|
|
llvm::raw_string_ostream OS(S);
|
|
|
|
if (Pretty)
|
|
|
|
OS << llvm::formatv("{0:2}", Message);
|
|
|
|
else
|
|
|
|
OS << Message;
|
|
|
|
OS.flush();
|
2017-02-07 18:28:20 +08:00
|
|
|
|
2017-02-10 22:08:40 +08:00
|
|
|
std::lock_guard<std::mutex> Guard(StreamMutex);
|
2017-02-07 18:28:20 +08:00
|
|
|
// Log without headers.
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
Logs << "--> " << S << '\n';
|
2017-02-07 18:28:20 +08:00
|
|
|
Logs.flush();
|
|
|
|
|
|
|
|
// Emit message with header.
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
Outs << "Content-Length: " << S.size() << "\r\n\r\n" << S;
|
2017-02-07 18:28:20 +08:00
|
|
|
Outs.flush();
|
|
|
|
}
|
|
|
|
|
2017-12-13 20:51:22 +08:00
|
|
|
void JSONOutput::log(const Context &Ctx, const Twine &Message) {
|
2017-12-14 23:04:59 +08:00
|
|
|
trace::log(Ctx, Message);
|
2017-02-16 00:44:11 +08:00
|
|
|
std::lock_guard<std::mutex> Guard(StreamMutex);
|
2017-12-01 07:21:34 +08:00
|
|
|
Logs << Message << '\n';
|
2017-02-16 00:44:11 +08:00
|
|
|
Logs.flush();
|
|
|
|
}
|
|
|
|
|
2017-10-10 17:08:47 +08:00
|
|
|
void JSONOutput::mirrorInput(const Twine &Message) {
|
|
|
|
if (!InputMirror)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*InputMirror << Message;
|
|
|
|
InputMirror->flush();
|
|
|
|
}
|
|
|
|
|
2017-12-13 20:51:22 +08:00
|
|
|
void clangd::reply(const Context &Ctx, json::Expr &&Result) {
|
|
|
|
auto ID = Ctx.get(RequestID);
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
if (!ID) {
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Ctx, "Attempted to reply to a notification!");
|
2017-10-12 21:29:58 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-12-13 20:51:22 +08:00
|
|
|
|
|
|
|
if (auto *Span = Ctx.get(RequestSpan))
|
|
|
|
SPAN_ATTACH(**Span, "Reply", Result);
|
|
|
|
|
|
|
|
Ctx.getExisting(RequestOut)
|
|
|
|
->writeMessage(json::obj{
|
|
|
|
{"jsonrpc", "2.0"},
|
|
|
|
{"id", *ID},
|
|
|
|
{"result", std::move(Result)},
|
|
|
|
});
|
2017-02-07 18:28:20 +08:00
|
|
|
}
|
|
|
|
|
2017-12-13 20:51:22 +08:00
|
|
|
void clangd::replyError(const Context &Ctx, ErrorCode code,
|
|
|
|
const llvm::StringRef &Message) {
|
|
|
|
log(Ctx, "Error " + Twine(static_cast<int>(code)) + ": " + Message);
|
|
|
|
if (auto *Span = Ctx.get(RequestSpan))
|
|
|
|
SPAN_ATTACH(**Span, "Error",
|
|
|
|
(json::obj{{"code", static_cast<int>(code)},
|
|
|
|
{"message", Message.str()}}));
|
|
|
|
|
|
|
|
if (auto ID = Ctx.get(RequestID)) {
|
|
|
|
Ctx.getExisting(RequestOut)
|
|
|
|
->writeMessage(json::obj{
|
|
|
|
{"jsonrpc", "2.0"},
|
|
|
|
{"id", *ID},
|
|
|
|
{"error",
|
|
|
|
json::obj{{"code", static_cast<int>(code)}, {"message", Message}}},
|
|
|
|
});
|
2017-10-12 21:29:58 +08:00
|
|
|
}
|
2017-02-07 18:28:20 +08:00
|
|
|
}
|
|
|
|
|
2017-12-13 20:51:22 +08:00
|
|
|
void clangd::call(const Context &Ctx, StringRef Method, json::Expr &&Params) {
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 21:39:15 +08:00
|
|
|
// FIXME: Generate/Increment IDs for every request so that we can get proper
|
|
|
|
// replies once we need to.
|
2017-12-13 20:51:22 +08:00
|
|
|
if (auto *Span = Ctx.get(RequestSpan))
|
|
|
|
SPAN_ATTACH(**Span, "Call",
|
|
|
|
(json::obj{{"method", Method.str()}, {"params", Params}}));
|
|
|
|
Ctx.getExisting(RequestOut)
|
|
|
|
->writeMessage(json::obj{
|
|
|
|
{"jsonrpc", "2.0"},
|
|
|
|
{"id", 1},
|
|
|
|
{"method", Method},
|
|
|
|
{"params", std::move(Params)},
|
|
|
|
});
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 21:39:15 +08:00
|
|
|
}
|
|
|
|
|
2017-10-12 21:29:58 +08:00
|
|
|
void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) {
|
2017-02-07 18:28:20 +08:00
|
|
|
assert(!Handlers.count(Method) && "Handler already registered!");
|
|
|
|
Handlers[Method] = std::move(H);
|
|
|
|
}
|
|
|
|
|
2017-11-28 17:37:43 +08:00
|
|
|
bool JSONRPCDispatcher::call(const json::Expr &Message, JSONOutput &Out) const {
|
|
|
|
// Message must be an object with "jsonrpc":"2.0".
|
|
|
|
auto *Object = Message.asObject();
|
|
|
|
if (!Object || Object->getString("jsonrpc") != Optional<StringRef>("2.0"))
|
2017-02-07 18:28:20 +08:00
|
|
|
return false;
|
2017-11-28 17:37:43 +08:00
|
|
|
// ID may be any JSON value. If absent, this is a notification.
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
llvm::Optional<json::Expr> ID;
|
2017-11-28 17:37:43 +08:00
|
|
|
if (auto *I = Object->get("id"))
|
|
|
|
ID = std::move(*I);
|
|
|
|
// Method must be given.
|
|
|
|
auto Method = Object->getString("method");
|
2017-02-07 18:28:20 +08:00
|
|
|
if (!Method)
|
|
|
|
return false;
|
2017-11-28 17:37:43 +08:00
|
|
|
// Params should be given, use null if not.
|
|
|
|
json::Expr Params = nullptr;
|
|
|
|
if (auto *P = Object->get("params"))
|
|
|
|
Params = std::move(*P);
|
2017-02-07 18:28:20 +08:00
|
|
|
|
2017-11-28 17:37:43 +08:00
|
|
|
auto I = Handlers.find(*Method);
|
|
|
|
auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
|
2017-12-13 20:51:22 +08:00
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
// Create a Context that contains request information.
|
|
|
|
auto Ctx = Context::empty().derive(RequestOut, &Out);
|
|
|
|
if (ID)
|
|
|
|
Ctx = std::move(Ctx).derive(RequestID, *ID);
|
|
|
|
|
|
|
|
// Create a tracing Span covering the whole request lifetime.
|
|
|
|
auto Tracer = llvm::make_unique<trace::Span>(Ctx, *Method);
|
2017-12-13 20:51:22 +08:00
|
|
|
if (ID)
|
|
|
|
SPAN_ATTACH(*Tracer, "ID", *ID);
|
|
|
|
SPAN_ATTACH(*Tracer, "Params", Params);
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
// Update Ctx to include Tracer.
|
|
|
|
Ctx = std::move(Ctx).derive(RequestSpan, std::move(Tracer));
|
2017-12-13 20:51:22 +08:00
|
|
|
|
2017-11-28 17:37:43 +08:00
|
|
|
Handler(std::move(Ctx), std::move(Params));
|
2017-02-07 18:28:20 +08:00
|
|
|
return true;
|
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
|
|
|
|
void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
|
|
|
|
JSONRPCDispatcher &Dispatcher,
|
|
|
|
bool &IsDone) {
|
|
|
|
while (In.good()) {
|
2017-09-04 20:28:15 +08:00
|
|
|
// A Language Server Protocol message starts with a set of HTTP headers,
|
|
|
|
// delimited by \r\n, and terminated by an empty line (\r\n).
|
|
|
|
unsigned long long ContentLength = 0;
|
|
|
|
while (In.good()) {
|
|
|
|
std::string Line;
|
|
|
|
std::getline(In, Line);
|
|
|
|
if (!In.good() && errno == EINTR) {
|
|
|
|
In.clear();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-10-10 17:08:47 +08:00
|
|
|
Out.mirrorInput(Line);
|
|
|
|
// Mirror '\n' that gets consumed by std::getline, but is not included in
|
|
|
|
// the resulting Line.
|
|
|
|
// Note that '\r' is part of Line, so we don't need to mirror it
|
|
|
|
// separately.
|
|
|
|
if (!In.eof())
|
|
|
|
Out.mirrorInput("\n");
|
|
|
|
|
2017-09-04 20:28:15 +08:00
|
|
|
llvm::StringRef LineRef(Line);
|
|
|
|
|
2017-11-28 17:37:43 +08:00
|
|
|
// We allow comments in headers. Technically this isn't part
|
2017-09-04 20:28:15 +08:00
|
|
|
// of the LSP specification, but makes writing tests easier.
|
|
|
|
if (LineRef.startswith("#"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Content-Type is a specified header, but does nothing.
|
|
|
|
// Content-Length is a mandatory header. It specifies the length of the
|
|
|
|
// following JSON.
|
|
|
|
// It is unspecified what sequence headers must be supplied in, so we
|
|
|
|
// allow any sequence.
|
|
|
|
// The end of headers is signified by an empty line.
|
|
|
|
if (LineRef.consume_front("Content-Length: ")) {
|
|
|
|
if (ContentLength != 0) {
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(),
|
|
|
|
"Warning: Duplicate Content-Length header received. "
|
|
|
|
"The previous value for this message (" +
|
|
|
|
std::to_string(ContentLength) + ") was ignored.\n");
|
2017-09-04 20:28:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
|
|
|
|
continue;
|
|
|
|
} else if (!LineRef.trim().empty()) {
|
|
|
|
// It's another header, ignore it.
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// An empty line indicates the end of headers.
|
|
|
|
// Go ahead and read the JSON.
|
|
|
|
break;
|
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2017-10-28 01:06:41 +08:00
|
|
|
// Guard against large messages. This is usually a bug in the client code
|
|
|
|
// and we don't want to crash downstream because of it.
|
|
|
|
if (ContentLength > 1 << 30) { // 1024M
|
|
|
|
In.ignore(ContentLength);
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(), "Skipped overly large message of " +
|
|
|
|
Twine(ContentLength) + " bytes.\n");
|
2017-10-28 01:06:41 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-09-04 20:28:15 +08:00
|
|
|
if (ContentLength > 0) {
|
2017-11-28 17:37:43 +08:00
|
|
|
std::vector<char> JSON(ContentLength);
|
2017-11-02 17:21:51 +08:00
|
|
|
llvm::StringRef JSONRef;
|
|
|
|
{
|
|
|
|
In.read(JSON.data(), ContentLength);
|
|
|
|
Out.mirrorInput(StringRef(JSON.data(), In.gcount()));
|
|
|
|
|
|
|
|
// If the stream is aborted before we read ContentLength bytes, In
|
|
|
|
// will have eofbit and failbit set.
|
|
|
|
if (!In) {
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(), "Input was aborted. Read only " +
|
|
|
|
std::to_string(In.gcount()) +
|
|
|
|
" bytes of expected " +
|
|
|
|
std::to_string(ContentLength) + ".\n");
|
2017-11-02 17:21:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSONRef = StringRef(JSON.data(), ContentLength);
|
2017-09-04 20:28:15 +08:00
|
|
|
}
|
|
|
|
|
2017-11-28 17:37:43 +08:00
|
|
|
if (auto Doc = json::parse(JSONRef)) {
|
|
|
|
// Log the formatted message.
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(),
|
|
|
|
llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc));
|
2017-11-28 17:37:43 +08:00
|
|
|
// Finally, execute the action for this JSON message.
|
|
|
|
if (!Dispatcher.call(*Doc, Out))
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(), "JSON dispatch failed!\n");
|
2017-11-28 17:37:43 +08:00
|
|
|
} else {
|
|
|
|
// Parse error. Log the raw message.
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(), "<-- " + JSONRef + "\n");
|
|
|
|
log(Context::empty(), llvm::Twine("JSON parse error: ") +
|
|
|
|
llvm::toString(Doc.takeError()) + "\n");
|
2017-11-28 17:37:43 +08:00
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
|
|
|
|
// If we're done, exit the loop.
|
|
|
|
if (IsDone)
|
|
|
|
break;
|
2017-09-04 20:28:15 +08:00
|
|
|
} else {
|
2017-12-13 20:51:22 +08:00
|
|
|
log(Context::empty(),
|
|
|
|
"Warning: Missing Content-Length header, or message has zero "
|
|
|
|
"length.\n");
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|