locked
How to run a legacy CGI from ASP.NET - i.e. using HttpHandler or hooking HttpModule? RRS feed

  • Question

  • User-948182666 posted

    Hi there

    I have a legacy application integration issue. As you already might have guessed, I need to use a few legacy CGIs along with ASP.NET. These CGIs will be generating HTML (or in some cases, maybe aspx, or some other template) pages and I need to capture their output and process it before sending it to the browser.

    I was thinking of writting a HttpHandler hooked into *.cgi's  where I can have the full control over them. However I am not sure what I can use to spawn a process to run the cgi. I am new to ASP.NET/C# environment so I am not so sure. Should I use some sort of system specific 'Process' api or is there 'CGIProcess' api that I can reuse - for example from IIS libraries.

    A second alternative might be using HttpModule, I suppose. From what I read modules can work like a filter, altering the input and output streams. If that's the case, do you know any way to setup IIS to run CGI's as an 'Application' so it's passed to HttpModule as well?

    Thanks in advance

    --Ziya

    Tuesday, September 25, 2007 11:54 AM

Answers

  • User-948182666 posted

    I must be the only sad person in the world who needed this. Here is what I have so far:

      

    1    using System;
    2    using System.Web;
    3    using System.Diagnostics;
    4    using System.ComponentModel;
    5    using System.Text;
    6    
    7    namespace Suzen.Web.Http
    8    {
    9        public class CGIHandler : IHttpHandler
    10       {
    11           public CGIHandler()
    12           {
    13           }
    14   
    15           public void ProcessRequest(System.Web.HttpContext context)
    16           {
    17               string script_name = "test.pl";
    18               string path_info = "/";
    19               int clen = context.Request.ContentLength;
    20               byte[] buf = new byte[clen];
    21               int res = context.Request.InputStream.Read(buf, 0, clen);
    22   
    23               ASCIIEncoding ae = new ASCIIEncoding();
    24               string sbuf = ae.GetString(buf);
    25   
    26               Process p = new Process();
    27               p.StartInfo.FileName = "perl";
    28               p.StartInfo.WorkingDirectory = "C:\\";
    29               p.StartInfo.Arguments = script_name + " " + context.Request.QueryString.ToString();
    30               p.StartInfo.EnvironmentVariables["CONTENT_LENGTH"] = clen.ToString();
    31               p.StartInfo.EnvironmentVariables["REQUEST_METHOD"] = context.Request.HttpMethod;
    32               p.StartInfo.EnvironmentVariables["CONTENT_TYPE"] = context.Request.ContentType;
    33               p.StartInfo.EnvironmentVariables["QUERY_STRING"] = context.Request.QueryString.ToString();
    34               p.StartInfo.EnvironmentVariables["SCRIPT_NAME"] = script_name;
    35               p.StartInfo.EnvironmentVariables["PATH_INFO"] = path_info;
    36               p.StartInfo.RedirectStandardOutput = true;
    37               p.StartInfo.RedirectStandardInput = true;
    38               p.StartInfo.UseShellExecute = false;
    39               p.Start();
    40   
    41               p.StandardInput.Write(sbuf);
    42               p.StandardInput.Flush();
    43   
    44               string p_output = p.StandardOutput.ReadToEnd();
    45   
    46               p.WaitForExit(3000);
    47   
    48               context.Response.Write("<pre>BUF\n" + context.Request.ContentLength + "-" + res + "\n"
    49                   + context.Request.QueryString.ToString() + sbuf + "\nOUT\n" + p_output + "&lt;/pre><hr/>");
    50               context.Response.Write("&lt;form method='post'><input name='aa' type='text'>");
    51               context.Response.Write("&lt;input type='submit'></form>");
    52           }
    53   
    54           public bool IsReusable
    55           {
    56               get
    57               {
    58                   return true;
    59               }
    60           }
    61       }
    62   }
    

     

    Cheers

    -z
     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, December 13, 2007 8:51 PM
  • User-319574463 posted

     Are you able to scrape from the existing CGI pages? If so the System.Net.WebClient function provides means to receive data from a resource identified by a URI. see http://msdn.microsoft.com/en-us/library/system.net.webclient(VS.80).aspx

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 7, 2008 1:27 AM

