Get Request from happstack-lite API - happstack

How would I go about getting the Request data from the happstack-lite API? I'm trying to get the client's IP address. From what I can tell it's in Request::rqPeer, and I get confused trying to dive into the monadic-layers of the happstack API.

You can use askRq in any ServerMonad to get at the Request, which you could pattern match on with record syntax to get the client hostname:
do Request {rqPeer = (host,_)} <- askRq
ok $ "Your IP: " ++ host

Related

HAProxy 2.0 LUA Fetches API - how to get request details and how to pass variable back to HAProxy

I have been scouring the internet with no luck. I have a basic LUA script for HAProxy, which looks like this:
core.Info("LUA script for parsing request ID element - loaded");
function parseId(txn, salt)
local payload = txn.sf:req_body()
-- parses hex value from element named "ID". Example payload: {"Platform":"xyz.hu","RecipientId":"xyz.hu","Channel":"xyz","CallbackURL":"http://x.x.x.x:123","ID":"5f99453d000000000a0c5164233e0002"}
local value = string.sub(string.match(payload, "\"ID\":\"[0-9a-f]+\""), 8, -2)
core.Info("ID : " .. value)
return value
end
-- register HAProxy "fetch"
core.register_fetches("parseId", parseId)
What it does is what it says: takes a 32 characater long ID from an incoming request. In the HAProxy config file, the result is used for sticky-session handling:
stick-table type string len 32 size 30k expire 30m
stick on "lua.parseId" table gw_back
This produces two lines of log for each request:
ID: xyz which is logged from the LUA script
The detailed request data which is logged from the HAProxy config file using "log-format", e.g.:
Jan 20 22:13:52 localhost haproxy[12991]: Client IP:port = [x.x.x.x:123], Start Time = [20/Jan/2022:22:13:52.069], Frontend Name = [gw_front], Backend Name = [gw_back], Backend Server = [gw1], Time to receive full request = [0 ms], Response time = [449 ms], Status Code = [200], Bytes Read = [308], Request = ["POST /Gateway/init HTTP/1.1"], ID = [""], Request Body = [{"Platform":"xyz.hu","RecipientId":"xyz.hu","Channel":"xyz","CallbackURL":"http://x.x.x.x:123","ID":"61e9d03e000000000a0c5164233e0002"}]
I wanted to extend logging due to some strange issues happening sometimes, so I wanted to one (or both) of below approaches:
Pass the "ID" value back from the LUA script into the HAProxy config as a variable, and log it along with the request details. I can log the full request body, but don't want to due to GDPR and whatnot.
Get some request details in the LUA script itself, and log it along with the ID.
So, basically, to be able to connect the ID with the request details. If multiple requests are coming to same URL very quickly, it is difficult to find which of them belongs to a specific ID. However I couldn't accomplish these.
For the first one, I added this line into the LUA before returning the "value" variable:
txn:set_var("req_id", value)
I was hoping this would create a variable in HAProxy called "req_id", and I can log it with "log-format", but all I got was empty string:
ID = [""]
For the second one, I'm at a complete loss. I'm not able to find ANY documentation on these. I have been scouring the internet with no luck. E.g. the txn.sf:req_body() function which I know is working, I simply cannot find it documented anywhere, so I'm not sure what other functions are available to get some request details.
Any ideas for either or both of my approaches? I'm attaching my full HAProxy config here at the end, just in case:
global
log 127.0.0.1 len 10000 local2 debug
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
lua-load /opt/LUA/parseId.lua
stats socket /etc/haproxy/haproxysock level admin
defaults
log global
option httplog
option dontlognull
mode http
timeout connect 5000
timeout client 50000
timeout server 50000
# Request body is temporarily logged in test environment
log-format "Client IP:port = [%ci:%cp], Start Time = [%tr], Frontend Name = [%ft], Backend Name = [%b], Backend Server = [%s], Time to receive full request = [%TR ms], Response time = [%Tr ms], Status Code = [%ST], Bytes Read = [%B], Request = [%{+Q}r], ID = [%{+Q}[var(txn.req_id)]], Request Body = [%[capture.req.hdr(0)]]"
frontend gw_front
bind *:8776
option http-buffer-request
declare capture request len 40000
http-request capture req.body id 0
http-request track-sc0 src table gw_back
use_backend gw_back
backend gw_back
balance roundrobin
stick-table type string len 32 size 30k expire 30m
stick on "lua.parseId" table gw_back
# Use HTTP check mode with /ping interface instead of TCP-only check
option httpchk POST /Gateway/ping
server gw1 x.x.x.x:8080 check inter 10s
server gw2 y.y.y.y:8080 check inter 10s
listen stats
bind *:8774 ssl crt /etc/haproxy/haproxy.cer
mode http
maxconn 5
stats enable
stats refresh 10s
stats realm Haproxy\ Statistics
stats uri /stats
stats auth user:password

Advice on how to set up a connection between nancy service and server

I am working on a project whereby we have sites (developed with ruby on rails) hosted on an Ubuntu server using tomcat. We want these sites to make HTTP calls to a service developed using Nancy. We have this working locally whereby the service is hosted on a machine that we can call within our network. We cannot however get it working when live. Here is an example call:
def get_call(routePath)
started_at = Time.now
enc_url = URI.encode("#{settings.service_endpoint}#{routePath}")
uri = URI.parse(enc_url)
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Get.new(uri.request_uri)
resp = http.request(req)
logger.bench 'SERVICE - GET', started_at, routePath
return resp if response_ok?(resp)
end
When working locally the settings are as follows:
settings.service_endpoint = http://10.10.10.27:7820
routePath = /Customers
When we upload it to the server we use the following:
settings.service_endpoint = http://127.0.0.1:24099
routePath = /Customers
We currently get the following error:
SocketError at /register
initialize: name or service not know
with the following line being highlighted:
resp = http.request(req)
Are we completely wrong with the IP being called. Should it be 127.0.0.1, localhost. 10.10.10.27 or something entirely different? The strange thing is we can do a GET call via telnet in our Ubuntu server (telnet 127.0.0.1 24099) so that must mean the server can make the calls but the site hosted on the server cannot. Do we need to include a HTTP proxy (have read some reference to that but dont really know if its needed).
Apologies if its obvious but we have never tried anything like this before so its all very perplexing. Any further information required just let me know.
We changed the service_endpoint to localhost and it worked. Not sure if this is because it didnt like "http://" or some other reason. Any explanation as to why this is the case would be much appreciated, just so we know. Thanks!

