title: C Webvserver – STDIN, sockets and CGI piping
body: <p>I want to create a remote control for <a href="http://en.wikipedia.org/wiki/GNUnet" rel="nofollow">GNUNet</a>, so I started writing a self-made multithreaded-generical-purpose webserver for the GNU OS, able to authenticate users (reading from the <a href="http://www.gnu.org/software/libc/manual/html_node/Lookup-User.html" rel="nofollow">system user database</a>) and able to execute generic CGI programs/scripts. I started from scratch and it's just a draft for now. However, everything seems to work fine.</p>
  
  <p>I have just a question.</p>
  
  <p>As you know, a CGI programs/scripts read the POST string from the STDIN and send their content to the STDOUT. The following is (part of) the code I wrote. And it seems to work.</p>
  
  <pre class="lang-c prettyprint-override"><code>if (pipe(cgiPipe))
  {
    perror("pipe");
  }
  
  cgiPid = fork();
  
  if (cgiPid == 0)
  {
  
    /* child */
  
    /* piping the POST content... */
  
    /* first, send the truncated part of the POST string contained within the request string... */
    if (nPOSTLength &amp;&amp; (nSentChrs = write(cgiPipe[1], sPOSTSegment, 
        nReqLen + requestString - sPOSTSegment)) &gt; 0)
    {
      nPOSTLength -= nSentChrs;
  
      /* after, read and send the rest of the POST string not received yet... */
      while (nPOSTLength &gt; 0 &amp;&amp; (nReadChrs = read(nRemote, reservedBuffer, 
          BUFFER_SIZE_PER_USER)) &gt; 0 &amp;&amp; (nSentChrs = write(cgiPipe[1], reservedBuffer, 
          nReadChrs)) &gt; 0 &amp;&amp; nReadChrs == nSentChrs)
      {
        nPOSTLength -= nReadChrs;
      }
  
      if (nReadChrs &lt; 0)
      {
        printf("Error reading POST string.\n");
        goto closeThread;
      }
      if (nSentChrs &lt; 0)
      {
        printf("Error sending POST string.\n");
        goto closeThread;
      }
    }
    else
    {
      write(cgiPipe[1], "(null)", 6);
    }
  
    close(cgiPipe[1]);
  
    /* redirecting the output of the pipe to the STDIN of the child process */
    dup2(cgiPipe[0], STDIN_FILENO);
    /* redirecting STDOUT of the child process to the remote client */
    dup2(nRemote, STDOUT_FILENO);
    setuid(nUserID);
  
    if (execve(sLocalPath, NULL, aCGIEnv))
    {
      /* unable to execute CGI... */
      perror("execve");
      sendString(nRemote,
          "HTTP/1.1 200 OK\r\n"
          "Content-length: 97\r\n"
          "Content-Type: text/html\r\n\r\n"
          "&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;CGI Error&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;CGI Error.&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;\r\n"
      );
    }
  
    goto closeThread;
  
  }
  else if (cgiPid &gt; 0)
  {
  
    /* parent */
  
    close(cgiPipe[0]);
  
    /* wait for child process. */
    if (waitpid(cgiPid, NULL, 0) == -1)
    {
      perror("wait");
    }
  
    goto closeThread;
  
  }
  else
  {
  
    /* parent */
  
    perror("fork");
  
    /* let's try to send it as normal file, if the user has the right permissions... */
  
  }
  </code></pre>
  
  <p>As you can see, <strong>before</strong> executing the CGI program, <strong>the whole POST string</strong> is received from the client and piped (first the truncated part of it contained within the request string – usually few bytes – and then the rest). <strong>Then</strong>, the CGI program is executed.</p>
  
  <p>And now my question…</p>
  
  <p>If I try to upload a file of several MBs, several MBs are piped <strong>before</strong> the invocation of the CGI: <strong>is there any way to redirect the socket directly to the STDIN of the new process, in order to not read it before?</strong> But, for sure, I have to send the read truncated part of the POST string, before. So, I can schematize what I would like to do in this way:</p>
  
  <ul>
  <li>piping a string (few bytes) to the STDIN, then</li>
  <li>redirecting the socket (the client) to the STDIN, then</li>
  <li>executing an external process (the CGI program)</li>
  </ul>
  
  <p>Is it possible? Can you show me <em>how</em>?</p>