コード例 #1
0
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;
}