#include <common.h> #include "RecordReader.h" #include "fastcgi.h" enum { // Limit the number of back-to-back receives done on one socket. MAX_READS = 10, // Largest possible record size (including overhead). MAX_RECORD_SIZE = 0x10108 }; FCGI::RecordReader::RecordReader() : pBuffer(0), iBuffer(0), nPayload(0), iRecord(0), nPadding(0), nNeeded(8), nRecord(0) { pBuffer = new char[MAX_RECORD_SIZE]; } FCGI::RecordReader::~RecordReader() { delete pBuffer; } bool FCGI::RecordReader::onRead(SOCKET socket) { // Perform back-to-back reads sufficient to flush out most messages. for (int i = 0; i < MAX_READS; ++i) { // Read as much as possible, into the remaining buffer space. int nSpace = MAX_RECORD_SIZE - nPayload; int nRead = ::recv(socket,pBuffer + nPayload,nSpace,0); if (nRead < 0) { return (EWOULDBLOCK == errno) || (EAGAIN == errno); } nPayload += nRead; // Parse out records from the buffer. int nPresent = nPayload - iRecord; while (nNeeded <= nPresent) { // Are we at the beginning of the record? if (iRecord == iBuffer) { char* p = pBuffer + iRecord; int v; v = 255 & *p++; if (FCGI_VERSION_1 != v) { return false; // We cannot handle this conversation. } v = 255 & *p++; recordDispatch.iType = v; v = 255 & *p++; v = (v << 8) | (255 & *p++); recordDispatch.idRequest = v; v = 255 & *p++; v = (v << 8) | (255 & *p++); recordDispatch.nLength = v; v = 255 & *p++; nPadding = v; ++p; // reserved iBuffer = (int) (p - pBuffer); nRecord = 8 + recordDispatch.nLength + nPadding; nNeeded = nRecord; continue; } // We now have the entire FCGI record. if (!recordDispatch.onRecord(pBuffer + iRecord + 8)) { return false; } nNeeded = 8; iRecord += nRecord; nPresent = nPayload - iRecord; assert(iRecord <= nPayload); // Is there anything left over after the record? if (0 == nPresent) { iBuffer = iRecord = nPayload = 0; break; } iBuffer = iRecord; } // Make room in buffer by moving down any record fragment. if (0 < iRecord) { if (0 < nPresent) { memcpy(pBuffer,pBuffer + iRecord,nPresent); } iRecord = iBuffer = 0; nPayload = nPresent; } } return true; }