mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-04 20:57:50 +08:00
252 lines
8.0 KiB
C++
Executable File
252 lines
8.0 KiB
C++
Executable File
// Copyright 2010, Shuo Chen. All rights reserved.
|
|
// http://code.google.com/p/muduo/
|
|
//
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the License file.
|
|
|
|
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
|
//
|
|
|
|
//taken from muduo and modified
|
|
|
|
/**
|
|
*
|
|
* @file
|
|
* @author An Tao
|
|
* @section LICENSE
|
|
*
|
|
* Copyright 2018, An Tao. All rights reserved.
|
|
* Use of this source code is governed by a MIT license
|
|
* that can be found in the License file.
|
|
*
|
|
* Drogon
|
|
*
|
|
*/
|
|
|
|
#include <trantor/utils/MsgBuffer.h>
|
|
#include <trantor/utils/Logger.h>
|
|
#include "HttpClientContext.h"
|
|
#include <iostream>
|
|
using namespace trantor;
|
|
using namespace drogon;
|
|
HttpClientContext::HttpClientContext(const trantor::TcpConnectionPtr &connPtr)
|
|
: _state(HttpResponseParseState::kExpectResponseLine),
|
|
_response(new HttpResponseImpl),
|
|
_conn(connPtr)
|
|
{
|
|
}
|
|
|
|
bool HttpClientContext::processResponseLine(const char *begin, const char *end)
|
|
{
|
|
const char *start = begin;
|
|
const char *space = std::find(start, end, ' ');
|
|
if (space != end)
|
|
{
|
|
LOG_TRACE << *(space - 1);
|
|
if (*(space - 1) == '1')
|
|
{
|
|
_response->setVersion(HttpResponse::kHttp11);
|
|
}
|
|
else if (*(space - 1) == '0')
|
|
{
|
|
_response->setVersion(HttpResponse::kHttp10);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
start = space + 1;
|
|
space = std::find(start, end, ' ');
|
|
if (space != end)
|
|
{
|
|
std::string status_code(start, space - start);
|
|
std::string status_message(space + 1, end - space - 1);
|
|
LOG_TRACE << status_code << " " << status_message;
|
|
auto code = atoi(status_code.c_str());
|
|
_response->setStatusCode(HttpResponse::HttpStatusCode(code), status_message);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// return false if any error
|
|
bool HttpClientContext::parseResponse(MsgBuffer *buf)
|
|
{
|
|
bool ok = true;
|
|
bool hasMore = true;
|
|
while (hasMore)
|
|
{
|
|
if (_state == HttpResponseParseState::kExpectResponseLine)
|
|
{
|
|
const char *crlf = buf->findCRLF();
|
|
if (crlf)
|
|
{
|
|
ok = processResponseLine(buf->peek(), crlf);
|
|
if (ok)
|
|
{
|
|
//_response->setReceiveTime(receiveTime);
|
|
buf->retrieveUntil(crlf + 2);
|
|
_state = HttpResponseParseState::kExpectHeaders;
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectHeaders)
|
|
{
|
|
const char *crlf = buf->findCRLF();
|
|
if (crlf)
|
|
{
|
|
const char *colon = std::find(buf->peek(), crlf, ':');
|
|
if (colon != crlf)
|
|
{
|
|
_response->addHeader(buf->peek(), colon, crlf);
|
|
}
|
|
else
|
|
{
|
|
std::string len = _response->getHeader("Content-Length");
|
|
//LOG_INFO << "content len=" << len;
|
|
if (len != "")
|
|
{
|
|
_response->_left_body_length = atoi(len.c_str());
|
|
_state = HttpResponseParseState::kExpectBody;
|
|
}
|
|
else
|
|
{
|
|
std::string encode = _response->getHeader("Transfer-Encoding");
|
|
if (encode == "chunked")
|
|
{
|
|
_state = HttpResponseParseState::kExpectChunkLen;
|
|
hasMore = true;
|
|
}
|
|
else
|
|
{
|
|
_state = HttpResponseParseState::kExpectClose;
|
|
hasMore = true;
|
|
}
|
|
}
|
|
}
|
|
buf->retrieveUntil(crlf + 2);
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectBody)
|
|
{
|
|
//LOG_INFO << "expectBody:len=" << request_->contentLen;
|
|
//LOG_INFO << "expectBody:buf=" << buf;
|
|
if (buf->readableBytes() == 0)
|
|
{
|
|
if (_response->_left_body_length == 0)
|
|
{
|
|
_state = HttpResponseParseState::kGotAll;
|
|
}
|
|
break;
|
|
}
|
|
if (_response->_left_body_length >= buf->readableBytes())
|
|
{
|
|
_response->_left_body_length -= buf->readableBytes();
|
|
_response->_bodyPtr->append(std::string(buf->peek(), buf->readableBytes()));
|
|
buf->retrieveAll();
|
|
}
|
|
else
|
|
{
|
|
_response->_bodyPtr->append(std::string(buf->peek(), _response->_left_body_length));
|
|
buf->retrieve(_response->_left_body_length);
|
|
_response->_left_body_length = 0;
|
|
}
|
|
if (_response->_left_body_length == 0)
|
|
{
|
|
_state = HttpResponseParseState::kGotAll;
|
|
LOG_TRACE << "post got all:len=" << _response->_left_body_length;
|
|
//LOG_INFO<<"content:"<<request_->content_;
|
|
LOG_TRACE << "content(END)";
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectClose)
|
|
{
|
|
_response->_bodyPtr->append(std::string(buf->peek(), buf->readableBytes()));
|
|
buf->retrieveAll();
|
|
break;
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectChunkLen)
|
|
{
|
|
const char *crlf = buf->findCRLF();
|
|
if (crlf)
|
|
{
|
|
//chunk length line
|
|
std::string len(buf->peek(), crlf - buf->peek());
|
|
char *end;
|
|
_response->_current_chunk_length = strtol(len.c_str(), &end, 16);
|
|
//LOG_TRACE << "chun length : " << _response->_current_chunk_length;
|
|
if (_response->_current_chunk_length != 0)
|
|
{
|
|
_state = HttpResponseParseState::kExpectChunkBody;
|
|
}
|
|
else
|
|
{
|
|
_state = HttpResponseParseState::kExpectLastEmptyChunk;
|
|
}
|
|
buf->retrieveUntil(crlf + 2);
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectChunkBody)
|
|
{
|
|
//LOG_TRACE<<"expect chunk len="<<_response->_current_chunk_length;
|
|
if (buf->readableBytes() >= (_response->_current_chunk_length + 2))
|
|
{
|
|
if (*(buf->peek() + _response->_current_chunk_length) == '\r' &&
|
|
*(buf->peek() + _response->_current_chunk_length + 1) == '\n')
|
|
{
|
|
_response->_bodyPtr->append(std::string(buf->peek(), _response->_current_chunk_length));
|
|
buf->retrieve(_response->_current_chunk_length + 2);
|
|
_response->_current_chunk_length = 0;
|
|
_state = HttpResponseParseState::kExpectChunkLen;
|
|
}
|
|
else
|
|
{
|
|
//error!
|
|
buf->retrieveAll();
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
else if (_state == HttpResponseParseState::kExpectLastEmptyChunk)
|
|
{
|
|
//last empty chunk
|
|
const char *crlf = buf->findCRLF();
|
|
if (crlf)
|
|
{
|
|
buf->retrieveUntil(crlf + 2);
|
|
_state = HttpResponseParseState::kGotAll;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hasMore = false;
|
|
}
|
|
}
|
|
}
|
|
return ok;
|
|
}
|