libMeatloaf/lib/meatloaf/network/http.cpp
2024-01-08 11:58:15 -06:00

576 lines
19 KiB
C++

// #include "http.h"
// #include <esp_idf_version.h>
// #include "../../../include/debug.h"
// #include "../../../include/global_defines.h"
// /********************************************************
// * File impls
// ********************************************************/
// MeatHttpClient* HttpFile::fromHeader() {
// if(client == nullptr) {
// //Debug_printv("Client was not present, creating");
// client = new MeatHttpClient();
// // let's just get the headers so we have some info
// //Debug_printv("Client requesting head");
// //Debug_printv("before head url[%s]", url.c_str());
// client->HEAD(url);
// //Debug_printv("after head url[%s]", client->url.c_str());
// resetURL(client->url);
// }
// return client;
// }
// bool HttpFile::isDirectory() {
// if(fromHeader()->m_isDirectory)
// return true;
// if(fromHeader()->m_isWebDAV) {
// // try webdav PROPFIND to get a listing
// return true;
// }
// else
// // otherwise return false
// return false;
// }
// MStream* HttpFile::getSourceStream(std::ios_base::openmode mode) {
// // has to return OPENED stream
// //Debug_printv("Input stream requested: [%s]", url.c_str());
// // headers have to be supplied here, they might be set on this channel using
// // i.e. CBM DOS commands like
// // H+:Accept: */*
// // H+:Accept-Encoding: gzip, deflate
// // here you add them all to a map, like this:
// std::map<std::string, std::string> headers;
// // headers["Accept"] = "*/*";
// // headers["Accept-Encoding"] = "gzip, deflate";
// // etc.
// MStream* istream = new HttpIStream(url, mode, headers);
// istream->open();
// return istream;
// }
// MStream* HttpFile::getDecodedStream(std::shared_ptr<MStream> is) {
// return is.get(); // DUMMY return value - we've overriden istreamfunction, so this one won't be used
// }
// time_t HttpFile::getLastWrite() {
// if(fromHeader()->m_isWebDAV) {
// return 0;
// }
// else
// // take from webdav PROPFIND or fallback to Last-Modified
// return 0;
// }
// time_t HttpFile::getCreationTime() {
// if(fromHeader()->m_isWebDAV) {
// return 0;
// }
// else
// // take from webdav PROPFIND or fallback to Last-Modified
// return 0;
// }
// bool HttpFile::exists() {
// return fromHeader()->_exists;
// }
// uint32_t HttpFile::size() {
// if(fromHeader()->m_isWebDAV) {
// // take from webdav PROPFIND
// return 0;
// }
// else
// // fallback to what we had from the header
// return fromHeader()->_size;
// }
// bool HttpFile::remove() {
// if(fromHeader()->m_isWebDAV) {
// // PROPPATCH allows deletion
// return false;
// }
// return false;
// }
// bool HttpFile::mkDir() {
// if(fromHeader()->m_isWebDAV) {
// // MKCOL creates dir
// return false;
// }
// return false;
// }
// bool HttpFile::rewindDirectory() {
// if(fromHeader()->m_isWebDAV) {
// // we can try if this is webdav, then
// // PROPFIND allows listing dir
// return false;
// }
// return false;
// };
// MFile* HttpFile::getNextFileInDir() {
// Debug_printv("");
// if(fromHeader()->m_isWebDAV) {
// // we can try if this is webdav, then
// // PROPFIND allows listing dir
// return nullptr;
// }
// return nullptr;
// };
// bool HttpFile::isText() {
// return fromHeader()->isText;
// }
// /********************************************************
// * Istream impls
// ********************************************************/
// bool HttpIStream::open() {
// bool r = false;
// m_http.setHeaders(headers);
// if(mode == (std::ios_base::out | std::ios_base::app))
// r = m_http.PUT(url);
// else if(mode == std::ios_base::out)
// r = m_http.POST(url);
// else
// r = m_http.GET(url);
// if ( r ) {
// _size = m_http._size;
// }
// return r;
// }
// void HttpIStream::close() {
// //Debug_printv("CLOSE called explicitly on this HTTP stream!");
// m_http.close();
// }
// bool HttpIStream::seek(uint32_t pos) {
// if ( !m_http._is_open )
// {
// Debug_printv("error");
// return false;
// }
// return m_http.seek(pos);
// }
// uint32_t HttpIStream::read(uint8_t* buf, uint32_t size) {
// uint32_t bytesRead = 0;
// if ( size > available() )
// size = available();
// if ( size > 0 )
// {
// bytesRead = m_http.read(buf, size);
// _position += bytesRead;
// }
// return bytesRead;
// };
// uint32_t HttpIStream::write(const uint8_t *buf, uint32_t size) {
// uint32_t bytesWritten = m_http.write(buf, size);
// _position += bytesWritten;
// return bytesWritten;
// }
// bool HttpIStream::isOpen() {
// return m_http._is_open;
// };
// // uint32_t HttpIStream::size() {
// // return m_http._size;
// // };
// // uint32_t HttpIStream::available() {
// // return m_http.m_bytesAvailable;
// // };
// // uint32_t HttpIStream::position() {
// // return m_http._position;
// // }
// // size_t HttpIStream::error() {
// // return m_http.m_error;
// // }
// /********************************************************
// * Meat HTTP client impls
// ********************************************************/
// bool MeatHttpClient::GET(std::string dstUrl) {
// Debug_printv("GET");
// return open(dstUrl, HTTP_METHOD_GET);
// }
// bool MeatHttpClient::POST(std::string dstUrl) {
// Debug_printv("POST");
// return open(dstUrl, HTTP_METHOD_POST);
// }
// bool MeatHttpClient::PUT(std::string dstUrl) {
// Debug_printv("PUT");
// return open(dstUrl, HTTP_METHOD_PUT);
// }
// bool MeatHttpClient::HEAD(std::string dstUrl) {
// Debug_printv("HEAD");
// bool rc = open(dstUrl, HTTP_METHOD_HEAD);
// close();
// return rc;
// }
// bool MeatHttpClient::processRedirectsAndOpen(int range) {
// wasRedirected = false;
// _size = -1;
// Debug_printv("reopening url[%s] from position:%d", url.c_str(), range);
// lastRC = openAndFetchHeaders(lastMethod, range);
// while(lastRC == HttpStatus_MovedPermanently || lastRC == HttpStatus_Found || lastRC == 303)
// {
// Debug_printv("--- Page moved, doing redirect to [%s]", url.c_str());
// close();
// lastRC = openAndFetchHeaders(lastMethod, range);
// wasRedirected = true;
// }
// if(lastRC != HttpStatus_Ok && lastRC != 301 && lastRC != 206) {
// Debug_printv("opening stream failed, httpCode=%d", lastRC);
// close();
// return false;
// }
// // TODO - set m_isWebDAV somehow
// _is_open = true;
// _exists = true;
// _position = 0;
// Debug_printv("length[%d] avail[%d] isFriendlySkipper[%d] isText[%d] httpCode[%d]", _size, available(), isFriendlySkipper, isText, lastRC);
// return true;
// }
// bool MeatHttpClient::open(std::string dstUrl, esp_http_client_method_t meth) {
// url = dstUrl;
// lastMethod = meth;
// //m_error = 0;
// return processRedirectsAndOpen(0);
// };
// void MeatHttpClient::close() {
// if(m_http != nullptr) {
// if ( _is_open ) {
// esp_http_client_close(m_http);
// }
// esp_http_client_cleanup(m_http);
// //Debug_printv("HTTP Close and Cleanup");
// m_http = nullptr;
// }
// _is_open = false;
// }
// void MeatHttpClient::setOnHeader(const std::function<int(char*, char*)> &lambda) {
// onHeader = lambda;
// }
// bool MeatHttpClient::seek(uint32_t pos) {
// if(pos==_position)
// return true;
// if(isFriendlySkipper) {
// esp_http_client_close(m_http);
// bool op = processRedirectsAndOpen(pos);
// Debug_printv("SEEK in HttpIStream %s: range request RC=%d", url.c_str(), lastRC);
// if(!op)
// return false;
// // 200 = range not supported! according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
// if(lastRC == 206){
// Debug_printv("Seek successful");
// _position = pos;
// return true;
// }
// }
// if(lastMethod == HTTP_METHOD_GET) {
// Debug_printv("Server doesn't support resume, reading from start and discarding");
// // server doesn't support resume, so...
// if(pos<_position || pos == 0) {
// // skipping backward let's simply reopen the stream...
// esp_http_client_close(m_http);
// bool op = open(url, lastMethod);
// if(!op)
// return false;
// // and read pos bytes - requires some buffer
// for(int i = 0; i<pos; i++) {
// char c;
// int rc = esp_http_client_read(m_http, &c, 1);
// if(rc == -1)
// return false;
// }
// }
// else {
// auto delta = pos-_position;
// // skipping forward let's skip a proper amount of bytes - requires some buffer
// for(int i = 0; i<delta; i++) {
// char c;
// int rc = esp_http_client_read(m_http, &c, 1);
// if(rc == -1)
// return false;
// }
// }
// _position = pos;
// Debug_printv("stream opened[%s]", url.c_str());
// return true;
// }
// else
// return false;
// }
// uint32_t MeatHttpClient::read(uint8_t* buf, uint32_t size) {
// if (_is_open) {
// auto bytesRead= esp_http_client_read(m_http, (char *)buf, size );
// if(bytesRead>0) {
// _position+=bytesRead;
// }
// return bytesRead;
// }
// return 0;
// };
// uint32_t MeatHttpClient::write(const uint8_t* buf, uint32_t size) {
// if (_is_open) {
// auto bytesWritten= esp_http_client_write(m_http, (char *)buf, size );
// _position+=bytesWritten;
// return bytesWritten;
// }
// return 0;
// };
// int MeatHttpClient::openAndFetchHeaders(esp_http_client_method_t meth, int resume) {
// if ( url.size() < 5)
// return 0;
// mstr::replaceAll(url, " ", "%20");
// esp_http_client_config_t config = {
// .url = url.c_str(),
// .user_agent = USER_AGENT,
// .method = meth,
// .timeout_ms = 10000,
// .max_redirection_count = 10,
// .event_handler = _http_event_handler,
// .user_data = this,
// .keep_alive_enable = true,
// .keep_alive_idle = 10,
// .keep_alive_interval = 1
// };
// //Debug_printv("HTTP Init url[%s]", url.c_str());
// m_http = esp_http_client_init(&config);
// for (const auto& pair : headers) {
// std::cout << pair.first << ": " << pair.second << std::endl;
// esp_http_client_set_header(m_http, pair.first.c_str(), pair.second.c_str());
// }
// if(resume > 0) {
// char str[40];
// snprintf(str, sizeof str, "bytes=%lu-", (unsigned long)resume);
// esp_http_client_set_header(m_http, "range", str);
// }
// //Debug_printv("--- PRE OPEN");
// esp_err_t initOk = esp_http_client_open(m_http, 0); // or open? It's not entirely clear...
// if(initOk == ESP_FAIL)
// return 0;
// //Debug_printv("--- PRE FETCH HEADERS");
// int lengthResp = esp_http_client_fetch_headers(m_http);
// if(_size == -1 && lengthResp > 0) {
// // only if we aren't chunked!
// _size = lengthResp;
// _position = 0;
// }
// //Debug_printv("--- PRE GET STATUS CODE");
// return esp_http_client_get_status_code(m_http);
// }
// esp_err_t MeatHttpClient::_http_event_handler(esp_http_client_event_t *evt)
// {
// MeatHttpClient* meatClient = (MeatHttpClient*)evt->user_data;
// switch(evt->event_id) {
// case HTTP_EVENT_ERROR: // This event occurs when there are any errors during execution
// Debug_printv("HTTP_EVENT_ERROR");
// //meatClient->m_error = 1;
// break;
// case HTTP_EVENT_ON_CONNECTED: // Once the HTTP has been connected to the server, no data exchange has been performed
// // Debug_printv("HTTP_EVENT_ON_CONNECTED");
// break;
// case HTTP_EVENT_HEADER_SENT: // After sending all the headers to the server
// // Debug_printv("HTTP_EVENT_HEADER_SENT");
// break;
// case HTTP_EVENT_ON_HEADER: // Occurs when receiving each header sent from the server
// // Does this server support resume?
// // Accept-Ranges: bytes
// if (mstr::equals("Accept-Ranges", evt->header_key, false))
// {
// if(meatClient != nullptr) {
// meatClient->isFriendlySkipper = mstr::equals("bytes", evt->header_value,false);
// //Debug_printv("* Ranges info present '%s', comparison=%d!",evt->header_value, strcmp("bytes", evt->header_value)==0);
// }
// }
// // what can we do UTF8<->PETSCII on this stream?
// else if (mstr::equals("Content-Type", evt->header_key, false))
// {
// std::string asString = evt->header_value;
// bool isText = mstr::isText(asString);
// if(meatClient != nullptr) {
// meatClient->isText = isText;
// //Debug_printv("* Content info present '%s', isText=%d!, type=%s", evt->header_value, isText, asString.c_str());
// }
// }
// else if(mstr::equals("Last-Modified", evt->header_key, false))
// {
// // Last-Modified, value=Thu, 03 Dec 1992 08:37:20 - may be used to get file date
// }
// else if(mstr::equals("Content-Disposition", evt->header_key, false))
// {
// // Content-Disposition, value=attachment; filename*=UTF-8''GeckOS-c64.d64
// // we can set isText from real file extension, too!
// std::string value = evt->header_value;
// if ( mstr::contains( value, (char *)"index.prg" ) )
// {
// Debug_printv("HTTP Directory Listing [%s]", meatClient->url.c_str());
// meatClient->m_isDirectory = true;
// }
// }
// else if(mstr::equals("Content-Length", evt->header_key, false))
// {
// //Debug_printv("* Content len present '%s'", evt->header_value);
// meatClient->_size = std::stoi(evt->header_value);
// }
// else if(mstr::equals("Location", evt->header_key, false))
// {
// Debug_printv("* This page redirects from '%s' to '%s'", meatClient->url.c_str(), evt->header_value);
// if ( mstr::startsWith(evt->header_value, (char *)"http") )
// {
// //Debug_printv("match");
// meatClient->url = evt->header_value;
// }
// else
// {
// //Debug_printv("no match");
// if ( mstr::startsWith(evt->header_value, (char *)"/") )
// {
// // Absolute path redirect
// PeoplesUrlParser *u = PeoplesUrlParser::parseURL( meatClient->url );
// meatClient->url = u->root() + evt->header_value;
// }
// else
// {
// // Relative path redirect
// meatClient->url += evt->header_value;
// }
// }
// Debug_printv("new url '%s'", meatClient->url.c_str());
// }
// // Allow override in lambda
// meatClient->onHeader(evt->header_key, evt->header_value);
// break;
// #if __cplusplus > 201703L
// //#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 3, 0)
// case HTTP_EVENT_REDIRECT:
// Debug_printv("* This page redirects from '%s' to '%s'", meatClient->url.c_str(), evt->header_value);
// if ( mstr::startsWith(evt->header_value, (char *)"http") )
// {
// //Debug_printv("match");
// meatClient->url = evt->header_value;
// }
// else
// {
// //Debug_printv("no match");
// meatClient->url += evt->header_value;
// }
// break;
// #endif
// case HTTP_EVENT_ON_DATA: // Occurs multiple times when receiving body data from the server. MAY BE SKIPPED IF BODY IS EMPTY!
// //Debug_printv("HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
// {
// // int status = esp_http_client_get_status_code(meatClient->m_http);
// // if ((status == HttpStatus_Found || status == HttpStatus_MovedPermanently || status == 303) /*&& client->_redirect_count < (client->_max_redirects - 1)*/)
// // {
// // //Debug_printv("HTTP_EVENT_ON_DATA: Redirect response body, ignoring");
// // }
// // else {
// // //Debug_printv("HTTP_EVENT_ON_DATA: Got response body");
// // }
// if (esp_http_client_is_chunked_response(evt->client)) {
// int len;
// esp_http_client_get_chunk_length(evt->client, &len);
// meatClient->_size = len;
// //Debug_printv("HTTP_EVENT_ON_DATA: Got chunked response, chunklen=%d, contentlen[%d]", len, meatClient->_size);
// }
// }
// break;
// case HTTP_EVENT_ON_FINISH:
// // Occurs when finish a HTTP session
// // This may get called more than once if esp_http_client decides to retry in order to handle a redirect or auth response
// //Debug_printv("HTTP_EVENT_ON_FINISH %u\r\n", uxTaskGetStackHighWaterMark(nullptr));
// // Keep track of how many times we "finish" reading a response from the server
// //Debug_printv("HTTP_EVENT_ON_FINISH");
// break;
// case HTTP_EVENT_DISCONNECTED: // The connection has been disconnected
// //Debug_printv("HTTP_EVENT_DISCONNECTED");
// //meatClient->m_bytesAvailable = 0;
// break;
// }
// return ESP_OK;
// }