Yammer: can no longer access messages from other network using Yammer API

I am part of two Yammer networks N1 and N2. N1 is my home network.
Since a few days/weeks, I can no longer access messages from the N2 network using the Yammer API.
Here's how I get messages from N1 (which is successful):
get auth code by browsing to https://www.yammer.com/dialog/oauth?client_id=[clientid]&redirect_uri=[redirecturi]
results in [authcode_N1] (after loggin in; in URL)
perform GET https://www.yammer.com/oauth2/access_token.json?client_id=[clientid]w&client_secret=[secret]&code=[authcode_N1]
results in JSON with [access_token1] (note: there is only one token in response)
get messages by performing GET https://www.yammer.com/api/v1/messages.json, with HTTP header Authorization: Bearer [access_token1]
result: messages from N1 only
Here's how I try to get messages from N2 (which fails):
get auth code by browsing to https://www.yammer.com/N2/dialog/oauth?client_id=[clientid]&redirect_uri=[redirecturi].
note 'N2' in URL
results in [authcode_N2] (wich is different then the one previously obtained for N1)
perform GET https://www.yammer.com/oauth2/access_token.json?client_id=[clientid]w&client_secret=[secret]&code=[authcode_N2]
results in status 403, body 'Your network is not allowed to request an OAuth token for this Application'
Here's another attempt to get messages from N2 (which fails too):
get tokens by performing GET on https://www.yammer.com/api/v1/oauth/tokens.json, with HTTP header 'Authorization: Bearer [access_token1]
results in JSON with two elements, both with a different network ID (one for N1 and one for N2) and a token for each network
note that the token for N1 in this JSON matches [access_token1] above
let's call the token for N2 in this JSON [access_token2]
perform GET https://www.yammer.com/api/v1/messages.json, with HTTP header Authorization: Bearer [access_token2]
response: {"response":{"stat":"fail","code":17,"message":"Attempt to access a protected resource failed."}}
Note that [clientid], [secret] and [redirecturi] are from our application. On its settings page (titled 'Registered applications') there is a green checkmark in the 'enabled' column and none in the 'global' column. In the 'Basic Info' section for this application, there is a green 'Deploy' button.
Maybe this is causing the problem (I have found some user responses in this direction about similar problems (see Yammer REST API: How to get access tokens for external networks?))? But this would not explain why getting the messages from N2 used to work previously...
Please let me know how I could get the data from N2.
Thanks in advance!
Use GET https://www.yammer.com/api/v1/oauth/tokens.json?access_token= with your N1 token to generate a token for all of your networks.
Read the N2 token from the response and call the yammer API with this token.
You can see how it works on the "famous" zapier "Api Quirks"
https://zapier.com/blog/api-quirks-yammer-external-networks/

How to use $remote_addr with rails and nginx secure_link

I have a rails application that makes calls to another server via net::http to retrieve documents.
I have set up Nginx with secure_link.
The nginx config has
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr mySecretCode";
On the client side (which is in fact my rails server) I have to create the secure url something like:
time = (Time.now + 5.minute).to_i
hmac = Digest::MD5.base64digest("#{time}/#{file_path}#{IP_ADDRESS} mySecretCode").tr("+/","-_").gsub("==",'')
return "#{DOCUMENT_BASE_URL}/#{file_path}?md5=#{hmac}&expires=#{time}"
What I want to know is the best way to get the value above for IP_ADDRESS
There are multiple answers in SO on how to get the ip address but alot of them do not seem as reliable as actually making a request to a web service that returns the ip address of the request as this is what the nginx secure link will see (we don't want some sort of localhost address).
I put the following method on my staging server:
def get_client_ip
data=Hash.new
begin
data[:ip_address]=request.ip
data[:error]=nil
rescue Exception =>ex
data[:error]=ex.message
end
render :json=>data
end
I then called the method from the requesting server:
response = Net::HTTP.get_response(URI("myserver.com/web_service/get_client_ip"))
if response.class==Net::HTTPOK
response_hash=JSON.parse response.body
ip=response_hash["ip_address"] unless response_hash[:error]
else
#deal with error
end
After getting the ip address successfully I just cached it and did not keep on calling the web service method.

How to get the correct proxy URL in Apigee?

In my Apigee API Proxy, I need to get the environment URL that is defined in my configuration, so that I can send it as part of the response.
For example: http://myorg-test.apigee.net/pricing
However, when I try to get it using proxy.url, I get an aliased path, like http://rrt18apigee.us-ea.4.apigee.com/pricing
Currently, I'm trying to get it like:
var response = {
proxyUrl : context.getVariable("proxy.url"),
};
Here is a work around. You can try to get the following variables and create the entire URL
Get the request scheme (http or https) from request.Headers.X-Forwarded-Proto (if you are using cloud version) or client.scheme if you are using on-prem
Get the host name from request.host
Get the entire request path from request.path
Entire list of URL query params and list from message.querystring
You can then construct the entire request URL.
( I know this should not be this painful. Please log a bug in case proxy.url is really broken. )

Resources