Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AcraReader http buffering #204

Merged
merged 9 commits into from
Jul 16, 2018
17 changes: 10 additions & 7 deletions cmd/acra-connector/acra-connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func main() {

if *acraServerHost == "" && *acraServerConnectionString == "" {
log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorWrongConfiguration).
Errorln("Configuration error: you must pass acraserver_connection_host or acra_connection_string parameter")
Errorln("Configuration error: you must pass acraserver_connection_host or acraserver_connection_string parameter")
os.Exit(1)
}
if *acraServerHost != "" {
Expand Down Expand Up @@ -240,11 +240,6 @@ func main() {
os.Exit(1)
}

if *verbose {
logging.SetLogLevel(logging.LOG_VERBOSE)
} else {
logging.SetLogLevel(logging.LOG_DISCARD)
}
if runtime.GOOS != "linux" {
*disableUserCheck = true
}
Expand All @@ -267,7 +262,7 @@ func main() {
os.Exit(1)
}

log.Debugf("Start listening connections")
log.Infof("Ready: start listening connections")
config := &Config{KeyStore: keyStore, KeysDir: *keysDir, ClientId: []byte(*clientId), AcraServerConnectionString: *acraServerConnectionString, ConnectionString: *connectionString, AcraServerId: []byte(*acraServerId), disableUserCheck: *disableUserCheck}
listener, err := network.Listen(*connectionString)
if err != nil {
Expand Down Expand Up @@ -346,6 +341,14 @@ func main() {
}

log.Infof("Start listening connection %s", *connectionString)

if *verbose {
logging.SetLogLevel(logging.LOG_VERBOSE)
} else {
log.Infof("Disabling future logs.. Set -v to see logs")
logging.SetLogLevel(logging.LOG_DISCARD)
}

for {
connection, err := listener.Accept()
if err != nil {
Expand Down
42 changes: 20 additions & 22 deletions cmd/acra-reader/http-api/decryptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ package http_api

import (
"bytes"
"encoding/binary"
"fmt"
"github.com/cossacklabs/acra/decryptor/base"
"github.com/cossacklabs/acra/keystore"
"github.com/cossacklabs/acra/logging"
"github.com/cossacklabs/acra/utils"
"github.com/cossacklabs/themis/gothemis/keys"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net"
"fmt"
"net/http"
"os"
"strings"
"os"
"github.com/cossacklabs/acra/keystore"
"net"
"io/ioutil"
"github.com/cossacklabs/acra/decryptor/base"
)

type HTTPConnectionsDecryptor struct {
Expand All @@ -25,26 +24,24 @@ func NewHTTPConnectionsDecryptor(keystorage keystore.KeyStore) (*HTTPConnections
return &HTTPConnectionsDecryptor{keystorage: keystorage}, nil
}

func (decryptor *HTTPConnectionsDecryptor) SendResponseAndCloseConnection(logger *log.Entry, response *http.Response, connection net.Conn) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.BigEndian, response)
func (decryptor *HTTPConnectionsDecryptor) SendResponse(logger *log.Entry, response *http.Response, connection net.Conn) {
r, err := ioutil.ReadAll(response.Body)
if err != nil {
logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorReaderCantReturnResponse).
Warningln("Can't read response body")
}
err = response.Body.Close()

if err != nil {
logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorReaderCantReturnResponse).
Warningln("Can't convert response to binary")
} else {
_, err = connection.Write(buf.Bytes())
_, err = connection.Write(r)
if err != nil {
logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorReaderCantReturnResponse).
Warningln("Can't write response to HTTP request")
}
}

err = connection.Close()
if err != nil {
logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorReaderCantCloseConnection).
Warningln("Can't close connection of HTTP request")
}
}

