Modify response header with nginx

11,058

Solution 1

"Why is it so darned difficult to modify a response header??"

Some people need to make a living too!

Ah, that wasn't the real question. Damn. Try this

map $upstream_http_x_xsplocation $m_replaceme {
    ""  "";
    "~^.*/page.xsp/(.*)$" "/$1";
    "~.*" "";
}

location / {
      proxy_pass   http://localhost:81/database.nsf/page.xsp/;
      proxy_hide_header X-XspLocation;
      add_header X-XspLocation  $m_replaceme;
}

Tested with nginx/1.14.2

Solution 2

Added always works for me

proxy_hide_header X-XspLocation;
add_header X-XspLocation  $m_replaceme always;
Share:
11,058
D.Bugger
Author by

D.Bugger

Updated on September 18, 2022

Comments

  • D.Bugger
    D.Bugger over 1 year

    I'm trying to configure nginx as a reverse proxy server for a web application on a back-end Domino server. We have 99.9% working, but that last 0.1% is really bugging me.

    I'll explain. In some cases, the application returns a partial refresh with a special response header called X-XspLocation. If it exists, it contains a url to be redirected to by the client. It's a header generated and used by the XPages environment, my code itself doesn't set or read it. Its value is then:

    http://localhost:81/database.nsf/page.xsp/ThankYou
    

    and I want it to be just this: /ThankYou

    I tried in a million ways, but it seems impossible to alter its value. As soon as I use proxy_hide_header X-XspLocation; no new headers can be added using add_header! If I leave the hide out, I get double values in the header, so I know my replacement value is correct. Here's my latest attempt that failed:

    map $sent_http_x_xsplocation $xsplocation_new {
        "~http://localhost:81/database.nsf/page.xsp/(.*)" "/$1";
    }
    server {
        ...
        location / {
          proxy_pass   http://localhost:81/database.nsf/page.xsp/;
          # redirect X-XspLocation
          proxy_hide_header X-XspLocation;
          add_header X-XspLocation $xsplocation_new;
          #add_header X-XspLocation2 $xsplocation_new;
        }
    }
    

    I even tried with njs to change the header, it probably failed because I don't know how to use js_set or js_content to call a function that doesn't return anything.

    Why is it so darned difficult to modify a response header??

    The real question is of course: how can I make this work?? Thanks for your assistance!!

    More info

    In order to prove that the map works, I tested with the following:

        location / {
          proxy_pass   http://localhost:81/database.nsf/page.xsp/;
          # redirect X-XspLocation
          # proxy_hide_header X-XspLocation;
          # add_header X-XspLocation $xsplocation_new;
          add_header X-XspLocation2 $xsplocation_new;
        }
    

    The result is now that the original header plus the new header X-XspLocation2 are present, and the 2nd one is exactly what I need in X-XspLocation.

    By the way, nginx version: nginx/1.18.0 on Ubuntu 16.04.6 LTS (My client's provider's system, not mine...)

    The full censored config file

    map $sent_http_x_xsplocation $xsplocation_new {
        "~http://localhost:81/database.nsf/page.xsp/(.*)" "/$1";
    }
    
    server {
        listen       4443 ssl;
        server_name  www.myclient.nl;
    
        ssl_certificate       /etc/nginx/ssl/www.myclient.nl.pem;
        ssl_certificate_key   /etc/nginx/ssl/www.myclient.nl.pem;
    
        # do not allow google to index this website
        # TODO: remove when going to production
        add_header  X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";
    
        # replace redirects in response header fields Location and Refresh
        proxy_redirect http://localhost:81/database.nsf/page.xsp/ https://www.myclient.nl:4443/;
        proxy_redirect http://localhost:81/ https://www.myclient.nl:4443/;
    
        # tell domino not to encode the response so we can use sub_filter
        proxy_set_header Accept-Encoding "";
    
        # substitute response content
        sub_filter 'localhost:81'       'www.myclient.nl:4443';
        sub_filter 'www.myclient.nl' 'www.myclient.nl:4443'; #TODO: remove when going production
        sub_filter '/database.nsf/page.xsp/'  '/';
        sub_filter '/database.nsf/'           '/other/';
        sub_filter_once off;
    
        # Domino
        location = /favicon.ico {
          access_log off; log_not_found off;
          proxy_pass http://localhost:81/database.nsf/Images/favicon.ico/%24file/favicon.ico;
        }
    
        # root / homepage
        location = / { proxy_pass   http://localhost:81/database.nsf/page.xsp/HomePage; }
    
        #login
        location /names.nsf { proxy_pass http://localhost:81/names.nsf; }
    
        # XPages
        location /xsp/ { proxy_pass  http://localhost:81/xsp/; }
        location /domjava/ { proxy_pass  http://localhost:81/domjava/; }
    
        # training
        location ~* ^/.*-training/(.*) {
          proxy_pass http://localhost:81/database.nsf/page.xsp/training/$1;
        }
        location ~* ^/(.*)-training$ {
          proxy_pass http://localhost:81/database.nsf/page.xsp/$1;
        }
    
        # IMAGES
        # image resources - any case insensitive match with 'images'
        location ~* '/images/(.*)$' {
          proxy_pass   'http://localhost:81/database.nsf/Images/$1';
        }
        # images referenced from css in file.xsp have this url, redirect to backend correctly
        location ~* '/file.xsp/images/(.*)$' {
          proxy_pass   'http://localhost:81/database.nsf/Images/$1';
        }
    
        # file resources
        location /file.xsp/ { proxy_pass  http://localhost:81/database.nsf/file.xsp/; }
    
        # other resources
        location /other/ { proxy_pass   http://localhost:81/database.nsf/; }
    
        # all other urls
        location / {
          proxy_pass   http://localhost:81/database.nsf/page.xsp/;
          # redirect X-XspLocation
          #add_header X-XspLocation $xsplocation_new always;
          proxy_hide_header X-XspLocation;
          add_header X-XspLocation $xsplocation_new;
        }
    }
    
  • D.Bugger
    D.Bugger almost 4 years
    It's always money, isn't it... :-(
  • D.Bugger
    D.Bugger almost 4 years
    Nope, doesn't work. The header X-XspLocation disappears but the new one isn't created. I forgot to mention that most of it works if I add a header, but not for the original header. I'll modify the question.
  • Gerard H. Pille
    Gerard H. Pille almost 4 years
    Did I forget to mention that I tested it? "Its value is then something like:". It might help to show us an exact value.
  • D.Bugger
    D.Bugger almost 4 years
    Nope. The chances of anything coming from Mars... and still it doesn't work here. I even left out the hide, and changed the header name to X-XspLocation2: no dice.
  • D.Bugger
    D.Bugger almost 4 years
    I can see if I can anonymize the whole configuration file and post that.
  • Gerard H. Pille
    Gerard H. Pille almost 4 years
    You did replace "$sent_http_x..." by "$upstream_http_x..." ?
  • D.Bugger
    D.Bugger almost 4 years
    Of course, nothing happened. The map I used on $sent_http_x_xsplocation works. It seems to be the proxy_hide_header that doesn't work. Or works too well...
  • Gerard H. Pille
    Gerard H. Pille almost 4 years
    Without the hide, the replacement gets appended to the original value, as expected.
  • D.Bugger
    D.Bugger almost 4 years
  • D.Bugger
    D.Bugger almost 4 years
    And with the hide both headers disappear...
  • D.Bugger
    D.Bugger almost 4 years
    Most likely the Ubuntu installation is somehow corrupt. Our short term workaround: instead of using the standard XPages call redirectTo, I used getResponse().setHeader with a name of my own and set that to the value I want in X-XspLocation. I added some rules to the nginx config file to move that header to the desired header.
  • Gerard H. Pille
    Gerard H. Pille almost 3 years
    Nog een weekje, en we trekken weer zuidwaarts.
  • D.Bugger
    D.Bugger almost 3 years
    Het is nu al 34°C hier, niet normaal voor half juni. Goede reis, en houd de neus proper!
  • Gerard H. Pille
    Gerard H. Pille almost 3 years
    De météo ziet er bijzonder slecht uit bij jullie, donderdag. Het zal geen plezierritje worden.
  • D.Bugger
    D.Bugger almost 3 years
    Deze site is redelijk betrouwbaar: meteorama.fr en ik zie niets wat ik echt slecht zou moeten noemen. Vab
  • D.Bugger
    D.Bugger almost 3 years
    Oeps... Vannacht was vreselijk, onweer, 20mm water, storm, rukwinden, zowat het einde der tijden...
  • Gerard H. Pille
    Gerard H. Pille almost 3 years
    Jullie maken er daar wel een gewoonte van. Wegens een fysisch akkefietje vervroegd teruggekeerd, tussen Vienne en Lyon daar een hoeveelheid water over ons gekregen, nog nooit zelf ervaren. Woog natuurlijk niet op tegen wat ze in de Ardennen en Duitsland over zich heen kregen.
  • D.Bugger
    D.Bugger almost 3 years
    Dat was een paar dagen geleden zeker. Het is hier ook wel nat geweest, iets van 30mm op een dag, maar bij Lyon kan het inderdaad flink spoken soms. Hoop dat de terugreis verder zonder incidenten was.
  • Gerard H. Pille
    Gerard H. Pille almost 3 years
    Nul incidenten, en een plezier om eens niet in de blakende zon te moeten rijden - geen liefhebber van airco.
  • D.Bugger
    D.Bugger almost 3 years
    Da's mooi! Dus een goede vakantie geweest. Nu nog de Covid weg en de tijgermuggen... Ik weet intussen niet meer hoe ik bovenstaand probleem heb opgelost. Fijne zomer verder!