mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-05-21 12:45:32 +01:00
applied platformio structure
This commit is contained in:
110
lib/spotify/cspot/bell/main/io/include/BellHTTPServer.h
Normal file
110
lib/spotify/cspot/bell/main/io/include/BellHTTPServer.h
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <BellLogger.h> // for bell
|
||||
#include <stdint.h> // for uint8_t
|
||||
#include <stdlib.h> // for free, size_t
|
||||
#include <functional> // for function
|
||||
#include <map> // for map
|
||||
#include <memory> // for unique_ptr
|
||||
#include <mutex> // for mutex
|
||||
#include <string> // for string, hash, operator==, operator<
|
||||
#include <unordered_map> // for unordered_map
|
||||
#include <utility> // for pair
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "CivetServer.h" // for CivetServer, CivetHandler
|
||||
|
||||
using namespace bell;
|
||||
namespace bell {
|
||||
class BellHTTPServer : public CivetHandler {
|
||||
public:
|
||||
BellHTTPServer(int serverPort);
|
||||
~BellHTTPServer();
|
||||
|
||||
enum class WSState { CONNECTED, READY, CLOSED };
|
||||
|
||||
struct HTTPResponse {
|
||||
uint8_t* body;
|
||||
size_t bodySize;
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
int status;
|
||||
|
||||
HTTPResponse() {
|
||||
body = nullptr;
|
||||
bodySize = 0;
|
||||
status = 200;
|
||||
}
|
||||
|
||||
~HTTPResponse() {
|
||||
if (body != nullptr) {
|
||||
free(body);
|
||||
body = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
typedef std::function<std::unique_ptr<HTTPResponse>(
|
||||
struct mg_connection* conn)>
|
||||
HTTPHandler;
|
||||
typedef std::function<void(struct mg_connection* conn, WSState)>
|
||||
WSStateHandler;
|
||||
typedef std::function<void(struct mg_connection* conn, char*, size_t)>
|
||||
WSDataHandler;
|
||||
|
||||
class Router {
|
||||
public:
|
||||
struct RouterNode {
|
||||
std::unordered_map<std::string, std::unique_ptr<RouterNode>> children;
|
||||
HTTPHandler value = nullptr;
|
||||
std::string paramName = "";
|
||||
|
||||
bool isParam = false;
|
||||
bool isCatchAll = false;
|
||||
};
|
||||
|
||||
RouterNode root = RouterNode();
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> Params;
|
||||
typedef std::pair<HTTPHandler, Params> HandlerAndParams;
|
||||
|
||||
std::vector<std::string> split(const std::string str,
|
||||
const std::string regex_str);
|
||||
|
||||
void insert(const std::string& route, HTTPHandler& value);
|
||||
|
||||
HandlerAndParams find(const std::string& route);
|
||||
};
|
||||
|
||||
std::vector<int> getListeningPorts() { return server->getListeningPorts(); };
|
||||
void close() { server->close(); }
|
||||
|
||||
std::unique_ptr<HTTPResponse> makeJsonResponse(const std::string& json,
|
||||
int status = 200);
|
||||
std::unique_ptr<HTTPResponse> makeEmptyResponse();
|
||||
|
||||
void registerNotFound(HTTPHandler handler);
|
||||
void registerGet(const std::string&, HTTPHandler handler);
|
||||
void registerPost(const std::string&, HTTPHandler handler);
|
||||
void registerWS(const std::string&, WSDataHandler dataHandler,
|
||||
WSStateHandler stateHandler);
|
||||
|
||||
static std::unordered_map<std::string, std::string> extractParams(
|
||||
struct mg_connection* conn);
|
||||
|
||||
private:
|
||||
std::unique_ptr<CivetServer> server;
|
||||
std::vector<std::string> civetWebOptions;
|
||||
int serverPort = 8080;
|
||||
|
||||
Router getRequestsRouter;
|
||||
Router postRequestsRouter;
|
||||
std::mutex responseMutex;
|
||||
HTTPHandler notFoundHandler;
|
||||
|
||||
static std::mutex initMutex;
|
||||
|
||||
bool handleGet(CivetServer* server, struct mg_connection* conn);
|
||||
bool handlePost(CivetServer* server, struct mg_connection* conn);
|
||||
};
|
||||
|
||||
} // namespace bell
|
||||
19
lib/spotify/cspot/bell/main/io/include/BellSocket.h
Normal file
19
lib/spotify/cspot/bell/main/io/include/BellSocket.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace bell {
|
||||
class Socket {
|
||||
public:
|
||||
Socket(){};
|
||||
virtual ~Socket() = default;
|
||||
|
||||
virtual void open(const std::string& host, uint16_t port) = 0;
|
||||
virtual size_t poll() = 0;
|
||||
virtual size_t write(uint8_t* buf, size_t len) = 0;
|
||||
virtual size_t read(uint8_t* buf, size_t len) = 0;
|
||||
virtual bool isOpen() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual int getFd() = 0;
|
||||
};
|
||||
} // namespace bell
|
||||
75
lib/spotify/cspot/bell/main/io/include/BellTar.h
Normal file
75
lib/spotify/cspot/bell/main/io/include/BellTar.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream> // for istream, ostream
|
||||
#include <string> // for string
|
||||
|
||||
namespace bell::BellTar {
|
||||
typedef long long unsigned file_size_t;
|
||||
|
||||
////////////////////////////////////////
|
||||
// Writing raw data
|
||||
////////////////////////////////////////
|
||||
class writer {
|
||||
std::ostream& _dst;
|
||||
|
||||
public:
|
||||
writer(std::ostream& dst) : _dst(dst) {}
|
||||
~writer() { finish(); }
|
||||
|
||||
// Append the data specified by |data| and |file_size| into the
|
||||
// tar file represented by |dst|.
|
||||
// In the tar file, the data will be available at |path_in_tar|.
|
||||
void put(std::string path_in_tar, char const* const data,
|
||||
const file_size_t data_size);
|
||||
|
||||
// Write empty folder at |path_in_tar|.
|
||||
// NOTE: to specify folders for files, just use / in the path
|
||||
// passed to |put()|.
|
||||
void put_directory(std::string path_in_tar);
|
||||
|
||||
// Call after everything has been added to the tar represented
|
||||
// by |dst| to make it a valid tar file.
|
||||
void finish();
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
// Reading raw data
|
||||
////////////////////////////////////////
|
||||
class reader {
|
||||
std::istream& _inp;
|
||||
struct {
|
||||
std::string file_name;
|
||||
file_size_t file_size;
|
||||
char file_type;
|
||||
} _cached_header_data;
|
||||
bool _cached_header_data_valid;
|
||||
void _cache_header();
|
||||
int _number_of_files;
|
||||
|
||||
public:
|
||||
// Constructor, pass input stream |inp| pointing to a tar file.
|
||||
reader(std::istream& inp)
|
||||
: _inp(inp), _cached_header_data_valid(false), _number_of_files(-1) {}
|
||||
|
||||
// Returns true if another file can be read from |inp|.
|
||||
bool contains_another_file();
|
||||
|
||||
// Returns file name of next file in |inp|.
|
||||
std::string get_next_file_name();
|
||||
// Returns file size of next file in |inp|. Use to allocate
|
||||
// memory for the |read_next_file()| call.
|
||||
file_size_t get_next_file_size();
|
||||
|
||||
// Read next file in |inp| to |data|.
|
||||
void read_next_file(char* const data);
|
||||
|
||||
char get_next_file_type();
|
||||
|
||||
void extract_all_files(std::string output_dir);
|
||||
// Skip next file in |inp|.
|
||||
void skip_next_file();
|
||||
|
||||
// Returns number of files in tar at |inp|.
|
||||
int number_of_files();
|
||||
};
|
||||
} // namespace bell::BellTar
|
||||
28
lib/spotify/cspot/bell/main/io/include/BinaryReader.h
Normal file
28
lib/spotify/cspot/bell/main/io/include/BinaryReader.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h> // for uint8_t, int16_t, int32_t, uint32_t
|
||||
#include <stdlib.h> // for size_t
|
||||
#include <memory> // for shared_ptr
|
||||
#include <vector> // for vector
|
||||
|
||||
namespace bell {
|
||||
class ByteStream;
|
||||
|
||||
class BinaryReader {
|
||||
std::shared_ptr<ByteStream> stream;
|
||||
size_t currentPos = 0;
|
||||
|
||||
public:
|
||||
BinaryReader(std::shared_ptr<ByteStream> stream);
|
||||
int32_t readInt();
|
||||
int16_t readShort();
|
||||
uint32_t readUInt();
|
||||
long long readLong();
|
||||
void close();
|
||||
uint8_t readByte();
|
||||
size_t size();
|
||||
size_t position();
|
||||
std::vector<uint8_t> readBytes(size_t);
|
||||
void skip(size_t);
|
||||
};
|
||||
} // namespace bell
|
||||
79
lib/spotify/cspot/bell/main/io/include/BinaryStream.h
Normal file
79
lib/spotify/cspot/bell/main/io/include/BinaryStream.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<bit>)
|
||||
#include <bit> // for endian
|
||||
#endif
|
||||
|
||||
#include <stdint.h> // for int16_t, int32_t, int64_t, uint16_t, uint32_t
|
||||
#include <cstddef> // for byte
|
||||
#include <iostream> // for istream, ostream
|
||||
|
||||
namespace bell {
|
||||
class BinaryStream {
|
||||
private:
|
||||
std::endian byteOrder;
|
||||
|
||||
std::istream* istr = nullptr;
|
||||
std::ostream* ostr = nullptr;
|
||||
|
||||
void ensureReadable();
|
||||
void ensureWritable();
|
||||
bool flipBytes = false;
|
||||
|
||||
template <typename T>
|
||||
T swap16(T value) {
|
||||
#ifdef _WIN32
|
||||
return _byteswap_ushort(value);
|
||||
#else
|
||||
return __builtin_bswap16(value);
|
||||
#endif
|
||||
}
|
||||
template <typename T>
|
||||
T swap32(T value) {
|
||||
#ifdef _WIN32
|
||||
return _byteswap_ulong(value);
|
||||
#else
|
||||
return __builtin_bswap32(value);
|
||||
#endif
|
||||
}
|
||||
template <typename T>
|
||||
T swap64(T value) {
|
||||
#ifdef _WIN32
|
||||
return _byteswap_uint64(value);
|
||||
#else
|
||||
return __builtin_bswap64(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
BinaryStream(std::ostream* ostr);
|
||||
BinaryStream(std::istream* istr);
|
||||
|
||||
/**
|
||||
* @brief Set byte order used by stream.
|
||||
*
|
||||
* @param byteOrder stream's byteorder. Defaults to native.
|
||||
*/
|
||||
void setByteOrder(std::endian byteOrder);
|
||||
|
||||
// Read operations
|
||||
BinaryStream& operator>>(char& value);
|
||||
BinaryStream& operator>>(std::byte& value);
|
||||
BinaryStream& operator>>(int16_t& value);
|
||||
BinaryStream& operator>>(uint16_t& value);
|
||||
BinaryStream& operator>>(int32_t& value);
|
||||
BinaryStream& operator>>(uint32_t& value);
|
||||
BinaryStream& operator>>(int64_t& value);
|
||||
BinaryStream& operator>>(uint64_t& value);
|
||||
|
||||
// Write operations
|
||||
BinaryStream& operator<<(char value);
|
||||
BinaryStream& operator<<(std::byte value);
|
||||
BinaryStream& operator<<(int16_t value);
|
||||
BinaryStream& operator<<(uint16_t value);
|
||||
BinaryStream& operator<<(int32_t value);
|
||||
BinaryStream& operator<<(uint32_t value);
|
||||
BinaryStream& operator<<(int64_t value);
|
||||
BinaryStream& operator<<(uint64_t value);
|
||||
};
|
||||
} // namespace bell
|
||||
127
lib/spotify/cspot/bell/main/io/include/BufferedStream.h
Normal file
127
lib/spotify/cspot/bell/main/io/include/BufferedStream.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint8_t
|
||||
#include <atomic> // for atomic
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr
|
||||
#include <mutex> // for mutex
|
||||
#include <string> // for string
|
||||
|
||||
#include "BellTask.h" // for Task
|
||||
#include "ByteStream.h" // for ByteStream
|
||||
#include "WrappedSemaphore.h" // for WrappedSemaphore
|
||||
|
||||
/**
|
||||
* This class implements a wrapper around an arbitrary bell::ByteStream,
|
||||
* providing a circular reading buffer with configurable thresholds.
|
||||
*
|
||||
* The BufferedStream runs a bell::Task when it's started, so the caller can
|
||||
* access the buffer's data asynchronously, whenever needed. The buffer is refilled
|
||||
* automatically from source stream.
|
||||
*
|
||||
* The class implements bell::ByteStream's methods, although for proper functioning,
|
||||
* the caller code should be modified to check isReady() and isNotReady() flags.
|
||||
*
|
||||
* If the actual reading code can't be modified, waitForReady allows to wait for buffer readiness
|
||||
* during reading. Keep in mind that using the semaphore is probably more resource effective.
|
||||
*
|
||||
* The source stream (passed to open() or returned by the reader) should implement the read()
|
||||
* method correctly, such as that 0 is returned if, and only if the stream ends.
|
||||
*/
|
||||
class BufferedStream : public bell::ByteStream, bell::Task {
|
||||
public:
|
||||
typedef std::shared_ptr<bell::ByteStream> StreamPtr;
|
||||
typedef std::function<StreamPtr(uint32_t rangeStart)> StreamReader;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param taskName name to use for the reading task
|
||||
* @param bufferSize total size of the reading buffer
|
||||
* @param readThreshold how much can be read before refilling the buffer
|
||||
* @param readSize amount of bytes to read from the source each time
|
||||
* @param readyThreshold minimum amount of available bytes to report isReady()
|
||||
* @param notReadyThreshold maximum amount of available bytes to report isNotReady()
|
||||
* @param waitForReady whether to wait for the buffer to be ready during reading
|
||||
* @param endWithSource whether to end the streaming as soon as source returns 0 from read()
|
||||
*/
|
||||
BufferedStream(const std::string& taskName, uint32_t bufferSize,
|
||||
uint32_t readThreshold, uint32_t readSize,
|
||||
uint32_t readyThreshold, uint32_t notReadyThreshold,
|
||||
bool waitForReady = false);
|
||||
~BufferedStream() override;
|
||||
bool open(const StreamPtr& stream);
|
||||
bool open(const StreamReader& newReader, uint32_t initialOffset = 0);
|
||||
void close() override;
|
||||
|
||||
// inherited methods
|
||||
public:
|
||||
/**
|
||||
* Read len bytes from the buffer to dst. If waitForReady is enabled
|
||||
* and readAvailable is lower than notReadyThreshold, the function
|
||||
* will block until readyThreshold bytes is available.
|
||||
*
|
||||
* @returns number of bytes copied to dst (might be lower than len,
|
||||
* if the buffer does not contain len bytes available), or 0 if the source
|
||||
* stream is already closed and there is no reader attached.
|
||||
*/
|
||||
size_t read(uint8_t* dst, size_t len) override;
|
||||
size_t skip(size_t len) override;
|
||||
size_t position() override;
|
||||
size_t size() override;
|
||||
|
||||
// stream status
|
||||
public:
|
||||
/**
|
||||
* Total amount of bytes served to read().
|
||||
*/
|
||||
uint32_t readTotal;
|
||||
/**
|
||||
* Total amount of bytes read from source.
|
||||
*/
|
||||
uint32_t bufferTotal;
|
||||
/**
|
||||
* Amount of bytes available to read from the buffer.
|
||||
*/
|
||||
std::atomic<uint32_t> readAvailable;
|
||||
/**
|
||||
* Whether the caller should start reading the data. This indicates that a safe
|
||||
* amount (determined by readyThreshold) of data is available in the buffer.
|
||||
*/
|
||||
bool isReady() const;
|
||||
/**
|
||||
* Whether the caller should stop reading the data. This indicates that the amount of data
|
||||
* available for reading is decreasing to a non-safe value, as data is being read
|
||||
* faster than it can be buffered.
|
||||
*/
|
||||
bool isNotReady() const;
|
||||
/**
|
||||
* Semaphore that is given when the buffer becomes ready (isReady() == true). Caller can
|
||||
* wait for the semaphore instead of continuously querying isReady().
|
||||
*/
|
||||
bell::WrappedSemaphore readySem;
|
||||
|
||||
private:
|
||||
std::mutex runningMutex;
|
||||
bool running = false;
|
||||
bool terminate = false;
|
||||
bell::WrappedSemaphore
|
||||
readSem; // signal to start writing to buffer after reading from it
|
||||
std::mutex
|
||||
readMutex; // mutex for locking read operations during writing, and vice versa
|
||||
uint32_t bufferSize;
|
||||
uint32_t readAt;
|
||||
uint32_t readSize;
|
||||
uint32_t readyThreshold;
|
||||
uint32_t notReadyThreshold;
|
||||
bool waitForReady;
|
||||
uint8_t* buf;
|
||||
uint8_t* bufEnd;
|
||||
uint8_t* bufReadPtr;
|
||||
uint8_t* bufWritePtr;
|
||||
StreamPtr source;
|
||||
StreamReader reader;
|
||||
void runTask() override;
|
||||
void reset();
|
||||
uint32_t lengthBetween(uint8_t* me, uint8_t* other);
|
||||
};
|
||||
25
lib/spotify/cspot/bell/main/io/include/ByteStream.h
Normal file
25
lib/spotify/cspot/bell/main/io/include/ByteStream.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef BELL_BYTE_READER_H
|
||||
#define BELL_BYTE_READER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* A class for reading bytes from a stream. Further implemented in HTTPStream.h
|
||||
*/
|
||||
namespace bell {
|
||||
class ByteStream {
|
||||
public:
|
||||
ByteStream(){};
|
||||
virtual ~ByteStream() = default;
|
||||
|
||||
virtual size_t read(uint8_t* buf, size_t nbytes) = 0;
|
||||
virtual size_t skip(size_t nbytes) = 0;
|
||||
|
||||
virtual size_t position() = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual void close() = 0;
|
||||
};
|
||||
} // namespace bell
|
||||
|
||||
#endif
|
||||
35
lib/spotify/cspot/bell/main/io/include/CircularBuffer.h
Normal file
35
lib/spotify/cspot/bell/main/io/include/CircularBuffer.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for uint8_t
|
||||
#include <cstring> // for size_t
|
||||
#include <memory> // for unique_ptr
|
||||
#include <mutex> // for mutex
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "WrappedSemaphore.h" // for WrappedSemaphore
|
||||
|
||||
namespace bell {
|
||||
class CircularBuffer {
|
||||
public:
|
||||
CircularBuffer(size_t dataCapacity);
|
||||
|
||||
std::unique_ptr<bell::WrappedSemaphore> dataSemaphore;
|
||||
|
||||
size_t size() const { return dataSize; }
|
||||
|
||||
size_t capacity() const { return dataCapacity; }
|
||||
|
||||
size_t write(const uint8_t* data, size_t bytes);
|
||||
size_t read(uint8_t* data, size_t bytes);
|
||||
void emptyBuffer();
|
||||
void emptyExcept(size_t size);
|
||||
|
||||
private:
|
||||
std::mutex bufferMutex;
|
||||
size_t begIndex = 0;
|
||||
size_t endIndex = 0;
|
||||
size_t dataSize = 0;
|
||||
size_t dataCapacity = 0;
|
||||
std::vector<uint8_t> buffer;
|
||||
};
|
||||
} // namespace bell
|
||||
56
lib/spotify/cspot/bell/main/io/include/EncodedAudioStream.h
Normal file
56
lib/spotify/cspot/bell/main/io/include/EncodedAudioStream.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <cstdint> // for uint8_t
|
||||
#include <memory> // for shared_ptr, unique_ptr
|
||||
#include <string> // for basic_string, string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "mp3dec.h" // for MP3FrameInfo
|
||||
|
||||
namespace bell {
|
||||
class ByteStream;
|
||||
|
||||
class EncodedAudioStream {
|
||||
public:
|
||||
EncodedAudioStream();
|
||||
~EncodedAudioStream();
|
||||
|
||||
// Codecs supported by this stream class
|
||||
enum class AudioCodec { AAC, MP3, OGG, NONE };
|
||||
|
||||
void openWithStream(std::unique_ptr<bell::ByteStream> byteStream);
|
||||
size_t decodeFrame(uint8_t* dst);
|
||||
bool isReadable();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ByteStream> innerStream;
|
||||
std::vector<uint8_t> inputBuffer;
|
||||
std::vector<short> outputBuffer;
|
||||
std::string TAG = "EncryptedAudioStream";
|
||||
|
||||
uint8_t* decodePtr = 0;
|
||||
int bytesInBuffer = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
size_t decodedSampleRate = 44100;
|
||||
|
||||
AudioCodec codec = AudioCodec::NONE;
|
||||
|
||||
void guessDataFormat();
|
||||
|
||||
void readFully(uint8_t* dst, size_t nbytes);
|
||||
bool vectorStartsWith(std::vector<uint8_t>&, std::vector<uint8_t>&);
|
||||
|
||||
std::vector<uint8_t> aacMagicBytes = {0xFF, 0xF1};
|
||||
std::vector<uint8_t> aacMagicBytes4 = {0xFF, 0xF9};
|
||||
std::vector<uint8_t> mp3MagicBytesUntagged = {0xFF, 0xFB};
|
||||
std::vector<uint8_t> mp3MagicBytesIdc = {0x49, 0x44, 0x33};
|
||||
|
||||
// AACFrameInfo aacFrameInfo;
|
||||
MP3FrameInfo mp3FrameInfo;
|
||||
|
||||
size_t decodeFrameMp3(uint8_t* dst);
|
||||
size_t decodeFrameAAC(uint8_t* dst);
|
||||
};
|
||||
} // namespace bell
|
||||
44
lib/spotify/cspot/bell/main/io/include/FileStream.h
Normal file
44
lib/spotify/cspot/bell/main/io/include/FileStream.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <ByteStream.h> // for ByteStream
|
||||
#include <stdint.h> // for uint8_t
|
||||
#include <stdio.h> // for size_t, FILE
|
||||
#include <string> // for string
|
||||
|
||||
/*
|
||||
* FileStream
|
||||
*
|
||||
* A class for reading and writing to files implementing the ByteStream interface.
|
||||
*
|
||||
*/
|
||||
namespace bell {
|
||||
class FileStream : public ByteStream {
|
||||
public:
|
||||
FileStream(const std::string& path, std::string mode);
|
||||
~FileStream();
|
||||
|
||||
FILE* file;
|
||||
|
||||
/*
|
||||
* Reads data from the stream.
|
||||
*
|
||||
* @param buf The buffer to read data into.
|
||||
* @param nbytes The size of the buffer.
|
||||
* @return The number of bytes read.
|
||||
* @throws std::runtime_error if the stream is closed.
|
||||
*/
|
||||
size_t read(uint8_t* buf, size_t nbytes);
|
||||
|
||||
/*
|
||||
* Skips nbytes bytes in the stream.
|
||||
*/
|
||||
size_t skip(size_t nbytes);
|
||||
|
||||
size_t position();
|
||||
|
||||
size_t size();
|
||||
|
||||
// Closes the connection
|
||||
void close();
|
||||
};
|
||||
} // namespace bell
|
||||
117
lib/spotify/cspot/bell/main/io/include/HTTPClient.h
Normal file
117
lib/spotify/cspot/bell/main/io/include/HTTPClient.h
Normal file
@@ -0,0 +1,117 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <cstdint> // for uint8_t, int32_t
|
||||
#include <memory> // for make_unique, unique_ptr
|
||||
#include <string> // for string
|
||||
#include <string_view> // for string_view
|
||||
#include <utility> // for pair
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "SocketStream.h" // for SocketStream
|
||||
#include "URLParser.h" // for URLParser
|
||||
#ifndef BELL_DISABLE_FMT
|
||||
#include "fmt/core.h" // for format
|
||||
#endif
|
||||
#include "picohttpparser.h" // for phr_header
|
||||
|
||||
namespace bell {
|
||||
class HTTPClient {
|
||||
public:
|
||||
// most basic header type, represents by a key-val
|
||||
typedef std::pair<std::string, std::string> ValueHeader;
|
||||
|
||||
typedef std::vector<ValueHeader> Headers;
|
||||
|
||||
// Helper over ValueHeader, formatting a HTTP bytes range
|
||||
struct RangeHeader {
|
||||
static ValueHeader range(int32_t from, int32_t to) {
|
||||
#ifndef BELL_DISABLE_FMT
|
||||
return ValueHeader{"Range", fmt::format("bytes={}-{}", from, to)};
|
||||
#else
|
||||
return ValueHeader{
|
||||
"Range", "bytes=" + std::to_string(from) + "-" + std::to_string(to)};
|
||||
#endif
|
||||
}
|
||||
|
||||
static ValueHeader last(int32_t nbytes) {
|
||||
#ifndef BELL_DISABLE_FMT
|
||||
return ValueHeader{"Range", fmt::format("bytes=-{}", nbytes)};
|
||||
#else
|
||||
return ValueHeader{"Range", "bytes=-" + std::to_string(nbytes)};
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class Response {
|
||||
public:
|
||||
Response(){};
|
||||
~Response();
|
||||
|
||||
/**
|
||||
* Initializes a connection with a given url.
|
||||
*/
|
||||
void connect(const std::string& url);
|
||||
|
||||
void rawRequest(const std::string& method, const std::string& url,
|
||||
const std::vector<uint8_t>& content, Headers& headers);
|
||||
void get(const std::string& url, Headers headers = {});
|
||||
void post(const std::string& url, Headers headers = {},
|
||||
const std::vector<uint8_t>& body = {});
|
||||
|
||||
std::string_view body();
|
||||
std::vector<uint8_t> bytes();
|
||||
|
||||
std::string_view header(const std::string& headerName);
|
||||
bell::SocketStream& stream() { return this->socketStream; }
|
||||
|
||||
size_t contentLength();
|
||||
size_t totalLength();
|
||||
|
||||
private:
|
||||
bell::URLParser urlParser;
|
||||
bell::SocketStream socketStream;
|
||||
|
||||
struct phr_header phResponseHeaders[32];
|
||||
const size_t HTTP_BUF_SIZE = 1024;
|
||||
|
||||
std::vector<uint8_t> httpBuffer = std::vector<uint8_t>(HTTP_BUF_SIZE);
|
||||
std::vector<uint8_t> rawBody = std::vector<uint8_t>();
|
||||
size_t httpBufferAvailable;
|
||||
|
||||
size_t contentSize = 0;
|
||||
bool hasContentSize = false;
|
||||
|
||||
Headers responseHeaders;
|
||||
|
||||
void readResponseHeaders();
|
||||
void readRawBody();
|
||||
};
|
||||
|
||||
enum class Method : uint8_t { GET = 0, POST = 1 };
|
||||
|
||||
struct Request {
|
||||
std::string url;
|
||||
Method method;
|
||||
Headers headers;
|
||||
};
|
||||
|
||||
static std::unique_ptr<Response> get(const std::string& url,
|
||||
Headers headers = {}) {
|
||||
auto response = std::make_unique<Response>();
|
||||
response->connect(url);
|
||||
response->get(url, headers);
|
||||
return response;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Response> post(const std::string& url,
|
||||
Headers headers = {},
|
||||
const std::vector<uint8_t>& body = {}) {
|
||||
auto response = std::make_unique<Response>();
|
||||
response->connect(url);
|
||||
response->post(url, headers, body);
|
||||
return response;
|
||||
}
|
||||
};
|
||||
} // namespace bell
|
||||
59
lib/spotify/cspot/bell/main/io/include/MGStreamAdapter.h
Normal file
59
lib/spotify/cspot/bell/main/io/include/MGStreamAdapter.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include "civetweb.h"
|
||||
|
||||
const size_t BUF_SIZE = 1024;
|
||||
|
||||
// Custom streambuf
|
||||
class mg_buf : public std::streambuf {
|
||||
private:
|
||||
struct mg_connection* conn;
|
||||
char buffer[BUF_SIZE];
|
||||
|
||||
public:
|
||||
mg_buf(struct mg_connection* _conn);
|
||||
|
||||
protected:
|
||||
virtual int_type overflow(int_type c);
|
||||
int flush_buffer();
|
||||
virtual int sync();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adapts ostream to mg_write
|
||||
*
|
||||
*/
|
||||
class MGStreamAdapter : public std::ostream {
|
||||
private:
|
||||
mg_buf buf;
|
||||
|
||||
public:
|
||||
MGStreamAdapter(struct mg_connection* _conn);
|
||||
};
|
||||
|
||||
// Custom streambuf
|
||||
class mg_read_buf : public std::streambuf {
|
||||
private:
|
||||
struct mg_connection* conn;
|
||||
char buffer[BUF_SIZE];
|
||||
|
||||
public:
|
||||
mg_read_buf(struct mg_connection* _conn);
|
||||
|
||||
protected:
|
||||
virtual int_type underflow();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adapts istream to mg_read
|
||||
*/
|
||||
class MGInputStreamAdapter : public std::istream {
|
||||
private:
|
||||
mg_read_buf buf;
|
||||
|
||||
public:
|
||||
MGInputStreamAdapter(struct mg_connection* _conn);
|
||||
};
|
||||
71
lib/spotify/cspot/bell/main/io/include/SocketStream.h
Normal file
71
lib/spotify/cspot/bell/main/io/include/SocketStream.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream> // for streamsize, basic_streambuf<>::int_type, ios...
|
||||
#include <memory> // for unique_ptr, operator!=
|
||||
#include <string> // for char_traits, string
|
||||
|
||||
#include "BellSocket.h" // for Socket
|
||||
|
||||
namespace bell {
|
||||
class SocketBuffer : public std::streambuf {
|
||||
private:
|
||||
std::unique_ptr<bell::Socket> internalSocket;
|
||||
|
||||
static const int bufLen = 1024;
|
||||
char ibuf[bufLen], obuf[bufLen];
|
||||
|
||||
public:
|
||||
SocketBuffer() { internalSocket = nullptr; }
|
||||
|
||||
SocketBuffer(const std::string& hostname, int port, bool isSSL = false) {
|
||||
open(hostname, port);
|
||||
}
|
||||
|
||||
int open(const std::string& hostname, int port, bool isSSL = false);
|
||||
|
||||
int close();
|
||||
|
||||
bool isOpen() {
|
||||
return internalSocket != nullptr && internalSocket->isOpen();
|
||||
}
|
||||
|
||||
~SocketBuffer() { close(); }
|
||||
|
||||
protected:
|
||||
virtual int sync();
|
||||
|
||||
virtual int_type underflow();
|
||||
|
||||
virtual int_type overflow(int_type c = traits_type::eof());
|
||||
|
||||
virtual std::streamsize xsgetn(char_type* __s, std::streamsize __n);
|
||||
|
||||
virtual std::streamsize xsputn(const char_type* __s, std::streamsize __n);
|
||||
};
|
||||
|
||||
class SocketStream : public std::iostream {
|
||||
private:
|
||||
SocketBuffer socketBuf;
|
||||
|
||||
public:
|
||||
SocketStream() : std::iostream(&socketBuf) {}
|
||||
|
||||
SocketStream(const std::string& hostname, int port, bool isSSL = false)
|
||||
: std::iostream(&socketBuf) {
|
||||
open(hostname, port, isSSL);
|
||||
}
|
||||
|
||||
SocketBuffer* rdbuf() { return &socketBuf; }
|
||||
|
||||
int open(const std::string& hostname, int port, bool isSSL = false) {
|
||||
int err = socketBuf.open(hostname, port, isSSL);
|
||||
if (err)
|
||||
setstate(std::ios::failbit);
|
||||
return err;
|
||||
}
|
||||
|
||||
int close() { return socketBuf.close(); }
|
||||
|
||||
bool isOpen() { return socketBuf.isOpen(); }
|
||||
};
|
||||
} // namespace bell
|
||||
19
lib/spotify/cspot/bell/main/io/include/StreamUtils.h
Normal file
19
lib/spotify/cspot/bell/main/io/include/StreamUtils.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <istream>
|
||||
#include <streambuf>
|
||||
|
||||
namespace bell {
|
||||
struct MemoryBuffer : std::streambuf {
|
||||
MemoryBuffer(std::byte const* base, size_t size) {
|
||||
std::byte* p(const_cast<std::byte*>(base));
|
||||
this->setg((char*)p, (char*)p, (char*)p + size);
|
||||
}
|
||||
};
|
||||
struct IMemoryStream : virtual MemoryBuffer, std::istream {
|
||||
IMemoryStream(std::byte const* base, size_t size)
|
||||
: MemoryBuffer(base, size),
|
||||
std::istream(static_cast<std::streambuf*>(this)) {}
|
||||
};
|
||||
} // namespace bell
|
||||
125
lib/spotify/cspot/bell/main/io/include/TCPSocket.h
Normal file
125
lib/spotify/cspot/bell/main/io/include/TCPSocket.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#ifndef BELL_BASIC_SOCKET_H
|
||||
#define BELL_BASIC_SOCKET_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "BellSocket.h"
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include "win32shim.h"
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __sun
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <BellLogger.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace bell {
|
||||
class TCPSocket : public bell::Socket {
|
||||
private:
|
||||
int sockFd;
|
||||
bool isClosed = true;
|
||||
|
||||
public:
|
||||
TCPSocket(){};
|
||||
~TCPSocket() { close(); };
|
||||
|
||||
int getFd() { return sockFd; }
|
||||
|
||||
void open(const std::string& host, uint16_t port) {
|
||||
int err;
|
||||
int domain = AF_INET;
|
||||
int socketType = SOCK_STREAM;
|
||||
|
||||
struct addrinfo hints {
|
||||
}, *addr;
|
||||
//fine-tune hints according to which socket you want to open
|
||||
hints.ai_family = domain;
|
||||
hints.ai_socktype = socketType;
|
||||
hints.ai_protocol =
|
||||
IPPROTO_IP; // no enum : possible value can be read in /etc/protocols
|
||||
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
|
||||
|
||||
// BELL_LOG(info, "http", "%s %d", host.c_str(), port);
|
||||
|
||||
char portStr[6];
|
||||
sprintf(portStr, "%u", port);
|
||||
err = getaddrinfo(host.c_str(), portStr, &hints, &addr);
|
||||
if (err != 0) {
|
||||
throw std::runtime_error("Resolve failed");
|
||||
}
|
||||
|
||||
sockFd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
err = connect(sockFd, addr->ai_addr, addr->ai_addrlen);
|
||||
if (err < 0) {
|
||||
close();
|
||||
BELL_LOG(error, "http", "Could not connect to %s. Error %d", host.c_str(),
|
||||
errno);
|
||||
throw std::runtime_error("Resolve failed");
|
||||
}
|
||||
|
||||
int flag = 1;
|
||||
setsockopt(sockFd, /* socket affected */
|
||||
IPPROTO_TCP, /* set option at TCP level */
|
||||
TCP_NODELAY, /* name of option */
|
||||
(char*)&flag, /* the cast is historical cruft */
|
||||
sizeof(int)); /* length of option value */
|
||||
|
||||
freeaddrinfo(addr);
|
||||
isClosed = false;
|
||||
}
|
||||
|
||||
size_t read(uint8_t* buf, size_t len) {
|
||||
return recv(sockFd, (char*)buf, len, 0);
|
||||
}
|
||||
|
||||
size_t write(uint8_t* buf, size_t len) {
|
||||
return send(sockFd, (char*)buf, len, 0);
|
||||
}
|
||||
|
||||
size_t poll() {
|
||||
#ifdef _WIN32
|
||||
unsigned long value;
|
||||
ioctlsocket(sockFd, FIONREAD, &value);
|
||||
#else
|
||||
int value;
|
||||
ioctl(sockFd, FIONREAD, &value);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
bool isOpen() {
|
||||
return !isClosed;
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (!isClosed) {
|
||||
#ifdef _WIN32
|
||||
closesocket(sockFd);
|
||||
#else
|
||||
::close(sockFd);
|
||||
#endif
|
||||
sockFd = -1;
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace bell
|
||||
|
||||
#endif
|
||||
48
lib/spotify/cspot/bell/main/io/include/TLSSocket.h
Normal file
48
lib/spotify/cspot/bell/main/io/include/TLSSocket.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef BELL_TLS_SOCKET_H
|
||||
#define BELL_TLS_SOCKET_H
|
||||
|
||||
#include <stdint.h> // for uint8_t, uint16_t
|
||||
|
||||
#include "BellSocket.h" // for Socket
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#endif
|
||||
#include <stdlib.h> // for size_t
|
||||
#include <string> // for string
|
||||
|
||||
#include "mbedtls/ctr_drbg.h" // for mbedtls_ctr_drbg_context
|
||||
#include "mbedtls/entropy.h" // for mbedtls_entropy_context
|
||||
#include "mbedtls/net_sockets.h" // for mbedtls_net_context
|
||||
#include "mbedtls/ssl.h" // for mbedtls_ssl_config, mbedtls_ssl_con...
|
||||
|
||||
namespace bell {
|
||||
class TLSSocket : public bell::Socket {
|
||||
private:
|
||||
mbedtls_net_context server_fd;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
|
||||
bool isClosed = true;
|
||||
|
||||
public:
|
||||
TLSSocket();
|
||||
~TLSSocket() { close(); };
|
||||
|
||||
void open(const std::string& host, uint16_t port);
|
||||
|
||||
size_t read(uint8_t* buf, size_t len);
|
||||
size_t write(uint8_t* buf, size_t len);
|
||||
size_t poll();
|
||||
bool isOpen();
|
||||
|
||||
void close();
|
||||
int getFd() { return server_fd.fd; }
|
||||
};
|
||||
|
||||
} // namespace bell
|
||||
|
||||
#endif
|
||||
107
lib/spotify/cspot/bell/main/io/include/URLParser.h
Normal file
107
lib/spotify/cspot/bell/main/io/include/URLParser.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib> // for strtol, size_t
|
||||
#include <regex> // for match_results, match_results<>::value_type, sub...
|
||||
#include <stdexcept> // for invalid_argument
|
||||
#include <string> // for string, allocator, operator+, char_traits, oper...
|
||||
|
||||
namespace bell {
|
||||
class URLParser {
|
||||
public:
|
||||
static std::string urlEncode(const std::string& value) {
|
||||
std::string new_str = "";
|
||||
static auto hex_digt = "0123456789ABCDEF";
|
||||
|
||||
std::string result;
|
||||
result.reserve(value.size() << 1);
|
||||
|
||||
for (auto ch : value) {
|
||||
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= 'a' && ch <= 'z') || ch == '-' || ch == '_' || ch == '!' ||
|
||||
ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '~' ||
|
||||
ch == '.') // !'()*-._~
|
||||
{
|
||||
result.push_back(ch);
|
||||
} else {
|
||||
result += std::string("%") +
|
||||
hex_digt[static_cast<unsigned char>(ch) >> 4] +
|
||||
hex_digt[static_cast<unsigned char>(ch) & 15];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
static std::string urlDecode(const std::string& value) {
|
||||
std::string result;
|
||||
result.reserve(value.size());
|
||||
|
||||
for (std::size_t i = 0; i < value.size(); ++i) {
|
||||
auto ch = value[i];
|
||||
|
||||
if (ch == '%' && (i + 2) < value.size()) {
|
||||
auto hex = value.substr(i + 1, 2);
|
||||
auto dec = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
|
||||
result.push_back(dec);
|
||||
i += 2;
|
||||
} else if (ch == '+') {
|
||||
result.push_back(' ');
|
||||
} else {
|
||||
result.push_back(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string host;
|
||||
int port = -1;
|
||||
|
||||
std::string schema = "http";
|
||||
std::string path;
|
||||
#ifdef BELL_DISABLE_REGEX
|
||||
void parse(const char* url, std::vector<std::string>& match);
|
||||
#else
|
||||
static const std::regex urlParseRegex;
|
||||
#endif
|
||||
|
||||
static URLParser parse(const std::string& url) {
|
||||
URLParser parser;
|
||||
|
||||
// apply parser.urlParseRegex to url
|
||||
#ifdef BELL_DISABLE_REGEX
|
||||
std::vector<std::string> match(6);
|
||||
parser.parse(url.c_str(), match);
|
||||
#else
|
||||
std::cmatch match;
|
||||
std::regex_match(url.c_str(), match, parser.urlParseRegex);
|
||||
#endif
|
||||
|
||||
if (match.size() < 3) {
|
||||
throw std::invalid_argument("Invalid URL");
|
||||
}
|
||||
|
||||
parser.schema = match[1];
|
||||
parser.host = match[2];
|
||||
parser.path = match[3];
|
||||
|
||||
if (match[4] != "") {
|
||||
parser.path += match[4];
|
||||
}
|
||||
|
||||
// check if parser.host contains ':'
|
||||
if (parser.host.find(':') != std::string::npos) {
|
||||
auto port = std::stoi(
|
||||
parser.host.substr(parser.host.find(':') + 1, parser.host.size()));
|
||||
auto host = parser.host.substr(0, parser.host.find(':'));
|
||||
parser.port = port;
|
||||
parser.host = host;
|
||||
}
|
||||
|
||||
if (parser.port == -1) {
|
||||
parser.port = parser.schema == "http" ? 80 : 443;
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
};
|
||||
} // namespace bell
|
||||
31
lib/spotify/cspot/bell/main/io/include/X509Bundle.h
Normal file
31
lib/spotify/cspot/bell/main/io/include/X509Bundle.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbedtls/x509_crt.h> // for mbedtls_x509_crt
|
||||
#include <stddef.h> // for size_t
|
||||
#include <cstdint> // for uint8_t, uint16_t, uint32_t
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "mbedtls/ssl.h" // for mbedtls_ssl_config
|
||||
|
||||
namespace bell::X509Bundle {
|
||||
|
||||
int crtCheckCertificate(mbedtls_x509_crt* child, const uint8_t* pub_key_buf,
|
||||
size_t pub_key_len);
|
||||
/* This callback is called for every certificate in the chain. If the chain
|
||||
* is proper each intermediate certificate is validated through its parent
|
||||
* in the x509_crt_verify_chain() function. So this callback should
|
||||
* only verify the first untrusted link in the chain is signed by the
|
||||
* root certificate in the trusted bundle
|
||||
*/
|
||||
int crtVerifyCallback(void* buf, mbedtls_x509_crt* crt, int depth,
|
||||
uint32_t* flags);
|
||||
|
||||
/* Initialize the bundle into an array so we can do binary search for certs,
|
||||
the bundle generated by the python utility is already presorted by subject name
|
||||
*/
|
||||
void init(const uint8_t* x509_bundle, size_t bundle_size);
|
||||
|
||||
void attach(mbedtls_ssl_config* conf);
|
||||
|
||||
bool shouldVerify();
|
||||
}; // namespace bell::X509Bundle
|
||||
93
lib/spotify/cspot/bell/main/io/include/picohttpparser.h
Normal file
93
lib/spotify/cspot/bell/main/io/include/picohttpparser.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
|
||||
* Shigeo Mitsunari
|
||||
*
|
||||
* The software is licensed under either the MIT License (below) or the Perl
|
||||
* license.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef picohttpparser_h
|
||||
#define picohttpparser_h
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(ssize_t)
|
||||
#define ssize_t intptr_t
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* contains name and value of a header (name == NULL if is a continuing line
|
||||
* of a multiline header */
|
||||
struct phr_header {
|
||||
const char* name;
|
||||
size_t name_len;
|
||||
const char* value;
|
||||
size_t value_len;
|
||||
};
|
||||
|
||||
/* returns number of bytes consumed if successful, -2 if request is partial,
|
||||
* -1 if failed */
|
||||
int phr_parse_request(const char* buf, size_t len, const char** method,
|
||||
size_t* method_len, const char** path, size_t* path_len,
|
||||
int* minor_version, struct phr_header* headers,
|
||||
size_t* num_headers, size_t last_len);
|
||||
|
||||
/* ditto */
|
||||
int phr_parse_response(const char* _buf, size_t len, int* minor_version,
|
||||
int* status, const char** msg, size_t* msg_len,
|
||||
struct phr_header* headers, size_t* num_headers,
|
||||
size_t last_len);
|
||||
|
||||
/* ditto */
|
||||
int phr_parse_headers(const char* buf, size_t len, struct phr_header* headers,
|
||||
size_t* num_headers, size_t last_len);
|
||||
|
||||
/* should be zero-filled before start */
|
||||
struct phr_chunked_decoder {
|
||||
size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
|
||||
char consume_trailer; /* if trailing headers should be consumed */
|
||||
char _hex_count;
|
||||
char _state;
|
||||
};
|
||||
|
||||
/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
|
||||
* encoding headers. When the function returns without an error, bufsz is
|
||||
* updated to the length of the decoded data available. Applications should
|
||||
* repeatedly call the function while it returns -2 (incomplete) every time
|
||||
* supplying newly arrived data. If the end of the chunked-encoded data is
|
||||
* found, the function returns a non-negative number indicating the number of
|
||||
* octets left undecoded, that starts from the offset returned by `*bufsz`.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
ssize_t phr_decode_chunked(struct phr_chunked_decoder* decoder, char* buf,
|
||||
size_t* bufsz);
|
||||
|
||||
/* returns if the chunked decoder is in middle of chunked data */
|
||||
int phr_decode_chunked_is_in_data(struct phr_chunked_decoder* decoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user