Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Issues using cgi.pm with POST requests. #1700

Closed
thestorm042 opened this issue Sep 21, 2015 · 9 comments
Closed

Issues using cgi.pm with POST requests. #1700

thestorm042 opened this issue Sep 21, 2015 · 9 comments

Comments

@thestorm042
Copy link

Apologies if this is the wrong place to post this; the wiki homepage says to create an issue if we need help with something.

I followed the recently posted instructions for Deploying Perl Apps (which were great, btw!) and successfully deployed a hello world app. Unfortunately, I'm having some trouble getting my real app to work.

First, I fully admit that I know next to nothing about Perl, so apologies in advance if this ends up being a basic or malformed question. I've got a script that's been working fine for years, running on IIS in house, which I'm helping migrate to Azure.

I think I've narrowed down the problem so will try to describe it as simply as possible; let me know if more/different details are needed.

  1. Accessing this test.pl in the browser works as expected:
    print ...hello world-y stuff...

  2. When I create the following test.html file and submit, it still works:
    <form action="test.pl" method="post" enctype="multipart/form-data">
    <input type="Submit" value="Submit">
    </form>

  3. Then, when I add the following lines to the top of test.pl, it still works fine when I access it directly.
    use CGI; # load the CGI.pm module
    my $GET = new CGI; # create a new object

  4. However, when I try to submit the form in test.html, there's a server error ("The page cannot be displayed because an internal server error has occurred."). I can't get any useful details from Azure..

  5. Last note: If I only have the first of the two lines in (3), it works fine with the form submission.

So... I'm thinking that the issue is with the "new CGI", but only when there are parameters (which there wouldn't be when accessing the .pl directly). I read something about having to install CGI.pm manually with newer versions of Perl (using Strawberry Perl 5.20), but I can't figure out how to do this in Azure.

Because of my lack of Perl knowledge, I can't make major structural changes to the script, so am hoping that whatever is causing my test example to fail is what's wrong with the real thing. If not, I may have to bite the bullet and redo the whole thing in Python or Java. But I'd rather not if the only problem is that I haven't set things up right in Azure.

Thanks in advance for your help!

Adam

@thestorm042
Copy link
Author

I should have mentioned that I also tried changing this line:
$GET = new CGI;

to this line:
$GET = CGI->new;

Based on some tutorials I saw. No change in behavior, though.

@snobu
Copy link
Contributor

snobu commented Sep 21, 2015

Do you have verbose logging turned on?
See this https://azure.microsoft.com/en-us/documentation/articles/web-sites-enable-diagnostic-log/
Turn on Web server logging, Detailed error messages and Failed Request Tracing, bump Level to Verbose and check /LogFiles/ after a few failed runs.

In the meantime i'm downloading Strawberry Perl and try to replicate what you're seeing.

@thestorm042
Copy link
Author

Thanks for the quick response!

I got the log, but I'm not sure if it's okay to post all 175KB -- chance of anything sensitive about accessing my app?

The gist of it is that there are 2 warnings, both for FastCgiModule:

ModuleName FastCgiModule
Data1 FASTCGI_RESPONSE_ERROR
Data2
ErrorCode The system cannot open the file.
(0x4)

ModuleName FastCgiModule
Notification EXECUTE_REQUEST_HANDLER
HttpStatus 500
HttpReason Internal Server Error
HttpSubStatus 0
ErrorCode The operation completed successfully.
(0x0)

I'm not sure which file it can't open or how to interpret it. Let me know what other info I can send and/or how your testing goes.

BTW, I'm using Strawberry Perl 5.20, and also tried 5.08 (thinking this is a very old script and some things might have changed) -- both work the same.

Thanks!

Adam

@snobu
Copy link
Contributor

snobu commented Sep 21, 2015

I got this.

So i Bingoogled for the first Perl CGI web form and found and used this one:
http://perlmeme.org/tutorials/cgi_form.html (bottom of the page)

Tried to run it, and got a 500, just like you did.

So then i turned on Failed Request Tracing, and got this nicely detailed error:
image

Important stuff here:

