Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug server side script for file uploading from client (curl at this example)?

I am trying to write a Perl Mojolicious request from CLI. I want to pass a file as a parameter to this request. Below are the things I have tried so far, but no avail.

Below Example is what working fine with me.

curl (working):          curl -X POST "http://localhost:3000/uploadtest.pl/status?Token=6d949625-2f07-1e7a-d57a-de0fa949035d"
Mojolicious (working):  perl ./uploadtest.pl get -v -M POST /status?"Token=3780e99a-fc2c-54e5-2c31-417f945c1792"

Below is the the example in which i am stuck, becouse below perl script take file as a input [file upload]:

curl (working):          curl -X POST -F Input_File=@d:/xml/test.xml "http://localhost:3000/uploadtest.pl/upload?Input_Type=XML
Mojolicious (not working):  perl ./uploadtest.pl get -v -M POST /upload?"Input_Type=XML&Input_File=d:/xml/test.xml"

It will be great help if someone helps me out with this.


#uploadtest.pl

use Mojolicious::Lite;

# Upload form in DATA section
get '/' => 'form';


# Check status
post '/status' => sub {
  my $self = shift;
  my $Token = $self->param('Token');
  $self->render(text => "In process: $Token");
};

# Multipart upload handler
post '/upload' => sub {
  my $self = shift;

  # Process uploaded file
  my $Input_File = $self->param('Input_File');
  my $Input_Type = $self->param('Input_Type');
  my $size = $Input_File->size;
  my $name = $Input_File->filename;
  my $upload = $self->req->upload('Input_File');
  $upload->move_to("d:/xml/$name");  #move location
  $self->render(text => "Thanks for uploading $size byte file $name.");
};

app->start;
__DATA__

@@ form.html.ep
<!DOCTYPE html>
<html>
  <head><title>File Upload</title></head>
  <body>
  <form name="FileUpload" action="http://localhost:3000/uploadtest.pl/upload" enctype="multipart/form-data" method="post">
       Input Type:</td><td><input type="text" name="Input_Type" />
       Please specify a file:</td><td><input type="file" name="Input_File" size="40"></td></tr>
       <input type="submit" value="Submit"/>
   </form>
   <br><br><br><hr><br><br><br>
  <form name="Status" action="http://localhost:3000/uploadtest.pl/status" method="post">
      Token ID: <input type="text" name="Token" />
     <input type="submit" value="Check Status"/>
  </form>
  </body>
</html>
like image 624
Neyaz Ahmad Avatar asked Jun 03 '16 10:06

Neyaz Ahmad


People also ask

How do I use Curl command to upload files?

To post a file with Curl, use the -d or -F command-line options and start the data with the @ symbol followed by the file name. To send multiple files, repeat the -F option several times.

What is transfer SH?

Transfer.sh is a simple, easy and fast service for file sharing from the command-line. It allows you to upload up to 10GB of data and files are stored for 14 days, for free. You can maximize amount of downloads and it also supports encryption for security.


2 Answers

The Mojolicious get command does not support generating requests from files i'm afraid.

perl -Mojo -E 'p("http://localhost:3000" => form => {Input_Type => "XML", Input_File => {file => "d:/xml/test.xml"}})'

You'd have to use an ojo one-liner.

like image 104
Sebastian Riedel Avatar answered Sep 21 '22 02:09

Sebastian Riedel


I think you are not understand what post '/upload' does and uploadtest.pl is.

Your script is a small HTTP server which receive requests and does responses. You can run your server permanently and do requests with, for example, curl or do one request to it and exit.

$ perl uploadtest.pl daemon
[Sat Jun 11 14:00:41 2016] [info] Listening at "http://*:3000"
Server available at http://127.0.0.1:3000

# in other shell
$ curl -X POST "http://localhost:3000/uploadtest.pl/status?Token=6d949625-2f07-1e7a-d57a-de0fa949035d"

Or both at once:

$perl ./uploadtest.pl get -v -M POST /status?"Token=3780e99a-fc2c-54e5-2c31-417f945c1792"

These POSTs make requests to permanent (first example) or onetime server (second one) with empty content

If you run your curl with -v options:

