Merge pull request #4234 from hashicorp/b-4159

Fix race in StreamFramer and truncation in api/AllocFS.Logs
This commit is contained in:
Michael Schurter
2018-05-04 14:24:07 -07:00
committed by GitHub
6 changed files with 238 additions and 82 deletions

View File

@@ -338,15 +338,16 @@ func (s *HTTPServer) fsStreamImpl(resp http.ResponseWriter,
return nil, CodedError(500, handlerErr.Error())
}
p1, p2 := net.Pipe()
decoder := codec.NewDecoder(p1, structs.MsgpackHandle)
encoder := codec.NewEncoder(p1, structs.MsgpackHandle)
// Create a pipe connecting the (possibly remote) handler to the http response
httpPipe, handlerPipe := net.Pipe()
decoder := codec.NewDecoder(httpPipe, structs.MsgpackHandle)
encoder := codec.NewEncoder(httpPipe, structs.MsgpackHandle)
// Create a goroutine that closes the pipe if the connection closes.
ctx, cancel := context.WithCancel(req.Context())
go func() {
<-ctx.Done()
p1.Close()
httpPipe.Close()
}()
// Create an output that gets flushed on every write
@@ -355,10 +356,11 @@ func (s *HTTPServer) fsStreamImpl(resp http.ResponseWriter,
// Create a channel that decodes the results
errCh := make(chan HTTPCodedError)
go func() {
defer cancel()
// Send the request
if err := encoder.Encode(args); err != nil {
errCh <- CodedError(500, err.Error())
cancel()
return
}
@@ -366,7 +368,6 @@ func (s *HTTPServer) fsStreamImpl(resp http.ResponseWriter,
select {
case <-ctx.Done():
errCh <- nil
cancel()
return
default:
}
@@ -374,29 +375,29 @@ func (s *HTTPServer) fsStreamImpl(resp http.ResponseWriter,
var res cstructs.StreamErrWrapper
if err := decoder.Decode(&res); err != nil {
errCh <- CodedError(500, err.Error())
cancel()
return
}
decoder.Reset(httpPipe)
if err := res.Error; err != nil {
if err.Code != nil {
errCh <- CodedError(int(*err.Code), err.Error())
cancel()
return
}
}
if _, err := io.Copy(output, bytes.NewBuffer(res.Payload)); err != nil {
if _, err := io.Copy(output, bytes.NewReader(res.Payload)); err != nil {
errCh <- CodedError(500, err.Error())
cancel()
return
}
}
}()
handler(p2)
handler(handlerPipe)
cancel()
codedErr := <-errCh
// Ignore EOF and ErrClosedPipe errors.
if codedErr != nil &&
(codedErr == io.EOF ||
strings.Contains(codedErr.Error(), "closed") ||