How can Plack debug a request? - perl

I am debugging an HTTP Client with Plack, where the plack server listens on port 80 and the client sends request. How can I see the client request using Plack? I am trying to do something like this:
my $app = sub {
my $self = shift;
[200, ['Content-Type' => 'text/html'], [ $self ]];
};
How can I debug the request?

PSGI/Plack is an abstraction around HTTP. Its goal is not to have to bother about the implementation details (as much as without it). At the time your app sees the request, it's already been parsed into the $env and is in Plack's representation.
You could monkey-patch something into Plack::HTTPParser::PP to dump the $chunks out to see what's coming in. You would have to set PLACK_HTTP_PARSER_PP=1 in your environment to make sure it loads the pure Perl version.
However that seems really tedious. If you're on Linux, you can use netcat (nc). Listen on your port, and send requests there with the client you are testing.
$ nc -l 3000
GET / HTTP/1.1
Host: localhost:3000
User-Agent: curl/7.68.0
Accept: */*
And on another terminal...
$ curl localhost:3000
If you don't care about the exact representation, but only about whether it's got the right stuff in it after parsing, start by dumping out $env in your Plack app instead.

Related

Very long response time from HTTP REST request on Extreme OS switch

I'm trying to use REST API on Extreme OS to retrieve information on interfaces, PoE etc.... It works perfectly fine with Cisco switches, but now I'm trying the same thing on an Extreme Networks switch. However the delay between my HTTP GET request and the answer is very long (~7 minutes). On Cisco it takes ~15 seconds.
I have used tcpdump, but it doesn't know how to interpret or solve the reset and keep-alive (response start at frame 1302).
tcpdump capture
I use the following command to make my HTTP request:
curl -k -v http://<ip>/rest/restconf/data/openconfig_interfaces:interfaces/ -u "<user>:<password>"

What is sent to the server when I modify the Host: header with FiddlerScript?

I'm using FiddlerScript to modify the request as follows:
oSession.oRequest["Host"] = "www.example.com";
oSession["x-overridehost"] = "Dotted.Quad.IP.Address";
Now, when I inspect one of the modified sessions, I see this:
GET https://www.example.com/rest/of/url HTTP/1.1
Host: www.example.com
My question is whether the host name from the full URL is passed to the server, or if the server is only sent something like:
GET /rest/of/url HTTP/1.1
in the first line of the request. I don't have access to the server's encryption key, so I can't use something like Wireshark to examine the exact traffic that is going out over the network.
If it helps at all, I see the following when performing a GET to an application running on my local machine:
GET http://localhost:51425/ HTTP/1.1
Host: localhost:51425
.
.
.
GET should always include a fully qualified domain name.

How to send HTTP Commands through Port 80

Breif Description of what I am trying to accomplish. So I am working with Crestrons Simpl+ software. My job is to create a module for a sound masking system called QT Pro. Now, QT Pro has an API where you can control it via HTTP. I need a way to establish a connection with the QT Pro via HTTP( I have everything I need, IP, Username, Password).
Whats the problem? I have just started working with this language. Unfortunately there isn't as much documentation as I would like, otherwise I wouldn't be here. I know I need to create a socket connection via TCP on port 80. I just don't know what I'm supposed to send through it.
Here is an example:
http://username:password#address/cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value
&mN=Value&auxA=Value&auxB=Value&autoR=Value
If I were to put this into the URL box, and fill it in correctly. then it would change the values that I specify. Am I supposed to send the entire thing? Or just after cmd.htm? Or is there some other way I'm supposed to send data? I'd like to stay away from the TCP/IP Module so I can keep this all within the same module.
Thanks.
You send
GET /cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value&mN=Value&auxA=Value&auxB=Value&autoR=Value HTTP/1.1
Host: address
Connection: close
(End with a couple of newlines.)
If you need to use HTTP basic authentication, then also include a header like
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
where the gibberish is the base64-encoded version of username:password.
But surely there is some mechanism for opening HTTP connections already there for you? Just blindly throwing out headers like this and hoping the response is what you expect is not robust, to say the least.
To see what is going on with your requests and responses, a great tool is netcat (or telnet, for that matter.)
Do nc address 80 to connect to server address on port 80, then paste your HTTP request:
GET /cmd.htm HTTP/1.1
Host: address
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Connection: close
and see what comes back. SOMETHING should come back. (Remember to terminate with two newlines.)
To see what requests your browser is sending when you do something that works, you can listen like this: nc -l -p 8080.
Then direct your browser to localhost:8080 with the rest of the URL as before, and you'll see the request that was sent. (Then you can type back to see how the browser handles the response.)

how to check whether perl cgi request originates from localhost

I would like to expose a service written in Perl to localhost HTTP requests. I do not want to modify Apache configuration. How to check whether a Perl CGI HTTP request originates from localhost?
I want for this check to succeed even if this call is made through a virtual host eg. https://www.myserivce.com/hidden/service.pl given that the call is made from inside of www.myserivce.com.
REMOTE_ADDR, but that's a dumb way to do it because you put the authentication logic in the application.
Instead, bind a stand-alone Web server to local interface only, thus the operating system's IP/networking stack guarantees that no request from outside can reach the server.
I think that if you put in /etc/hosts file an entry with myservice.com and ip 127.0.0.1 then all the requests from localhost to your site will have the REMOTE_ADDR set to 127.0.0.1 .
I am afraid that this is the only way to do it, unless you are making requests to 127.0.0.1/hidden/service.pl instead of myservice.com/hidden/service.pl
I have used the following code:
my $server_addr = inet_ntoa(scalar gethostbyname(hostname() || 'localhost'));
my $call_addr = $query->remote_addr();
die unless $call_addr eq "127.0.0.1" || $call_addr eq $server_addr;
I do not think it covers all cases, but seems to work with my setup. If anybody knows a generic solution then please submit it here.

Perl - creating multiple HTTP servers listening on different ports

An external application will send HTTP POST request to multiple HTTP/HTTPS servers (e.g. 10 HTTP servers). These HTTP servers may get almost same HTTP Post request. These HTTP servers will analyze the data and send 200 OK response if data validation pass.
I am having all these HTTP servers listening on single host with different ports.
Please suggest me some way to achieve it.
FYI - This request response between Application and HTTP Server(s) will happen only once and then HTTP server will be closed.
I am thinking to implement it using forking the HTTP:Daemon 10 times but looking forward for some light solution.
Also I am thinking to capture these data through a single interface rather then checking the data from all 10 individual 10 HTTP server.
for PORT in `seq 11111 11121` ; do plackup -Ilib --listen :$PORT app.psgi & done