Netflix / zuul

Zuul is a gateway service that provides dynamic routing, monitoring, resiliency, security, and more.
Apache License 2.0
13.4k stars 2.36k forks source link

Intercepting and injecting parameter in the request body #264

Closed paolo-rendano closed 8 years ago

paolo-rendano commented 8 years ago

Hi to all, I'm trying to intercept a call directed to zuul through a route filter, to inject a parameter in the body. I've written the following code:

    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        logger.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
        String uri = request.getRequestURI();

        List<String> parameterList = environment.getProperty("zuul.routes." + ctx.get("proxy") + ".bodyParameterInjector.parametersList", List.class);
        Map<String, String[]> extras = new TreeMap<>();

        if (parameterList!=null)
            for (String parameterName:parameterList) {
                List<String> parameterValues = environment.getProperty("zuul.routes." + ctx.get("proxy") + ".bodyParameterInjector.parametersValues." + parameterName, List.class);
                if (parameterValues!=null)
                    extras.put(parameterName, parameterValues.toArray(new String[]{}));
            }

        MyHttpServletRequestWrapper req = new MyHttpServletRequestWrapper(request, extras);
        for (Enumeration<String> e = req.getRequest().getParameterNames(); e.hasMoreElements();)
            logger.info("Parameter: [" + e.nextElement() + "]");
        ctx.setRequest(req);
        return null;
    }

Basic Steps: 1) intercept call 2) read the list of properties to inject in the body from the application.yml 3) create a list of extra parameters to add to the request 4) use the method of ServletRequestWrapper to add parameters to the request 5) log the body parameters resulting (here I see the one i've injected) 6) rewrite the request with the modified request 7) sniffing the call at the endpoint, I do not receive the body parameter that i've seen at the step 5

Now I'm not sure if ctx.setRequest is the right solution to sobstitute the request and this dirty job.

Anyone helping me?

thanks Paolo

mikeycohen commented 8 years ago

You can do this by simply adding a "pre" filter and in it add your headers:

RequestContext.currentContext.addZuulRequestHeader(HEADER_NAME, VALUE);

loliver1234 commented 8 years ago

Hi, as far as I understood correctly @paolo-rendano is speaking here about modifying body message, not adding the headers.

paolo-rendano commented 8 years ago

Hi @mikeycohen thanks for your time, Yes as @loliver1234 said, I'm speaking about body parameters (x-www-form-urlencoded). For header no problem, I'm already using them and they works, but it seems there is no support for body params.

aivans commented 8 years ago

@paolo-rendano you would do the same for modifying the body, just that you need to buffer the entire body content before modifying it. This means that you need to exhaust the request input stream. By default Zuul does not buffer request body.

liweiv commented 7 years ago

Map<String, List> qps = new HashMap<String, List>(); //copy request param map Map<String, String[]> qpmap = request.getParameterMap(); for (Map.Entry<String, String[]> entry : qpmap.entrySet()) { String key = entry.getKey(); String[] values = entry.getValue(); qps.put(key, Arrays.asList(values)); } ctx.setRequestQueryParams(qps);

rashad-farajullayev commented 6 years ago

@paolo-rendano , did you manage to alter request body in the "pre" filter. I am currently fighting with this problems, still with no success.

neshant commented 6 years ago

@rashad-farajullayev The Headers can be be modified easily, It is the body that is tricky part . I managed to achieve request and response modification by blocking the stream unless completely received. However I used a different framework for it. My requirement was to reverse proxy a server so that I can do modifications to request before sending it to server and again modify the response received before returning it to client. The framework I used was this https://github.com/membrane/service-proxy

sliard commented 4 years ago

+1 Header size is limited. For my case I have informations about connected user to pass to my microservice and it's to big to use header.

kinowarrior commented 4 years ago

+1 Unclear atm on how to proceed. The receiving service must have body parameters (x-www-form-urlencoded).

@mikeycohen - any suggestions?

kinowarrior commented 4 years ago

Ok, was able to override the body, and change the method from GET to POST, doing the following:


    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        context.addZuulRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        String body = String.format("a=%s&b=%s", a, b);

        final byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        context.setRequest(new HttpServletRequestWrapper(context.getRequest()) {
            @Override
            public ServletInputStream getInputStream() {
                return new ServletInputStreamWrapper(bytes);
            }

            @Override
            public int getContentLength() {
                return bytes.length;
            }

            @Override
            public long getContentLengthLong() {
                return bytes.length;
            }

            @Override
            public String getMethod() {
                return "POST";
            }
        });

        return null;
    }