Esempio n. 1
0
HTTPRequest HTTPRequest::post(
		const Str & body,
		const Str & uri,
		const Str & version)
{
	return HTTPRequest(Str("POST"), uri, body, version);
}
Esempio n. 2
0
HTTPRequest HTTPRequest::get(
		const Str & uri,
		const Str & version)
{
	(void)uri;
	(void)version;
	return HTTPRequest("GET", uri, "", version);
}
Esempio n. 3
0
HTTPServer::HTTPServer(const std::string &addr, const std::string &port, int maxClientsCount,
                       std::function<HTTPResponse(HTTPRequest &request)> onGet,
                       std::function<HTTPResponse(HTTPRequest &request)> onPost,
                       EpollHandler &epoll) {
    std::function<void(TCPSocket &)> onAccept = [&onGet, &onPost, this](TCPSocket &sock) {
        const int BUF_MAX_SIZE = 4096;
        char buf[BUF_MAX_SIZE];

        int len;
        while (true) {
            len = sock.recieveMsg(buf, BUF_MAX_SIZE);
            if (len <= 0) break;
            addBufToString(currentRequest[sock.sockfd], buf, len);
        }
        std::cerr << " ======\n" << currentRequest[sock.sockfd] << "\n===========\n";
        HTTPRequest httpRequest;
        HTTPResponse httpResponse;
        try {
            //std::cout << currentRequest << "\n";
            httpRequest = HTTPRequest(currentRequest[sock.sockfd]);

            //std::cout << "Request from soket " << sock.sockfd << ": " << currentRequest << "\n";
            if (httpRequest.getMethod() == "GET") {
                httpResponse = onGet(httpRequest);
            } else if (httpRequest.getMethod() == "POST") {
                httpResponse = onPost(httpRequest);
            }
            std::cout << "Response for socket " << sock.sockfd << ": \n";
            sock.sendMsg(httpResponse.buildResponse().c_str());
            currentRequest[sock.sockfd] = "";
        } catch (NotFullRequestException &e) {
            std::cerr << "Not full request: " << e.getMessage() << "\n";
        } catch (HTTPException &e) {
            std::cerr << "Bad HTTP Request: " << e.getMessage() << "\n";

            httpResponse.setHttpVersion("HTTP/1.1");
            httpResponse.setStatusCode(400);
            httpResponse.setReasonPhrase("Bad Request");
            httpResponse.addEntityHeader("Content-Type", "*/*");

            std::cout << "Response for socket " << sock.sockfd << ": \n";
            sock.sendMsg(httpResponse.buildResponse().c_str());
            currentRequest[sock.sockfd] = "";
        }


    };
    tcpServer = new TCPServer(addr.c_str(), port.c_str(), maxClientsCount * 2, onAccept, epoll);
}
Esempio n. 4
0
//Request Process(HTTP part)
bool __fastcall HTTPRequestProcess(
	const DNS_PACKET_DATA &Packet, 
	char *OriginalRecv, 
	const size_t RecvSize, 
	const SOCKET_DATA &LocalSocketData)
{
	size_t DataLength = 0;
	memset(OriginalRecv, 0, RecvSize);

//EDNS switching(Part 1)
	size_t EDNS_SwitchLength = Packet.Length;
	uint16_t EDNS_Packet_Flags = ((dns_hdr *)(Packet.Buffer))->Flags;
	if (Parameter.EDNS_Label && !Parameter.EDNS_Switch.EDNS_HTTP)
	{
	//Reset EDNS flags, resource record counts and packet length.
		((dns_hdr *)(Packet.Buffer))->Flags = htons(ntohs(((dns_hdr *)(Packet.Buffer))->Flags) & (~DNS_GET_BIT_AD));
		((dns_hdr *)(Packet.Buffer))->Flags = htons(ntohs(((dns_hdr *)(Packet.Buffer))->Flags) & (~DNS_GET_BIT_CD));
		if (((dns_hdr *)(Packet.Buffer))->Additional > 0)
			((dns_hdr *)(Packet.Buffer))->Additional = htons(ntohs(((dns_hdr *)(Packet.Buffer))->Additional) - 1U);
		EDNS_SwitchLength -= Packet.EDNS_Record;
	}

//HTTP request
	DataLength = HTTPRequest(Packet.Buffer, EDNS_SwitchLength, OriginalRecv, RecvSize);

//Send response.
	if (DataLength >= DNS_PACKET_MINSIZE && DataLength < RecvSize)
	{
		SendToRequester(OriginalRecv, DataLength, RecvSize, Packet.Protocol, LocalSocketData);
		return true;
	}

//EDNS switching(Part 2)
	if (Parameter.EDNS_Label && !Parameter.EDNS_Switch.EDNS_HTTP)
	{
		((dns_hdr *)(Packet.Buffer))->Flags = EDNS_Packet_Flags;
		((dns_hdr *)(Packet.Buffer))->Additional = htons(ntohs(((dns_hdr *)(Packet.Buffer))->Additional) + 1U);
	}

	return false;
}
Esempio n. 5
0
bool HTTPParser::parse(HTTPRequest &request)
{
    static const string delim = "\r\n\r\n";
    int pos = m_buf.find(delim);
    if (pos == string::npos)
        return false;
    string data = m_buf.substr(0, pos);
    m_buf.erase(0, pos + delim.length());
    vector<string> lines = move(Utils::Strings::split(data, "\r\n"));
    vector<string> parts = move(Utils::Strings::split(lines[0]));
    if (parts.size() != 3)
        throw HTTPIncompleteRequest(Utils::Strings::format("Invalid HTTP request \"%s\"", lines[0].c_str()));
    string method = parts[0];
    if (!isMethod(method))
        throw HTTPInvalidMethod(Utils::Strings::format("Invalid HTTP method \"%s\"", method.c_str()));
    string uri = parts[1];
    map<string, string> params;
    parseURI(uri, params);
    string version = parts[2];
    if (version != "HTTP/1.1")
        throw HTTPUnsupportedVersion(Utils::Strings::format("Unsupported HTTP version \"%s\"", version.c_str()));
    request = HTTPRequest(method, uri, version, params);
    return true;
}
Esempio n. 6
0
QByteArray SSLConnect::getUrl( RequestType type, const QString &value )
{
	if( !d->ssl )
		return QByteArray();

	if( !SSL_check_private_key( d->ssl ) )
	{
		d->setError();
		return QByteArray();
	}

	QString label;
	HTTPRequest req;
	switch( type )
	{
	case AccessCert:
	{
		label = tr("Loading server access certificate. Please wait.");
		SOAPDocument s( "GetAccessToken", "urn:GetAccessToken" );
		s.writeParameter( "Language", Settings::language().toUpper() );
		s.writeParameter( "RequestTime", "" );
		s.writeParameter( "SoftwareName", "DigiDoc3" );
		s.writeParameter( "SoftwareVersion", qApp->applicationVersion() );
		s.finalize();
		req = HTTPRequest( "POST", "1.1", "https://id.sk.ee/GetAccessTokenWS/" );
		req.setRawHeader( "Content-Type", "text/xml" );
		req.setRawHeader( "SOAPAction", QByteArray() );
		req.setRawHeader( "Connection", "close" );
		req.setContent( s.document() );
		break;
	}
	case MobileInfo:
	{
		label = tr("Loading Mobile info");
		SOAPDocument s( "GetMIDTokens", "urn:GetMIDTokens" );
		s.finalize();
		req = HTTPRequest( "POST", "1.1", "https://id.sk.ee/MIDInfoWS/" );
		req.setRawHeader( "Content-Type", "text/xml" );
		req.setRawHeader( "SOAPAction", QByteArray() );
		req.setRawHeader( "Connection", "close" );
		req.setContent( s.document() );
		break;
	}
	case EmailInfo:
		label = tr("Loading Email info");
		req = HTTPRequest( "GET", "1.0",
			"https://sisene.www.eesti.ee/idportaal/postisysteem.naita_suunamised" );
		break;
	case ActivateEmails:
		label = tr("Loading Email info");
		req = HTTPRequest( "GET", "1.0",
			QString("https://www.eesti.ee/portaal/!postisysteem.suunamised?%1").arg( value ) );
		break;
	case PictureInfo:
		label = tr("Downloading picture");
		req = HTTPRequest( "GET", "1.0",
			"https://sisene.www.eesti.ee/idportaal/portaal.idpilt" );
		break;
	default: return QByteArray();
	}

	QByteArray url = req.url().host().toUtf8();
	BIO *sock = BIO_new_connect( (char*)url.constData() );
	BIO_set_conn_port( sock, "https" );
	if( BIO_do_connect( sock ) <= 0 )
	{
		d->setError( tr( "Failed to connect to host. Are you connected to the internet?" ) );
		return QByteArray();
	}

	SSL_set_bio( d->ssl, sock, sock );
	if( !SSL_connect( d->ssl ) )
	{
		d->setError();
		return QByteArray();
	}

	QByteArray header = req.request();
	if( !SSL_write( d->ssl, header.constData(), header.size() ) )
	{
		d->setError();
		return QByteArray();
	}

	QProgressDialog p( label, QString(), 0, 0, qApp->activeWindow() );
	p.setWindowFlags( (p.windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowCloseButtonHint );
	if( QProgressBar *bar = p.findChild<QProgressBar*>() )
		bar->setTextVisible( false );
	p.open();

	return SSLReadThread( d ).waitForDone();
}
Esempio n. 7
0
SInt64 EasyCMSSession::Run()
{	
	OS_Error theErr = OS_NoErr;
	EventFlags events = this->GetEvents();

	if(events & Task::kKillEvent)
	{
		qtss_printf("kill event but not handle it!\n");
	}

	while(1)
	{
		switch (fState)
		{
			case kIdle://空闲
				{
					qtss_printf("kIdle state \n");

					if(!IsConnected())
					{
						// TCPSocket未连接的情况,首先进行登录连接
						Login();
					}
					else
					{
						// TCPSocket已连接的情况下区分具体事件类型
						if(events & Task::kStartEvent)
						{
							// CMSSession掉线,重新进行上线动作
							if(kSessionOffline == fSessionStatus)
								Login();
						}

						if(events & Task::kReadEvent)
						{
							// 对已连接的TCP进行消息读取
							fState = kReadingRequest;
						}
						if(events & Task::kTimeoutEvent)
						{
							// 保活时间到,需要发送保活报文
							Login();
						}
					}
					
					// 如果有消息需要发送则进入发送流程
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingResponse;
					}

					if(kIdle == fState) return 0;

					break;
				}

			case kReadingRequest:
				{
					qtss_printf("kReadingRequest state \n");

					// 读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理
					OSMutexLocker readMutexLocker(&fReadMutex);

					// 网络请求报文存储在fInputStream中
					if ((theErr = fInputStream.ReadRequest()) == QTSS_NoErr)
					{
						//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
						//但,还不能构成一个整体报文,还要继续等待读取...
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_RE);
						return 0;
					}
                
					if ((theErr != QTSS_RequestArrived) && (theErr != E2BIG) && (theErr != QTSS_BadArgument))
					{
						//Any other error implies that the input connection has gone away.
						// We should only kill the whole session if we aren't doing HTTP.
						// (If we are doing HTTP, the POST connection can go away)
						Assert(theErr > 0);
						// If we've gotten here, this must be an HTTP session with
						// a dead input connection. If that's the case, we should
						// clean up immediately so as to not have an open socket
						// needlessly lingering around, taking up space.
						Assert(!fSocket->GetSocket()->IsConnected());
						this->ResetClientSocket();

						return 0;
					}
					fState = kProcessingRequest;
					break;
				}
			case kProcessingRequest:
				{
					qtss_printf("kProcessingRequest state \n");
					// 处理网络报文
					Assert( fInputStream.GetRequestBuffer() );
                
					Assert(fRequest == NULL);
					// 根据具体请求报文构造HTTPRequest请求类
					fRequest = NEW HTTPRequest(&sServiceStr, fInputStream.GetRequestBuffer());

					// 在这里,我们已经读取了一个完整的Request,并准备进行请求的处理,直到响应报文发出
					// 在此过程中,此Session的Socket不进行任何网络数据的读/写;
					fReadMutex.Lock();
					fSessionMutex.Lock();
                
					// 清空发送缓冲区
					fOutputStream.ResetBytesWritten();
                
					// 网络请求超过了缓冲区,返回Bad Request
					if (theErr == E2BIG)
					{
						// 返回HTTP报文,错误码408
						//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong);
						fState = kSendingResponse;
						break;
					}
					// Check for a corrupt base64 error, return an error
					if (theErr == QTSS_BadArgument)
					{
						//返回HTTP报文,错误码408
						//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
						fState = kSendingResponse;
						break;
					}

					Assert(theErr == QTSS_RequestArrived);
					ProcessRequest();

					// 每一步都检测响应报文是否已完成,完成则直接进行回复响应
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingResponse;
					}
					else
					{
						fState = kCleaningUp;
					}
					break;
				}
			case kSendingResponse:
				{
					qtss_printf("kSendingResponse state \n");

					// 响应报文发送,确保完全发送
					// Assert(fRequest != NULL);

					//发送响应报文
					theErr = fOutputStream.Flush();
                
					if (theErr == EAGAIN || theErr == EINPROGRESS)
					{
						// If we get this error, we are currently flow-controlled and should
						// wait for the socket to become writeable again
						// 如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
						this->ForceSameThread();
						// We are holding mutexes, so we need to force
						// the same thread to be used for next Run()
						return 0;
					}
					else if (theErr != QTSS_NoErr)
					{
						// Any other error means that the client has disconnected, right?
						Assert(!this->IsConnected());
						ResetClientSocket();
						return 0;
					}
            
					fState = kCleaningUp;
					break;
				}
			case kCleaningUp:
				{
					qtss_printf("kCleaningUp state \n");
					// 清理已经处理的请求或者已经发送的报文缓存
					// Cleaning up consists of making sure we've read all the incoming Request Body
					// data off of the socket
					////if (this->GetRemainingReqBodyLen() > 0)
					////{
					////	err = this->DumpRequestData();
              
					////	if (err == EAGAIN)
					////	{
					////		fInputSocketP->RequestEvent(EV_RE);
					////		this->ForceSameThread();    // We are holding mutexes, so we need to force
					////									// the same thread to be used for next Run()
					////		return 0;
					////	}
					////}

					// 一次请求的读取、处理、响应过程完整,等待下一次网络报文!
					this->CleanupRequest();
					fState = kIdle;
					
					if(IsConnected())
					{
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
					}
					return 0;
				}
		}
	}
    return 0;
}
Esempio n. 8
0
SInt64 EasyCMSSession::Run()
{	
	OSMutexLocker locker(&fMutex);

	OS_Error theErr = OS_NoErr;
	EventFlags events = this->GetEvents();

    if ((events & Task::kTimeoutEvent) || (events & Task::kKillEvent))
        fLiveSession = false;

	while(fLiveSession)
	{
		switch (fState)
		{
			case kIdle:
				{
					//根据事件类型执行不同的动作
					if(events & Task::kStartEvent)
					{
						switch(fEasyMsgType)
						{
						case MSG_CS_FREE_STREAM_REQ:
							{
								CSFreeStream();
								break;
							}
						default:
							break;
						}
					}

					if(events & Task::kReadEvent)
					{
						// 已连接,有新消息需要读取(数据或者断开)
						fState = kReadingMessage;
					}

					// 如果有消息需要发送则进入发送流程
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingMessage;
					}

					//当前状态没有进行数据发送,则等待下一次事件触发
					if(kIdle == fState)
					{
						return 0;
					}
					break;
				}

			case kReadingMessage:
				{
					// 网络请求报文存储在fInputStream中
					if ((theErr = fInputStream.ReadRequest()) == QTSS_NoErr)
					{
						//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
						//但!还不能构成一个整体报文Header部分,还要继续等待读取...
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_RE);

						fState = kIdle;
						return 0;
					}
                
					if ((theErr != QTSS_RequestArrived) && (theErr != E2BIG) && (theErr != QTSS_BadArgument))
					{
						//Any other error implies that the input connection has gone away.
						// We should only kill the whole session if we aren't doing HTTP.
						// (If we are doing HTTP, the POST connection can go away)
						Assert(theErr > 0);
						// If we've gotten here, this must be an HTTP session with
						// a dead input connection. If that's the case, we should
						// clean up immediately so as to not have an open socket
						// needlessly lingering around, taking up space.
						Assert(!fSocket->GetSocket()->IsConnected());
						//this->ResetClientSocket();
						//return 0;
						//读取数据失败,直接进入析构
					}
					// 网络请求超过了缓冲区,返回Bad Request
					if ( (theErr == E2BIG) || (theErr == QTSS_BadArgument) )
					{
						//返回HTTP报文,错误码408
						//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
						fState = kCleaningUp;
					}
					else
					{
						fState = kProcessingMessage;
					}
					break;
				}
			case kProcessingMessage:
				{
					// 处理网络报文
					Assert( fInputStream.GetRequestBuffer() );
					Assert(fRequest == NULL);

					// 根据具体请求报文构造HTTPRequest请求类
					fRequest = NEW HTTPRequest(&QTSServerInterface::GetServerHeader(), fInputStream.GetRequestBuffer());
                
					// 清空发送缓冲区
					fOutputStream.ResetBytesWritten();

					Assert(theErr == QTSS_RequestArrived);

					// 处理收到的具体报文
					ProcessMessage();

					// 每一步都检测响应报文是否已完成,完成则直接进行回复响应
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingMessage;
					}
					else
					{
						fState = kCleaningUp;
					}
					break;
				}
			case kSendingMessage:
				{
					//发送响应报文
					theErr = fOutputStream.Flush();

					if(theErr == 115)
					{
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_WR);
						this->ForceSameThread();
						return 0;
					}

					if (theErr == EAGAIN || theErr == EINPROGRESS)
					{
						// If we get this error, we are currently flow-controlled and should
						// wait for the socket to become writeable again
						// 如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
						this->ForceSameThread();
						// We are holding mutexes, so we need to force
						// the same thread to be used for next Run()
						return 0;
					}
					else if (theErr != QTSS_NoErr)
					{
						// Any other error means that the client has disconnected, right?
						Assert(!this->IsConnected());
						//向服务器发送数据失败,直接进入析构
						//ResetClientSocket();
						return -1;
					}
            
					fState = kCleaningUp;
					break;
				}
			case kCleaningUp:
				{
					// 一次请求的读取、处理、响应过程完整,等待下一次网络报文!
					this->CleanupRequest();
					fState = kIdle;
					if(IsConnected())
					{
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_RE | EV_WR);//网络事件监听
					}
					return 0;
				}
		}
	}
    return -1;
}
Esempio n. 9
0
/*!
	\brief 事件由ServiceSession Task进行处理,大多数为网络报文处理事件 
	\param 
	\return 处理完成返回0,断开Session返回-1
	\ingroup 
	\see 
*/
SInt64 CServiceSession::Run()
{
	//获取事件类型
    EventFlags events = this->GetEvents();
    QTSS_Error err = QTSS_NoErr;
    QTSSModule* theModule = NULL;
    UInt32 numModules = 0;
    // Some callbacks look for this struct in the thread object
    OSThreadDataSetter theSetter(&fModuleState, NULL);
        
    //超时事件或者Kill事件,进入释放流程:清理 & 返回-1
    if (events & Task::kKillEvent)
        fLiveSession = false;

	if(events & Task::kTimeoutEvent)
	{
		//客户端Session超时,暂时不处理 
		char msgStr[512];
		qtss_snprintf(msgStr, sizeof(msgStr), "session timeout,release session\n");
		QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);
		return -1;
	}

	//正常事件处理流程
    while (this->IsLiveSession())
    {
        //报文处理以状态机的形式,可以方便多次处理同一个消息
        switch (fState)
        {
            case kReadingFirstRequest://首次对Socket进行读取
            {
                if ((err = fInputStream.ReadRequest()) == QTSS_NoErr)
                {
					//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
					//但,还不能构成一个整体报文,还要继续等待读取...
                    fInputSocketP->RequestEvent(EV_RE);
                    return 0;
                }
                
                if ((err != QTSS_RequestArrived) && (err != E2BIG))
                {
                    // Any other error implies that the client has gone away. At this point,
                    // we can't have 2 sockets, so we don't need to do the "half closed" check
                    // we do below
                    Assert(err > 0); 
                    Assert(!this->IsLiveSession());
                    break;
                }

                if ((err == QTSS_RequestArrived) || (err == E2BIG))
                    fState = kHaveCompleteMessage;
            }
            continue;            
            case kReadingRequest://读取请求报文
            {
				//读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理
                OSMutexLocker readMutexLocker(&fReadMutex);

				//网络请求报文存储在fInputStream中
                if ((err = fInputStream.ReadRequest()) == QTSS_NoErr)
                {
					//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
					//但,还不能构成一个整体报文,还要继续等待读取...
                    fInputSocketP->RequestEvent(EV_RE);
                    return 0;
                }
                
                if ((err != QTSS_RequestArrived) && (err != E2BIG) && (err != QTSS_BadArgument))
                {
                    //Any other error implies that the input connection has gone away.
                    // We should only kill the whole session if we aren't doing HTTP.
                    // (If we are doing HTTP, the POST connection can go away)
                    Assert(err > 0);
                    if (fOutputSocketP->IsConnected())
                    {
                        // If we've gotten here, this must be an HTTP session with
                        // a dead input connection. If that's the case, we should
                        // clean up immediately so as to not have an open socket
                        // needlessly lingering around, taking up space.
                        Assert(fOutputSocketP != fInputSocketP);
                        Assert(!fInputSocketP->IsConnected());
                        fInputSocketP->Cleanup();
                        return 0;
                    }
                    else
                    {
                        Assert(!this->IsLiveSession());
                        break;
                    }
                }
                fState = kHaveCompleteMessage;
            }
            case kHaveCompleteMessage://读取到完整的请求报文
            {
                Assert( fInputStream.GetRequestBuffer() );
                
                Assert(fRequest == NULL);
				//根据具体请求报文构造HTTPRequest请求类
				fRequest = NEW HTTPRequest(&sServiceStr, fInputStream.GetRequestBuffer());

				//在这里,我们已经读取了一个完整的Request,并准备进行请求的处理,直到响应报文发出
				//在此过程中,此Session的Socket不进行任何网络数据的读/写;
                fReadMutex.Lock();
                fSessionMutex.Lock();
                
                //清空发送缓冲区
                fOutputStream.ResetBytesWritten();
                
				//网络请求超过了缓冲区,返回Bad Request
                if (err == E2BIG)
                {
					//返回HTTP报文,错误码408
                    //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong);
                    fState = kSendingResponse;
                    break;
                }
                // Check for a corrupt base64 error, return an error
                if (err == QTSS_BadArgument)
                {
					//返回HTTP报文,错误码408
                    //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
                    fState = kSendingResponse;
                    break;
                }

                Assert(err == QTSS_RequestArrived);
                fState = kFilteringRequest;
            }
            
            case kFilteringRequest:
            {
                //刷新Session保活时间
                fTimeoutTask.RefreshTimeout();

				//对请求报文进行解析
				QTSS_Error theErr = SetupRequest();
				//当SetupRequest步骤未读取到完整的网络报文,需要进行等待
				if(theErr == QTSS_WouldBlock)
				{
					this->ForceSameThread();
					fInputSocketP->RequestEvent(EV_RE);
					// We are holding mutexes, so we need to force
					// the same thread to be used for next Run()
                    return 0;//返回0表示有事件才进行通知,返回>0表示规定事件后调用Run

				}
                
                //每一步都检测响应报文是否已完成,完成则直接进行回复响应
                if (/*fRequest->HasResponseBeenSent()*/fOutputStream.GetBytesWritten() > 0)
                {
                    fState = kSendingResponse;
                    break;
                }

                fState = kPreprocessingRequest;
                break;
            }
                       
            case kPreprocessingRequest:
            {
                //请求预处理过程
				//TODO:报文处理过程
                fState = kCleaningUp;
				break;
            }

            case kProcessingRequest:
            {
                if (fOutputStream.GetBytesWritten() == 0)
                {
					//如果到这里,响应报文还没有形成,返回500 Server Internal Error
					////QTSSModuleUtils::SendErrorResponse(fRequest, qtssServerInternal, qtssMsgNoModuleForRequest);
                }

                fState = kSendingResponse;
            }
            case kSendingResponse:
            {
                //响应报文发送,确保完全发送
                Assert(fRequest != NULL);

				//发送响应报文
                err = fOutputStream.Flush();
                
                if (err == EAGAIN)
                {
                    // If we get this error, we are currently flow-controlled and should
                    // wait for the socket to become writeable again
					//如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送
                    fSocket.RequestEvent(EV_WR);
                    this->ForceSameThread();
					// We are holding mutexes, so we need to force
					// the same thread to be used for next Run()
                    return 0;
                }
                else if (err != QTSS_NoErr)
                {
                    // Any other error means that the client has disconnected, right?
                    Assert(!this->IsLiveSession());
                    break;
                }
            
                fState = kCleaningUp;
            }
            
            case kCleaningUp:
            {
                // Cleaning up consists of making sure we've read all the incoming Request Body
                // data off of the socket
                if (this->GetRemainingReqBodyLen() > 0)
                {
                    err = this->DumpRequestData();
                    
                    if (err == EAGAIN)
                    {
                        fInputSocketP->RequestEvent(EV_RE);
                        this->ForceSameThread();    // We are holding mutexes, so we need to force
                                                    // the same thread to be used for next Run()
                        return 0;
                    }
                }

				//一次请求的读取、处理、响应过程完整,等待下一次网络报文!
                this->CleanupRequest();
                fState = kReadingRequest;
            }
        }
    } 

	//清空Session占用的所有资源
    this->CleanupRequest();

    //Session引用数为0,返回-1后,系统会将此Session删除
    if (fObjectHolders == 0)
        return -1;

	//如果流程走到这里,Session实际已经无效了,应该被删除,但没有,因为还有其他地方引用了Session对象
    return 0;
}
Esempio n. 10
0
SInt64 EasyCMSSession::Run()
{
	//OSMutexLocker locker(&fMutex);

	OS_Error theErr = OS_NoErr;
	EventFlags events = this->GetEvents();

	while (true)
	{
		switch (fState)
		{
		case kIdle:
			{
				if (!isConnected())
				{
					// TCPSocket未连接的情况,首先进行登录连接
					doDSRegister();
				}
				else
				{
					if (fNoneACKMsgCount > 3)
					{
						this->resetClientSocket();

						return 0;
					}

					// TCPSocket已连接的情况下先区分具体事件类型
					if (events & Task::kStartEvent)
					{
						// 已连接,但状态为离线,重新进行上线动作
						if (kSessionOffline == fSessionStatus)
							doDSRegister();
					}

					if (events & Task::kReadEvent)
					{
						// 已连接,有新消息需要读取(数据或者断开)
						fState = kReadingMessage;
					}

					if (events & Task::kTimeoutEvent)
					{
						// 已连接,保活时间到需要发送保活报文
						if(fCSeq%3 == 1)
							doDSPostSnap();
						else
							doDSRegister();

						fTimeoutTask.RefreshTimeout();
					}

					if (events & Task::kUpdateEvent)
					{
						//已连接,发送快照更新
						doDSPostSnap();
					}
				}

				// 如果有消息需要发送则进入发送流程
				if (fOutputStream.GetBytesWritten() > 0)
				{
					fState = kSendingMessage;
				}

				// 
				if (kIdle == fState)
				{
					return 0;
				}

				break;
			}
		case kReadingMessage:
			{
				// 网络请求报文存储在fInputStream中
				if ((theErr = fInputStream.ReadRequest()) == QTSS_NoErr)
				{
					//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
					//但!还不能构成一个整体报文Header部分,还要继续等待读取...
					fSocket->GetSocket()->SetTask(this);
					fSocket->GetSocket()->RequestEvent(EV_RE);

					fState = kIdle;
					return 0;
				}

				if ((theErr != QTSS_RequestArrived) && (theErr != E2BIG) && (theErr != QTSS_BadArgument))
				{
					//Any other error implies that the input connection has gone away.
					// We should only kill the whole session if we aren't doing HTTP.
					// (If we are doing HTTP, the POST connection can go away)
					Assert(theErr > 0);
					// If we've gotten here, this must be an HTTP session with
					// a dead input connection. If that's the case, we should
					// clean up immediately so as to not have an open socket
					// needlessly lingering around, taking up space.
					Assert(!fSocket->GetSocket()->IsConnected());
					this->resetClientSocket();

					return 0;
				}

				// 网络请求超过了缓冲区,返回Bad Request
				if ((theErr == E2BIG) || (theErr == QTSS_BadArgument))
				{
					//返回HTTP报文,错误码408
					//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
					fState = kCleaningUp;
				}
				else
				{
					fState = kProcessingMessage;
				}
				break;
			}
		case kProcessingMessage:
			{
				// 处理网络报文
				Assert(fInputStream.GetRequestBuffer());
				Assert(fRequest == NULL);

				// 根据具体请求报文构造HTTPRequest请求类
				fRequest = NEW HTTPRequest(&QTSServerInterface::GetServerHeader(), fInputStream.GetRequestBuffer());

				// 清空发送缓冲区
				fOutputStream.ResetBytesWritten();

				Assert(theErr == QTSS_RequestArrived);

				QTSS_Error theErr = processMessage();

				// 每一步都检测响应报文是否已完成,完成则直接进行回复响应
				if (fOutputStream.GetBytesWritten() > 0)
				{
					fState = kSendingMessage;
				}
				else
				{
					fState = kCleaningUp;
				}
				break;
			}
		case kSendingMessage:
			{
				theErr = fOutputStream.Flush();

				if (theErr == EAGAIN || theErr == EINPROGRESS)
				{
					qtss_printf("EasyCMSSession::Run fOutputStream.Flush() theErr:%d \n", theErr);
					fSocket->GetSocket()->SetTask(this);
					fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
					this->ForceSameThread();
					return 0;
				}
				else if (theErr != QTSS_NoErr)
				{
					// Any other error means that the client has disconnected, right?
					Assert(!this->isConnected());
					resetClientSocket();
					return 0;
				}

				++fNoneACKMsgCount;

				fState = kCleaningUp;
				break;
			}
		case kCleaningUp:
			{
				// Cleaning up consists of making sure we've read all the incoming Request Body
				// data off of the socket
				////if (this->GetRemainingReqBodyLen() > 0)
				////{
				////	err = this->DumpRequestData();

				////	if (err == EAGAIN)
				////	{
				////		fInputSocketP->RequestEvent(EV_RE);
				////		this->ForceSameThread();    // We are holding mutexes, so we need to force
				////									// the same thread to be used for next Run()
				////		return 0;
				////	}
				////}

				// clean up and wait for next run
				cleanupRequest();
				fState = kIdle;

				if (isConnected())
				{
					fSocket->GetSocket()->SetTask(this);
					fSocket->GetSocket()->RequestEvent(EV_RE | EV_WR);
				}
				return 0;
			}

		}
	}
	return 0;
}