Changed the directory structure, added a build script
[theodwalha.git] / theodwalha / source / client.cpp
blob3aca03b5dfaca5edf1a1fea933ebfa627c9ccfa2
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 std::cout << "Reading" << std::endl;
38 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));
41 void http_server_client::write(std::string const & data)
43 std::cout << "Writing:" << std::endl << data << std::endl;
45 char * write_buffer = new char[data.size()];
46 std::memcpy(write_buffer, data.c_str(), data.size());
47 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));
50 void http_server_client::terminate()
52 std::cout << "Terminating" << std::endl;
53 if(!temporary_file_name.empty())
55 temporary_file.close();
56 file_manager.release(temporary_file_name);
58 delete this;
61 void http_server_client::read_event(boost::system::error_code const & error, std::size_t bytes_in_buffer)
63 std::cout << "Read event" << std::endl;
64 if(!error)
66 std::cout << "Read " << bytes_in_buffer << " bytes:" << std::endl;
67 bytes_read += bytes_in_buffer;
69 if(bytes_read > maximal_request_size)
71 std::cout << "Request too large" << std::endl;
72 terminate();
73 return;
76 std::string new_data(read_buffer, bytes_in_buffer);
78 if(temporary_file_name.empty())
80 extended_buffer += new_data;
82 std::cout << extended_buffer << std::endl;
84 if(!got_header)
86 std::string error_message;
87 current_request = http_request();
88 process_header_result::type result = process_header(extended_buffer, current_request, error_message);
89 switch(result)
91 case process_header_result::no_delimiter:
92 std::cout << "No delimiter yet" << std::endl;
93 break;
95 case process_header_result::error:
96 std::cout << error_message << std::endl;
97 terminate();
98 return;
100 case process_header_result::success:
101 got_header = true;
102 std::cout << "Retrieved the full HTTP header" << std::endl;
103 break;
107 if(extended_buffer.size() > maximal_extended_buffer_size)
109 if(!got_header)
111 std::cout << "A client exceeded the maximal extended buffer size without delivering the HTTP header" << std::endl;
112 terminate();
113 return;
116 temporary_file_name = file_manager.generate_name();
117 if(!temporary_file.open_create(temporary_file_name))
119 std::cout << "Failed to open temporary file " << temporary_file_name << std::endl;
120 exit(1);
123 temporary_file.write(extended_buffer);
124 extended_buffer.clear();
126 std::cout << "Using temporary file name " << temporary_file_name << std::endl;
129 else
130 temporary_file.write(new_data);
132 if(got_header)
134 std::size_t expected_byte_count = current_request.header_size + current_request.content_length;
135 std::cout << "Expected byte count: " << current_request.header_size << " + " << current_request.content_length << " = " << expected_byte_count << std::endl;
136 if(bytes_read > expected_byte_count)
138 std::cout << "Received too many bytes from a client: " << bytes_read << " > " << expected_byte_count << std::endl;
139 terminate();
140 return;
142 else if(bytes_read == expected_byte_count)
144 std::cout << "Ready to serve data for " << current_request.path << std::endl;
145 module_result result;
146 if(modules.process_request(current_request, result))
148 std::cout << "The module manager successfully processed the request" << std::endl;
149 std::string data;
150 if(generate_content(current_request, result, data))
152 std::cout << "Successfully generated the HTTP content, serving it to the client" << std::endl;
153 write(data);
154 return;
156 else
158 std::cout << "Failed to generate HTTP content" << std::endl;
159 terminate();
160 return;
163 else
165 std::cout << "The module manager failed to process this request" << std::endl;
166 terminate();
167 return;
172 read();
174 else
175 terminate();
178 void http_server_client::write_event(boost::system::error_code const & error, char * write_buffer)
180 delete write_buffer;
182 std::cout << "Got a write event" << std::endl;
184 if(!error)
186 if(current_request.keep_alive)
188 keep_alive_counter--;
189 if(keep_alive_counter <= 0)
191 std::cout << "Client keep alive counter is zero" << std::endl;
192 terminate();
193 return;
195 else
197 std::cout << "Reinitialising the state" << std::endl;
198 initialise();
199 read();
203 else
204 terminate();
207 bool http_server_client::generate_content(http_request & request, module_result & result, std::string & content)
209 http_reply reply;
210 reply.protocol = request.protocol_version;
211 switch(result.return_code)
213 case request_handler_return_code::ok:
214 reply.ok();
215 break;
217 case request_handler_return_code::forbidden:
218 reply.forbidden();
219 break;
221 case request_handler_return_code::not_found:
222 reply.not_found();
223 break;
225 default:
226 std::cout << "Unknown request handler return code specified" << std::endl;
227 return false;
230 reply.gzip = request.gzip;
231 reply.keep_alive = request.keep_alive;
232 reply.content_type = result.content_type;
233 reply.keep_alive_timeout = keep_alive_timeout;
234 reply.keep_alive_max = keep_alive_counter;
235 reply.content = result.content;
237 if(!reply.get_packet(content))
239 std::cout << "Failed to build reply packet" << std::endl;
240 return false;
243 return true;