Project

General

Profile

What does proxy.header do, that setenv.set-request-header doesn't?

Added by bwechner over 3 years ago

I just installed a Collabora CODE server under lighty. And it works charmingly with this:

$REQUEST_HEADER["Upgrade"] == "websocket" {
setenv.set-request-header = ("Connection" => "Upgrade")
proxy.header = ( "upgrade" => "enable" )
proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )
}
else {
proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )
}

I'm an ever curious person who want to understand what's going on. My understanding was, but proves to be wrong, that this should be functionally identical:

$REQUEST_HEADER["Upgrade"] == "websocket" {
setenv.set-request-header = ("Connection" => "Upgrade", "Upgrade" => "websocket")
proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )
}
else {
proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )
}

But it's not. Because the first ones a dream. And the second doesn't. Collabora simply doesn't load properly.

So what has me curious is what proxy.header is doing exactly. I can't find it documented.


Replies (9)

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by bwechner over 3 years ago

Wow, zero activity at all on these forums in the last 12 days? Is the lighty community waning? Being lost to nginx? Just curious. I like lighty, and use it extensively, for consistency with my OpenWRT routers that implement it, but I also ove an active community ;-). Maybe stackoverflow is where all the action is?

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by gstrauss over 3 years ago

Wow, zero activity at all on these forums in the last 12 days?

Incorrect. No response to your specific post is not an indication of no activity at all. It may suggest something else.

So what has me curious is what proxy.header is doing exactly. I can't find it documented.

proxy.header is documented in mod_proxy, the obvious location where someone would look for such documentation. I hope you will attempt a closer read of the existing (albeit imperfect) documentation.

proxy.header = ( "upgrade" => "enable" )
proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by bwechner over 3 years ago

A point taken re: activity, though the truth is midway between. There was zero activity on the Support forum in 12 days. Still when I zoom up a level Dev seems quiet for 17 days, Misc of 6 days and Feedback for 3 years ;-O.

But pardon me, of course I checked the doc. In fact I always check ALL the doc I can as thoroughly as I can before posting anything. For two obvious reasons 1) I'd have the answer rigth away rather than waiting and hoping for one, so completely self centered efficiency and b) yeah I provide support on numerous forums and I ignore questions that are so poorly researched or worded as to make a useful response that isn't critical quite challenging ;- 0, so the empathetic "I know whee you're coming from" motivation.

But the doc does precisely NOT explain what it does, nor, with due respect did you read my question well it seems. What I want to know is what it does that is different to or in addition to setting the Upgrade header in the request. Or is it perhaps the case that setting the Upgrade request header with setenv does not stick (transport to the downstream proxy.server?

What I could do, and would do, in time (maybe will do) is check the source itself to find out ;-). But I was sort of thinking someone might know as that's usually another significant investment, to download it, and start scanning it with na aim to understanding.

Thanks enormously though for the sign of life.

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by gstrauss over 3 years ago

You could help yourself more by doing less. You have a tendency towards complexity and, at least what you have posted here, that complexity can be wrong-headed.

I already posted the simple solution above, which you appear to have ignored in favor of more questions about the problems you have created for yourself.

.

Not everything you post will get a response. Not every question you ask must be answered. Some questions have more value than others, and you are not the sole arbiter of such value. Neither am I. However, I am the arbiter of whether or not I spend my time answering a question or not. Others may each make that choice for themselves.

A point taken re: activity, though the truth is midway between. There was zero activity on the Support forum in 12 days. Still when I zoom up a level Dev seems quiet for 17 days, Misc of 6 days and Feedback for 3 years ;-O.

Have you heard the story about the drunk looking for his house keys under a lamppost because that is where there is light?
lighttpd development is active and most lighttpd development does not take place on this forum.

If, as you say, you indeed attempt to help others on other forums, I hope that in the future you will try to be a bit more humble and to test your logic before posting your assumptions couched as (incorrect) "conclusions", or else you come across as "confidentally incorrect/ignorant", which is helpful to no one.

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by bwechner over 3 years ago

Seriously? You still didn't read the OP it seems. I asked a simple question, namely what does this do:

proxy.header = ( "upgrade" => "enable" )

because, guess what? I have just that implemented and said so, that it works charmingly, in my intro.

And then you suggest that I implement it and then suggest I 'ignored' the simple solution - which I have implemented (because it works) and you think a desire to understand what is going on, to better oneself, to learn how stuff works rather than just accepting the simple scripted solution might be wrong-headed.

Well I guess I agree. Striving to learn and understand stuff could indeed be wrong-headed if all you want is a working solution (I have that). Of course if what you want is to understand what's going on under the hood, it's not wrong-headed though. And it seems to me you didn't understand that as my intent when I ask clearly what the the difference between that and this is:

setenv.set-request-header = ("Upgrade" => "websocket")

Curiosity drives me. But you seem either unaware of that or intolerant of it. Not sure which. All the same, as grateful as I am for your responses (and I am) it does look like studying the code base might be less painful if all I get is judgments and misunderstandings that seem on the face of it to rest in either not reading the OP or my needing to work on clarity some. But I reread this OP and am puzzled how any of that is unclear. As in I have a working solution and it works well. But I have a curiosity.

If you want to understand the source of the curiosity it is this:

https://www.collaboraoffice.com/code/nginx-reverse-proxy/

where they recommend:

    location ~ ^/lool/(.*)/ws$ {
        proxy_pass https://localhost:9980;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $http_host;
        proxy_read_timeout 36000s;
    }

I short it seems the set an Upgrade, Connection and Host header in the request forwarded to localhost:9980

Now it turns out that in a world dominated by nginx and Apache support a literal like this isn't useful. Skills are. Understanding what's going on is.

And so I read mod_proxy, implemented the recommended solution (1 above) and it's good. But out of curiosity, observing that nginx has one syntax for the three headers it sets, and lighttpd uses two different ones (see solution 1 in OP) I tried a consistent approach, and it fails (that is scenario 2 in the OP0. Fine, I run with scenario 1.

I could then move right on. But I have a niggling curiosity. What is the difference? I can satisfy that a number of ways, ask here or on Stackoverflow

https://stackoverflow.com/questions/tagged/lighttpd

as it has a large active community (and I take a punt is all), or I can check the code base of either lighty to see what the working scenario does that the other does not.

Moreover, I tested both scenarios above pretty thoroughly before asking. Wondering what makes so apparently grumpy. I underscore "apparently" I too have no idea how you feel in person, we have but a few words typed as indicators ... and as an active listener by training rest assured, I hear, I feed back what I've heard and then await acknowledgement ro correction (either is fine).

I have an unsolved problem in the CLONE request in another thread. But slowly think StackOverflow might find more fruit in understanding this. But I shall take another (yet another I am not sort on efforts) to find answers in the wiki and docs on that one..

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by gstrauss over 3 years ago

Seriously? You still didn't read the OP it seems. I asked a simple question, namely what does this do:
proxy.header = ( "upgrade" => "enable" )

I pointed you to the documentation for mod_proxy which states very simply in plain English:

        #"upgrade" => "enable",
            # enable support for Upgrade: websocket

If you want to understand the source of the curiosity it is this:
https://www.collaboraoffice.com/code/nginx-reverse-proxy/

If you wanted to demonstrate that you knew how to intelligently ask a good technical question, you would have included such context in your original post. You did not.
A better source: https://www.nginx.com/blog/websocket-nginx/

lighttpd is not nginx, and those instructions do not apply to lighttpd.
I posted the two-line solution for lighttpd above: configure lighttpd mod_proxy to allow Upgrade and set the target backend for the reverse proxy.

For the rest of your scattershot questions: please ask a concise and well-scoped question in a new topic. The question you ask should reference existing documentation to demonstrate that you have tried to understand the documentation. Of course, you do not need to do that if you do not want to do so. You also might not get a response.

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by bwechner over 3 years ago

The OP is concise, it is clear and it is simple. It asks precisely what the doc does not state. Namely how is "enable support for Upgrade: websocket" different from `setenv.set-request-header = ("Upgrade" => "websocket")` of perhaps better said, why does the latter not work.

More detail is distracting and most of this thread has been to that fundamental question that as already concluded may be easier to extract from code analysis than asking a question.

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by gstrauss over 3 years ago

Let me repeat myself for the last time here:

I pointed you to the documentation for mod_proxy which states very simply in plain English:

        #"upgrade" => "enable",
            # enable support for Upgrade: websocket

It logically follows that if support is not enabled in mod_proxy for Upgrade: websocket, mod_proxy does not support Upgrade: websocket. This is basic logic. A configuration switch likely exists for a reason, or else it likely would not exist. Why are these such difficult concepts for you?

I will also repeat this:
lighttpd is not nginx, and those instructions do not apply to lighttpd.

You started with incorrect assumptions and have yet to retrace and reassess. My hunch is that this continues to be the source of your confusion.

The title of this post is: "What does proxy.header do, that setenv.set-request-header doesn't?"

proxy.header is a directive for mod_proxy and configures mod_proxy, as documented in mod_proxy documentation.
setenv.set-request-header is a directive for mod_setenv and configures mod_setenv, as documented in mod_setenv documentation.
Thus far, you appear unable to grasp that proxy.header = ( "upgrade" => "enable" ) is the only config directive for mod_proxy that is documented to "enable support for Upgrade: websocket" in mod_proxy.

Did you find other documentation in lighttpd's wiki to suggest otherwise? Or are you wrong-headedly imposing your own incorrect assumptions instead of reading the documentation literally and drawing logical conclusions based on the literal documentation?

RE: What does proxy.header do, that setenv.set-request-header doesn't? - Added by bwechner over 3 years ago

You can repeat yourself all you like, doesn't make you any better at interacting with willing learners or users no matter how supportive or passionate alas.

I have since done something much easier and less insulting to one's intelligence than this discourse and consulted dev docs and code. Alas it is not up to date, and the code base lacks any semblance of internal doc but it is relatively crisp and well laid out and digestible and does have an impressive history of documentation and development. Of course I have to expect that any honest reflection on the statelof light affronts you and risk insulting you winning insult in return, but hey.

