Permalink
Browse files

Add nghttpx reverse-proxy in front of ext interface. This will be use…

…d (1) to distinguish gRPC traffic from REST API traffic and (2) as TLS termination.
  • Loading branch information...
vlad-alexandru-ionescu committed Apr 27, 2016
1 parent 26a13e9 commit cfb6272907052c07c9a049b951ab40218fcdab51
View
@@ -128,7 +128,7 @@ runcommon:
$(MAKE) \
upload-config \
init-db-tables
- $(DOCKER_COMPOSE) up --force-recreate leveroshost
+ $(DOCKER_COMPOSE) up --force-recreate leveroshost nghttpxext
.PHONY: install-cli
install-cli: $(BIN_DIR)/lever
@@ -266,6 +266,7 @@ docker-%: $(SERVICES_DIR)/%/Dockerfile FORCE
$(DOCKER) build -t leveros/$(@:docker-%=%) $(dir $<)
docker-consul: | docker-base
+docker-nghttpx: | docker-base
docker-levercontainer: | docker-base
docker-levercontainer: $(SERVICES_DIR)/levercontainer/js/leveros-server
docker-levercontainer: $(SERVICES_DIR)/levercontainer/js/leveros-common
View
@@ -328,5 +328,13 @@ func (client *Client) invokeChanInternal(
grpcStream.CloseSend()
return nil, err
}
+ // First message received must be empty.
+ fstMsg, err := grpcStream.Recv()
+ if err != nil {
+ return nil, err
+ }
+ if fstMsg.GetMessageOneof() != nil {
+ return nil, fmt.Errorf("First server message needs to be empty")
+ }
return newClientStream(grpcStream), nil
}
View
@@ -226,10 +226,11 @@ func (server *Server) HandleStreamingRPC(
if rpc == nil {
return fmt.Errorf("First message needs to have RPC field set")
}
-
if rpc.GetArgsOneof() == nil {
return fmt.Errorf("RPC has no args oneof")
}
+ // Reply with an empty msg (first response message must be empty).
+ grpcStream.Send(&core.StreamMessage{})
server.lock.RLock()
entry, handlerOK := server.streamingHandlers[leverURL.Method]
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -12,7 +12,6 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:z
- ${LEVEROS_REPO_DIR}:/leveros/custcodetree:Z
ports:
- - ${LEVEROS_IP_PORT}:8080
- 127.0.0.1:6514:6514 # Dev logger.
command: >-
--config leveroshost
@@ -23,6 +22,22 @@ services:
environment:
LEVEROS_IP_PORT: ${LEVEROS_IP_PORT}
+ nghttpxext:
+ image: leveros/nghttpx:latest
+ container_name: leverosnghttpxext
+ ports:
+ - ${LEVEROS_IP_PORT}:8080
+ command: >-
+ --frontend=*,8080;no-tls
+ --backend=leveroshost,3502;/core.LeverRPC/;proto=h2
+ --backend=leveroshost,3503
+ --backend-address-family=IPv4
+ --backend-keep-alive-timeout=30s
+ --strip-incoming-x-forwarded-for
+ --add-x-forwarded-for
+ --backend-http2-max-concurrent-streams=10000
+ --workers=4
+
consul:
image: leveros/consul:latest
container_name: leverosconsul
View
@@ -42,7 +42,7 @@ var (
PackageName, "envInListenPortFlag", "3500")
// EnvExtListenPortFlag is the listen port for external connections.
EnvExtListenPortFlag = config.DeclareString(
- PackageName, "envExtListenPortFlag", "8080")
+ PackageName, "envExtListenPortFlag", "3502")
)
// LeverProxy is a proxy server that mediates Lever RPCs from the outside world
View
@@ -10,7 +10,6 @@ import (
)
func (proxy *LeverProxy) serveExt() (err error) {
- // TODO: Restrict to external network.
listenAddr := ":" + EnvExtListenPortFlag.Get()
proxy.extLogger.WithFields("listenAddr", listenAddr).Info("Listening")
proxy.extListener, _, err = proxy.inServer.Serve(
@@ -14,8 +14,6 @@ class Handler {
}
handleRpc(call, callback) {
- // TODO RPC gateway
- //call.metadata.get('x-lever-internal-rpc-gateway')[0];
setInternalRPCGateway(call.metadata);
let leverURL;
try {
@@ -50,8 +48,6 @@ class Handler {
}
handleStreamingRpc(call) {
- // TODO RPC gateway
- //call.metadata.get('x-lever-internal-rpc-gateway')[0];
setInternalRPCGateway(call.metadata);
let leverURL;
try {
@@ -66,7 +62,7 @@ class Handler {
};
call.on('error', onError);
call.once('data', (streamMsg) => {
- call.removeListener(onError);
+ call.removeListener('error', onError);
if (streamMsg.message_oneof !== 'rpc') {
call.write({error: "First message was not rpc"});
call.end();
@@ -80,6 +76,10 @@ class Handler {
return;
}
const method = this._custHandler[leverURL.method];
+
+ // First message sent back must be empty.
+ call.write({});
+
const args = [new common.Stream(call)];
if (leverURL.resource !== "") {
args.push(leverURL.resource);
View
@@ -149,7 +149,22 @@ class Client {
const call = sendStreamingLeverRPC(connection, leverURL);
call.write({rpc: common.jsToRpc(args)});
- callback(null, new common.Stream(call));
+ const onError = (error) => {
+ callback(error);
+ };
+ call.on('error', onError);
+ call.once('data', (streamMsg) => {
+ call.removeListener('error', onError);
+ if (streamMsg.message_oneof !== null) {
+ const errorStr = "First message must be empty";
+ call.write({error: errorStr});
+ call.end();
+ callback(new Error(errorStr));
+ return;
+ }
+
+ callback(null, new common.Stream(call));
+ });
});
}
}
@@ -30,10 +30,13 @@ message StreamMessage {
// Note that the invokation details (rpc field) are part of the very first
// message sent by the client. It is an error for any other message to have
// that field set.
+ // Also, the very first message sent by the server must be an empty
+ // message. This is a workaround for some reverse-proxies which do funny
+ // things if there's no data frame.
oneof message_oneof {
// First message, client-to-server only.
RPC rpc = 1;
- // Other messages (all server-to-client and non-first client-to-server).
+ // Non-first messages.
// These are passed to the Lever application's handlers.
JSON message = 2;
bytes byte_message = 3;
@@ -2,7 +2,7 @@ FROM leveros/base:latest
COPY ./leveroshost /leveros/bin/
-EXPOSE 3500 3501 3838 6514 8080
+EXPOSE 3500 3501 3502 3838 6514
VOLUME /var/run/docker.sock
WORKDIR /leveros
@@ -0,0 +1,13 @@
+FROM leveros/base:latest
+
+RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
+ addgroup -S nghttpx && \
+ adduser -S -D -h /dev/null -s /sbin/nologin -G nghttpx nghttpx && \
+ apk add --update nghttp2 && \
+ rm -rf /var/cache/apk/*
+
+EXPOSE 8080
+USER nghttpx
+
+ENTRYPOINT ["/usr/bin/nghttpx"]
+CMD ["--help"]

0 comments on commit cfb6272

Please sign in to comment.