ModuleName  FastCgiModule
Data2   [Mon Sep 21 07:21:45 2015] form.pl: CGI::param called in list
context from D:\home\site\wwwroot\form.pl line 81, this can lead to vulnerabilities.
See the warning in "Fetching the value or values of a single named parameter" at 
d:/home/site/perl/perl/vendor/lib/CGI.pm line 404.
ErrorCode   Access is denied. (0x5)

Turns out that new Perl builds treat this "param in list context" thing as a serious security vulnerability and won't let you get away with it.

Line 81 in the perl cgi script (referenced in the error above) reads:

    my @favourite_languages = sort $q->param('language');

At this point you turn to perlmonks.org for help, where else? :)
http://www.perlmonks.org/?node_id=1105051

And the suggestion is to make it a scalar.

So, Line 81 becomes:

    my @favourite_languages = sort scalar $q->param('language');

Save, and it works.
Check it out: https://thefailchoochoo.azurewebsites.net/form.pl

@snobu
Copy link
Contributor

snobu commented Sep 21, 2015

ErrorCode The system cannot open the file.
(0x4)

This one might be a whole different thing.
You should get more info in the Failed Request Traces /LogFiles/W3SVCxxxx/

Just saw that you did paste from the traces.
Try to grep your script for snippets that might access files on disk, if you can sanitize it enough it might be helpful to paste it into https://gist.github.com/ and link it here, but be careful with sensitive info.

@thestorm042
Copy link
Author

What I pasted before was from the top part from the /LogFIles/W3SVCxxxx/ (like your screenshot). And here's the part from down below in the list of 151 events. My errors were also No. 94 and 95.

ModuleName="FastCgiModule", Data1="FASTCGI_RESPONSE_ERROR", Data2="", ErrorCode="The system cannot open the file.
(0x4)

and

ModuleName="FastCgiModule", Notification="EXECUTE_REQUEST_HANDLER", HttpStatus="500", HttpReason="Internal Server Error", HttpSubStatus="0", ErrorCode="The operation completed successfully.
(0x0)", ConfigExceptionInfo=""

Unlike your error, I don't see anything useful here.

I can attach the whole log if you think it will help (and can confirm that it doesn't require any santization first -- I don't think so, just being safe).

@snobu
Copy link
Contributor

snobu commented Sep 21, 2015

You can email me the script privately at
<undisclosed email>

@snobu
Copy link
Contributor

snobu commented Sep 21, 2015

Looks like perl doesn't like your enctype="multipart/form-data". Probably it expects a file as input, that's why you get the 500 Can't open file. (http://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean)

test.html

<html>
<head>
<title>Run your first Perl script</title>
</head>
<body>

<form action="/test.pl" method="post">
  <input type="Submit" value="Submit">
</form>


</body>
</html>

test.pl

use warnings;
use strict;

use CGI; # load the CGI.pm module
my $GET = new CGI; # create a new object

print "Content-type: text/html\n\n";
print <<"EOF";
<HTML>
<BODY>
<H1>Hello!</H1>
</BODY>

</HTML>
EOF

Try it here:
https://thefailchoochoo.azurewebsites.net/test.html

Source:
https://thefailchoochoo.azurewebsites.net/test.html.txt
https://thefailchoochoo.azurewebsites.net/test.pl.txt

@snobu
Copy link
Contributor

snobu commented Sep 23, 2015

The Problem

Strawberry Perl on Web Apps. A script that takes one file from a web form and writes it to disk. And fails with:
a
image

ErrorCode The system cannot open the file.
(0x4)

The Fix