I have some clues to my thirst for knowledge from that review just conducted out of interest.

  1. The Upgrade header is formally describes and hop to hop header is a message from one node to the next in the network not from the source to the destination and is interpreted and acted on by the network node it reaches.
  1. It follows that at some point lighty (or any server) drops the Upgrade header from the request it forwards. I can't quite find how or where that happens in the code base yet, and may not find it.
  1. In lighty state-engine it seems likely mod_setenv is called from in the readpost state (for it's request-header tweaks) and in the write state (for its reponse-tweaks). But I haven't quite found exactly how and when is functions are called yet. Only started a scan of the code base I guess and some hops around to see what I could divine.
  1. mod_proxy of course handles a subrequest and is called while in the handlreq state, explicitly from the function `http_response_prepare()` which is called in that state.
  1. A best guess at why setting the Upgrade header setenv does not work is that it simply does nothing. That is it sets the Upgrade header that was already set (zero effect) and it is mod_proxy that is introducing a new hop, and so abides by the hop to hop nature of the Upgrade header and drops it.
  1. The hypothesis is further, that mod_proxy by default just ignores it and leaves it dropped, unless it is asked explicitly in its config to forward it onwards.

Anyhow I think that porbbaly nails the gist of what's going on and answers my question.

You have made little effort to help, a lot to preach, some to belittle, and consistently repeat nonsense like lighty is no nginx as if I'm some abject idiot who can't tell the difference. I could waste my breath repeating that I has an ngninx config suggested and was trying to understand it. Not attempting to convince a short tempered judgmental developer that it's the same thing (whatever that might mean) or works the same way.

In fact the comparison also sheds some light on whats' going on. Namley ngninx has a `proxy_set_header` directive and that is not comparable to `setenv.set-request-header`.

What it also suggested was that the Connection header I set with setenv is functionless. Primarily because the web specs on-line point out that Upgrade and Connection are a pair of headers that work in concert hop to hop. That is, Connection too is a hop to hop header, and already set in the request so the setenv call does nothing. I removed it to confirm and indeed it is pointless.

There's a small win in tidiness ;-).

I contend that a simple response from someone knowledgeable (who yes, is not obliged by any measure to provide such a response) and respectfully interested in helping (so if I assume I'm now more knowledgable, that my hypothesis above is pretty solid) and I chose to respond, it might look like this:

The Connection and Upgrade headers are hop to hop headers in the web specifications, and are already set in the request coming in as stipulated by the condition:

$REQUEST_HEADER["Upgrade"] == "websocket" {
}

so setting them with the setenv module does nothing (they are already set). mod_proxy, which handles another hop when you configure it with:

proxy.server = ( "" => ( ( "host" => "localhost", "port" => "9980" ) ) )

is responsible for acting on and optionally forwarding these hop to hop headers. It's default position is to ignore Upgrade requests, and if it's forwarding a request to drop the Connection and Upgrade headers in the request it forwards. Transport of these headers can be enabled with:

        proxy.header = ( "upgrade" => "enable" )

==========================
Of course I may have made progress but I'm still guessing a bit. I'm not 100% sure that on a websocket upgrade these headers are even forwarded to the configured proxy.server, or if they rather, trigger a change in operational mode for mod_proxy.

I'd lap up learning in that space too, but it's optional. I think the gist of the answer is right ... maybe ;-).

And answer like this:

proxy.header is a directive for mod_proxy and configures mod_proxy, as documented in mod_proxy documentation.
setenv.set-request-header is a directive for mod_setenv and configures mod_setenv, as documented in mod_setenv documentation.

while better intentioned than some your comments (as in it actually conveys some information) is not helpful to me, as the distinction between mod this and mod that means little to me.

What I think is relevant is that mod_setenv tweaks request headers BEFORE mod_proxy sees them and if Connection and Upgrade headers are already there setting them achieves nothing, and mod_proxy manages the subrequest but by default ignores these headers (upgrade requests) but support can be enabled and it will act on them/forward them (not sure of that last bit).

Look, I mean you no ill. I see you are a solid developer and also happy to communicate. But take on board that interacting with you conjures images of Torvalds ;-). I hope that's flattering at some level ;-). I say it because you come across like Torvalds did to many in his community as a bright and dedicated guy, a solid contributor arguably a genius, but are so tired at some level of people and their apparent idiocy (a common problem very bright people have ;-) that your efforts to communicate come across as harsh, judgmental, preachy and intolerant at times. Take that or leave it, it's just feedback.

I might turn to look at CLONE requests. I have another (nonessential) service on the Nextcloud failing and I can't find why, but oddly the browser sends a CLONE request and the lighty access log never registers one but does register an oddly blank request. I have a gut feel it's WebDAV related and the writers of this request are using some non-standard extension as I can't find a CLONE request method on-line in a webdav specs (COPY yes, CLONE no). And it definitely sends a CLONE request ... Given I can't find it specced anywhere I'll go back to the authors of that request methinks and converse ...

    (1-9/9)