$ curl -v -X POST "http://localhost:3000/status?Token=6d949625-2f07-1e7a-d57a-de0fa949035d"
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> POST /status?Token=6d949625-2f07-1e7a-d57a-de0fa949035d HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:3000
> Accept: */*
> 
< HTTP/1.1 200 OK
* Server Mojolicious (Perl) is not blacklisted
< Server: Mojolicious (Perl)
< Date: Sat, 11 Jun 2016 11:42:24 GMT
< Content-Length: 48
< Content-Type: text/html;charset=UTF-8
< 
* Connection #0 to host localhost left intact
In process: 6d949625-2f07-1e7a-d57a-de0fa949035d

You even may do tcpdump while querying your server:

$ sudo tcpdump -x -X -i lo port 3000
14:41:51.665032 IP localhost.49063 > localhost.3000: Flags [P.], seq 1:129, ack 1, win 342, options [nop,nop,TS val 1097613 ecr 1097613], length 128
    0x0000:  4500 00b4 38c4 4000 4006 037e 7f00 0001  E...8.@.@..~....
    0x0010:  7f00 0001 bfa7 0bb8 3b17 8750 a281 4839  ........;..P..H9
    0x0020:  8018 0156 fea8 0000 0101 080a 0010 bf8d  ...V............
    0x0030:  0010 bf8d 504f 5354 202f 7374 6174 7573  ....POST./status
    0x0040:  3f54 6f6b 656e 3d36 6439 3439 3632 352d  ?Token=6d949625-
    0x0050:  3266 3037 2d31 6537 612d 6435 3761 2d64  2f07-1e7a-d57a-d
    0x0060:  6530 6661 3934 3930 3335 6420 4854 5450  e0fa949035d.HTTP
    0x0070:  2f31 2e31 0d0a 5573 6572 2d41 6765 6e74  /1.1..User-Agent
    0x0080:  3a20 6375 726c 2f37 2e33 352e 300d 0a48  :.curl/7.35.0..H
    0x0090:  6f73 743a 206c 6f63 616c 686f 7374 3a33  ost:.localhost:3
    0x00a0:  3030 300d 0a41 6363 6570 743a 202a 2f2a  000..Accept:.*/*
    0x00b0:  0d0a 0d0a                                ....

When you want to upload file to your server you use -F Input_File=@d:/xml/test.xml curl option. You also expect you can do same onetime request, but next command:

$perl ./uploadtest.pl get -v -M POST /upload?"Input_Type=XML&Input_File=d:/xml/test.xml"

does not support such option.

$perl ./uploadtest.pl help get
Usage: APPLICATION get [OPTIONS] URL [SELECTOR|JSON-POINTER] [COMMANDS]

  ./myapp.pl get /
  ./myapp.pl get -H 'Accept: text/html' /hello.html 'head > title' text
  ./myapp.pl get //sri:secr3t@/secrets.json /1/content
  mojo get mojolicious.org
  mojo get -v -r google.com
  mojo get -v -H 'Host: mojolicious.org' -H 'Accept: */*' mojolicious.org
  mojo get -M POST -H 'Content-Type: text/trololo' -c 'trololo' perl.org
  mojo get mojolicious.org 'head > title' text
  mojo get mojolicious.org .footer all
  mojo get mojolicious.org a attr href
  mojo get mojolicious.org '*' attr id
  mojo get mojolicious.org 'h1, h2, h3' 3 text
  mojo get https://api.metacpan.org/v0/author/SRI /name

Options:
  -C, --charset <charset>     Charset of HTML/XML content, defaults to
                              auto-detection
  -c, --content <content>     Content to send with request
  -H, --header <name:value>   Additional HTTP header
  -h, --help                  Show this summary of available options
      --home <path>           Path to home directory of your application,
                              defaults to the value of MOJO_HOME or
                              auto-detection
  -M, --method <method>       HTTP method to use, defaults to "GET"
  -m, --mode <name>           Operating mode for your application, defaults to
                              the value of MOJO_MODE/PLACK_ENV or
                              "development"
  -r, --redirect              Follow up to 10 redirects
  -v, --verbose               Print request and response headers to STDERR

As you can see from help, you can send short text message:

  ./uploadtest.pl get -M POST -H 'Content-Type: text/trololo' -c 'trololo' perl.org

