fixed: last packet from a file was not sent to the browser
git-svn-id: svn://ttmath.org/publicrep/libscorpiohttpserver/trunk@1064 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
80b53a7fd5
commit
3d7148e8c0
|
@ -10,7 +10,7 @@ Client::Client()
|
||||||
socket = 0;
|
socket = 0;
|
||||||
close_connection = false;
|
close_connection = false;
|
||||||
PrepareToNewRequest();
|
PrepareToNewRequest();
|
||||||
read_static_buffer_size = 1500 * 3; // this will be testing (size of one packet * how many packets)
|
read_static_buffer_size = 1500 * 30; // 1500 * 30 // this will be testing (size of one packet * how many packets)
|
||||||
read_static_buffer = new char[read_static_buffer_size]; // add to config
|
read_static_buffer = new char[read_static_buffer_size]; // add to config
|
||||||
std::cout << "alokuje buforek: " << (void*)read_static_buffer << std::endl;
|
std::cout << "alokuje buforek: " << (void*)read_static_buffer << std::endl;
|
||||||
|
|
||||||
|
@ -76,6 +76,10 @@ Client & Client::operator=(const Client & c)
|
||||||
|
|
||||||
memcpy(read_static_buffer, c.read_static_buffer, read_static_buffer_size);
|
memcpy(read_static_buffer, c.read_static_buffer, read_static_buffer_size);
|
||||||
|
|
||||||
|
|
||||||
|
out_headers = c.out_headers;
|
||||||
|
status = c.status;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +124,9 @@ void Client::PrepareToNewRequest()
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
memset(&iocb, 0, sizeof(iocb));
|
||||||
|
|
||||||
|
out_headers.Clear();
|
||||||
|
status = 404;
|
||||||
|
|
||||||
// don't set flag close_connection to false here
|
// don't set flag close_connection to false here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
src/client.h
13
src/client.h
|
@ -85,6 +85,19 @@ public:
|
||||||
HTTPMethod http_method;
|
HTTPMethod http_method;
|
||||||
HTTPVersion http_version;
|
HTTPVersion http_version;
|
||||||
|
|
||||||
|
|
||||||
|
// a better name?
|
||||||
|
PT::Space out_headers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int status;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool answer_generated;
|
bool answer_generated;
|
||||||
|
|
||||||
bool close_connection;
|
bool close_connection;
|
||||||
|
|
|
@ -12,11 +12,17 @@ void HeadersParser::ParseHeaders(Client & client)
|
||||||
|
|
||||||
if( !ParseFirstHeader(client) )
|
if( !ParseFirstHeader(client) )
|
||||||
{
|
{
|
||||||
std::cout << "incorrect first header, closing connection" << std::endl;
|
std::cout << "incorrect first header, closing connection ------------------------------------" << std::endl;
|
||||||
client.close_connection = true;
|
client.close_connection = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove me
|
||||||
|
if( client.url == L"/static/styles.css" )
|
||||||
|
{
|
||||||
|
header_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// we are testing header_index + 3 < client.input_buffer.size() because we know
|
// we are testing header_index + 3 < client.input_buffer.size() because we know
|
||||||
// that the \r\n\r\n sequence already exists in this string
|
// that the \r\n\r\n sequence already exists in this string
|
||||||
// so there is no a problem that we leave some characters at the end of the string
|
// so there is no a problem that we leave some characters at the end of the string
|
||||||
|
@ -163,6 +169,8 @@ bool HeadersParser::ParseFirstHeaderURL(Client & client)
|
||||||
url_ascii += static_cast<char>(c);
|
url_ascii += static_cast<char>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "URL ASCII: " << url_ascii << "-----------------" << std::endl;
|
||||||
|
|
||||||
bool utf8_correct = PT::UTF8ToWide(url_ascii, client.url);
|
bool utf8_correct = PT::UTF8ToWide(url_ascii, client.url);
|
||||||
|
|
||||||
SkipWhite(client);
|
SkipWhite(client);
|
||||||
|
|
281
src/server.cpp
281
src/server.cpp
|
@ -135,8 +135,13 @@ void Server::Wait()
|
||||||
int how_many_external_resources;
|
int how_many_external_resources;
|
||||||
|
|
||||||
PrepareSocketsForSelect(fd_max, t, how_many_external_resources);
|
PrepareSocketsForSelect(fd_max, t, how_many_external_resources);
|
||||||
// sprawdzic czy jak t jest zerem to select czeka nieskonczenie dlugo czy od razu przerywa
|
|
||||||
int ready_fd = select(fd_max + 1, &read_set, &write_set, 0, &t);
|
timeval * pt = 0;
|
||||||
|
|
||||||
|
if( how_many_external_resources > 0 )
|
||||||
|
pt = &t;
|
||||||
|
|
||||||
|
int ready_fd = select(fd_max + 1, &read_set, &write_set, 0, pt);
|
||||||
|
|
||||||
if( how_many_external_resources > 0 )
|
if( how_many_external_resources > 0 )
|
||||||
ReadExternalResource(how_many_external_resources);
|
ReadExternalResource(how_many_external_resources);
|
||||||
|
@ -363,6 +368,10 @@ void Server::ReadExternalResource(Client & client, std::string & output_buffer)
|
||||||
|
|
||||||
if( res < 0 )
|
if( res < 0 )
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
int err = errno;
|
int err = errno;
|
||||||
std::cout << "aio_return returned error, errno: " << err << std::endl;
|
std::cout << "aio_return returned error, errno: " << err << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -385,42 +394,43 @@ void Server::ReadExternalResource(Client & client, std::string & output_buffer)
|
||||||
|
|
||||||
output_buffer.append(client.read_static_buffer, res);
|
output_buffer.append(client.read_static_buffer, res);
|
||||||
client.external_resource.file_how_many_read += (size_t)res;
|
client.external_resource.file_how_many_read += (size_t)res;
|
||||||
|
}
|
||||||
|
|
||||||
if( output_buffer.size() > 1500 ) // add to config
|
client.external_resource.waiting_for_last_read = false;
|
||||||
|
|
||||||
|
if( output_buffer.size() > 1500 ) // send at least one full packed, add to config
|
||||||
|
{
|
||||||
|
if( client.reading_to_buffer == 1 )
|
||||||
{
|
{
|
||||||
if( client.reading_to_buffer == 1 )
|
client.reading_to_buffer = 0;
|
||||||
|
|
||||||
|
if( client.sending_from_buffer != 2 )
|
||||||
{
|
{
|
||||||
client.reading_to_buffer = 0;
|
client.reading_to_buffer = 2;
|
||||||
|
|
||||||
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 )
|
if( client.sending_from_buffer == 0 )
|
||||||
{
|
{
|
||||||
client.reading_to_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 )
|
if( client.sending_from_buffer != 1 )
|
||||||
{
|
{
|
||||||
client.reading_to_buffer = 1;
|
client.reading_to_buffer = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( client.sending_from_buffer == 0 )
|
if( client.sending_from_buffer == 0 )
|
||||||
{
|
{
|
||||||
client.sending_from_buffer = 2;
|
client.sending_from_buffer = 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client.external_resource.waiting_for_last_read = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -442,13 +452,14 @@ void Server::ReadInputFromClient(Client & client)
|
||||||
{
|
{
|
||||||
// read failed, we do not parse this request
|
// read failed, we do not parse this request
|
||||||
|
|
||||||
std::cout << "read failed" << std::endl;
|
std::cout << "read failed for client " << client.socket << std::endl;
|
||||||
client.close_connection = true;
|
client.close_connection = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( read_len == 0 )
|
if( read_len == 0 )
|
||||||
{
|
{
|
||||||
// the client has terminated connection
|
// the client has terminated connection
|
||||||
|
std::cout << "read returned 0, client " << client.socket << " closed the connection" << std::endl;
|
||||||
client.close_connection = true;
|
client.close_connection = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -457,6 +468,13 @@ void Server::ReadInputFromClient(Client & client)
|
||||||
|
|
||||||
client.input_buffer.append(in_buffer, read_len);
|
client.input_buffer.append(in_buffer, read_len);
|
||||||
|
|
||||||
|
std::cout << "read from client " << client.socket << ":";
|
||||||
|
|
||||||
|
for(size_t i=0 ; i<(size_t)read_len ; ++i)
|
||||||
|
std::cout << in_buffer[i];
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
if( client.parsing_headers )
|
if( client.parsing_headers )
|
||||||
CheckHeaders(client, input_buffer_index);
|
CheckHeaders(client, input_buffer_index);
|
||||||
}
|
}
|
||||||
|
@ -468,53 +486,54 @@ void Server::WriteOutputToClient(Client & client, std::string & output_buffer, s
|
||||||
{
|
{
|
||||||
const char * data = output_buffer.c_str() + output_buffer_sent;
|
const char * data = output_buffer.c_str() + output_buffer_sent;
|
||||||
size_t how_many_to_send = output_buffer.size() - output_buffer_sent;
|
size_t how_many_to_send = output_buffer.size() - output_buffer_sent;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
if( how_many_to_send > 0 )
|
if( how_many_to_send > 0 )
|
||||||
{
|
{
|
||||||
int len = send(client.socket, data, how_many_to_send, 0);
|
len = send(client.socket, data, how_many_to_send, 0);
|
||||||
|
|
||||||
if( len < 0 )
|
if( len < 0 )
|
||||||
{
|
{
|
||||||
std::cout << "writing failed" << std::endl;
|
std::cout << "writing failed" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if( len >= 0 )
|
||||||
|
{
|
||||||
|
output_buffer_sent += len;
|
||||||
|
|
||||||
|
if( output_buffer_sent >= output_buffer.size() )
|
||||||
{
|
{
|
||||||
output_buffer_sent += len;
|
output_buffer.clear();
|
||||||
|
output_buffer_sent = 0;
|
||||||
|
|
||||||
if( output_buffer_sent >= output_buffer.size() )
|
if( client.sending_from_buffer == 1 )
|
||||||
{
|
{
|
||||||
output_buffer.clear();
|
client.sending_from_buffer = 0;
|
||||||
output_buffer_sent = 0;
|
|
||||||
|
|
||||||
|
if( client.reading_to_buffer != 2 && !client.output_buffer_two.empty() )
|
||||||
if( client.sending_from_buffer == 1 )
|
|
||||||
{
|
{
|
||||||
client.sending_from_buffer = 0;
|
client.sending_from_buffer = 2;
|
||||||
|
|
||||||
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 )
|
if( client.external_resource.reading_external_resource && client.reading_to_buffer == 0 )
|
||||||
{
|
{
|
||||||
client.sending_from_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() )
|
if( client.reading_to_buffer != 1 && !client.output_buffer.empty() )
|
||||||
{
|
{
|
||||||
client.sending_from_buffer = 1;
|
client.sending_from_buffer = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( client.external_resource.reading_external_resource && client.reading_to_buffer == 0 )
|
if( client.external_resource.reading_external_resource && client.reading_to_buffer == 0 )
|
||||||
{
|
{
|
||||||
client.reading_to_buffer = 2;
|
client.reading_to_buffer = 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -692,6 +711,58 @@ int Server::FileLen(std::string & file_name, size_t & file_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Server::CreateOutputHeaders(Client & client)
|
||||||
|
{
|
||||||
|
std::wstring a;
|
||||||
|
wchar_t buf[32];
|
||||||
|
swprintf(buf, sizeof(buf)/sizeof(wchar_t), L"%d", client.status);
|
||||||
|
|
||||||
|
a = L"HTTP/";
|
||||||
|
|
||||||
|
if( client.http_version == http_version_1_0 )
|
||||||
|
a += L"1.0";
|
||||||
|
else
|
||||||
|
a += L"1.1";
|
||||||
|
|
||||||
|
a += L" ";
|
||||||
|
a += buf;
|
||||||
|
a += L" ";
|
||||||
|
|
||||||
|
|
||||||
|
if( client.status == 200 )
|
||||||
|
a += L"OK";
|
||||||
|
else
|
||||||
|
if( client.status == 404 )
|
||||||
|
a += L"Not Found";
|
||||||
|
|
||||||
|
a += L"\r\n";
|
||||||
|
PT::WideToUTF8(a, client.output_buffer); // we can use directly client.output_buffer without 'a'
|
||||||
|
|
||||||
|
auto i = client.out_headers.table_single.begin();
|
||||||
|
bool has_connection = false;
|
||||||
|
|
||||||
|
for( ; i != client.out_headers.table_single.end() ; ++i)
|
||||||
|
{
|
||||||
|
a = i->first;
|
||||||
|
a += L": ";
|
||||||
|
a += i->second;
|
||||||
|
a += L"\r\n";
|
||||||
|
PT::WideToUTF8(a, client.output_buffer, false);
|
||||||
|
|
||||||
|
if( CompareNoCase(i->first, L"connection") )
|
||||||
|
has_connection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !has_connection && CompareNoCase(client.in.Text(L"connection"), L"keep-alive") )
|
||||||
|
{
|
||||||
|
client.output_buffer += "Connection: keep-alive\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a = L"\r\n";
|
||||||
|
PT::WideToUTF8(a, client.output_buffer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -702,39 +773,30 @@ void Server::CreateAnswer(Client & client)
|
||||||
std::wstring a, c;
|
std::wstring a, c;
|
||||||
std::string c_ascii;
|
std::string c_ascii;
|
||||||
|
|
||||||
if( client.url == L"/swinka.jpg" )
|
if( client.url == L"/static/styles.css" )
|
||||||
|
{
|
||||||
|
a.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( client.url == L"/quit" )
|
||||||
|
{
|
||||||
|
close_server = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if( client.url == L"/swinka.jpg" )
|
||||||
{
|
{
|
||||||
std::string file_name_ascii;
|
std::string file_name_ascii;
|
||||||
|
|
||||||
client.send_file = L"/home/tomek/pani.jpg";
|
client.send_file = L"/home/tomek/roboczy/prog/libscorpiohttpserver/www-data";
|
||||||
|
client.send_file += client.url;
|
||||||
PT::WideToUTF8(client.send_file, file_name_ascii);
|
PT::WideToUTF8(client.send_file, file_name_ascii);
|
||||||
|
|
||||||
if( FileLen(file_name_ascii, client.external_resource.file_len) )
|
if( FileLen(file_name_ascii, client.external_resource.file_len) )
|
||||||
{
|
{
|
||||||
a = L"HTTP/";
|
client.status = 200;
|
||||||
|
//client.out_headers.Add(L"Content-Type", L"image/jpeg;");
|
||||||
if( client.http_version == http_version_1_0 )
|
client.out_headers.Add(L"Content-Length", client.external_resource.file_len);
|
||||||
a += L"1.0";
|
CreateOutputHeaders(client);
|
||||||
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 )
|
if( client.external_resource.external_resource_fd != -1 )
|
||||||
close(client.external_resource.external_resource_fd);
|
close(client.external_resource.external_resource_fd);
|
||||||
|
@ -744,6 +806,7 @@ void Server::CreateAnswer(Client & client)
|
||||||
|
|
||||||
if( client.external_resource.external_resource_fd >= 0 )
|
if( client.external_resource.external_resource_fd >= 0 )
|
||||||
{
|
{
|
||||||
|
std::cout << "przygotowuje do czytania pliku " << file_name_ascii << std::endl;
|
||||||
client.reading_to_buffer = 1;
|
client.reading_to_buffer = 1;
|
||||||
client.sending_from_buffer = 0;
|
client.sending_from_buffer = 0;
|
||||||
client.answering_to_client = true;
|
client.answering_to_client = true;
|
||||||
|
@ -756,13 +819,29 @@ void Server::CreateAnswer(Client & client)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// return an error page?
|
client.status = 404;
|
||||||
|
client.out_headers.Add(L"Content-Type", L"text/html; charset=UTF-8");
|
||||||
|
|
||||||
|
c = L"404 nie ma czegos takiego";
|
||||||
|
PT::WideToUTF8(c, c_ascii);
|
||||||
|
|
||||||
|
client.out_headers.Add(L"Content-Length", c_ascii.size());
|
||||||
|
CreateOutputHeaders(client);
|
||||||
|
client.output_buffer += c_ascii;
|
||||||
|
|
||||||
|
client.reading_to_buffer = 0;
|
||||||
|
client.sending_from_buffer = 1;
|
||||||
|
client.answering_to_client = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
client.status = 200;
|
||||||
|
client.out_headers.Add(L"Content-Type", L"text/html; charset=UTF-8");
|
||||||
|
|
||||||
c = L"hello world from my webserver, your requested: " + client.url;
|
c = L"hello world from my webserver, your requested: " + client.url;
|
||||||
c += L"\r\n";
|
c += L"\r\n";
|
||||||
|
|
||||||
|
@ -774,41 +853,15 @@ void Server::CreateAnswer(Client & client)
|
||||||
|
|
||||||
PT::WideToUTF8(c,c_ascii);
|
PT::WideToUTF8(c,c_ascii);
|
||||||
|
|
||||||
|
client.out_headers.Add(L"Content-Length", c_ascii.size());
|
||||||
a = L"HTTP/";
|
CreateOutputHeaders(client);
|
||||||
|
|
||||||
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.output_buffer += c_ascii;
|
||||||
|
|
||||||
client.reading_to_buffer = 0;
|
client.reading_to_buffer = 0;
|
||||||
client.sending_from_buffer = 1;
|
client.sending_from_buffer = 1;
|
||||||
client.answering_to_client = true;
|
client.answering_to_client = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ private:
|
||||||
void PrepareMainSocket();
|
void PrepareMainSocket();
|
||||||
int FileLen(std::string & file_name, size_t & file_len);
|
int FileLen(std::string & file_name, size_t & file_len);
|
||||||
|
|
||||||
|
|
||||||
|
void CreateOutputHeaders(Client & client);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue