OVMS3/OVMS.V3/components/ovms_http/src/ovms_http.cpp

281 lines
6.3 KiB
C++

/*
; Project: Open Vehicle Monitor System
; Date: 14th March 2017
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.
*/
#include "ovms_log.h"
static const char *TAG = "http";
#include "ovms_http.h"
#include "ovms_config.h"
#include "metrics_standard.h"
OvmsHttpClient::OvmsHttpClient()
{
m_buf = NULL;
m_bodysize = 0;
m_responsecode = 0;
}
OvmsHttpClient::OvmsHttpClient(std::string url, const char* method)
{
m_buf = NULL;
Request(url, method);
}
OvmsHttpClient::~OvmsHttpClient()
{
if (m_buf)
{
delete m_buf;
m_buf = NULL;
}
}
bool OvmsHttpClient::Request(std::string url, const char* method)
{
m_bodysize = 0;
m_responsecode = 0;
// First, split URL into server and path components
if (url.compare(0, 7, "http://", 7) == 0)
{
url = url.substr(7);
}
else if (url.compare(0, 8, "https://", 8) == 0)
{
url = url.substr(8);
}
std::string server;
std::string path;
std::string service;
size_t delim = url.find('/');
if (delim==std::string::npos)
{
server = url;
path = std::string("");
}
else
{
server = url.substr(0,delim);
path = url.substr(delim);
}
delim = server.find(':');
if (delim==std::string::npos)
{
service = std::string("80");
}
else
{
service = server.substr(delim+1);
server = server.substr(0,delim);
}
Connect(server.c_str(), service.c_str());
if (!IsOpen())
{
return false;
}
// Now, we need to send the HTTP request...
// ESP_LOGI(TAG, "Server is %s, path is %s",server.c_str(),path.c_str());
std::string req(method);
req.append(" ");
req.append(path);
req.append(" HTTP/1.0\r\nHost: ");
req.append(server);
req.append("\r\nUser-Agent: ");
req.append(get_user_agent());
req.append("\r\n\r\n");
if (Write(req.c_str(), req.length()) < 0)
{
ESP_LOGE(TAG, "Unable to write to server connection");
Disconnect();
return false;
}
m_buf = new OvmsBuffer(1024);
bool inheaders = true;
// ESP_LOGI(TAG,"Reading headers...");
while((inheaders)&&(m_buf->PollSocket(m_sock, 10000) >= 0))
{
// ESP_LOGI(TAG, "Now buffered %d bytes",m_buf->UsedSpace());
int k = m_buf->HasLine();
while ((inheaders)&&(k >= 0))
{
if (k == 0)
{
inheaders = 0;
}
else
{
// ESP_LOGI(TAG, "Got response %s",m_buf->ReadLine().c_str());
std::string header = m_buf->ReadLine();
if (strncasecmp(header.c_str(), "Content-Length:", 15) == 0)
{
m_bodysize = atoi(header.substr(15).c_str());
}
if (header.compare(0,5,"HTTP/") == 0)
{
size_t space = header.find(' ');
if (space!=std::string::npos)
{
m_responsecode = atoi(header.substr(space+1).c_str());
}
}
k = m_buf->HasLine();
}
}
}
if (inheaders)
{
ESP_LOGE(TAG, "Error: Premature end of server response");
Disconnect();
return false;
}
// Process the separator line
// m_buf->Diagnostics();
m_buf->ReadLine(); // Discard the empty header/body line
return true;
}
void OvmsHttpClient::Disconnect()
{
if (m_buf != NULL)
{
delete m_buf;
m_buf = NULL;
}
OvmsNetTcpConnection::Disconnect();
}
size_t OvmsHttpClient::BodyRead(void *buf, size_t nbyte)
{
// char *x = (char*)buf;
if ((m_buf == NULL)||(m_buf->UsedSpace() == 0))
{
size_t n = Read(buf,nbyte);
// ESP_EARLY_LOGI(TAG, "BodyRead got %d bytes direct (%02x %02x %02x %02x)",n,x[0],x[1],x[2],x[3]);
return n;
}
else
{
size_t n = m_buf->Pop(nbyte,(uint8_t*)buf);
// ESP_EARLY_LOGI(TAG, "Body Read got %d bytes from buf (%d left) (%02x %02x %02x %02x)",n,m_buf->UsedSpace(),x[0],x[1],x[2],x[3]);
if (m_buf->UsedSpace() == 0)
{
delete m_buf;
m_buf = NULL;
}
return n;
}
}
int OvmsHttpClient::BodyHasLine()
{
if (m_buf == NULL)
return -1;
if (m_buf->HasLine()<0)
{
m_buf->PollSocket(m_sock, 10000);
// m_buf->Diagnostics();
}
return m_buf->HasLine();
}
std::string OvmsHttpClient::BodyReadLine()
{
if (m_buf == NULL)
return std::string("");
if (m_buf->HasLine()<0)
{
m_buf->PollSocket(m_sock, 10000);
// m_buf->Diagnostics();
}
return m_buf->ReadLine();
}
size_t OvmsHttpClient::BodySize()
{
return m_bodysize;
}
int OvmsHttpClient::ResponseCode()
{
return m_responsecode;
}
std::string OvmsHttpClient::GetBodyAsString()
{
std::string body;
if (!IsOpen())
{
ESP_LOGE(TAG, "http request failed");
return body;
}
size_t expected = BodySize();
body.reserve(expected);
uint8_t rbuf[512];
size_t filesize = 0;
while (int k = BodyRead(rbuf,512))
{
filesize += k;
body.append((const char*)rbuf,k);
}
Disconnect();
if (filesize != expected)
{
ESP_LOGE(TAG, "Download file size (%d) does not match expected (%d)", filesize, expected);
body.empty();
}
Disconnect();
return body;
}
void OvmsHttpClient::Reset()
{
if (m_buf)
{
delete m_buf;
m_buf = NULL;
}
m_bodysize = 0;
m_responsecode = 0;
}