/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a zlib-style license that can
* be found in the License.txt file in the root of the source tree.
*/
//---------------------------------------------------------------------------
#include "ZenLib/PreComp.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "ZenLib/Conf_Internal.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "ZenLib/Format/Http/Http_Request.h"
#include "ZenLib/Format/Http/Http_Utils.h"
#include "ZenLib/Ztring.h"
using namespace std;
//---------------------------------------------------------------------------
namespace ZenLib
{
namespace Format
{
namespace Http
{
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
Request::Request()
{
//Config
Http=new ZenLib::Format::Http::Handler;
IsCopy=false;
}
//---------------------------------------------------------------------------
Request::Request(const Request &Req)
{
//Config
Http=Req.Http;
IsCopy=true;
}
//---------------------------------------------------------------------------
Request::~Request()
{
//Config
if (!IsCopy)
delete Http; //Http=NULL
}
//***************************************************************************
//
//***************************************************************************
//---------------------------------------------------------------------------
bool Request::Http_Begin(std::istream &In, std::ostream &Out)
{
//First line, "Method Path Norm"
//-Method
string Method;
In>>Method;
if (Method.size()==3 && Method[0]=='G' && Method[1]=='E' && Method[2]=='T')
;
else if (Method.size()==4 && Method[0]=='P' && Method[1]=='O' && Method[2]=='S' && Method[3]=='T')
;
else if (Method.size()==4 && Method[0]=='H' && Method[1]=='E' && Method[2]=='A' && Method[3]=='D')
Http->HeadersOnly=true;
else
{
Out << "HTTP/1.0 501\r\n";
Out << "\r\n";
return false; //Unknown request
}
//-Path
In>>Http->Path;
if (Http->Path.empty() || Http->Path[0]!='/')
{
Out << "HTTP/1.0 404\r\n";
Out << "\r\n";
return false; //Problem
}
if (Http->Path.size()>8096) //Browsers/Servers have a 2K-8K limit, we do same
{
Out << "HTTP/1.0 414\r\n";
Out << "\r\n";
return false; //Problem
}
if (Http->Path.find('%')!=string::npos)
Http->Path=Format::Http::URL_Encoded_Decode(Http->Path);
//-Norm
string Line;
getline(In, Line); //Drop the first line, no more needed
//Headers
do
{
//Getting the line
getline(In, Line);
if (!Line.empty() && Line[Line.size()-1]=='\r')
Line.resize(Line.size()-1); //Remove the \r
//Processing the line, form is "aaa: bbb"
if (!Line.empty())
{
string::size_type Separator_Pos=Line.find(':');
string::size_type Content_Begin=Line.find_first_not_of(' ', Separator_Pos+1);
if (Separator_Pos!=string::npos && Content_Begin!=string::npos)
{
string Command=Line.substr(0, Separator_Pos);
if (Command=="Cookie")
{
string Cookie=Line.substr(Separator_Pos+1, string::npos);
while (!Cookie.empty())
{
string::size_type Cookie_Pos=Cookie.rfind(';');
if (Cookie_Pos==string::npos)
Cookie_Pos=(string::size_type)-1;
string Line2=Cookie.substr(Cookie_Pos+1, string::npos);
TrimLeft(Line2, ' ');
if (Cookie_Pos!=(string::size_type)-1)
{
Cookie.resize(Cookie_Pos);
TrimLeft(Line2, ' ');
}
else
Cookie.clear();
string::size_type Separator_Pos2=Line2.find('=');
if (Separator_Pos2!=string::npos)
Http->Request_Cookies[Line2.substr(0, Separator_Pos2)]=Format::Http::URL_Encoded_Decode(Line2.substr(Separator_Pos2+1, string::npos));
}
}
else
Http->Request_Headers[Command]=Line.substr(Content_Begin, string::npos);
}
}
}
while (!Line.empty());
//Info
if ((Method.size()==3 && Method[0]=='G' && Method[1]=='E' && Method[2]=='T')
|| (Method.size()==4 && Method[0]=='P' && Method[1]=='O' && Method[2]=='S' && Method[3]=='T'))
{
do
{
string Content;
//Getting the line
string::size_type Interogation_Pos=Http->Path.find('?');
if (Interogation_Pos!=string::npos)
{
Content=Http->Path.substr(Interogation_Pos+1, string::npos);
Http->Path.resize(Interogation_Pos);
}
if (Method.size()==4) //Only for POST
{
int64u Content_Lengh=0;
std::map<std::string, std::string>::iterator Header_Content_Lengh_Element=Http->Request_Headers.find("Content-Length");
if (Header_Content_Lengh_Element==Http->Request_Headers.end())
Header_Content_Lengh_Element=Http->Request_Headers.find("Content-length");
if (Header_Content_Lengh_Element!=Http->Request_Headers.end())
#ifdef UNICODE
Content_Lengh=Ztring().From_UTF8(Header_Content_Lengh_Element->second).To_int64u();
#else
Content_Lengh=Ztring(Header_Content_Lengh_Element->second).To_int64u();
#endif
if (Content_Lengh>1024) //Verifying there is no big element
{
Out << "HTTP/1.0 501\r\n";
Out << "\r\n";
return false; //Malformed request
}
size_t Content_Size_Current=Content.size();
if (Content_Size_Current)
{
Content+='&';
Content_Size_Current++;
}
Content.resize(Content_Size_Current+(size_t)Content_Lengh+1);
In.read(&Content[Content_Size_Current], (streamsize)Content_Lengh);
Content[Content_Size_Current+(size_t)Content_Lengh]='\0';
}
//Processing the line, form is "aaa=bbb&..."
while (!Content.empty())
{
string::size_type Content_Pos=Content.rfind('&');
if (Content_Pos==string::npos)
Content_Pos=(string::size_type)-1;
std::string Line2=Content.substr(Content_Pos+1, string::npos);
if (Content_Pos!=(string::size_type)-1)
Content.resize(Content_Pos);
else
Content.clear();
string::size_type Separator_Pos=Line2.find('=');
if (Separator_Pos!=string::npos)
Http->Request_Queries[Line2.substr(0, Separator_Pos)]=Format::Http::URL_Encoded_Decode(Line2.substr(Separator_Pos+1, string::npos));
}
}
while (!Line.empty());
}
return true;
}
void Request::Http_End(std::ostream &Out)
{
Out << "HTTP/1.0 "<< Http->Response_HTTP_Code << "\r\n";
for (std::map<std::string, std::string>::iterator Temp=Http->Response_Headers.begin(); Temp!=Http->Response_Headers.end(); ++Temp)
Out << Temp->first << ": " << Temp->second << "\r\n";
Http->Response_Cookies.Create_Lines(Out);
std::map<std::string, std::string>::iterator Content_Type_Element=Http->Response_Headers.find("Content-Type");
if (Content_Type_Element!=Http->Response_Headers.end())
Out << "Content-Type: "<< Content_Type_Element->second << "\r\n";
else if (Http->Response_HTTP_Code==200)
{
if (!Http->Response_Body.empty() && Http->Response_Body[0]=='<')
Out << "Content-Type: "<< "text/html; charset=utf-8" << "\r\n";
}
if (!Http->Response_Body.empty())
Out << "Content-Length: " << Http->Response_Body.size() << "\r\n";
Out << "\r\n";
if (!Http->HeadersOnly && !Http->Response_Body.empty())
Out << Http->Response_Body.c_str();
}
} //Namespace
} //Namespace
} //Namespace
↑ V128 The 'Http->Response_HTTP_Code' variable of the memsize type is written to a stream. Consider verifying the compatibility of 32 and 64 bit versions of the application in the context of a stored data.
↑ V128 The 'Http->Response_Body.size()' variable of the memsize type is written to a stream. Consider verifying the compatibility of 32 and 64 bit versions of the application in the context of a stored data.
↑ V654 The condition '!Line.empty()' of loop is always false.
↑ V1048 The 'Cookie_Pos' variable was assigned the same value.
↑ V1048 The 'Content_Pos' variable was assigned the same value.