start adding support for sending files

git-svn-id: svn://ttmath.org/publicrep/libscorpiohttpserver/trunk@1063 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2017-05-07 22:56:44 +00:00
parent 71eb0ef4bf
commit 80b53a7fd5
6 changed files with 636 additions and 226 deletions

View File

@ -1,34 +1,33 @@
#include "client.h" #include "client.h"
#include <string.h>
#include <iostream>
Client::Client() Client::Client()
{ {
in_buffer_max_len = WEBSERVER_INPUT_BUFFER_MAX_LEN; socket = 0;
socket = 0; close_connection = false;
in_buffer = nullptr; PrepareToNewRequest();
in_buffer_len = 0; read_static_buffer_size = 1500 * 3; // this will be testing (size of one packet * how many packets)
parsing_headers = true; read_static_buffer = new char[read_static_buffer_size]; // add to config
parsing_first_header = true; std::cout << "alokuje buforek: " << (void*)read_static_buffer << std::endl;
http_method = http_method_unsupported;
http_version = http_version_unsupported; // check whether there is no too much copying when we add Client to a list
answer_generated = false;
output_buffer_sent = 0;
close_connection = false;
} }
Client::Client(const Client & c) Client::Client(const Client & c)
{ {
in_buffer = nullptr;
operator=(c); operator=(c);
} }
Client::~Client() Client::~Client()
{ {
delete [] in_buffer; std::cout << "usuwam buforek: " << (void*)read_static_buffer << std::endl;
delete [] read_static_buffer;
} }
@ -36,13 +35,6 @@ Client & Client::operator=(const Client & c)
{ {
socket = c.socket; socket = c.socket;
if( c.in_buffer )
AllocInputBuffer();
else
in_buffer = nullptr;
in_buffer_len = c.in_buffer_len;
in_buffer_max_len = c.in_buffer_max_len;
parsing_headers = c.parsing_headers; parsing_headers = c.parsing_headers;
parsing_first_header = c.parsing_first_header; parsing_first_header = c.parsing_first_header;
http_method_str = c.http_method_str; http_method_str = c.http_method_str;
@ -54,6 +46,35 @@ Client & Client::operator=(const Client & c)
output_buffer = c.output_buffer; output_buffer = c.output_buffer;
output_buffer_sent = c.output_buffer_sent; output_buffer_sent = c.output_buffer_sent;
close_connection = c.close_connection; close_connection = c.close_connection;
output_buffer_two = c.output_buffer_two;
//is_sending_file = c.is_sending_file;
// external_resource_fd = c.external_resource_fd;
// waiting_for_last_read = c.waiting_for_last_read;
// send_file = c.send_file;
// file_how_many_read = c.file_how_many_read;
//file_has_been_read = c.file_has_been_read;
// file_len = c.file_len;
//file_how_many_send = c.file_how_many_send;
output_buffer_two_sent = c.output_buffer_two_sent;
external_resource = c.external_resource;
reading_to_buffer = c.reading_to_buffer;
sending_from_buffer = c.sending_from_buffer;
reading_to_buffer_two = c.reading_to_buffer_two;
sending_from_buffer_two = c.sending_from_buffer_two;
answering_to_client = c.answering_to_client;
// reading_external_resource = c.reading_external_resource;
read_static_buffer_size = c.read_static_buffer_size;
read_static_buffer = new char[read_static_buffer_size];
std::cout << "alokuje buforek: " << (void*)read_static_buffer << std::endl;
memcpy(read_static_buffer, c.read_static_buffer, read_static_buffer_size);
return *this; return *this;
} }
@ -61,29 +82,44 @@ Client & Client::operator=(const Client & c)
void Client::AllocInputBuffer()
{
delete [] in_buffer;
in_buffer = new char[in_buffer_max_len];
}
void Client::PrepareToNewRequest() void Client::PrepareToNewRequest()
{ {
if( !in_buffer )
AllocInputBuffer();
parsing_headers = true; parsing_headers = true;
parsing_first_header = true; parsing_first_header = true;
in_buffer_len = 0;
http_method = http_method_unsupported; http_method = http_method_unsupported;
http_version = http_version_unsupported; http_version = http_version_unsupported;
answer_generated = false; answer_generated = false;
output_buffer_sent = 0; output_buffer_sent = 0;
//is_sending_file = false;
//external_resource_fd = -1;
//waiting_for_last_read = false;
//file_how_many_read = 0;
//file_has_been_read = false;
output_buffer_two_sent = 0;
//file_len = 0;
//file_how_many_send = 0;
reading_to_buffer_two = false;
sending_from_buffer_two = false;
reading_to_buffer = 0;
sending_from_buffer = 0;
answering_to_client = false;
//reading_external_resource = false;
http_method_str.clear(); http_method_str.clear();
output_buffer.clear(); output_buffer.clear();
output_buffer_two.clear();
url.clear(); url.clear();
send_file.clear();
external_resource.Clear();
memset(&iocb, 0, sizeof(iocb));
// don't set flag close_connection to false here // don't set flag close_connection to false here
} }

View File

@ -2,6 +2,7 @@
#define headerfile_libscorpiohttpserver_src_client_h #define headerfile_libscorpiohttpserver_src_client_h
#include <aio.h>
#include <space/space.h> #include <space/space.h>
@ -28,12 +29,55 @@ enum HTTPVersion
}; };
struct ExternalResource
{
enum Type
{
type_file,
type_none,
};
ExternalResource()
{
Clear();
}
void Clear()
{
type = type_none;
reading_external_resource = false;
external_resource_fd = -1;
file_len = 0;
waiting_for_last_read = false;
file_how_many_read = 0;
}
Type type;
/*
* reading an external resource such as a file
*
*/
bool reading_external_resource;
int external_resource_fd;
size_t file_len;
bool waiting_for_last_read;
size_t file_how_many_read;
};
class Client class Client
{ {
public: public:
int socket; int socket;
PT::Space in; PT::Space in;
@ -52,9 +96,39 @@ public:
bool parsing_first_header; bool parsing_first_header;
std::string output_buffer;
size_t output_buffer_sent; // how many characters were sent
std::wstring send_file;
//size_t how_many_to_send;
ExternalResource external_resource;
std::string output_buffer;
std::string output_buffer_two;
size_t output_buffer_sent; // how many characters were sent
size_t output_buffer_two_sent; // how many characters were sent
int reading_to_buffer;
int sending_from_buffer;
bool reading_to_buffer_two;
bool sending_from_buffer_two;
/*
* if true then all headers has been read and now the server
* is creating the response
*
*/
bool answering_to_client;
char * read_static_buffer;
size_t read_static_buffer_size;
aiocb iocb;
Client(); Client();
Client(const Client & c); Client(const Client & c);
@ -62,15 +136,14 @@ public:
Client & operator=(const Client & c); Client & operator=(const Client & c);
void AllocInputBuffer();
void PrepareToNewRequest(); void PrepareToNewRequest();
private: private:
char * in_buffer; // rename to a better name //char * in_buffer; // rename to a better name
size_t in_buffer_max_len; // at least two characters //size_t in_buffer_max_len; // at least two characters
size_t in_buffer_len; //size_t in_buffer_len;
std::wstring http_method_str; std::wstring http_method_str;

View File

@ -35,9 +35,9 @@ void HeadersParser::ParseHeaders(Client & client)
if( tmp_header.size() > 0 ) if( tmp_header.size() > 0 )
{ {
std::wcout << L"header parsed: "; //std::wcout << L"header parsed: ";
std::wcout << L"\"" << tmp_header << L"\"=\""; //std::wcout << L"\"" << tmp_header << L"\"=\"";
std::wcout << tmp_value << L"\"" << std::endl; //std::wcout << tmp_value << L"\"" << std::endl;
client.in.Add(tmp_header, tmp_value); client.in.Add(tmp_header, tmp_value);
} }
else else

View File

@ -40,8 +40,8 @@ int main()
signal(SIGPIPE, signal_handler_sigpipe); signal(SIGPIPE, signal_handler_sigpipe);
server.Prepare();
server.PrepareMainSocket();
server.Wait(); server.Wait();

View File

@ -7,6 +7,8 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <utf8/utf8.h> #include <utf8/utf8.h>
#include <errno.h>
#include <sys/stat.h>
#include "server.h" #include "server.h"
#include "string_functions.h" #include "string_functions.h"
@ -16,8 +18,13 @@ Server::Server()
{ {
main_socket = -1; main_socket = -1;
close_server = false; close_server = false;
in_buffer_max_len = 2048;
in_buffer = nullptr;
} }
Server::~Server() Server::~Server()
{ {
Close(); Close();
@ -36,8 +43,13 @@ void Server::CloseMainSocket()
void Server::CloseClientSockets() void Server::CloseClientSockets()
{ {
for(size_t i=0 ; i<client_tab.size() ; ++i) for(auto i=client_tab.begin() ; i != client_tab.end() ; ++i)
close(client_tab[i].socket); {
close(i->socket);
if( i->external_resource.external_resource_fd >= 0 )
close(i->external_resource.external_resource_fd);
}
client_tab.clear(); client_tab.clear();
} }
@ -50,9 +62,21 @@ void Server::Close()
} }
void Server::AllocInputBuffer()
{
delete [] in_buffer;
in_buffer = new char[in_buffer_max_len];
}
void Server::Prepare()
{
PrepareMainSocket();
AllocInputBuffer();
}
void Server::PrepareMainSocket() void Server::PrepareMainSocket()
{ {
@ -106,14 +130,16 @@ void Server::Wait()
{ {
while( !close_server ) while( !close_server )
{ {
int fd_max = AddSocketsToSet(); timeval t;
int ready_fd = select(fd_max + 1, &read_set, &write_set, 0, 0); int fd_max;
int how_many_external_resources;
if( ready_fd < 0 ) PrepareSocketsForSelect(fd_max, t, how_many_external_resources);
{ // sprawdzic czy jak t jest zerem to select czeka nieskonczenie dlugo czy od razu przerywa
std::cout << "select failed" << std::endl; int ready_fd = select(fd_max + 1, &read_set, &write_set, 0, &t);
return;
} if( how_many_external_resources > 0 )
ReadExternalResource(how_many_external_resources);
if( ready_fd > 0 ) if( ready_fd > 0 )
{ {
@ -131,27 +157,44 @@ void Server::Wait()
int Server::AddSocketsToSet() void Server::PrepareSocketsForSelect(int & fd_max, timeval & t, int & how_many_external_resources)
{ {
FD_ZERO(&read_set); FD_ZERO(&read_set);
FD_ZERO(&write_set); FD_ZERO(&write_set);
int fd_max = 0; fd_max = 0;
t.tv_sec = 0;
t.tv_usec = 0;
how_many_external_resources = 0;
if( main_socket >= 0 ) if( main_socket >= 0 )
{ {
FD_SET(main_socket, &read_set); FD_SET(main_socket, &read_set);
fd_max = main_socket; fd_max = main_socket;
for(size_t i=0 ; i<client_tab.size() ; ++i) for(auto i=client_tab.begin() ; i != client_tab.end() ; ++i)
{ {
FD_SET(client_tab[i].socket, &read_set); if( !i->answering_to_client )
{
/*
* do not read the next request until the answer is sent
* (client can use pipelining)
*
*/
FD_SET(i->socket, &read_set);
}
else
{
FD_SET(i->socket, &write_set);
}
if( client_tab[i].answer_generated && !client_tab[i].output_buffer.empty() ) if( i->socket > fd_max )
FD_SET(client_tab[i].socket, &write_set); fd_max = i->socket;
if( client_tab[i].socket > fd_max ) if( i->external_resource.reading_external_resource )
fd_max = client_tab[i].socket; {
how_many_external_resources += 1;
}
} }
} }
else else
@ -159,7 +202,8 @@ int Server::AddSocketsToSet()
std::cout << "there is no main socket" << std::endl; std::cout << "there is no main socket" << std::endl;
} }
return fd_max; if( how_many_external_resources > 0 )
t.tv_usec = 1;
} }
@ -194,9 +238,9 @@ int client_socket;
c.socket = client_socket; c.socket = client_socket;
c.close_connection = false; c.close_connection = false;
c.PrepareToNewRequest();
client_tab.push_back(c); client_tab.push_back(c);
client_tab.back().PrepareToNewRequest();
} }
else else
{ {
@ -209,30 +253,179 @@ int client_socket;
void Server::ReadWriteToClients() void Server::ReadWriteToClients()
{ {
size_t i = 0; for(auto i=client_tab.begin() ; i != client_tab.end() ; )
while( i < client_tab.size() )
{ {
if( FD_ISSET(client_tab[i].socket, &read_set)) if( FD_ISSET(i->socket, &read_set))
{ {
ReadInputFromClient(client_tab[i]); ReadInputFromClient(*i);
} }
if( client_tab[i].answer_generated && FD_ISSET(client_tab[i].socket, &write_set) ) if( FD_ISSET(i->socket, &write_set) )
{ {
WriteOutputToClient(client_tab[i]); WriteOutputToClient(*i);
} }
if( client_tab[i].output_buffer.empty() && client_tab[i].close_connection ) if( !i->answering_to_client && i->close_connection && (!i->external_resource.reading_external_resource || !i->external_resource.waiting_for_last_read) )
{ {
std::cout << "closing connection for client nr " << client_tab[i].socket << std::endl; std::cout << "closing connection for client nr " << i->socket << std::endl;
close(client_tab[i].socket); close(i->socket);
client_tab.erase(client_tab.begin() + i);
if( i->external_resource.external_resource_fd >= 0 )
close(i->external_resource.external_resource_fd);
auto next_i = i;
++next_i;
client_tab.erase(i);
i = next_i;
} }
else else
{ {
i += 1; ++i;
}
}
}
void Server::ReadExternalResource(int how_many_external_resources)
{
int count = 0;
for(auto i=client_tab.begin() ; i != client_tab.end() && count < how_many_external_resources ; ++i)
{
if( i->external_resource.reading_external_resource )
{
if( i->reading_to_buffer == 1 )
{
ReadExternalResource(*i, i->output_buffer);
}
else
if( i->reading_to_buffer == 2 )
{
ReadExternalResource(*i, i->output_buffer_two);
}
count += 1;
}
}
}
void Server::ReadExternalResource(Client & client, std::string & output_buffer)
{
if( !client.external_resource.waiting_for_last_read )
{
client.iocb.aio_fildes = client.external_resource.external_resource_fd;
client.iocb.aio_offset = client.external_resource.file_how_many_read;
client.iocb.aio_buf = (volatile void*)client.read_static_buffer;
client.iocb.aio_nbytes = client.read_static_buffer_size;
/*
* at the beginning we have some headers in the first output buffer
*
* zmniejszamy ilosc bajtow do odczytania tak aby cala dlugosc bufora byla podzielna przez ilosc pakietow do wyslania
*
*/
if( output_buffer.size() < client.iocb.aio_nbytes )
client.iocb.aio_nbytes -= output_buffer.size();
int res = aio_read(&client.iocb);
if( res < 0 )
{
int err = errno;
std::cout << "aio_read has problems: errno: " << err << std::endl;
}
else
{
client.external_resource.waiting_for_last_read = true;
}
}
else
{
int res = aio_error(&client.iocb);
std::cout << "aio_error returned: " << res << std::endl;
if( res == EINPROGRESS )
{
std::cout << "res is equal EINPROGRESS" << std::endl;
}
else
if( res == 0 )
{
std::cout << "reading completed" << std::endl;
res = aio_return(&client.iocb);
if( res < 0 )
{
int err = errno;
std::cout << "aio_return returned error, errno: " << err << std::endl;
}
else
if( res == 0 )
{
std::cout << "koniec czytania pliku" << std::endl;
if( client.sending_from_buffer == 0 )
client.sending_from_buffer = client.reading_to_buffer;
client.reading_to_buffer = 0;
client.external_resource.reading_external_resource = false;
close(client.external_resource.external_resource_fd);
client.external_resource.external_resource_fd = -1;
}
else
{
std::cout << "przeczytano bajtow: " << res << std::endl;
output_buffer.append(client.read_static_buffer, res);
client.external_resource.file_how_many_read += (size_t)res;
if( output_buffer.size() > 1500 ) // add to config
{
if( client.reading_to_buffer == 1 )
{
client.reading_to_buffer = 0;
if( client.sending_from_buffer != 2 )
{
client.reading_to_buffer = 2;
}
if( client.sending_from_buffer == 0 )
{
client.sending_from_buffer = 1;
}
}
else
if( client.reading_to_buffer == 2 )
{
client.reading_to_buffer = 0;
if( client.sending_from_buffer != 1 )
{
client.reading_to_buffer = 1;
}
if( client.sending_from_buffer == 0 )
{
client.sending_from_buffer = 2;
}
}
}
}
client.external_resource.waiting_for_last_read = false;
}
else
{
std::cout << "some error" << std::endl;
// what about this buffer?
} }
} }
} }
@ -241,24 +434,9 @@ void Server::ReadWriteToClients()
void Server::ReadInputFromClient(Client & client) void Server::ReadInputFromClient(Client & client)
{ {
std::cout << "trying read something from client number: " << client.socket << std::endl; int read_len = read(client.socket, in_buffer, in_buffer_max_len);
// we need at least one char more (for terminating zero for logging/debugging)
if( client.in_buffer_max_len - client.in_buffer_len < 2 )
{
client.input_buffer.append(client.in_buffer, client.in_buffer_len);
client.in_buffer_len = 0;
}
char * old_pointer = client.in_buffer + client.in_buffer_len;
// after adding to client.input_buffer we set in_buffer_len to 0
// so here is sufficient client.in_buffer (without adding client.in_buffer_len)
int read_len = read(client.socket, client.in_buffer + client.in_buffer_len, client.in_buffer_max_len - client.in_buffer_len - 1);
if( read_len < 0 ) if( read_len < 0 )
{ {
@ -270,51 +448,26 @@ void Server::ReadInputFromClient(Client & client)
else else
if( read_len == 0 ) if( read_len == 0 )
{ {
// end
if( client.in_buffer_len > 0 )
{
client.input_buffer.append(client.in_buffer, client.in_buffer_len);
client.in_buffer_len = 0;
}
std::cout << "------------------------------ client: " << client.socket << " calosc komunikatu " << std::endl;
std::cout << client.input_buffer;
std::cout << "----------------------------------------" << std::endl;
// the client has terminated connection // the client has terminated connection
client.close_connection = true; client.close_connection = true;
} }
else else
{ {
client.in_buffer_len += read_len;
size_t input_buffer_index = client.input_buffer.size(); size_t input_buffer_index = client.input_buffer.size();
client.input_buffer.append(client.in_buffer, client.in_buffer_len); client.input_buffer.append(in_buffer, read_len);
client.in_buffer_len = 0;
if( client.parsing_headers ) if( client.parsing_headers )
CheckHeaders(client, input_buffer_index); CheckHeaders(client, input_buffer_index);
client.in_buffer[client.in_buffer_len] = 0; // only for logging (we have at least one character more for terminating zero)
std::cout << "------------------------------ client: " << client.socket << std::endl;
std::cout << old_pointer;
std::cout << "----------------------------------------" << std::endl;
} }
} }
void Server::WriteOutputToClient(Client & client) void Server::WriteOutputToClient(Client & client, std::string & output_buffer, size_t & output_buffer_sent)
{ {
std::cout << "writing to client nr " << client.socket << std::endl; const char * data = output_buffer.c_str() + output_buffer_sent;
size_t how_many_to_send = output_buffer.size() - output_buffer_sent;
const char * data = client.output_buffer.c_str() + client.output_buffer_sent;
size_t how_many_to_send = client.output_buffer.size() - client.output_buffer_sent;
if( how_many_to_send > 0 ) if( how_many_to_send > 0 )
{ {
@ -326,11 +479,43 @@ void Server::WriteOutputToClient(Client & client)
} }
else else
{ {
client.output_buffer_sent += len; output_buffer_sent += len;
if( client.output_buffer_sent == client.output_buffer.size() ) if( output_buffer_sent >= output_buffer.size() )
{ {
client.PrepareToNewRequest(); output_buffer.clear();
output_buffer_sent = 0;
if( client.sending_from_buffer == 1 )
{
client.sending_from_buffer = 0;
if( client.reading_to_buffer != 2 && !client.output_buffer_two.empty() )
{
client.sending_from_buffer = 2;
}
if( client.external_resource.reading_external_resource && client.reading_to_buffer == 0 )
{
client.reading_to_buffer = 1;
}
}
else
if( client.sending_from_buffer == 2 )
{
client.sending_from_buffer = 0;
if( client.reading_to_buffer != 1 && !client.output_buffer.empty() )
{
client.sending_from_buffer = 1;
}
if( client.external_resource.reading_external_resource && client.reading_to_buffer == 0 )
{
client.reading_to_buffer = 2;
}
}
} }
} }
} }
@ -338,10 +523,31 @@ void Server::WriteOutputToClient(Client & client)
void Server::WriteOutputToClient(Client & client)
{
if( client.sending_from_buffer == 1 )
{
WriteOutputToClient(client, client.output_buffer, client.output_buffer_sent);
}
else
if( client.sending_from_buffer == 2 )
{
WriteOutputToClient(client, client.output_buffer_two, client.output_buffer_two_sent);
}
else
if( !client.external_resource.reading_external_resource && client.output_buffer.empty() && client.output_buffer_two.empty() )
{
client.PrepareToNewRequest();
}
}
void Server::CheckHeaders(Client & client, size_t input_buffer_index) void Server::CheckHeaders(Client & client, size_t input_buffer_index)
{ {
// at least 3 bytes before // we check at least 3 bytes before because we are looking for \r\n\r\n
// and the input_buffer_index can point at the last \n now
if( input_buffer_index > 3 ) if( input_buffer_index > 3 )
input_buffer_index -= 3; input_buffer_index -= 3;
@ -352,50 +558,59 @@ void Server::CheckHeaders(Client & client, size_t input_buffer_index)
{ {
if( headers_parser.IsHeadersEnding(client.input_buffer.c_str() + input_buffer_index) ) if( headers_parser.IsHeadersEnding(client.input_buffer.c_str() + input_buffer_index) )
{ {
headers_parser.ParseHeaders(client); ParseHeaders(client);
if( !SelectMethodName(client, client.http_method_str) )
{
std::cout << "unsupported http method" << std::endl;
client.close_connection = true;
}
client.parsing_headers = false;
client.input_buffer.erase(0, input_buffer_index + 4); client.input_buffer.erase(0, input_buffer_index + 4);
// temporarily we are using only get method with http 1.0 (closing connection after answering)
if( client.http_method == http_method_get )
{
CreateAnswer(client);
client.answer_generated = true;
if( client.http_version == http_version_1_0 )
{
if( !CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
{
std::cout << "answer generated, closing connection for http 1.0" << std::endl;
client.close_connection = true;
}
else
{
std::cout << "keep-alive is set, not closing connection for http 1.0" << std::endl;
}
}
}
if( client.http_method != http_method_get )
{
// at the moment only get method
client.close_connection = true;
}
break; break;
} }
} }
} }
void Server::ParseHeaders(Client & client)
{
headers_parser.ParseHeaders(client);
if( !SelectMethodName(client, client.http_method_str) )
{
std::cout << "unsupported http method" << std::endl;
client.close_connection = true;
}
client.parsing_headers = false;
// temporarily we are using only get method with http 1.0 (closing connection after answering)
if( client.http_method == http_method_get )
{
CreateAnswer(client);
/*
*
* we cannot close the connection here (a file can be send)
*
if( client.http_version == http_version_1_0 )
{
if( !CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
{
//std::cout << "answer generated, closing connection for http 1.0" << std::endl;
client.close_connection = true;
}
else
{
//std::cout << "keep-alive is set, not closing connection for http 1.0" << std::endl;
}
}
*/
}
if( client.http_method != http_method_get )
{
// at the moment only get method
client.close_connection = true;
}
}
@ -437,6 +652,8 @@ bool Server::SelectMethodName(Client & client, const std::wstring & method_name)
//void Server::RemoveClientSocket(int client_socket) //void Server::RemoveClientSocket(int client_socket)
//{ //{
// for(size_t i=0 ; i<client_tab.size() ; ++i) // for(size_t i=0 ; i<client_tab.size() ; ++i)
@ -456,51 +673,142 @@ bool Server::SelectMethodName(Client & client, const std::wstring & method_name)
void Server::CreateAnswer(Client & client)
int Server::FileLen(std::string & file_name, size_t & file_len)
{ {
std::wstring a, c; struct stat s;
c = L"hello world from my webserver, your requested: " + client.url; file_len = 0;
c += L"\r\n";
if( client.url == L"/quit" ) int res = stat(file_name.c_str(), &s);
if( res == 0 )
{ {
c += L"<br><br>bye bye"; file_len = s.st_size;
close_server = true; return true;
}
return false;
}
void Server::CreateAnswer(Client & client)
{
// tmp, a user method will be called
std::wstring a, c;
std::string c_ascii;
if( client.url == L"/swinka.jpg" )
{
std::string file_name_ascii;
client.send_file = L"/home/tomek/pani.jpg";
PT::WideToUTF8(client.send_file, file_name_ascii);
if( FileLen(file_name_ascii, client.external_resource.file_len) )
{
a = L"HTTP/";
if( client.http_version == http_version_1_0 )
a += L"1.0";
else
a += L"1.1";
a += L" 200 OK\r\n";
a += L"Content-Type: image/jpeg;\r\n";
if( CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
{
a += L"Connection: keep-alive\r\n";
}
wchar_t buf[32];
swprintf(buf, sizeof(buf)/sizeof(wchar_t), L"%d", client.external_resource.file_len);
a += L"Content-Length: ";
a += buf;
a += L"\r\n";
a += L"\r\n";
PT::WideToUTF8(a, client.output_buffer);
if( client.external_resource.external_resource_fd != -1 )
close(client.external_resource.external_resource_fd);
// improve me (utf8)
client.external_resource.external_resource_fd = open(file_name_ascii.c_str(), O_RDONLY | O_NONBLOCK);
if( client.external_resource.external_resource_fd >= 0 )
{
client.reading_to_buffer = 1;
client.sending_from_buffer = 0;
client.answering_to_client = true;
client.external_resource.reading_external_resource = true;
client.external_resource.type = ExternalResource::type_file;
}
return;
}
else
{
// return an error page?
}
return;
}
else
{
c = L"hello world from my webserver, your requested: " + client.url;
c += L"\r\n";
if( client.url == L"/quit" )
{
c += L"<br><br>bye bye";
close_server = true;
}
PT::WideToUTF8(c,c_ascii);
a = L"HTTP/";
if( client.http_version == http_version_1_0 )
a += L"1.0";
else
a += L"1.1";
a += L" 200 OK\r\n";
a += L"Content-Type: text/html; charset=UTF-8\r\n";
if( CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
{
a += L"Connection: keep-alive\r\n";
}
wchar_t buf[32];
swprintf(buf, sizeof(buf)/sizeof(wchar_t), L"%d", c_ascii.size());
a += L"Content-Length: ";
a += buf;
a += L"\r\n";
a += L"\r\n";
PT::WideToUTF8(a, client.output_buffer);
client.output_buffer += c_ascii;
client.reading_to_buffer = 0;
client.sending_from_buffer = 1;
client.answering_to_client = true;
} }
std::string c_ascii;
PT::WideToUTF8(c,c_ascii);
a = L"HTTP/";
if( client.http_version == http_version_1_0 )
a += L"1.0";
else
a += L"1.1";
a += L" 200 OK\r\n";
a += L"Content-Type: text/html; charset=UTF-8\r\n";
if( CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
{
a += L"Connection: keep-alive\r\n";
}
wchar_t buf[32];
swprintf(buf, sizeof(buf)/sizeof(wchar_t), L"%d", c_ascii.size());
a += L"Content-Length: ";
a += buf;
a += L"\r\n";
a += L"\r\n";
PT::WideToUTF8(a, client.output_buffer);
client.output_buffer += c_ascii;
} }

View File

@ -1,7 +1,7 @@
#ifndef headerfile_libscorpiohttpserver_src_server_h #ifndef headerfile_libscorpiohttpserver_src_server_h
#define headerfile_libscorpiohttpserver_src_server_h #define headerfile_libscorpiohttpserver_src_server_h
#include <list>
#include <sys/select.h> #include <sys/select.h>
#include "client.h" #include "client.h"
#include "headers_parser.h" #include "headers_parser.h"
@ -14,6 +14,10 @@ public:
Server(); Server();
Server(const Server & s) = delete;
Server & operator=(const Server & s) = delete;
virtual ~Server(); virtual ~Server();
@ -21,38 +25,52 @@ public:
void CloseClientSockets(); void CloseClientSockets();
void Close(); void Close();
void PrepareMainSocket(); void Prepare();
void Wait(); void Wait();
private: private:
std::vector<Client> client_tab; // we cannot use vector here because Client has aiocb struct
// and when adding clients to tab pointers can be invalidated for aio reading
std::list<Client> client_tab;
int main_socket; int main_socket;
fd_set read_set, write_set; fd_set read_set, write_set;
bool close_server; bool close_server;
HeadersParser headers_parser; HeadersParser headers_parser;
char * in_buffer; // rename to a better name
size_t in_buffer_max_len;
//size_t how_many_sending_file; // how many sockets currently is used for sending files
void PrepareSocketsForSelect(int & fd_max, timeval & t, int & how_many_external_resources);
int AddSocketsToSet();
void AddNewClient(); void AddNewClient();
void AllocInputBuffer();
void ReadWriteToClients(); void ReadWriteToClients();
void ReadInputFromClient(Client & client); void ReadInputFromClient(Client & client);
void WriteOutputToClient(Client & client); void WriteOutputToClient(Client & client);
void ReadExternalResource(int how_many_external_resources);
void CheckHeaders(Client & client, size_t input_buffer_index); void CheckHeaders(Client & client, size_t input_buffer_index);
void ParseHeaders(Client & client);
virtual bool SelectMethodName(Client & client, const std::wstring & method_name); virtual bool SelectMethodName(Client & client, const std::wstring & method_name);
void ReadExternalResource(Client & client, std::string & output_buffer);
void WriteOutputToClient(Client & client, std::string & output_buffer, size_t & output_buffer_sent);
//void RemoveClientSocket(int client_socket); //void RemoveClientSocket(int client_socket);
virtual void CreateAnswer(Client & client); virtual void CreateAnswer(Client & client);
void PrepareMainSocket();
int FileLen(std::string & file_name, size_t & file_len);
}; };
@ -61,31 +79,6 @@ private:
#endif #endif