func (decryptor *HTTPConnectionsDecryptor) ParseRequestPrepareResponse(logger *log.Entry, request *http.Request, clientId []byte) *http.Response {
Expand Down Expand Up @@ -110,7 +107,7 @@ func (decryptor *HTTPConnectionsDecryptor) ParseRequestPrepareResponse(logger *l
return responseWithMessage(request, http.StatusBadRequest, msg)
}

decryptedStruct, err := decryptor.decryptAcraStruct(acraStruct, zoneId, clientId)
decryptedStruct, err := decryptor.decryptAcraStruct(logger, acraStruct, zoneId, clientId)

if err != nil {
msg := fmt.Sprintf("Can't decrypt AcraStruct")
Expand All @@ -122,7 +119,7 @@ func (decryptor *HTTPConnectionsDecryptor) ParseRequestPrepareResponse(logger *l

response := emptyResponseWithStatus(request, http.StatusOK)
response.Header.Set("Content-Type", "application/octet-stream")
response.Body = ioutil.NopCloser(bytes.NewBuffer(decryptedStruct))
response.Body = ioutil.NopCloser(bytes.NewReader(decryptedStruct))
response.ContentLength = int64(len(decryptedStruct))
return response
default:
Expand All @@ -138,7 +135,7 @@ func (decryptor *HTTPConnectionsDecryptor) ParseRequestPrepareResponse(logger *l
return responseWithMessage(request, http.StatusBadRequest, msg)
}

func (decryptor *HTTPConnectionsDecryptor) decryptAcraStruct(acraStruct []byte, zoneId []byte, clientId []byte) ([]byte, error) {
func (decryptor *HTTPConnectionsDecryptor) decryptAcraStruct(logger *log.Entry, acraStruct []byte, zoneId []byte, clientId []byte) ([]byte, error) {
var err error
var privateKey *keys.PrivateKey
var decryptionContext []byte = nil
Expand All @@ -151,6 +148,7 @@ func (decryptor *HTTPConnectionsDecryptor) decryptAcraStruct(acraStruct []byte,
}

if err != nil {
logger.Errorln("Can't load private key to decrypt AcraStruct")
return nil, err
}

Expand Down Expand Up @@ -182,8 +180,8 @@ func emptyResponseWithStatus(request *http.Request, status int) *http.Response {
func responseWithMessage(request *http.Request, status int, body string) *http.Response {
response := emptyResponseWithStatus(request, status)
response.Header.Set("Content-Type", "text/plain")
response.Body = ioutil.NopCloser(bytes.NewBufferString(body))
response.ContentLength = int64(len(body))
response.Body = ioutil.NopCloser(bytes.NewReader([]byte(body)))
response.ContentLength = int64(len([]byte(body)))
return response
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/acra-reader/http-api/decryptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestHTTPDecryptionAcraStruct(t *testing.T) {
data := []byte("some data")

// not an acrastruct
decrypted, err := httpConnectionsDecryptor.decryptAcraStruct([]byte("some garbage not acrastruct"), nil, clientId)
decrypted, err := httpConnectionsDecryptor.decryptAcraStruct(nil, []byte("some garbage not acrastruct"), nil, clientId)
if err == nil {
t.Fatalf("Should not be able to decrypt garbage")
}
Expand All @@ -182,7 +182,7 @@ func TestHTTPDecryptionAcraStruct(t *testing.T) {
t.Fatal(err)
}

decrypted, err = httpConnectionsDecryptor.decryptAcraStruct(acrastruct, nil, clientId)
decrypted, err = httpConnectionsDecryptor.decryptAcraStruct(nil, acrastruct, nil, clientId)
if err != nil {
t.Fatalf("Should be able to decrypt acrastruct without zone")
}
Expand All @@ -198,7 +198,7 @@ func TestHTTPDecryptionAcraStruct(t *testing.T) {
t.Fatal(err)
}

decrypted, err = httpConnectionsDecryptor.decryptAcraStruct(acrastructWithZone, zoneId, clientId)
decrypted, err = httpConnectionsDecryptor.decryptAcraStruct(nil, acrastructWithZone, zoneId, clientId)
if err != nil {
t.Fatalf("Should be able to decrypt acrastruct with zone")
}
Expand Down
16 changes: 9 additions & 7 deletions cmd/acra-reader/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ func AcceptConnections(parentContext context.Context, connectionString string, e

// run goroutine that just accept connections and return them and stop on error. you can stop it by closing listener
go func() {
conn, err := listener.Accept()
if err != nil {
logger.WithError(err).Errorln("Error on accept connection")
errCh <- err
cancel()
return
for {
conn, err := listener.Accept()
if err != nil {
logger.WithError(err).Errorln("Error on accept connection")
errCh <- err
cancel()
return
}
connectionChannel <- conn
}
connectionChannel <- conn
}()

// wait Done signal from caller or from "accept" goroutine and stop listener
Expand Down
21 changes: 15 additions & 6 deletions cmd/acra-reader/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,22 @@ func (server *ReaderServer) HandleConnectionString(parentContext context.Context

go func() {
if err := server.connectionManager.AddConnection(wrappedConnection); err != nil {
logger.WithError(err).Errorln("can't add connection to connection manager")
wrappedConnection.Close()
logger.WithError(err).Errorln("Can't add connection to connection manager, closing connection")
return
}

processingFunc(parentContext, clientId, wrappedConnection)
if err := server.connectionManager.RemoveConnection(wrappedConnection); err != nil {
logger.WithError(err).Errorln("can't remove connection from connection manager")

err := server.connectionManager.RemoveConnection(wrappedConnection)
if err != nil {
logger.WithError(err).Errorln("Can't remove connection from connection manager")
}
err = wrappedConnection.Close()
if err != nil {
logger.WithError(err).Errorln("Can't close connections")
}
logger.Debugln("Closing connection")
}()
}
}()
Expand All @@ -128,7 +137,7 @@ func (server *ReaderServer) HandleConnectionString(parentContext context.Context
case <-parentContext.Done():
log.WithError(parentContext.Err()).Debugln("Exit from handling connection string. Close all connections")
case outErr = <-errCh:
log.WithError(err).Errorln("error on accepting new connections")
log.WithError(err).Errorln("Error on accepting new connections")

}
return outErr
Expand Down Expand Up @@ -199,11 +208,11 @@ func (server *ReaderServer) processHTTPConnection(parentContext context.Context,
if err != nil {
logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorReaderCantHandleHTTPRequest).
Warningln("Got new HTTP request, but can't read it")
server.httpDecryptor.SendResponseAndCloseConnection(logger,
server.httpDecryptor.SendResponse(logger,
server.httpDecryptor.EmptyResponseWithStatus(request, http.StatusBadRequest), connection)
return
}

response := server.httpDecryptor.ParseRequestPrepareResponse(logger, request, clientId)
server.httpDecryptor.SendResponseAndCloseConnection(logger, response, connection)
server.httpDecryptor.SendResponse(logger, response, connection)
}
6 changes: 6 additions & 0 deletions network/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
url_ "net/url"
"os"
"strings"
"reflect"
log "github.com/sirupsen/logrus"
)

const (
Expand Down Expand Up @@ -92,7 +94,11 @@ func GetConnectionDescriptor(connection net.Conn) (uintptr, error) {
file, err = connection.(*net.TCPConn).File()
case *net.UnixConn:
file, err = connection.(*net.UnixConn).File()
case *secureSessionConnection:
// get description of own connection
return GetConnectionDescriptor(connection.(*secureSessionConnection).Conn)
default:
log.Errorf("Unsupported connection type: %s", reflect.TypeOf(connection))
return 0, ErrUnsupportedConnectionType
}
if err != nil {
Expand Down