To upload files into your uploadtest.pl server you may write your own uploader. For this need you should use Mojo::UserAgent module. Example

use Mojo::UserAgent;

# Upload file via POST and "multipart/form-data"
my $ua = Mojo::UserAgent->new;
$ua->post("http://localhost:3000" => form => {Input_Type => "XML", Input_File => {file => "d:/xml/test.xml"}});

But this is same as:

perl -Mojo -E 'p("http://localhost:3000" => form => {Input_Type => "XML", Input_File => {file => "d:/xml/test.xml"}})'

UPD

To debug server side script for file uploading you should

perl -d uploadtest.pl daemon

Loading DB routines from perl5db.pl version 1.49_04
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(tx.pl:6):    get '/' => 'form';
  DB<1>

This will bring you into perl debugger (Tutorial)

  DB<1> l 1-30
1   #uploadtest.pl
2   
3:  use Mojolicious::Lite;
4   
5   # Upload form in DATA section
6==>    get '/' => 'form';
7   
8   
9   # Check status
10  post '/status' => sub {
11:   my $self = shift;
12:   my $Token = $self->param('Token');
13:   $self->render(text => "In process: $Token");
14: };
15  
16  # Multipart upload handler
17  post '/upload' => sub {
18:   my $self = shift;
19  
20    # Process uploaded file
21:   my $Input_File = $self->param('Input_File');
22:   my $Input_Type = $self->param('Input_Type');
23:   my $size = $Input_File->size;
24:   my $name = $Input_File->filename;
25:   my $upload = $self->req->upload('Input_File');
26:   $upload->move_to("d:/xml/$name");  #move location
27:   $self->render(text => "Thanks for uploading $size byte file $name.");
28: };
29  
30: app->start;
  DB<2> b 11
  DB<3> b 18
  DB<4> l 1-30
1   #uploadtest.pl
2   
3:  use Mojolicious::Lite;
4   
5   # Upload form in DATA section
6==>    get '/' => 'form';
7   
8   
9   # Check status
10  post '/status' => sub {
11:b      my $self = shift;
12:   my $Token = $self->param('Token');
13:   $self->render(text => "In process: $Token");
14: };
15  
16  # Multipart upload handler
17  post '/upload' => sub {
18:b      my $self = shift;
19  
20    # Process uploaded file
21:   my $Input_File = $self->param('Input_File');
22:   my $Input_Type = $self->param('Input_Type');
23:   my $size = $Input_File->size;
24:   my $name = $Input_File->filename;
25:   my $upload = $self->req->upload('Input_File');
26:   $upload->move_to("d:/xml/$name");  #move location
27:   $self->render(text => "Thanks for uploading $size byte file $name.");
28: };
29  
30: app->start;
  DB<5> c
[Tue Jun 14 16:43:06 2016] [info] Listening at "http://*:3000"
Server available at http://127.0.0.1:3000
[Tue Jun 14 16:43:10 2016] [debug] POST "/status"
[Tue Jun 14 16:43:10 2016] [debug] Routing to a callback
main::CODE(0x23f7be0)(tx.pl:11):      my $self = shift;
  DB<5> n
main::CODE(0x23f7be0)(tx.pl:12):      my $Token = $self->param('Token');
  DB<5> n
main::CODE(0x23f7be0)(tx.pl:13):      $self->render(text => "In process: $Token");
  DB<5> x $Token
0  '6d949625-2f07-1e7a-d57a-de0fa949035d'
  DB<6> 

Here I list source from 1 to 30 line l 1-30, set two breakpoints b 11 b 18, list source again l 1-30 to see that breakpoints are in effect (Notice b near the line), run script from current point (Notice ==> sign near the line) until next break point, done two steps with n command and view value of $Token variable with x $Token command.

Notice, that after c script wait interaction. I do that with curl

http://localhost:3000/status?Token=6d949625-2f07-1e7a-d57a-de0fa949035d

NOTICE: You should request '/status' and '/upload' NOT '/updater.pl/status' as you did. It has no matter for the outer word how your server script is named. Just only two things:

  1. Where your script listen: localhost:3000
  2. Which request may serve: '/upload' and '/status'
like image 36
Eugen Konkov Avatar answered Sep 20 '22 02:09

Eugen Konkov