PRStatus FcgiParser::formatRequest(CircularBuffer& from, CircularBuffer& to, PRUint8 streamType) { int toLen = 0; int fromLen = 0; char *toBuf = NULL; int available = to.requestSpace(toBuf, toLen) - sizeof(FCGI_Header); int dataSize = from.hasData(); int dataToBeMoved = min(dataSize, available); if(dataToBeMoved > 0) { if(toBuf) { //if(makePacketHeader(streamType, maxLen, to) == PR_SUCCESS) { if(makePacketHeader(streamType, dataToBeMoved, to) == PR_SUCCESS) { if(from.move(to, dataToBeMoved) < dataToBeMoved) return PR_FAILURE; } else return PR_FAILURE; } } return PR_SUCCESS; }
PRStatus FcgiParser::parse(CircularBuffer& from, CircularBuffer& to) { int len = 0; char *endReqBodyPtr = (char *)(&endRequestBody); PRBool noDataMoved = PR_FALSE; serverError.clear(); //clear logs. while((len = from.hasData()) > 0 && !exitStatusSet) { if(noDataMoved) { //nothing was moved - could be because the to buffer was full //so break out and let the buffer be cleared. break; } //look for a complete header if(waitingForBeginRequest) { if(len < sizeof(FCGI_Header)) return PR_SUCCESS; // incomplete header wait till we get the complete header int l = from.getData((char *)&header, sizeof(FCGI_Header)); from.releaseData(l); len -= l; //check the version if(header.version != FCGI_VERSION_1) { lastError = INVALID_VERSION; request->log(LOG_FAILURE, GetString(DBT_invalid_header_version), header.version); return PR_FAILURE; } //check the header type if(header.type > FCGI_MAXTYPE) { lastError = INVALID_TYPE; request->log(LOG_FAILURE, GetString(DBT_invalid_header_type), header.type); return PR_FAILURE; } dataLen = (header.contentLengthB1 << 8) + header.contentLengthB0; waitingForBeginRequest = PR_FALSE; } //got the header; process the data len = min(dataLen, len); if(len < 0) { lastError = INVALID_RECORD; return PR_FAILURE; } switch(header.type) { case FCGI_STDOUT: if(len > 0) { if(fcgiRole == FCGI_AUTHORIZER || waitingForDataParse) { char *buf = (char *)MALLOC(len); memset(buf, 0, len); len = from.getData(buf, len); httpHeader.append(buf, len); from.releaseData(len); FREE(buf); buf = NULL; } else { len = from.move(to, len); if(len < 1) noDataMoved = PR_TRUE; } dataLen -= len; } break; case FCGI_STDERR: if(len > 0) { char *buf = (char *)MALLOC(len);; memset(buf, 0, len); len = from.getData(buf, len); if(len) serverError.append(buf, len); from.releaseData(len); FREE(buf); dataLen -= len; } break; case FCGI_END_REQUEST: if(waitingForEndRequest) { if(dataLen != sizeof(FCGI_EndRequestBody)) { lastError = INVALID_RECORD; request->log(LOG_FAILURE, GetString(DBT_invalid_end_request_record), dataLen); return PR_FAILURE; } len = from.getData((char *)&endRequestBody, sizeof(FCGI_EndRequestBody)); if(len < sizeof(FCGI_EndRequestBody)) { //incomplete FCGI_EndRequestBody data - hence //return and wait for additional data return PR_SUCCESS; } waitingForEndRequest = PR_FALSE; from.releaseData(len); dataLen -= len; } switch(endRequestBody.protocolStatus) { case FCGI_REQUEST_COMPLETE: lastError = NO_FCGI_ERROR; break; case FCGI_CANT_MPX_CONN: lastError = CANT_MPX; request->log(LOG_FAILURE, GetString(DBT_cannot_multiplex)); break; case FCGI_OVERLOADED: lastError = OVER_LOADED; request->log(LOG_FAILURE, GetString(DBT_overloaded_status)); break; case FCGI_UNKNOWN_ROLE: lastError = UNKNOWN_ROLE; request->log(LOG_FAILURE, GetString(DBT_unknown_fcgi_role)); break; default: lastError = INVALID_RECORD; } //switch protocolstatus exitStatus = (endRequestBody.appStatusB3 << 24) + (endRequestBody.appStatusB2 << 16) + (endRequestBody.appStatusB1 << 8) + (endRequestBody.appStatusB0); if(!header.paddingLength) exitStatusSet = PR_TRUE; break; case FCGI_GET_VALUES_RESULT: /* yet to implement */ case FCGI_UNKNOWN_TYPE: /* yet to implement */ /* * Ignore unknown packet types from the FastCGI server. */ default: from.releaseData(len); dataLen -= len; } //switch(header.type) if (dataLen == 0) { if (header.paddingLength > 0) { len = min(header.paddingLength, from.hasData()); from.releaseData(len); header.paddingLength -= len; } /* * If we're done with the data in the packet, then start looking for * the next header. */ if (header.paddingLength == 0) { waitingForBeginRequest = PR_TRUE; if(!waitingForEndRequest && !exitStatusSet) exitStatusSet = PR_TRUE; } } } // while (len > 0) return PR_SUCCESS; }