Ask Reuben

Getting The IP Address

How can I get the IP address of the user of the Genero web application?

How can I get the IP address of the consumer of the Genero web service? 

In the Genero Application Server architecture, a request to start a Genero application comes in via a Web Server that results in the launch of the application.  The Web Server has some information about the request and that information can be passed through to the Genero application.  This includes information such as the IP address.

The information coming from the Web Server through the Genero Application Server to the Genero application is passed through as environment variables.  Your Genero application can read this information via the FGL_GETENV() command.  The environment variables coming from the Web Server have their names prefixed with FGL_WEBSERVER_,  this includes FGL_WEBSERVER_REMOTE_ADDR for the IP address.  So you can get the IP address as

LET ip_address = FGL_GETENV("FGL_WEBSERVER_REMOTE_ADDR")

Any HTTP request headers are also sent through and they will be prefixed by FGL_WEBSERVER_HTTP_.  The Genero application will also get environment variable information available from the proxy process and these will be prefixed FGL_VMPROXY_ such as FGL_VMPROXY_START_URL.

To find out what is available, you can do a test like

RUN "env | grep 'FGL_' | sort > /tmp/yourname.env "

and you should see a number of variables beginning FGL_VMPROXY and FGL_WEBSERVER.  Also if you look in the proxy logs, you will see the FGL_VMPROXY information e.g.

grep "Info-Environment" uaproxy-sessionid*.log | grep "FGL_"
11:58:00.995647 0.000846 [log.c:1571] 31042 0 - "Info-Environment" FGL_VMPROXY_PROXY="/Applications/fourjs/gas/3.20.09/bin/uaproxy" --development
11:58:00.995673 0.000873 [log.c:1571] 31042 0 - "Info-Environment" FGL_VMPROXY_START_URL=http://localhost:6394/ua/r/gwc-demo
...

… as well as the information from the Web Server in the request details e.g. (split over multiple lines to add readability)

11:58:00.998192 0.003392 [gasrequest.c:1673] 31042 0 REQID=194;HTTP=0 "Receiving UA" GET /ua/r/gwc-demo?ConnectorURI=&Bootstrap=done HTTP/1.1\r\n
X-FourJs-Client-Features: prompt\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36\r\n
Accept: application/octet-stream\r\n
Sec-Fetch-Dest: empty\r\n
Referer: http://localhost:6394/ua/r/gwc-demo\r\n
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8\r\n
Accept-Encoding: gzip, deflate, br\r\n
Sec-Fetch-Mode: cors\r\n
Sec-Fetch-Site: same-origin\r\n
X-FourJs-Client: GBC/1.00.58-202009221650\r\n
Host: localhost:6394\r\n
Connection: keep-alive\r\n
Cookie: lang=en-US; Genero-SID=607183f8cdb36a7a12a81963bace4d0d\r\n
Content-Length: 0\r\n
X-FourJs-Environment-Variable-REMOTE_ADDR: 127.0.0.1\r\n
X-FourJs-Environment-Variable-SERVER_NAME: localhost\r\n\r\n

… note the X-FourJS-Environment-Variable-REMOTE_ADDR header which is what populates the FGL_WEBSERVER_REMOTE_ADDR environment variable.

For Web Services  we have a similar process however there is a trap a lot of people seem to run into.  With a web service you need to remember that an individual Genero Web Service server program can be used to service many requests from many different clients.  That is we can’t inject these variables into the environment because the values may change for each request.  (This is also why you need to be careful with modular and global variables in web service programs, and database connections and cursors that maybe preserved from one request to the next).  The common mistake we see is developers having used FGL_GETENV() to retrieve this information for their Genero web application trying to use the same FGL_GETENV() technique to retrieve this information in their Genero web service.

Instead the  information for each individual request is passed through to the web service program as request headers.  The header names are prefixed with “X-FourJs-Environment-Variable-“.

For the older low-level web services, you could retrieve this information via the com.HTTPServiceRequest.getRequestHeader() method.  e.g.

DEFINE req com.HTTPServiceRequest
...
LET ip_address = req.getRequestHeader("X-FourJs-Environment-Variable-REMOTE_ADDR")

For the newer high-level web services code you have two techniques, you can use the WSHeader attribute as part of the web service function definition to pass the information in as a parameter of the function e.g.

FUNCTION function-name( ...
     ip_address STRING ATTRIBUTE(WSHeader, WSOptional, WSName="X-FourJs-Environment-Variable-REMOTE_ADDR")
...)

There is a second technique which will be available soon (if not already) which is to use the WSContext functionality.  This is a private DICTIONARY variable for each web service module which will be populated on each request with information including what has been sent as request headers.

PRIVATE DEFINE context DICTIONARY ATTRIBUTE(WSContext) OF STRING
...
LET ip_address = context["Variable-REMOTE-ADDR"]

You can read more about these techniques, either here in the Genero Application Server documentation, and more specifically about Web Services here in the BDL documentation.

The key thing to remember is that the technique you use for web applications is different from web services, and the reason it is different is a web service server program can service many different requests from many different users in its lifetime, and so the value may be different in each request.