badkins
2021-9-30 16:17:48

I’m trying to get the scheme and host of the current web request. When I inspect (request-uri req) I get the following: (struct:url #f #f #f #f #t (#(struct:path/param user ()) #(struct:path/param 45ee5a16a2 ()) #(struct:path/param view ()) #(struct:path/param 1 ())) () #f) I suspect this is because I’m redirecting using relative URLs. What’s the easiest way to get the scheme and host of the current request? Use the headers?


badkins
2021-9-30 16:19:12

Hmm.. I see a host header, but there is no scheme info in the request struct.


badkins
2021-9-30 16:23:08

No, it wasn’t due to the relative URL redirect, the info is missing when I use an absolute URL also.


badkins
2021-9-30 16:23:51

Any pointers @jeapostrophe?


soegaard2
2021-9-30 16:25:57

What’s the context - i.e. where is the value in req coming from?



badkins
2021-9-30 16:27:39

More specifically: (define (axio-app-init environment route) (let* ([ instance-id (string->number (vector-ref (current-command-line-arguments) 0)) ] [ env (get-app-env environment) ] [ port (+ (app-env-port-base env) instance-id) ] [ axio-context (axio-init environment) ]) (void (serve #:dispatch (seq:make (log:make #:format log:extended-format #:log-path (format "~a.log" (symbol->string environment))) (lift:make (λ (request) (front-controller axio-context request route)))) #:port port)) (do-not-return)))


badkins
2021-9-30 16:28:22

(require (prefix-in lift: web-server/dispatchers/dispatch-lift) (prefix-in log: web-server/dispatchers/dispatch-log) (prefix-in seq: web-server/dispatchers/dispatch-sequencer) web-server/web-server)


soegaard2
2021-9-30 16:30:57

It’s just odd, that the scheme and host is missing. Could it be the first dispatcher that is removing it?


soegaard2
2021-9-30 16:31:13

Probably not.


badkins
2021-9-30 16:31:22

Yeah, that would be quite odd.


badkins
2021-9-30 16:33:49

I wonder if it’s due to my nginx proxy config.


soegaard2
2021-9-30 16:37:01

That’s probably it. I think, I have the same problem with a racket web-server behind nginx.


badkins
2021-9-30 16:37:50

No, I just checked. I went directly to the Racket web server (bypassing nginx), and the struct fields are still #f :(


badkins
2021-9-30 16:39:00

I can workaround with (define scheme-host "<https://foo.bar.com>") , but that’s hacky


soegaard2
2021-9-30 16:42:08

I was about to say, that your first suggestion (looking at the headers) sounds as the right thing. According to https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ nginx passes extra information in headers:

> By default, NGINX redefines two header fields in proxied requests, “Host” and “Connection”, and eliminates the header fields whose values are empty strings. “Host” is set to the $proxy_host variable, and “Connection” is set to close. But … if it doesn’t work when bypassing nginx, I have no clue about what’s going on.


badkins
2021-9-30 16:42:51

I’ll try and dig into the web server code later. First I need to meet a deadline :)


samdphillips
2021-9-30 17:08:03

I don’t think there is anywhere in the HTTP protocol where the scheme is set. In other web frameworks (in other languages) I’ve used either the server passes that knowledge back to the application code (because it got a request via https vs. http) or it needs to be hardwired in.


samdphillips
2021-9-30 17:09:04

Maybe if you are reverse proxying or through a loadbalancer there can be X-Forwarded-For header set.


samdphillips
2021-9-30 17:10:30

X-Forwarded-For only captures the IP. In AWS (maybe others) there is also set X-Forwarded-Proto and X-Forwarded-Port



badkins
2021-9-30 17:20:12

Maybe those fields in the URI struct are only set when creating a request vs. receiving one in the web server.


samdphillips
2021-9-30 17:27:25

Quite possibly. I figured they were reused because why have more than one URI type in the language.


djholtby
2021-9-30 22:10:01

It’s grabbed by using string->url on the URL component of the HTTP request, which does not include the host or the scheme. You can grab the host from either the Host header (if a direct connection), or X-Forwarded-Host (if reverse proxied). The usual snippet used for proxy headers (on nginx) is something like this: proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; This also sets X-Forwarded-Proto to be the request’s scheme. If connecting directly to the racket server you’d need to compare request-host-port with which is the http and which is the https port