📄 httpclnt.cxx
字号:
outMIME.SetAt(ConnectionTag, KeepAliveTag);
for (PINDEX retry = 0; retry < 3; retry++) {
if (!AssureConnect(url, outMIME))
break;
if (!WriteCommand(cmdName, url.AsString(PURL::URIOnly), outMIME, dataBody)) {
lastResponseCode = -1;
lastResponseInfo = GetErrorText(LastWriteError);
break;
}
// If not persisting need to shut down write so other end stops reading
if (!persist)
Shutdown(ShutdownWrite);
// Await a response, if all OK exit loop
if (ReadResponse(replyMime))
break;
// If not persisting, we have no oppurtunity to write again, just error out
if (!persist)
break;
// If have had a failure to read a response but there was no error then
// we have a shutdown socket probably due to a lack of persistence so ...
if (GetErrorCode(LastReadError) != NoError)
break;
// ... we close the channel and allow AssureConnet() to reopen it.
Close();
}
return lastResponseCode;
}
BOOL PHTTPClient::WriteCommand(Commands cmd,
const PString & url,
PMIMEInfo & outMIME,
const PString & dataBody)
{
return WriteCommand(commandNames[cmd], url, outMIME, dataBody);
}
BOOL PHTTPClient::WriteCommand(const PString & cmdName,
const PString & url,
PMIMEInfo & outMIME,
const PString & dataBody)
{
ostream & this_stream = *this;
PINDEX len = dataBody.GetSize()-1;
if (!outMIME.Contains(ContentLengthTag))
outMIME.SetInteger(ContentLengthTag, len);
if (cmdName.IsEmpty())
this_stream << "GET";
else
this_stream << cmdName;
this_stream << ' ' << (url.IsEmpty() ? "/" : (const char*) url) << " HTTP/1.1\r\n"
<< setfill('\r') << outMIME;
return Write((const char *)dataBody, len);
}
BOOL PHTTPClient::ReadResponse(PMIMEInfo & replyMIME)
{
PString http = ReadString(7);
if (!http) {
UnRead(http);
if (http.Find("HTTP/") == P_MAX_INDEX) {
lastResponseCode = PHTTP::RequestOK;
lastResponseInfo = "HTTP/0.9";
return TRUE;
}
if (http[0] == '\n')
ReadString(1);
else if (http[0] == '\r' && http[1] == '\n')
ReadString(2);
if (PHTTP::ReadResponse())
if (replyMIME.Read(*this))
return TRUE;
}
lastResponseCode = -1;
if (GetErrorCode(LastReadError) != NoError)
lastResponseInfo = GetErrorText(LastReadError);
else {
lastResponseInfo = "Premature shutdown";
SetErrorValues(ProtocolFailure, 0, LastReadError);
}
return FALSE;
}
BOOL PHTTPClient::ReadContentBody(PMIMEInfo & replyMIME, PString & body)
{
BOOL ok = InternalReadContentBody(replyMIME, body);
body.SetSize(body.GetSize()+1);
return ok;
}
BOOL PHTTPClient::ReadContentBody(PMIMEInfo & replyMIME, PBYTEArray & body)
{
return InternalReadContentBody(replyMIME, body);
}
BOOL PHTTPClient::InternalReadContentBody(PMIMEInfo & replyMIME, PAbstractArray & body)
{
PCaselessString encoding = replyMIME(TransferEncodingTag);
if (encoding != ChunkedTag) {
if (replyMIME.Contains(ContentLengthTag)) {
PINDEX length = replyMIME.GetInteger(ContentLengthTag);
body.SetSize(length);
return ReadBlock(body.GetPointer(), length);
}
if (!(encoding.IsEmpty())) {
lastResponseCode = -1;
lastResponseInfo = "Unknown Transfer-Encoding extension";
return FALSE;
}
// Must be raw, read to end file variety
static const PINDEX ChunkSize = 2048;
PINDEX bytesRead = 0;
while (ReadBlock((char *)body.GetPointer(bytesRead+ChunkSize)+bytesRead, ChunkSize))
bytesRead += GetLastReadCount();
body.SetSize(bytesRead + GetLastReadCount());
return GetErrorCode(LastReadError) == NoError;
}
// HTTP1.1 chunked format
PINDEX bytesRead = 0;
for (;;) {
// Read chunk length line
PString chunkLengthLine;
if (!ReadLine(chunkLengthLine))
return FALSE;
// A zero length chunk is end of output
PINDEX chunkLength = chunkLengthLine.AsUnsigned(16);
if (chunkLength == 0)
break;
// Read the chunk
if (!ReadBlock((char *)body.GetPointer(bytesRead+chunkLength)+bytesRead, chunkLength))
return FALSE;
bytesRead+= chunkLength;
// Read the trailing CRLF
if (!ReadLine(chunkLengthLine))
return FALSE;
}
// Read the footer
PString footer;
do {
if (!ReadLine(footer))
return FALSE;
} while (replyMIME.AddMIME(footer));
return TRUE;
}
BOOL PHTTPClient::GetTextDocument(const PURL & url,
PString & document,
BOOL persist)
{
PMIMEInfo outMIME, replyMIME;
if (!GetDocument(url, outMIME, replyMIME, persist))
return FALSE;
return ReadContentBody(replyMIME, document);
}
BOOL PHTTPClient::GetDocument(const PURL & _url,
PMIMEInfo & _outMIME,
PMIMEInfo & replyMIME,
BOOL persist)
{
int count = 0;
static const char locationTag[] = "Location";
PURL url = _url;
for (;;) {
PMIMEInfo outMIME = _outMIME;
replyMIME.RemoveAll();
PString u = url.AsString();
int code = ExecuteCommand(GET, url, outMIME, PString(), replyMIME, persist);
switch (code) {
case RequestOK:
return TRUE;
case MovedPermanently:
case MovedTemporarily:
{
if (count > 10)
return FALSE;
PString str = replyMIME(locationTag);
if (str.IsEmpty())
return FALSE;
PString doc;
if (!ReadContentBody(replyMIME, doc))
return FALSE;
url = str;
count++;
}
break;
default:
return FALSE;
}
}
}
BOOL PHTTPClient::GetHeader(const PURL & url,
PMIMEInfo & outMIME,
PMIMEInfo & replyMIME,
BOOL persist)
{
return ExecuteCommand(HEAD, url, outMIME, PString(), replyMIME, persist) == RequestOK;
}
BOOL PHTTPClient::PostData(const PURL & url,
PMIMEInfo & outMIME,
const PString & data,
PMIMEInfo & replyMIME,
BOOL persist)
{
PString dataBody = data;
if (!outMIME.Contains(ContentTypeTag)) {
outMIME.SetAt(ContentTypeTag, "application/x-www-form-urlencoded");
dataBody += "\r\n"; // Add CRLF for compatibility with some CGI servers.
}
return ExecuteCommand(POST, url, outMIME, data, replyMIME, persist) == RequestOK;
}
BOOL PHTTPClient::PostData(const PURL & url,
PMIMEInfo & outMIME,
const PString & data,
PMIMEInfo & replyMIME,
PString & body,
BOOL persist)
{
if (!PostData(url, outMIME, data, replyMIME, persist))
return FALSE;
return ReadContentBody(replyMIME, body);
}
BOOL PHTTPClient::AssureConnect(const PURL & url, PMIMEInfo & outMIME)
{
PString host = url.GetHostName();
// Is not open or other end shut down, restablish connection
if (!IsOpen()) {
if (host.IsEmpty()) {
lastResponseCode = BadRequest;
lastResponseInfo = "No host specified";
return SetErrorValues(ProtocolFailure, 0, LastReadError);
}
#if P_SSL
if (url.GetScheme() == "https") {
PTCPSocket * tcp = new PTCPSocket(url.GetPort());
tcp->SetReadTimeout(readTimeout);
if (!tcp->Connect(host)) {
lastResponseCode = -2;
lastResponseInfo = tcp->GetErrorText();
delete tcp;
return FALSE;
}
PSSLChannel * ssl = new PSSLChannel;
if (!ssl->Connect(tcp)) {
lastResponseCode = -2;
lastResponseInfo = ssl->GetErrorText();
delete ssl;
return FALSE;
}
if (!Open(ssl)) {
lastResponseCode = -2;
lastResponseInfo = GetErrorText();
return FALSE;
}
}
else
#endif
if (!Connect(host, url.GetPort())) {
lastResponseCode = -2;
lastResponseInfo = GetErrorText();
return FALSE;
}
}
// Have connection, so fill in the required MIME fields
static char HostTag[] = "Host";
if (!outMIME.Contains(HostTag)) {
if (!host)
outMIME.SetAt(HostTag, host);
else {
PIPSocket * sock = GetSocket();
if (sock != NULL)
outMIME.SetAt(HostTag, sock->GetHostName());
}
}
return TRUE;
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -