service/dap: validate the client configurations in initialize request (#2435)

The client can specify certain configurations in the initialize request.
For example, pathFormat determines the pathFormat. We do not currently
support configuring pathFormat, linesStartAt1, or columnsStartAt1, so
we report an error if the client attempts to set these to an
unsupported value.
This commit is contained in:
Suzy Mueller 2021-05-06 03:56:29 -04:00 committed by GitHub
parent c5d58f494a
commit 49555a9e8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 5 deletions

@ -346,6 +346,13 @@ func (c *Client) InitializeRequest() {
c.send(request)
}
// InitializeRequestWithArgs sends an 'initialize' request with specified arguments.
func (c *Client) InitializeRequestWithArgs(args dap.InitializeRequestArguments) {
request := &dap.InitializeRequest{Request: *c.newRequest("initialize")}
request.Arguments = args
c.send(request)
}
// LaunchRequest sends a 'launch' request with the specified args.
func (c *Client) LaunchRequest(mode, program string, stopOnEntry bool) {
request := &dap.LaunchRequest{Request: *c.newRequest("launch")}

@ -12,6 +12,7 @@ const (
// values below are inspired the original vscode-go debug adaptor.
FailedToLaunch = 3000
FailedToAttach = 3001
FailedToInitialize = 3002
UnableToSetBreakpoints = 2002
UnableToDisplayThreads = 2003
UnableToProduceStackTrace = 2004

@ -608,6 +608,22 @@ func (s *Server) logToConsole(msg string) {
}
func (s *Server) onInitializeRequest(request *dap.InitializeRequest) {
if request.Arguments.PathFormat != "path" {
s.sendErrorResponse(request.Request, FailedToInitialize, "Failed to initialize",
fmt.Sprintf("Unsupported 'pathFormat' value '%s'.", request.Arguments.PathFormat))
return
}
if !request.Arguments.LinesStartAt1 {
s.sendErrorResponse(request.Request, FailedToInitialize, "Failed to initialize",
"Only 1-based line numbers are supported.")
return
}
if !request.Arguments.ColumnsStartAt1 {
s.sendErrorResponse(request.Request, FailedToInitialize, "Failed to initialize",
"Only 1-based column numbers are supported.")
return
}
// TODO(polina): Respond with an error if debug session is in progress?
response := &dap.InitializeResponse{Response: *newResponse(request.Request)}
response.Body.SupportsConfigurationDoneRequest = true

@ -50,6 +50,16 @@ func runTest(t *testing.T, name string, test func(c *daptest.Client, f protest.F
var buildFlags protest.BuildFlags = protest.AllNonOptimized
fixture := protest.BuildFixture(name, buildFlags)
// Start the DAP server.
client := startDapServer(t)
// client.Close will close the client connectinon, which will cause a connection error
// on the server side and signal disconnect to unblock Stop() above.
defer client.Close()
test(client, fixture)
}
func startDapServer(t *testing.T) *daptest.Client {
// Start the DAP server.
listener, err := net.Listen("tcp", ":0")
if err != nil {
@ -76,11 +86,7 @@ func runTest(t *testing.T, name string, test func(c *daptest.Client, f protest.F
}()
client := daptest.NewClient(listener.Addr().String())
// This will close the client connectinon, which will cause a connection error
// on the server side and signal disconnect to unblock Stop() above.
defer client.Close()
test(client, fixture)
return client
}
// TestLaunchStopOnEntry emulates the message exchange that can be observed with
@ -3337,6 +3343,66 @@ func TestBadAttachRequest(t *testing.T) {
})
}
func TestBadInitializeRequest(t *testing.T) {
runInitializeTest := func(args dap.InitializeRequestArguments, err string) {
t.Helper()
// Only one initialize request is allowed, so use a new server
// for each test.
client := startDapServer(t)
// client.Close will close the client connectinon, which will cause a connection error
// on the server side and signal disconnect to unblock Stop() above.
defer client.Close()
client.InitializeRequestWithArgs(args)
response := client.ExpectErrorResponse(t)
if response.Command != "initialize" {
t.Errorf("Command got %q, want \"launch\"", response.Command)
}
if response.Message != "Failed to initialize" {
t.Errorf("Message got %q, want \"Failed to launch\"", response.Message)
}
if response.Body.Error.Id != 3002 {
t.Errorf("Id got %d, want 3002", response.Body.Error.Id)
}
if response.Body.Error.Format != err {
t.Errorf("\ngot %q\nwant %q", response.Body.Error.Format, err)
}
}
// Bad path format.
runInitializeTest(dap.InitializeRequestArguments{
AdapterID: "go",
PathFormat: "url", // unsupported 'pathFormat'
LinesStartAt1: true,
ColumnsStartAt1: true,
Locale: "en-us",
},
"Failed to initialize: Unsupported 'pathFormat' value 'url'.",
)
// LinesStartAt1 must be true.
runInitializeTest(dap.InitializeRequestArguments{
AdapterID: "go",
PathFormat: "path",
LinesStartAt1: false, // only 1-based line numbers are supported
ColumnsStartAt1: true,
Locale: "en-us",
},
"Failed to initialize: Only 1-based line numbers are supported.",
)
// ColumnsStartAt1 must be true.
runInitializeTest(dap.InitializeRequestArguments{
AdapterID: "go",
PathFormat: "path",
LinesStartAt1: true,
ColumnsStartAt1: false, // only 1-based column numbers are supported
Locale: "en-us",
},
"Failed to initialize: Only 1-based column numbers are supported.",
)
}
func TestBadlyFormattedMessageToServer(t *testing.T) {
runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
// Send a badly formatted message to the server, and expect it to close the