Ticket #5815: http_connection.cpp

File http_connection.cpp, 5.8 KB (added by mileandrei@…, 11 years ago)
Line 
1
2#include "http_connection.h"
3#include "http_request.h"
4#include "http_response.h"
5#include "connection_manager.h"
6#include "pagebuilder.h"
7#include "../../engine/session.h"
8#include "../../engine/logger.h"
9#include "../../engine/command_creator.h"
10
11
12
13#include <iostream>
14#include <cassert>
15#include <boost/bind.hpp>
16
17
18namespace http_server
19{
20
21#define STYLE_CSS "/styles.css"
22#define WEBGL_JS "/webgl.js"
23#define COMPANEL_JS "/command_panel.js"
24
25//static members
26std::map<unsigned int, cSession*> cHttpConnection::s_Sessions;
27cEstimator cHttpConnection::s_Estimator;
28
29typedef std::pair<unsigned int, cSession*> ses_pair;
30
31
32cHttpConnection::cHttpConnection(boost::asio::io_service& io_service, cConnectionManager &conn_manager)
33 :m_Socket(io_service),
34 m_ConnectionManager(conn_manager),
35 m_IoTimeout(io_service)
36 //m_TimeoutStarted(false)
37{
38};
39
40cHttpConnection::~cHttpConnection()
41{
42};
43
44void cHttpConnection::HandleClient()
45{
46 //read
47 boost::asio::async_read_until(m_Socket, m_RequestBuf, "\r\n",
48 boost::bind(&cHttpConnection::HandleRequest, shared_from_this(),
49 boost::asio::placeholders::error));
50};
51
52void cHttpConnection::StartTimeout()
53{
54 m_IoTimeout.expires_from_now(boost::posix_time::seconds(30));
55 m_IoTimeout.async_wait(boost::bind(&cHttpConnection::HandleTimeout, shared_from_this(),
56 boost::asio::placeholders::error));
57 m_TimeoutStarted = true;
58};
59
60
61void cHttpConnection::HandleTimeout(const boost::system::error_code &e)
62{
63// if (e != boost::asio::error::operation_aborted)
64// m_ConnectionManager.StopConnection(shared_from_this());
65};
66
67
68void cHttpConnection::HandleRequest(const boost::system::error_code& error)
69{
70 if(!error)
71 {
72
73// if(m_TimeoutStarted)
74// m_IoTimeout.cancel();
75 std::istream is(&m_RequestBuf);
76 cRequest _request(is);
77 if(false == _request.ParseRequest())
78 {
79 std::string request_str;
80 is>>request_str;
81 throw std::runtime_error(CONTEXT_STR + "failed to parse request :" + request_str);
82 }
83 m_HttpVersion = (_request.GetVersion() == HTTP_VER1)? 1 : 0;
84 switch(_request.GetMethod())
85 {
86 case GET_M:
87 if(_request.GetResource() == "/" || _request.GetResource() == "/index.html")
88 {
89 //add new session
90 unsigned int ses_id = cHttpConnection::GetRandUniqueId();
91 cHttpConnection::s_Sessions.insert(ses_pair(ses_id, new cSession(ses_id)));
92
93 //build response
94 cResponse response(m_ResponseBuf);
95 const std::string index_page=cPageBuilder::GetInstance()->GetIndexPage(ses_id);
96 response.BuildResponse(OK, index_page);
97 }
98 else if( STYLE_CSS == _request.GetResource() ||
99 COMPANEL_JS == _request.GetResource() ||
100 WEBGL_JS == _request.GetResource() )
101 {
102 cResponse response(m_ResponseBuf);
103 const std::string resource = cPageBuilder::GetInstance()->GetPageResource(
104 _request.GetResource());
105 response.BuildResponse(OK, resource);
106 }
107 else //request is a command
108 {
109 cResponse response(m_ResponseBuf);
110 _request.ParseResource();
111 unsigned int ses_id = _request.GetSessionId();
112
113 if(cHttpConnection::s_Sessions.find(ses_id)!=cHttpConnection::s_Sessions.end())
114 {
115 HandleExistingSession(response, _request, ses_id);
116 }
117 else //session lost
118 {
119 assert(false);
120 //add new session
121 cHttpConnection::s_Sessions.insert(ses_pair(ses_id, new cSession(ses_id)));
122
123 const std::string index_page = cPageBuilder::GetInstance()->GetIndexPage(
124 ses_id);
125 response.BuildResponse(OK, index_page);
126 }
127 }
128 boost::asio::async_write(m_Socket, m_ResponseBuf,
129 boost::bind(&cHttpConnection::HandleWriteResponse, shared_from_this(),
130 boost::asio::placeholders::error));
131 break;
132 case POST_M:
133 break;
134 case HEAD_M:
135 break;
136 case PUT_M:
137 break;
138 case OPTIONS_M:
139 break;
140 case DELETE_M:
141 break;
142 case TRACE_M:
143 break;
144 case CONNECT_M:
145 break;
146 default:
147 break;
148
149 }
150 }
151 else
152 {
153 throw std::runtime_error(CONTEXT_STR + error.message());
154 }
155};
156
157void cHttpConnection::HandleExistingSession(cResponse& response, const cRequest& _request, const unsigned int ses_id)
158{
159 cSession* session = cHttpConnection::s_Sessions[ses_id];
160 if(session->GetState() == STATE_FREE)
161 {
162 cCommand* command = cCommandCreator<cCreator>::GetCommand(
163 _request.GetCommandId(), _request.GetParam(),
164 session->GetResult());
165 int runtime_estimation = command->EstimateRunTime(s_Estimator);
166
167 if( runtime_estimation <= 360/*seconds*/)
168 {
169 session->RunCommand(command);
170 response.BuildResponse(OK, cPageBuilder::GetInstance()->GetPage(
171 *session->GetResult(), ses_id));
172 }
173 else
174 {
175 session->ScheduleCommand(command);
176 response.BuildResponse(OK,
177 cPageBuilder::GetInstance()->GetLoadingPage(
178 runtime_estimation, ses_id));
179 }
180 }
181 else if(session->GetState() == STATE_RESULT_PENDING)
182 {
183 response.BuildResponse(OK, cPageBuilder::GetInstance()->GetPage(
184 *session->GetResult(), ses_id));
185 }
186};
187
188void cHttpConnection::HandleWriteResponse(const boost::system::error_code& error)
189{
190 if(error)
191 {
192 throw std::runtime_error(CONTEXT_STR + error.message());
193 }
194 else
195 {
196 if(m_HttpVersion == true) //persistent connection
197 {
198 StartTimeout();
199 HandleClient();
200 }
201 else
202 {
203 m_ConnectionManager.StopConnection(shared_from_this());
204 }
205
206 }
207};
208
209void cHttpConnection::Stop()
210{
211 //m_IoTimeout.cancel();
212 boost::system::error_code error;
213 m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, error);
214 m_Socket.close();
215};
216
217}
218
219