/* Default callback routine for the mprRunCmd routines. Uses may supply their own callback instead of this routine. The callback is run whenever there is I/O to read/write to the CGI gateway. */ static void defaultCmdCallback(MprCmd *cmd, int channel, void *data) { MprBuf *buf; ssize len, space; int errCode; /* Note: stdin, stdout and stderr are named from the client's perspective */ buf = 0; switch (channel) { case MPR_CMD_STDIN: return; case MPR_CMD_STDOUT: buf = cmd->stdoutBuf; break; case MPR_CMD_STDERR: buf = cmd->stderrBuf; break; default: /* Child death notification */ return; } /* Read and aggregate the result into a single string */ space = mprGetBufSpace(buf); if (space < (ME_BUFSIZE / 4)) { if (mprGrowBuf(buf, ME_BUFSIZE) < 0) { mprCloseCmdFd(cmd, channel); return; } space = mprGetBufSpace(buf); } len = mprReadCmd(cmd, channel, mprGetBufEnd(buf), space); errCode = mprGetError(); if (len <= 0) { if (len == 0 || (len < 0 && !(errCode == EAGAIN || errCode == EWOULDBLOCK))) { mprCloseCmdFd(cmd, channel); return; } } else { mprAdjustBufEnd(buf, len); } mprAddNullToBuf(buf); mprEnableCmdEvents(cmd, channel); }
static void readFromCgi(Cgi *cgi, int channel) { HttpConn *conn; HttpPacket *packet; HttpTx *tx; HttpQueue *q, *writeq; MprCmd *cmd; ssize nbytes; int err; cmd = cgi->cmd; conn = cgi->conn; tx = conn->tx; q = cgi->readq; writeq = conn->writeq; assert(conn->sock); assert(conn->state > HTTP_STATE_BEGIN); if (tx->finalized) { mprCloseCmdFd(cmd, channel); } while (mprGetCmdFd(cmd, channel) >= 0 && !tx->finalized && writeq->count < writeq->max) { if ((packet = cgi->headers) != 0) { if (mprGetBufSpace(packet->content) < ME_MAX_BUFFER && mprGrowBuf(packet->content, ME_MAX_BUFFER) < 0) { break; } } else if ((packet = httpCreateDataPacket(ME_MAX_BUFFER)) == 0) { break; } nbytes = mprReadCmd(cmd, channel, mprGetBufEnd(packet->content), ME_MAX_BUFFER); if (nbytes < 0) { err = mprGetError(); if (err == EINTR) { continue; } else if (err == EAGAIN || err == EWOULDBLOCK) { break; } mprCloseCmdFd(cmd, channel); break; } else if (nbytes == 0) { mprCloseCmdFd(cmd, channel); break; } else { traceData(cmd, mprGetBufEnd(packet->content), nbytes); mprAdjustBufEnd(packet->content, nbytes); } if (channel == MPR_CMD_STDERR) { mprLog("error cgi", 0, "CGI failed uri=\"%s\", details: %s", conn->rx->uri, mprGetBufStart(packet->content)); httpSetStatus(conn, HTTP_CODE_SERVICE_UNAVAILABLE); cgi->seenHeader = 1; } if (!cgi->seenHeader) { if (!parseCgiHeaders(cgi, packet)) { cgi->headers = packet; return; } cgi->headers = 0; cgi->seenHeader = 1; } if (!tx->finalizedOutput && httpGetPacketLength(packet) > 0) { /* Put the data to the CGI readq, then cgiToBrowserService will take care of it */ httpPutPacket(q, packet); } } }
static void readFromCgi(Cgi *cgi, int channel) { HttpConn *conn; HttpPacket *packet; HttpTx *tx; HttpQueue *q, *writeq; MprCmd *cmd; ssize nbytes; int err; cmd = cgi->cmd; conn = cgi->conn; tx = conn->tx; q = cgi->readq; writeq = conn->writeq; assert(conn->sock); assert(conn->state > HTTP_STATE_BEGIN); if (tx->finalized) { mprCloseCmdFd(cmd, channel); } while (mprGetCmdFd(cmd, channel) >= 0 && !tx->finalized && writeq->count < writeq->max) { if ((packet = cgi->headers) != 0) { if (mprGetBufSpace(packet->content) < ME_MAX_BUFFER && mprGrowBuf(packet->content, ME_MAX_BUFFER) < 0) { break; } } else if ((packet = httpCreateDataPacket(ME_MAX_BUFFER)) == 0) { break; } nbytes = mprReadCmd(cmd, channel, mprGetBufEnd(packet->content), ME_MAX_BUFFER); if (nbytes < 0) { err = mprGetError(); if (err == EINTR) { continue; } else if (err == EAGAIN || err == EWOULDBLOCK) { break; } mprTrace(6, "CGI: Gateway read error %d for %s", err, (channel == MPR_CMD_STDOUT) ? "stdout" : "stderr"); mprCloseCmdFd(cmd, channel); break; } else if (nbytes == 0) { mprTrace(6, "CGI: Gateway EOF for %s, pid %d", (channel == MPR_CMD_STDOUT) ? "stdout" : "stderr", cmd->pid); mprCloseCmdFd(cmd, channel); break; } else { mprTrace(6, "CGI: Gateway read %d bytes from %s", nbytes, (channel == MPR_CMD_STDOUT) ? "stdout" : "stderr"); traceData(cmd, mprGetBufEnd(packet->content), nbytes); mprAdjustBufEnd(packet->content, nbytes); } if (channel == MPR_CMD_STDERR) { // FUTURE - should be an option to keep going despite stderr output mprError("CGI: Error for \"%s\"\n\n%s", conn->rx->uri, mprGetBufStart(packet->content)); httpSetStatus(conn, HTTP_CODE_SERVICE_UNAVAILABLE); cgi->seenHeader = 1; } if (!cgi->seenHeader) { if (!parseCgiHeaders(cgi, packet)) { cgi->headers = packet; return; } cgi->headers = 0; cgi->seenHeader = 1; } if (!tx->finalizedOutput && httpGetPacketLength(packet) > 0) { /* Put the data to the CGI readq, then cgiToBrowserService will take care of it */ httpPutPacket(q, packet); } } }