summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormadmaxoft <github@xoft.cz>2013-10-04 20:28:30 +0200
committermadmaxoft <github@xoft.cz>2013-10-04 20:28:30 +0200
commitdb3d83b38dd61b90466a0721fa9104e742f3fb8b (patch)
treeba45a5a87eb7a688cbbe05587abaf1bea667371f
parentHTTP Server can now parse multipart/form-data forms; better architecture. (diff)
downloadcuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar.gz
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar.bz2
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar.lz
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar.xz
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.tar.zst
cuberite-db3d83b38dd61b90466a0721fa9104e742f3fb8b.zip
-rw-r--r--source/HTTPServer/HTTPConnection.cpp18
-rw-r--r--source/HTTPServer/HTTPConnection.h3
-rw-r--r--source/HTTPServer/HTTPMessage.cpp17
-rw-r--r--source/HTTPServer/HTTPMessage.h18
-rw-r--r--source/HTTPServer/HTTPServer.cpp10
-rw-r--r--source/StringUtils.cpp68
-rw-r--r--source/StringUtils.h3
7 files changed, 136 insertions, 1 deletions
diff --git a/source/HTTPServer/HTTPConnection.cpp b/source/HTTPServer/HTTPConnection.cpp
index 61f4b3a31..e3a6be494 100644
--- a/source/HTTPServer/HTTPConnection.cpp
+++ b/source/HTTPServer/HTTPConnection.cpp
@@ -26,6 +26,18 @@ void cHTTPConnection::SendStatusAndReason(int a_StatusCode, const AString & a_Re
{
AppendPrintf(m_OutgoingData, "%d %s\r\n\r\n", a_StatusCode, a_Response.c_str());
m_HTTPServer.NotifyConnectionWrite(*this);
+ m_State = wcsRecvHeaders;
+}
+
+
+
+
+
+void cHTTPConnection::SendNeedAuth(const AString & a_Realm)
+{
+ AppendPrintf(m_OutgoingData, "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"%s\"\r\n\r\n", a_Realm.c_str());
+ m_HTTPServer.NotifyConnectionWrite(*this);
+ m_State = wcsRecvHeaders;
}
@@ -73,6 +85,12 @@ void cHTTPConnection::AwaitNextRequest(void)
{
switch (m_State)
{
+ case wcsRecvHeaders:
+ {
+ // Nothing has been received yet, or a special response was given (SendStatusAndReason() or SendNeedAuth() )
+ break;
+ }
+
case wcsRecvIdle:
{
// The client is waiting for a response, send an "Internal server error":
diff --git a/source/HTTPServer/HTTPConnection.h b/source/HTTPServer/HTTPConnection.h
index 9e05d342b..941a29000 100644
--- a/source/HTTPServer/HTTPConnection.h
+++ b/source/HTTPServer/HTTPConnection.h
@@ -43,6 +43,9 @@ public:
/// Sends HTTP status code together with a_Reason (used for HTTP errors)
void SendStatusAndReason(int a_StatusCode, const AString & a_Reason);
+ /// Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm
+ void SendNeedAuth(const AString & a_Realm);
+
/// Sends the headers contained in a_Response
void Send(const cHTTPResponse & a_Response);
diff --git a/source/HTTPServer/HTTPMessage.cpp b/source/HTTPServer/HTTPMessage.cpp
index ed5c87e84..6cf9464a3 100644
--- a/source/HTTPServer/HTTPMessage.cpp
+++ b/source/HTTPServer/HTTPMessage.cpp
@@ -71,7 +71,8 @@ cHTTPRequest::cHTTPRequest(void) :
super(mkRequest),
m_EnvelopeParser(*this),
m_IsValid(true),
- m_UserData(NULL)
+ m_UserData(NULL),
+ m_HasAuth(false)
{
}
@@ -204,6 +205,20 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value)
{
+ if (
+ (NoCaseCompare(a_Key, "Authorization") == 0) &&
+ (strncmp(a_Value.c_str(), "Basic ", 6) == 0)
+ )
+ {
+ AString UserPass = Base64Decode(a_Value.substr(6));
+ size_t idxCol = UserPass.find(':');
+ if (idxCol != AString::npos)
+ {
+ m_AuthUsername = UserPass.substr(0, idxCol);
+ m_AuthPassword = UserPass.substr(idxCol + 1);
+ m_HasAuth = true;
+ }
+ }
AddHeader(a_Key, a_Value);
}
diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h
index ef8e12ca4..151eb468f 100644
--- a/source/HTTPServer/HTTPMessage.h
+++ b/source/HTTPServer/HTTPMessage.h
@@ -91,6 +91,15 @@ public:
/// Returns true if more data is expected for the request headers
bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); }
+ /// Returns true if the request did present auth data that was understood by the parser
+ bool HasAuth(void) const { return m_HasAuth; }
+
+ /// Returns the username that the request presented. Only valid if HasAuth() is true
+ const AString & GetAuthUsername(void) const { return m_AuthUsername; }
+
+ /// Returns the password that the request presented. Only valid if HasAuth() is true
+ const AString & GetAuthPassword(void) const { return m_AuthPassword; }
+
protected:
/// Parser for the envelope data
cEnvelopeParser m_EnvelopeParser;
@@ -110,6 +119,15 @@ protected:
/// Data that the HTTPServer callbacks are allowed to store.
void * m_UserData;
+ /// Set to true if the request contains auth data that was understood by the parser
+ bool m_HasAuth;
+
+ /// The username used for auth
+ AString m_AuthUsername;
+
+ /// The password used for auth
+ AString m_AuthPassword;
+
/** Parses the incoming data for the first line (RequestLine)
Returns the number of bytes consumed, or -1 for an error
diff --git a/source/HTTPServer/HTTPServer.cpp b/source/HTTPServer/HTTPServer.cpp
index 4102d1047..43bb751c4 100644
--- a/source/HTTPServer/HTTPServer.cpp
+++ b/source/HTTPServer/HTTPServer.cpp
@@ -73,6 +73,16 @@ class cDebugCallbacks :
return;
}
+ // Test the auth failure and success:
+ if (a_Request.GetURL() == "/auth")
+ {
+ if (!a_Request.HasAuth() || (a_Request.GetAuthUsername() != "a") || (a_Request.GetAuthPassword() != "b"))
+ {
+ a_Connection.SendNeedAuth("MCServer WebAdmin");
+ return;
+ }
+ }
+
cHTTPResponse Resp;
Resp.SetContentType("text/plain");
a_Connection.Send(Resp);
diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp
index c62bb3acb..530eda086 100644
--- a/source/StringUtils.cpp
+++ b/source/StringUtils.cpp
@@ -745,3 +745,71 @@ AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_
+
+/// Converts one Hex character in a Base64 encoding into the data value
+static inline int UnBase64(char c)
+{
+ if (c >='A' && c <= 'Z')
+ {
+ return c - 'A';
+ }
+ if (c >='a' && c <= 'z')
+ {
+ return c - 'a' + 26;
+ }
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0' + 52;
+ }
+ if (c == '+')
+ {
+ return 62;
+ }
+ if (c == '/')
+ {
+ return 63;
+ }
+ if (c == '=')
+ {
+ return -1;
+ }
+ return -2;
+}
+
+
+
+
+
+AString Base64Decode(const AString & a_Base64String)
+{
+ AString res;
+ size_t i, len = a_Base64String.size();
+ int o, c;
+ res.resize((len * 4) / 3 + 5, 0); // Approximate the upper bound on the result length
+ for (o = 0, i = 0; i < len; i++)
+ {
+ c = UnBase64(a_Base64String[i]);
+ if (c >= 0)
+ {
+ switch (o & 7)
+ {
+ case 0: res[o >> 3] |= (c << 2); break;
+ case 6: res[o >> 3] |= (c >> 4); res[(o >> 3) + 1] |= (c << 4); break;
+ case 4: res[o >> 3] |= (c >> 2); res[(o >> 3) + 1] |= (c << 6); break;
+ case 2: res[o >> 3] |= c; break;
+ }
+ o += 6;
+ }
+ if (c == -1)
+ {
+ // Error while decoding, invalid input. Return as much as we've decoded:
+ res.resize(o >> 3);
+ return ERROR_SUCCESS;
+ }
+ }
+ res.resize(o >> 3);
+ return res;}
+
+
+
+
diff --git a/source/StringUtils.h b/source/StringUtils.h
index e35e58c9f..ec9ba96ce 100644
--- a/source/StringUtils.h
+++ b/source/StringUtils.h
@@ -81,6 +81,9 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut
/// Replaces all occurrences of char a_From inside a_String with char a_To.
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
+/// Decodes a Base64-encoded string into the raw data
+extern AString Base64Decode(const AString & a_Base64String);
+
// If you have any other string helper functions, declare them here