In the Portal > Web Apps > Your Perl Web App (http://manage.windowsazure.com/)

Change FastCGI operating mode to eval so errors get piped to your browser even before your script outputs Content-type: text/whatever

image

Some other operation modes for FastCGI for reference:

-MFCGI::IIS=test

This is a simple test routine, that displays a counter that increments by 1 each time
the script is called as a FastCGI.

-MFCGI::IIS=carp

In this mode, CGI::Carp qw(fatalsToBrowser) is invoked before running the do method.

-MFCGI::IIS=eval

With this mode eval is used instead of the do operator. Slower run time, but allows
you to trap errors.

-MFCGI::IIS=evalhead

With this mode eval is used instead of the do operator, also the content-type
text/html header is returned first, allowing you to trap wrong header errors.

-MFCGI::IIS=do

AKA "Production Mode". This is the default mode, and will be called if no arguments are given, i.e.
perl -MFCGI::IIS. The calling script is loaded into the FastCGI using the do operator.

I restarted the web app from the portal and hit the script URL again.

This time I got this:
cgitemppath

Error! Error in tempfile() using template C:\temp\XXXXXXXXXX:
Could not create temp file C:\temp\GETc1GXQrE: 
Permission denied at d:/home/site/perl/perl/vendor/lib/CGI.pm line 3382.

Looks like CGI.pm has the wrong TEMP path. Because we now have a fancy editor in Kudu let's get right into CGI.pm at line 3382.

CGI.pm

      require CGI::File::Temp;
      my $filehandle = CGI::File::Temp->new(
        UNLINK => $UNLINK_TMP_FILES,
        DIR    => $tmp_dir,
      );

Hmm, alright, so let's dig into CGI::File::Temp then.

# this is a back compatibility wrapper around File::Temp. DO NOT
# use this package outside of CGI, i won't provide any help if
# you use it directly and your code breaks horribly.
package CGI::File::Temp;

$CGI::File::Temp::VERSION = '4.21';

use parent File::Temp;

Not much here. Let's dig into File::Temp then.

  # Retrieve the temporary directory name
  my $tmpdir = File::Spec->tmpdir;

I forgot to mention, I do have a lot of patience.

File::Spec

...
Something something File::Spec::Win32

File::Spec::Win32

sub tmpdir {
    my $tmpdir = $_[0]->_cached_tmpdir(qw(TMPDIR TEMP TMP));
    return $tmpdir if defined $tmpdir;
    $tmpdir = $_[0]->_tmpdir( map( $ENV{$_}, qw(TMPDIR TEMP TMP) ),
                  'SYS:/temp',
                  'C:\system\temp',
                  'C:/temp',
                  '/tmp',
                  '/'  );
    $_[0]->_cache_tmpdir($tmpdir, qw(TMPDIR TEMP TMP));
}

disasterfirl

Hard coded paths for Windows.

You can't write to the system drive C:\ in Web Apps. But you do have %TEMP% setup correctly.

Here's an example from Kudu console:

D:\home>dir c:\temp
 Volume in drive C has no label.
 Volume Serial Number is 9CD4-1B4B

 Directory of c:\

07/02/2015  12:22 PM    <DIR>          temp
               0 File(s)              0 bytes
               1 Dir(s)  1,014,714,900,480 bytes free

D:\home>touch c:\temp\TempFile.txt
touch: 
creating `c:\\temp\\TempFile.txt': Permission denied
D:\home>dir %temp%
 Volume in drive D is Windows
 Volume Serial Number is 6089-EC9F

 Directory of D:\local\Temp

09/23/2015  08:44 AM    <DIR>          .
09/23/2015  08:44 AM    <DIR>          ..
09/23/2015  08:44 AM    <DIR>          siteExtLogs
               0 File(s)              0 bytes
               3 Dir(s)     523,321,344 bytes free

D:\home>touch %temp%\TempFile.txt

D:\home>dir %temp%
 Volume in drive D is Windows
 Volume Serial Number is 6089-EC9F

 Directory of D:\local\Temp

09/23/2015  10:38 AM    <DIR>          .
09/23/2015  10:38 AM    <DIR>          ..
09/23/2015  08:44 AM    <DIR>          siteExtLogs
09/23/2015  10:38 AM                 0 TempFile.txt
               1 File(s)              0 bytes
               3 Dir(s)     523,317,248 bytes free

D:\home> 

TL;DR:

Manually specify temporary directory for CGI if using Perl on Web Apps.
Add this at the top of your .pl script:

BEGIN { $ENV{TMPDIR} = "d:\\local\\temp"; }

Yes yes, I know, hardcoded paths :)
Change back FastCGI into do mode, restart Web App, and the CGI script will now happily run.

@snobu snobu closed this as completed Sep 23, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants