Fixed some of the Keep Alive issues
[theodwalha.git] / theodwalha / client.cpp
blob538d493bac796ea75a0e2c83954a3def898a6590
1 #include <boost/bind.hpp>
2 #include <iostream>
3 #include <cstdlib>
4 #include <theodwalha/client.hpp>
5 #include <theodwalha/configuration.hpp>
6 #include <theodwalha/temporary.hpp>
7 #include <theodwalha/reply.hpp>
9 http_server_client::http_server_client(boost::asio::io_service & io_service, temporary_file_manager & file_manager, module_manager & modules):
10 socket(io_service),
11 file_manager(file_manager),
12 modules(modules),
13 keep_alive_counter(keep_alive_max)
15 read_buffer = new char[read_buffer_size];
18 http_server_client::~http_server_client()
20 delete read_buffer;
23 void http_server_client::start()
25 initialise();
26 read();
29 void http_server_client::initialise()
31 bytes_read = 0;
32 got_header = false;
35 void http_server_client::read()
37 socket.async_read_some(boost::asio::buffer(read_buffer, read_buffer_size), boost::bind(&http_server_client::read_event, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
40 void http_server_client::write(std::string const & data)
42 std::cout << "Writing:" << std::endl << data << std::endl;
44 char * write_buffer = new char[data.size()];
45 std::memcpy(write_buffer, data.c_str(), data.size());
46 boost::asio::async_write(socket, boost::asio::buffer(write_buffer, data.size()), boost::bind(&http_server_client::write_event, this, boost::asio::placeholders::error, write_buffer));
49 void http_server_client::terminate()
51 std::cout << "Terminating" << std::endl;
52 if(!temporary_file_name.empty())
54 temporary_file.close();
55 file_manager.release(temporary_file_name);
57 delete this;
60 void http_server_client::read_event(boost::system::error_code const & error, std::size_t bytes_in_buffer)
62 if(!error)
64 std::cout << "Read " << bytes_in_buffer << " bytes:" << std::endl;
65 bytes_read += bytes_in_buffer;
67 if(bytes_read > maximal_request_size)
69 std::cout << "Request too large" << std::endl;
70 terminate();
71 return;
74 std::string new_data(read_buffer, bytes_in_buffer);
76 if(temporary_file_name.empty())
78 extended_buffer += new_data;
80 std::cout << extended_buffer << std::endl;
82 if(!got_header)
84 std::string error_message;
85 current_request = http_request();
86 process_header_result::type result = process_header(extended_buffer, current_request, error_message);
87 switch(result)
89 case process_header_result::no_delimiter:
90 std::cout << "No delimiter yet" << std::endl;
91 break;
93 case process_header_result::error:
94 std::cout << error_message << std::endl;
95 terminate();
96 return;
98 case process_header_result::success:
99 got_header = true;
100 std::cout << "Retrieved the full HTTP header" << std::endl;
101 break;
105 if(extended_buffer.size() > maximal_extended_buffer_size)
107 if(!got_header)
109 std::cout << "A client exceeded the maximal extended buffer size without delivering the HTTP header" << std::endl;
110 terminate();
111 return;
114 temporary_file_name = file_manager.generate_name();
115 if(!temporary_file.open_create(temporary_file_name))
117 std::cout << "Failed to open temporary file " << temporary_file_name << std::endl;
118 exit(1);
121 temporary_file.write(extended_buffer);
122 extended_buffer.clear();
124 std::cout << "Using temporary file name " << temporary_file_name << std::endl;
127 else
128 temporary_file.write(new_data);
130 if(got_header)
132 std::size_t expected_byte_count = current_request.header_size + current_request.content_length;
133 std::cout << "Expected byte count: " << current_request.header_size << " + " << current_request.content_length << " = " << expected_byte_count << std::endl;
134 if(bytes_read > expected_byte_count)
136 std::cout << "Received too many bytes from a client" << std::endl;
137 terminate();
138 return;
140 else if(bytes_read == expected_byte_count)
142 std::cout << "Ready to serve data for " << current_request.path << std::endl;
143 module_result result;
144 if(modules.process_request(current_request, result))
146 std::cout << "The module manager successfully processed the request" << std::endl;
147 std::string data;
148 if(generate_content(current_request, result, data))
150 std::cout << "Successfully generated the HTTP content, serving it to the client" << std::endl;
151 write(data);
153 else
155 std::cout << "Failed to generate HTTP content" << std::endl;
156 terminate();
157 return;
160 else
162 std::cout << "The module manager failed to process this request" << std::endl;
163 terminate();
164 return;
169 read();
171 else
172 terminate();
175 void http_server_client::write_event(boost::system::error_code const & error, char * write_buffer)
177 delete write_buffer;
179 std::cout << "Got a write event" << std::endl;
181 if(!error)
183 if(current_request.keep_alive)
185 keep_alive_counter--;
186 if(keep_alive_counter <= 0)
188 std::cout << "Client keep alive counter is zero" << std::endl;
189 terminate();
191 else
192 read();
195 else
196 terminate();
199 bool http_server_client::generate_content(http_request & request, module_result & result, std::string & content)
201 http_reply reply;
202 reply.protocol = request.protocol_version;
203 switch(result.return_code)
205 case request_handler_return_code::ok:
206 reply.ok();
207 break;
209 case request_handler_return_code::forbidden:
210 reply.forbidden();
211 break;
213 case request_handler_return_code::not_found:
214 reply.not_found();
215 break;
217 default:
218 std::cout << "Unknown request handler return code specified" << std::endl;
219 return false;
222 reply.gzip = request.gzip;
223 reply.keep_alive = request.keep_alive;
224 reply.content_type = result.content_type;
225 reply.keep_alive_timeout = keep_alive_timeout;
226 reply.keep_alive_max = keep_alive_counter;
227 reply.content = result.content;
229 if(!reply.get_packet(content))
231 std::cout << "Failed to build reply packet" << std::endl;
232 return false;
235 return true;