Skip to content

Pass same request method as original to sub-request made by ngx.location.capture #536

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

Closed
ram-nadella opened this issue Jul 17, 2015 · 5 comments

Comments

@ram-nadella
Copy link

Hey Mr. agentzh,

It's Ram, your old co-worker :)

Been playing around with nginx lua more these days. I am trying to do something with the power of nginx lua and mofo Sikora's aka @PiotrSikora :P cache purge module.

I've got it compiled by downloading source and adding cache purge repo to bundle folder and editing the configure script. I have a content_by_lua_file setup and in my lua code I am able to make a sub-request and when making the sub-request, I want to pass the same request method as the original request.

It appears that the method key in the options passed to ngx.location.capture expects one of the constants (eg. ngx.HTTP_GET) where as both ngx.var.request_method and ngx.req.get_method both return the request method string (GET).

Is there any way to auto-map the request method without doing a switch statement and compare the strings?

(Also, I am not seeing all the headers I expect in the sub-request. I see them all when I hit the location directly using curl but when I do a sub-request using local res = ngx.location.capture(...) and print headers by iterating over res.header I don't see them all)

Edit: ignore the part about the missing headers. That was my bad, I was not passing the args from the original request to the sub-request and the header I was expecting is only returned when those particular args are present. oops.

@agentzh
Copy link
Member

agentzh commented Jul 17, 2015

@ram-nadella Hey Ram. Long time no see! Glad you're on OpenResty :)

Regarding your question, yes, right now you need a Lua table to do the mapping, as in

local map = {
    GET = ngx.HTTP_GET,
    POST = ngx.HTTP_POST,
    ...
}

There is a pending pull request that enables ngx.location.capture to accept string values for the methods too:

#479

I'm going to merge that soon.

BTW, you may also find some of the lua-resty-http* libraries interesting:

https://github.com/bakins/lua-resty-http-simple
https://github.com/pintsized/lua-resty-http

They may be more efficient and more flexible than the ngx.location.capture + proxy_pass combination, depending on your use cases :)

@agentzh
Copy link
Member

agentzh commented Jul 17, 2015

@ram-nadella BTW, you may want to join the openresty-en mailing list for general discussions around NGINX and/or OpenResty :) Please see

https://openresty.org/#Community

Thanks!

@ram-nadella
Copy link
Author

Thanks @agentzh!!

I have joined the mailing list and took a look at the two modules you mentioned. Seems like the newer one is based on the other. Looks promising. I do have a question about the cache status response header (from add_header ... $upstream_cache_status;) not being available in the res.header of the sub-request. Will ask in the mailing list.

Closing this issue since the patch has already been contributed, hoping it gets merged soon. I have worked around the issue for now.

@ram-nadella
Copy link
Author

Found the answer to the header issue in #68 :) Used more_set_headers "X-Cache-Status: $upstream_cache_status"; and it worked like a charm.

@bor8
Copy link

bor8 commented Dec 22, 2019

Here is another example to intercept redirects that would lead away from your backend and thus stay on your own website. With GET/POST mapping, POST requests are passed through to the backend as such and are not replaced by GET calls. Note that the default Nginx docker container does not have Lua installed. Therefore, below is my Dockerfile (with somehow awesome nginx-extras package) and a docker-compose.yml file.

./dings/nginx_default.conf:

server
{
    listen       80;
    server_name  localhost;

    resolver 127.0.0.11:53;  # Docker-DNS. Needed for proxy_pass with variables inside!

    set $MY_SCHEME https;
    set $MY_HOST www.your-website.com;
    set $ziel "${MY_SCHEME}://${MY_HOST}";

    location /
    {
        rewrite_by_lua_block
        {
            local map = {
                GET = ngx.HTTP_GET,
                POST = ngx.HTTP_POST,
            }
            ngx.req.read_body()
            local res = ngx.location.capture('/redirect_checker' .. ngx.var.request_uri, {
                method = map[ngx.var.request_method],
                body = ngx.var.request_body
            })
            -- Detect/change redirect...
            local redirect_target = res.header.Location
            if redirect_target and res.status > 300 and res.status < 309 then
                -- ngx.log(ngx.ALERT, 'redirect_target: '..redirect_target)
                local redirect_target_changed, n, err = ngx.re.gsub(redirect_target, '^https?[:][/][/][^/]+', ngx.var.ziel)
                -- ngx.log(ngx.ALERT, 'redirect_target_changed: '..redirect_target_changed)
                return ngx.redirect(redirect_target_changed, 303)
            elseif res.status == 500 then
                return ngx.exit(500)
            else
                ngx.exec('@backend1')
                return ngx.exit(ngx.HTTP_OK)
            end
        }
    }

    location ~ ^/redirect_checker(.*)$
    {
        # ...
        proxy_pass http://backend1:80$1$is_args$args;
        # ...
    }

    location @backend1
    {
        # ...
        proxy_pass http://backend1:80$request_uri;
        # ...
    }
}

./dings/Dockerfile:

FROM ubuntu:18.04
LABEL maintainer="Ob Rzwo <obr2pd@gmail.com>"
ARG HTTP_PROXY
ENV HTTP_PROXY ${HTTP_PROXY}
ARG HTTPS_PROXY
ENV HTTPS_PROXY ${HTTPS_PROXY}
ARG NO_PROXY
ENV NO_PROXY ${NO_PROXY}
ENV http_proxy ${HTTP_PROXY}
ENV https_proxy ${HTTPS_PROXY}
ENV no_proxy ${NO_PROXY}
RUN touch /etc/apt/apt.conf
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \
        iproute2 \
        mc \
        mlocate \
        nginx-extras \
        tcpflow \
        vim \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stdout /var/log/nginx/error.log
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]

docker-compose.yml:

version: "3"
services:
    dings:
        build:
            args:
                HTTP_PROXY: ${HTTP_PROXY}
                HTTPS_PROXY: ${HTTPS_PROXY}
                NO_PROXY: ${NO_PROXY}
            context: ./dings/
        # image: nginx:1.17.6
        # networks:
            # blah:
        ports:
            - 80:80
        volumes:
            - ./dings/nginx_default.conf:/etc/nginx/sites-available/default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants