eclipse-vertx / vert.x

Vert.x is a tool-kit for building reactive applications on the JVM
http://vertx.io
Other
14.26k stars 2.07k forks source link

Proxy multipart/form-data with API-Gateway #2460

Closed xkguq007 closed 6 years ago

xkguq007 commented 6 years ago

Sorry for bad English.

I made simple solution dealing with multipart. My reference is vertx-blueprint-microservice which use MSA. I got problem How can I handle multipart.

PROBLEM IS HANGING RESPONSE. Simple summary until now I found is CLIENT ------ API_GATEWAY ----- SERVICE (multipart X, json O) CLIENT ------ SERVICE (multipart O, json O)

In ApiGateway source,

if (context.getBody() == null) {
  toReq.end();
} else {
  toReq.end(context.getBody());
}

hanging point is toReq.end(context.getBody()); after 10sec, it timeout.

I don't know how can I solve this. I doubt that SERVICE can't accept multipart, however CLIENT ------ SERVICE (multipart O, json O) this is succeed. it's wierd.

Is there any more example how can I handle multipart proxying?

PS vertx-blueprint-microservice I saw this repo in vertx homepage. I think this means quite important reference for understanding vertx. However this repo looks dead. There is no response at all.

tsegismont commented 6 years ago

Can you create a small reproducer with: client code, gateway code, backend code? Thanks

2018-05-17 23:31 GMT+02:00 Uyeong Connor Kim notifications@github.com:

Sorry for bad English.

I made simple solution dealing with multipart. My reference is vertx-blueprint-microservice which use MSA. I got problem How can I handle multipart.

PROBLEM IS HANGING RESPONSE. Simple summary until now I found is CLIENT ------ API_GATEWAY ----- SERVICE (multipart X, json O) CLIENT ------ SERVICE (multipart O, json O)

In ApiGateway source,

if (context.getBody() == null) { toReq.end(); } else { toReq.end(context.getBody()); }

hanging point is toReq.end(context.getBody()); after 10sec, it timeout.

I don't know how can I solve this. I doubt that SERVICE can't accept multipart, however CLIENT ------ SERVICE (multipart O, json O) this is succeed. it's wierd.

Is there any more example how can I handle multipart proxying?

PS vertx-blueprint-microservice I saw this repo in vertx homepage. I think this means quite important reference for understanding vertx. However this repo looks dead. There is no response at all.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/eclipse/vert.x/issues/2460, or mute the thread https://github.com/notifications/unsubscribe-auth/ABblttyjpo5xvqGFmwaZv7D9V-X_xynnks5tzewggaJpZM4UDzc_ .

xkguq007 commented 6 years ago

@tsegismont Thanks for your reply.

I hope I understand your request right.

First of all, Client code was built by postman. so it is unnecessary. (I also check this request work good using Node.JS.)

Next, Api gateway code is exactly same with vertx-blueprint-microservice api gateway. Below is partial code

---------------- API GATEWAY ---------------- server creation.

vertx.createHttpServer()
      .requestHandler(req -> {
        req.setExpectMultipart(true);
        router.accept(req);
      })
      .listen(port, host, ar -> {
        if (!ar.succeeded()) {
          future.fail(ar.cause());
          return;
        }
       ... server start ...

router split

// api dispatcher
router.route("/api/*").handler(this::dispatchRequests);

dispatchRequests CODE -> IMPORTANT

HttpClientRequest toReq = client
      .request(context.request().method(), path, response -> {
        response.bodyHandler(body -> {
          if (response.statusCode() >= 500) { // api endpoint server error, circuit breaker should fail
            cbFuture.fail(response.statusCode() + ": " + body.toString());
          } else {
            HttpServerResponse toRsp = context.response()
              .setStatusCode(response.statusCode());
            response.headers().forEach(header -> {
              toRsp.putHeader(header.getKey(), header.getValue());
            });;
            // send response
            toRsp.end(body);
            cbFuture.complete();
          }
          ServiceDiscovery.releaseServiceObject(discovery, client);
        });
      });
    // set headers
    context.request().headers().forEach(header -> {
      toReq.putHeader(header.getKey(), header.getValue());
    });
    if (context.user() != null) {
      toReq.putHeader("user-principal", context.user().principal().encode());
    }

    // send request
    if (context.getBody() == null) {
      toReq.end();
    } else {
      // stuck this request. when multipart
      toReq.end(context.getBody());
    }

THE THING is that this code works greatly with 'application/json' but not work with 'multipart/form-data'

---------------- BACKEND (Actual multipart processing part) ----------------

This source also based on vertx-blueprint-microservice. server creation.

router.route().handler(BodyHandler.create());
vertx
      .createHttpServer()
      .requestHandler(req -> {
        req.setExpectMultipart(true);
        router.accept(req);
      })
      .listen(port, host, httpServerFuture.completer());

When I calling this BACKEND directly, It works. (Just check using System.out.println) With API Gateway? It hangs.

PLUS I clone vertx-blueprint-microservice this repository, and running it self. If this source works with 'multipart', I might do something wrong. But This source without any changing is not working with 'multipart/form-data' too.

So, It should be more added the code which can handle multipart. But I don't know what I put the code is.

PLUS 2 I found uploadHandler does not exist on API-GATEWAY source. Is this necessary even this is just gateway? I don't want handle multipart, just proxying it.

This is my junit test code which works great with multipart.

vertx = Vertx.vertx();
    server =
      vertx.createHttpServer().requestHandler(
        req -> {
          req.setExpectMultipart(true);
          req.uploadHandler(upload -> {
            upload.exceptionHandler(cause -> {
              req.response().setChunked(true).end("Upload failed");
            });

            upload.endHandler(v -> {
              req.response().setChunked(true).end("Successfully uploaded to " + upload.filename());
            });
            // FIXME - Potential security exploit! In a real system you must check this filename
            // to make sure you're not saving to a place where you don't want!
            // Or better still, just use Vert.x-Web which controls the upload area.
            upload.streamToFileSystem(upload.filename());
          });
        })
      .listen(8080, context.asyncAssertSuccess());
});
tsegismont commented 6 years ago

@xkguq007 we don't maintain the msa blueprint repo so I can't really say what's wrong there. However, I can help if you create a small project on GitHub, which I can build with Maven/Gradle and test locally.

xkguq007 commented 6 years ago

@tsegismont okay, I'll close this issue and recreate when I set up the small project related on this problem. Thanks for your help.