summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/BString.h2
-rw-r--r--includes/BWebSocket.h62
-rw-r--r--includes/Base64.h19
-rw-r--r--includes/Http.h1
-rw-r--r--includes/HttpServer.h2
-rw-r--r--includes/SHA1.h24
-rw-r--r--includes/Selectable.h5
-rw-r--r--includes/Task.h7
8 files changed, 120 insertions, 2 deletions
diff --git a/includes/BString.h b/includes/BString.h
index a4178a4..e783935 100644
--- a/includes/BString.h
+++ b/includes/BString.h
@@ -117,6 +117,8 @@ class String : private std::string {
const char & operator[](ssize_t i) const { if (i < 0) i = strlen() + i; return at(i); }
char & operator[](ssize_t i) { if (i < 0) i = strlen() + i; return at(i); }
+
+ void reserve(size_t s) { std::string::reserve(s); }
};
};
diff --git a/includes/BWebSocket.h b/includes/BWebSocket.h
new file mode 100644
index 0000000..41e5a7d
--- /dev/null
+++ b/includes/BWebSocket.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <Task.h>
+#include <StacklessTask.h>
+#include <BStream.h>
+#include <HttpServer.h>
+
+namespace Balau {
+
+class WebSocketActionBase;
+
+class WebSocketWorker : public StacklessTask {
+ public:
+ virtual bool parse(Http::Request & req) { return true; }
+ protected:
+ WebSocketWorker(IO<Handle> socket, const String & url) : m_socket(new BStream(socket)) { m_name = String("WebSocket:") + url + "/" + m_socket->getName(); }
+ ~WebSocketWorker() { free(m_payload); }
+ private:
+ void processMessage();
+ const char * getName() const { return m_name.to_charp(); }
+ void Do();
+ String m_name;
+ IO<BStream> m_socket;
+ enum {
+ READ_H,
+ READ_PLB,
+ READ_PLL,
+ READ_MK,
+ READ_PL,
+ } m_status = READ_H;
+ enum { MAX_WEBSOCKET_LIMIT = 4 * 1024 * 1024 };
+ uint8_t * m_payload = NULL;
+ uint64_t m_payloadLen;
+ uint64_t m_totalLen;
+ uint64_t m_remainingBytes;
+ uint32_t m_mask;
+ uint8_t m_opcode;
+ bool m_hasMask;
+ bool m_fin;
+ bool m_firstFragment = true;
+ bool m_enforceServer = false;
+ bool m_enforceClient = false;
+ friend class WebSocketActionBase;
+};
+
+class WebSocketServerBase : public HttpServer::Action {
+ protected:
+ WebSocketServerBase(const Regex & regex) : Action(regex) { }
+ virtual WebSocketWorker * spawnWorker(IO<Handle> socket, const String & url) = 0;
+ private:
+ void sendError(IO<Handle> out, const char * serverName);
+ bool Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException);
+};
+
+template<class T>
+class WebSocketServer : public WebSocketServerBase {
+ protected:
+ WebSocketServer(const Regex & regex) : WebSocketServerBase(regex) { }
+ virtual WebSocketWorker * spawnWorker(IO<Handle> socket, const String & url) { return new T(socket, url); }
+};
+
+};
diff --git a/includes/Base64.h b/includes/Base64.h
new file mode 100644
index 0000000..d039c73
--- /dev/null
+++ b/includes/Base64.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <Exceptions.h>
+
+namespace Balau {
+
+class Base64 {
+public:
+ static String encode(const uint8_t * data, int len);
+ static int decode(const String & str_in, uint8_t * data_out);
+ static const double ratio;
+
+private:
+ static void encode_block(unsigned char in_tab[3], int len, char out[4]);
+ static int stri(char);
+ static int decode_block(char s1, char s2, char s3, char s4, unsigned char * out_tab);
+};
+
+};
diff --git a/includes/Http.h b/includes/Http.h
index 7c351a6..fae2ad9 100644
--- a/includes/Http.h
+++ b/includes/Http.h
@@ -27,6 +27,7 @@ struct Request {
StringMap headers;
FileList files;
bool persistent;
+ bool upgrade;
String version;
};
diff --git a/includes/HttpServer.h b/includes/HttpServer.h
index d044e92..683390c 100644
--- a/includes/HttpServer.h
+++ b/includes/HttpServer.h
@@ -24,6 +24,7 @@ class HttpServer {
Response(HttpServer * server, Http::Request req, IO<Handle> out) : m_server(server), m_req(req), m_out(out), m_buffer(new Buffer()), m_responseCode(200), m_type("text/html; charset=UTF-8"), m_flushed(false) { }
void SetResponseCode(int code) { m_responseCode = code; }
void SetContentType(const String & type) { m_type = type; }
+ void setNoSize() { m_noSize = true; }
IO<Buffer> get() { return m_buffer; }
IO<Buffer> operator->() { return m_buffer; }
void Flush();
@@ -39,6 +40,7 @@ class HttpServer {
String m_type;
std::list<String> m_extraHeaders;
bool m_flushed;
+ bool m_noSize = false;
Response(const Response &) = delete;
Response & operator=(const Response &) = delete;
diff --git a/includes/SHA1.h b/includes/SHA1.h
new file mode 100644
index 0000000..f70f6b7
--- /dev/null
+++ b/includes/SHA1.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <Exceptions.h>
+
+namespace Balau {
+
+class SHA1 {
+ public:
+ SHA1() { reset(); }
+ void reset();
+ void update(const uint8_t* data, const size_t len);
+ void final(uint8_t * digest);
+
+ enum { DIGEST_SIZE = 20 };
+
+ private:
+ void transform(uint32_t state[5], const uint8_t buffer[64]);
+
+ uint32_t m_state[5];
+ uint32_t m_count[2];
+ uint8_t m_buffer[64];
+};
+
+};
diff --git a/includes/Selectable.h b/includes/Selectable.h
index b3b5b8c..8667415 100644
--- a/includes/Selectable.h
+++ b/includes/Selectable.h
@@ -24,14 +24,17 @@ class Selectable : public Handle {
class SelectableEvent : public Events::BaseEvent {
public:
- SelectableEvent(int fd, int evt = ev::READ | ev::WRITE) : m_task(NULL) { Printer::elog(E_SELECT, "Got a new SelectableEvent at %p", this); m_evt.set<SelectableEvent, &SelectableEvent::evt_cb>(this); m_evt.set(fd, evt); }
+ SelectableEvent(int fd, int evt = ev::READ | ev::WRITE) : m_task(NULL), m_evtType(evt), m_fd(fd) { Printer::elog(E_SELECT, "Got a new SelectableEvent at %p", this); m_evt.set<SelectableEvent, &SelectableEvent::evt_cb>(this); m_evt.set(fd, evt); }
virtual ~SelectableEvent() { Printer::elog(E_SELECT, "Destroying a SelectableEvent at %p", this); m_evt.stop(); }
void stop() { Printer::elog(E_SELECT, "Stopping a SelectableEvent at %p", this); reset(); m_evt.stop(); }
private:
void evt_cb(ev::io & w, int revents) { Printer::elog(E_SELECT, "Got a libev callback on a SelectableEvent at %p", this); doSignal(); }
virtual void gotOwner(Task * task);
+ virtual bool relaxed() { return true; }
ev::io m_evt;
+ int m_evtType;
+ int m_fd;
Task * m_task = NULL;
};
diff --git a/includes/Task.h b/includes/Task.h
index 1041d08..7521b9f 100644
--- a/includes/Task.h
+++ b/includes/Task.h
@@ -50,6 +50,10 @@ class BaseEvent {
virtual ~BaseEvent() { if (m_cb) delete m_cb; }
bool gotSignal() { return m_signal; }
void doSignal();
+ void resetMaybe() {
+ if (m_task)
+ reset();
+ }
void reset() {
// could be potentially changed into a simple return
AAssert(m_task != NULL, "Can't reset an event that doesn't have a task");
@@ -60,12 +64,13 @@ class BaseEvent {
void registerOwner(Task * task) {
if (m_task == task)
return;
- AAssert(m_task == NULL, "Can't register an event for another task");
+ AAssert(m_task == NULL || relaxed(), "Can't register an event for another task");
m_task = task;
gotOwner(task);
}
protected:
virtual void gotOwner(Task * task) { }
+ virtual bool relaxed() { return false; }
private:
Callback * m_cb = NULL;
bool m_signal = false;