All replies

  • User-948182666 posted

    I must be the only sad person in the world who needed this. Here is what I have so far:

      

    1    using System;
    2    using System.Web;
    3    using System.Diagnostics;
    4    using System.ComponentModel;
    5    using System.Text;
    6    
    7    namespace Suzen.Web.Http
    8    {
    9        public class CGIHandler : IHttpHandler
    10       {
    11           public CGIHandler()
    12           {
    13           }
    14   
    15           public void ProcessRequest(System.Web.HttpContext context)
    16           {
    17               string script_name = "test.pl";
    18               string path_info = "/";
    19               int clen = context.Request.ContentLength;
    20               byte[] buf = new byte[clen];
    21               int res = context.Request.InputStream.Read(buf, 0, clen);
    22   
    23               ASCIIEncoding ae = new ASCIIEncoding();
    24               string sbuf = ae.GetString(buf);
    25   
    26               Process p = new Process();
    27               p.StartInfo.FileName = "perl";
    28               p.StartInfo.WorkingDirectory = "C:\\";
    29               p.StartInfo.Arguments = script_name + " " + context.Request.QueryString.ToString();
    30               p.StartInfo.EnvironmentVariables["CONTENT_LENGTH"] = clen.ToString();
    31               p.StartInfo.EnvironmentVariables["REQUEST_METHOD"] = context.Request.HttpMethod;
    32               p.StartInfo.EnvironmentVariables["CONTENT_TYPE"] = context.Request.ContentType;
    33               p.StartInfo.EnvironmentVariables["QUERY_STRING"] = context.Request.QueryString.ToString();
    34               p.StartInfo.EnvironmentVariables["SCRIPT_NAME"] = script_name;
    35               p.StartInfo.EnvironmentVariables["PATH_INFO"] = path_info;
    36               p.StartInfo.RedirectStandardOutput = true;
    37               p.StartInfo.RedirectStandardInput = true;
    38               p.StartInfo.UseShellExecute = false;
    39               p.Start();
    40   
    41               p.StandardInput.Write(sbuf);
    42               p.StandardInput.Flush();
    43   
    44               string p_output = p.StandardOutput.ReadToEnd();
    45   
    46               p.WaitForExit(3000);
    47   
    48               context.Response.Write("&lt;pre>BUF\n" + context.Request.ContentLength + "-" + res + "\n"
    49                   + context.Request.QueryString.ToString() + sbuf + "\nOUT\n" + p_output + "&lt;/pre><hr/>");
    50               context.Response.Write("&lt;form method='post'><input name='aa' type='text'>");
    51               context.Response.Write("&lt;input type='submit'></form>");
    52           }
    53   
    54           public bool IsReusable
    55           {
    56               get
    57               {
    58                   return true;
    59               }
    60           }
    61       }
    62   }
    

     

    Cheers

    -z
     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, December 13, 2007 8:51 PM
  • User-1055665710 posted

    Did you find a way to do this otherwise.  I am trying to secure CGI exe's with ASP.NET 2.0 Forms Authorization.  Thank You jeff@orionfusion.com

    Sunday, January 13, 2008 11:32 PM
  • User-948182666 posted

    Unfortunately not. But I improved my CGI handler. Have a go if you like:

    http://zeealpha.googlecode.com/svn/trunk/csharp/CGIHandler/

    It does not handle some of the environment variables and I did not test uploads (probably does not work because of encoding).

    Cookie handling done a little crudely as well. Only values are passed (no path, expiration..)

    It seems to work fine for simple cases, although I have not used it in production at all. It is still experimental code!!!

    Let me know if it works for you. I'd be very interested to work on it more if there will be some use for it.

    -z

     

    Wednesday, January 23, 2008 7:58 PM
  • User-319574463 posted

     Are you able to scrape from the existing CGI pages? If so the System.Net.WebClient function provides means to receive data from a resource identified by a URI. see http://msdn.microsoft.com/en-us/library/system.net.webclient(VS.80).aspx

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 7, 2008 1:27 AM
  • User-948182666 posted

     [sorry for the late reply]

    No. I can't scrape them, since CGI needs to receive the request from the client browser. In fairness your suggestion should work if the session cookie is set when talking to the cgi. One last thing would be passing the users IP. That would be sorted as well (assuming CGI understands it) by pretending to be a proxy and feeding X-Forward (or something like that) HTTP header as well (which seems to be possible by using WebClient).

    Thanks for your reply.

    -z

    Monday, November 3, 2008 7:22 AM
  • User-319574463 posted

     For a straight screen scrape there is now a function for doing that in the CommonDate project at http://www.CodePlex.Com/CommonData.

    Your problem with the session cookie may be solved if you use WatiN  see http://sourceforge.net/projects/watin/

    Monday, November 3, 2008 7:30 AM
  • User-948182666 posted

     For a straight screen scrape there is now a function for doing that in the CommonDate project at http://ww.CodePlex.Com/CommonData.

    I will look into this one. Thanks. Diverging a bit, but I learned a few new (new for me) tools from your project, thaks for that too :)

    Your problem with the session cookie may be solved if you use WatiN  see http://sourceforge.net/projects/watin/

    That might help. But I think the original issue as I tried to describe it, is essentially hiding the CGI from the user, while using its functions. watin might be a little heavy weight and not serve the porpose (session cookies, IPs and that). just saying..

    Cheers

    -z


    Monday, November 3, 2008 8:01 AM
  • User135641708 posted

    Hey zsuzen,

    One thing caught my attention in your original post,

    These CGIs will be generating HTML (or in some cases, maybe aspx, or some other template) pages

    If you want to also process the output of your CGIs as ASPX, then you might want to look into the utilities of VirtualPathProvider (http://msdn.microsoft.com/en-us/library/system.web.hosting.virtualpathprovider.aspx).

    The VirtualPathProvider class provides a set of methods for implementing a virtual file system for a Web application. In a virtual file system, the files and directories are managed by a data store other than the file system provided by the server's operating system. For example, you can use a virtual file system to store content in a SQL Server database.

    Basically, you can tell ASP.NET where to get the source for ASPX pages. In the implementation of VirtualPathProvider, you can then invoke the necessary CGI scripts.

    Hope this helps,
    Max Kukartsev

    Tuesday, November 4, 2008 4:27 PM
  • User-948182666 posted

    Awesome!

    I did come across VirtualPathProvider, but I must say name deceived me! I thought it's only about paths and never occurred to me the 'page content' can be ‘virtual’ as well.

    Anyway, I will look into this asap and let you know if it works as I am imagining it right now...

    --Ziya

    Wednesday, November 5, 2008 8:00 AM
  • User1048071487 posted

    zsuzen...

    i haven't tried yet, but... does your code work for an .exe (cgi) app? how must the server be configured?

    I'm trying to deploy a redatam webserver, and the cgi app works, but i need to set execute permissions on IIS manager (on my dev server), but i can't even touch the production server, can't access its IIS manager, can't set special permissions (server admin hate me). i can only say where are the files of the website, and tey will copy them to the server.

    Can you code be a workaround for this situation?


    redatam: www.cepal.org/redatam (spanish)

    sorry for my english... i only speak on spanish... and my writed english could be bad... i don't know, jajaj

    Wednesday, August 5, 2009 12:05 PM
  • User-319574463 posted

    One further thought - you can generate HTML and inject in into the InnerHtml property of a server control.

    There is an alternative way provided:

    • The section of the page to be genererated is static (plain HTML possibly with hyperlinks)  with controls causing post backs.

    To do this:

    1. Produce a sample page in aspx.
    2. Simplify the markup using CSS for the styling
    3. XHTML validate the page
    4. Get sign-off from your client on the sample page format.
    5. Extract the section of HTML that you need to produce.
    6. From where the HTML section was extracted (e.g. a table cell), make it runat="server" and give it an Id
    7. Use HtmltextWriter2 from http://www.codeplex.com/HtmlTextWriter2 to convert to the HTML to either VB.NET or C#
    8. Make this static code read your data and thereby generate dynamic HTML
    9. Inject the generated HTML into the form using the InnerHtml property of the control you created in step 6.

    For a sample of this, please see the Default.aspx form in the VBDEMO project of the CommonData solution at http://commondata.codeplex.com/

    Wednesday, August 5, 2009 12:17 PM