http part 3

This commit is contained in:
darkrose 2013-10-06 00:30:07 +10:00
parent c6cd8c8619
commit f13cf01980
17 changed files with 911 additions and 329 deletions

4
data/html/footer.html Normal file
View File

@ -0,0 +1,4 @@
</div>
</body>
</html>

52
data/html/header.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Minetest Classic</title>
<style type="text/css">
html, body {background:#323246; color:#F0F0F0; font: 14px sans-serif; line-height:1.2em; position:relative; min-width:100%; min-height:100%; margin:0; padding:0;}
header.site-header {display:block; margin:0; padding:0; background:#1E1E32; color:#101010; height:50px;}
header.site-header div.main-header {display:block; margin:0 auto; padding:0; width:1000px; height:50px; position:relative;}
header.site-header h1 {display:block; line-height:50px; margin:0; padding:0; width:300px; font-weight:bold; font-size:20px; background:transparent; color:#C0C0C0; text-align:center; float:left;}
header.site-header nav {display:block; float:left; margin:0; padding:0; height:50px; width:600px;}
header.site-header nav ul {display:block; float:left; margin:0; padding:0; height:50px; width:600px; list-style-type:none;}
header.site-header nav ul li {display:block; float:left; margin:0; padding:0; text-align:center;}
header.site-header nav ul li a {display:block; float:left; margin:0; padding:0 10px; height:50px; line-height:50px; background:transparent; color:#A5A5A5; text-decoration:none; font-size:16px; font-weight:bold;}
header.site-header nav ul li a:hover {line-height:42px; height:42px; border-top:4px solid #1E1E32; border-bottom:4px solid #616161; border-left:none; border-right:none;}
div.body {margin:0 auto; width:1000px; min-height:80%; padding:20px 0; position:relative; height:auto; overflow:hidden;}
div.body div.panel {background:#1E1E32; color:#C0C0C0; margin:10px; padding:10px; border:1px solid #3C3C50; height:auto; overflow:hidden;}
div.body div.panel img {margin:10px;}
div.body div.panel a.secret {color:#C0C0C0; text-decoration:none;}
div.body h1 {text-align:center; font-size:20px; font-weight:bold; margin:0; margin-bottom:20px; padding:0;}
div.body h2 {text-align:left; font-size:18px; font-weight:bold; margin:0; margin-bottom:20px; padding:0;}
div.body p {padding:0; margin:0 0 10px; line-height:1.2em;}
div.body ul {list-style-type:square;}
div.body ul, div.body ol {margin:0; padding:0; padding-left:15px;}
div.body ul li, div.body ol li {margin:0; padding:0; margin-bottom:5px;}
.green {color:#0EAB13;}
.red {color:#AB0E1B;}
.bold {font-weight:bold;}
.small {font-size:12px;}
.tiny {font-size:10px;}
.centre {text-align:center;}
.right {float:right;}
</style>
</head>
<body>
<header class="site-header">
<div class="main-header">
<h1>Minetest Classic</h1>
<nav class="main-menu">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/player">Players</a></li>
</ul>
</nav>
</div>
</header>
<div class="body">

View File

@ -129,6 +129,7 @@ set(common_SRCS
base64.cpp
ban.cpp
http.cpp
path.cpp
)
# This gives us the icon

View File

@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "content_cao.h"
#include "tile.h"
#include "path.h"
#include "environment.h"
#include "settings.h"
#include <ICameraSceneNode.h>

View File

@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include "map.h"
#include "client.h"
#include "path.h"
#include "mapgen.h"
FarMesh::FarMesh(

View File

@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gettext.h"
#include "log.h"
#include "filesys.h"
#include "path.h"
/*
TODO: Move content-aware stuff to separate file by adding properties

View File

@ -21,6 +21,9 @@
#include "socket.h"
#include "http.h"
#include "main.h"
#include "settings.h"
#include "filesys.h"
#include "debug.h"
#include <stdio.h>
#include <iostream>
@ -30,7 +33,10 @@
#include "connection.h"
#include "log.h"
#include "sha1.h"
#include "path.h"
#include "config.h"
/* server thread main loop */
void * HTTPServerThread::Thread()
{
ThreadStarted();
@ -59,16 +65,19 @@ void * HTTPServerThread::Thread()
* HTTPServer
*/
/* constructor */
HTTPServer::HTTPServer(Server &server):
m_thread(this)
{
m_server = &server;
}
/* destructor */
HTTPServer::~HTTPServer()
{
}
/* start the server running */
void HTTPServer::start(u16 port)
{
DSTACK(__FUNCTION_NAME);
@ -86,6 +95,7 @@ void HTTPServer::start(u16 port)
infostream<<"HTTPServer: Started on port "<<port<<std::endl;
}
/* stop the running server */
void HTTPServer::stop()
{
DSTACK(__FUNCTION_NAME);
@ -96,6 +106,7 @@ void HTTPServer::stop()
infostream<<"HTTPServer: Threads stopped"<<std::endl;
}
/* the main function for the server loop */
void HTTPServer::step()
{
if (m_socket->WaitData(50)) {
@ -104,19 +115,22 @@ void HTTPServer::step()
m_peers.push_back(c);
}
for (std::vector<HTTPRemoteClient*>::iterator it = m_peers.begin(); it != m_peers.end(); ++it) {
HTTPRemoteClient *c = *it;
std::vector<HTTPRemoteClient*> p;
p.swap(m_peers);
for (std::vector<HTTPRemoteClient*>::iterator i = p.begin(); i != p.end(); ++i) {
HTTPRemoteClient *c = *i;
try{
if (c->receive()) {
m_peers.erase(it);
delete c;
continue;
}
}catch (SocketException &e) {
// assume it's closed
m_peers.erase(it);
delete c;
continue;
}
m_peers.push_back(c);
}
}
@ -124,119 +138,443 @@ void HTTPServer::step()
* HTTPRemoteClient
*/
/* destructor */
HTTPRemoteClient::~HTTPRemoteClient()
{
delete m_socket;
}
/* receive and handle data from a remote http client */
int HTTPRemoteClient::receive()
{
char buff[2048];
if (!m_socket->WaitData(30))
int r = fillBuffer();
if (!r)
return 0;
int r = m_socket->Receive(buff,2048);
if (r<1)
return 1;
m_recv_headers.clear();
m_send_headers.clear();
int h = m_recv_headers.read(buff,r);
if (h == 1) {
int h = m_recv_headers.read(m_buff,r);
if (h == -1) {
return 1;
}else if (h == 2) {
//if (m_recv_headers.url() == "")
//return 1;
//while (m_socket->WaitData(1000)) {
//r = m_socket->Receive(buff,2048);
//if (r<1)
//return 1;
//h = m_recv_headers.read(buff,r);
//if (!h)
//break;
//if (h == 1)
//return 1;
//}
//if (h)
}else if (h == -2) {
if (m_recv_headers.getUrl() == "")
return 1;
while (m_socket->WaitData(1000)) {
r = fillBuffer();
if (r<1)
return 1;
h = m_recv_headers.read(m_buff,r);
if (h > -1)
break;
if (h == -1)
return 1;
}
if (h < 0)
return 1;
}
if (m_recv_headers.cookie() != "" && m_recv_headers.get("User") != "") {
if (m_recv_headers.cookie() == m_server->getPlayerCookie(m_recv_headers.get("User"))) {
m_send_headers.setCookie(m_recv_headers.cookie());
if (m_recv_headers.getCookie() != "" && m_recv_headers.getHeader("User") != "") {
if (m_recv_headers.getCookie() == m_server->getPlayerCookie(m_recv_headers.getHeader("User"))) {
m_send_headers.setCookie(m_recv_headers.getCookie());
m_auth = true;
}
}
//std::string u;
//for (int i=0; (u = m_recv_headers.url(i)) != ""; i++) {
//printf("%d: '%s'\n",i,u.c_str());
//}
if (m_recv_headers.getUrl(0) == "texture") {
return handleTexture();
}else if (m_recv_headers.getUrl(0) == "player") {
return handlePlayer();
}else if (m_recv_headers.getUrl(0) == "") {
return handleIndex();
}
//setResponse("404 Not Found");
//std::string html("<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1></body></html>");
//send(html);
send((char*)"grar");
return 0;//m_recv_headers.keepAlive() == true ? 0 : 1;
return handleSpecial("404 Not Found");
}
/* read data from a remote http client */
int HTTPRemoteClient::read(char* buff, int size)
{
if (size > 2048) {
int r = 0;
int l;
int c = 2048;
int s = size;
while (fillBuffer()) {
c = 2048;
if (s<c)
c = s;
l = m_end-m_start;
if (l<c)
c = l;
if (c < 1)
break;
memcpy(buff+r,m_buff+m_start,c);
m_start += c;
r += c;
s -= c;
}
return r;
}
if (fillBuffer() < size)
return 0;
memcpy(buff,m_buff+m_start,size);
m_start+=size;
return size;
}
/* data read from remote http clients is buffered, fill the buffer */
int HTTPRemoteClient::fillBuffer()
{
int l = m_end-m_start;
if (l && m_start) {
memcpy(m_buff,m_buff+m_start,l);
m_start = 0;
m_end = l;
}
l = 2048-m_end;
if (!m_socket->WaitData(30))
return m_end;
return m_end+m_socket->Receive(m_buff+m_end,l);
}
/* handle /player/<name> url's */
int HTTPRemoteClient::handlePlayer()
{
char buff[2048];
/* player list */
if (m_recv_headers.getUrl(1) == "") {
core::list<Player*> players = m_server->getGameServer()->getPlayers();
std::string html("<h1>Players</h1>\n");
for (core::list<Player*>::Iterator i = players.begin(); i != players.end(); i++) {
Player *player = *i;
html += "<div class=\"panel\"><h2><a href=\"/player/";
html += player->getName();
html += "\" class=\"secret\">";
html += player->getName();
html += "</a></h2>";
html += "<p class=\"right\"><img src=\"/player/";
html += player->getName();
html += "/skin\" /></p>";
snprintf(buff, 2048,"% .1f, % .1f, % .1f",player->getPosition().X/BS,player->getPosition().Y/BS,player->getPosition().Z/BS);
if (player->peer_id == 0) {
html += "<p class=\"red\">Offline</p>";
html += "<p><strong>Last seen at:</strong> ";
}else{
html += "<p class=\"green bold\">Online</p>";
html += "<p><strong>Currently at:</strong> ";
}
html += buff;
html += "</p><p><strong>Privileges:</strong> ";
html += m_server->getPlayerPrivs(player->getName());
html += "</p></div>";
}
sendHTML((char*)html.c_str());
return 1;
/* player skin */
}else if (m_recv_headers.getUrl(2) == "skin") {
std::string data_path = g_settings->get("data_path");
if (data_path == "")
data_path = "data";
std::string file = data_path + DIR_DELIM + "textures" + DIR_DELIM + "players" + DIR_DELIM + "player_" + m_recv_headers.getUrl(1) + ".png";
/* compare hash */
if (m_recv_headers.getUrl(3) != "") {
FILE *f;
f = fopen(file.c_str(),"rb");
if (!f)
return handleSpecial("204 No Content");
fclose(f);
SHA1 s;
s.addFile(file.c_str());
s.getDigest(buff);
if (std::string(buff) == m_recv_headers.getUrl(3)) {
return handleSpecial("204 No Content");
}else if (m_auth && m_recv_headers.getHeader("User") == m_recv_headers.getUrl(1)) {
return handleSpecial("304 Not Modified");
}
m_send_headers.setHeader("Content-Type","image/png");
sendFile(file);
return 1;
}
/* get file */
if (m_recv_headers.getMethod() != "PUT") {
m_send_headers.setHeader("Content-Type","image/png");
sendFile(file);
return 1;
}
/* put only works for the owner */
if (!m_auth || m_recv_headers.getHeader("User") != m_server->getPlayerFromCookie(m_recv_headers.getCookie()))
return handleSpecial("405 Method Not Allowed");
FILE *f;
f = fopen(file.c_str(),"wb");
if (!f)
return handleSpecial("500 Internal Server Error");
size_t s = m_recv_headers.getLength();
if (!s)
return handleSpecial("411 Length Required");
size_t l;
size_t c = 2048;
if (c > s)
c = s;
if (c) {
while ((l = read(buff,c)) > 0) {
s -= l;
c = fwrite(buff,1,l,f);
if (c != l) {
fclose(f);
return handleSpecial("500 Internal Server Error");
}
c = 2048;
if (c > s)
c = s;
if (!c)
break;
}
}
fclose(f);
return handleSpecial("201 Created");
}else if (m_server->getGameServer()->getPlayer(m_recv_headers.getUrl(1))) {
std::string html("<h1>Players</h1>\n");
Player *player = m_server->getGameServer()->getPlayer(m_recv_headers.getUrl(1));
html += "<div class=\"panel\"><h2>";
html += player->getName();
html += "</h2>";
html += "<p class=\"right\"><img src=\"/player/";
html += player->getName();
html += "/skin\" /></p>";
snprintf(buff, 2048,"% .1f, % .1f, % .1f",player->getPosition().X/BS,player->getPosition().Y/BS,player->getPosition().Z/BS);
if (player->peer_id == 0) {
html += "<p class=\"red\">Offline</p>";
html += "<p><strong>Last seen at:</strong> ";
}else{
html += "<p class=\"green bold\">Online</p>";
html += "<p><strong>Currently at:</strong> ";
}
html += buff;
html += "</p><p><strong>Privileges:</strong> ";
html += m_server->getPlayerPrivs(player->getName());
html += "</p></div>";
sendHTML((char*)html.c_str());
return 1;
}
return handleSpecial("404 Not Found");
}
/* handle /texture/<file> url's */
int HTTPRemoteClient::handleTexture()
{
std::string file = getTexturePath(m_recv_headers.getUrl(1));
m_send_headers.setHeader("Content-Type","image/png");
sendFile(file);
return 1;
}
/* handle /model/<file> url's */
int HTTPRemoteClient::handleModel()
{
std::string file = getModelPath(m_recv_headers.getUrl(1));
m_send_headers.setHeader("Content-Type","application/octet-stream");
sendFile(file);
return 1;
}
/* handle /map/<x>/<y>/<z> url's */
int HTTPRemoteClient::handleMap()
{
return handleSpecial("404 Not Found");
}
/* handle / url's */
int HTTPRemoteClient::handleIndex()
{
int c = 0;
std::string html("<div class=\"panel\"><h2>");
html += g_settings->get("motd");
html += "</h2><p><strong>Version: </strong>";
html += VERSION_STRING;
html += "<br /><strong><a href=\"/player\" class=\"secret\">Players</a>: </strong>";
core::list<Player*> players = m_server->getGameServer()->getPlayers();
for (core::list<Player*>::Iterator i = players.begin(); i != players.end(); i++) {
Player *player = *i;
if (player->peer_id != 0) {
if (c++)
html += ", ";
html += "<a href=\"/player/";
html += player->getName();
html += "\" class=\"secret\">";
html += player->getName();
html += "</a>";
}
}
html += "</div>";
sendHTML((char*)html.c_str());
return 1;
}
/* simple wrapper for sending html content and/or errors */
int HTTPRemoteClient::handleSpecial(const char* response, std::string content)
{
setResponse(response);
std::string html("<h1>");
html += std::string(response) + "</h1>" + content;
sendHTML(html);
return 1;
}
/* send text data to a remote http client */
void HTTPRemoteClient::send(char* data)
{
int l = strlen(data);
m_send_headers.set("Content-Type","text/plain");
m_send_headers.setHeader("Content-Type","text/plain");
m_send_headers.setLength(l);
sendHeaders();
m_socket->Send(data,l);
}
/* send html data to a remote http client */
void HTTPRemoteClient::sendHTML(char* data)
{
int l = strlen(data);
m_send_headers.set("Content-Type","text/html");
m_send_headers.setLength(l);
FILE *h;
FILE *f;
int l[4];
char* b;
std::string data_path = g_settings->get("data_path");
if (data_path == "")
data_path = "data";
std::string file = data_path + DIR_DELIM + "html" + DIR_DELIM + "header.html";
h = fopen(file.c_str(),"r");
if (!h && data_path != "data") {
file = std::string("data") + DIR_DELIM + "html" + DIR_DELIM + "header.html";
h = fopen(file.c_str(),"r");
}
file = data_path + DIR_DELIM + "html" + DIR_DELIM + "footer.html";
f = fopen(file.c_str(),"r");
if (!f && data_path != "data") {
file = std::string("data") + DIR_DELIM + "html" + DIR_DELIM + "footer.html";
f = fopen(file.c_str(),"r");
}
if (h) {
fseek(h,0,SEEK_END);
l[0] = ftell(h);
fseek(h,0,SEEK_SET);
}else{
l[0] = 0;
}
l[1] = strlen(data);
if (f) {
fseek(f,0,SEEK_END);
l[2] = ftell(f);
fseek(f,0,SEEK_SET);
}else{
l[2] = 0;
}
if (l[0] > l[2]) {
b = (char*)alloca(l[0]);
}else{
b = (char*)alloca(l[2]);
}
l[3] = l[0]+l[1]+l[2];
m_send_headers.setHeader("Content-Type","text/html");
m_send_headers.setLength(l[3]);
sendHeaders();
m_socket->Send(data,l);
if (h) {
l[3] = fread(b,1,l[0],h);
m_socket->Send(b,l[3]);
fclose(h);
}
m_socket->Send(data,l[1]);
if (f) {
l[3] = fread(b,1,l[2],f);
m_socket->Send(b,l[3]);
fclose(f);
}
}
/* send a file to a remote http client */
void HTTPRemoteClient::sendFile(std::string &file)
{
m_send_headers.set("Content-Type","text/plain");
m_send_headers.setLength(0);
FILE *f;
f = fopen(file.c_str(),"rb");
if (!f) {
std::string data_path = g_settings->get("data_path");
if (data_path == "")
data_path = "data";
if (file.substr(data_path.size()+1,24) == "textures/players/player_") {
m_send_headers.setHeader("Location","/texture/character.png");
handleSpecial("303 See Other","<p><a href=\"/texture/character.png\">/texture/character.png</a></p>");
return;
}
handleSpecial("404 Not Found");
return;
}
fseek(f,0,SEEK_END);
size_t l = ftell(f);
fseek(f,0,SEEK_SET);
m_send_headers.setLength(l);
sendHeaders();
char buff[1024];
while ((l = fread(buff,1,1024,f)) > 0) {
m_socket->Send(buff,l);
}
fclose(f);
}
/* send response headers to a remote http client */
void HTTPRemoteClient::sendHeaders()
{
std::string v;
int s;
char buff[1024];
//v = m_response;
//if (v == "")
//v = std::string("200 OK");
v = m_response;
if (v == "")
v = std::string("200 OK");
//s = snprintf(buff,1024,"HTTP/1.1 %s\r\n",v.c_str());
//m_socket->Send(buff,s);
m_socket->Send("HTTP/1.1 200 OK\r\n",17);
s = snprintf(buff,1024,"HTTP/1.0 %s\r\n",v.c_str());
m_socket->Send(buff,s);
//m_socket->Send("HTTP/1.0 200 OK\r\n",17);
//v = m_send_headers.get("Content-Type");
//if (v == "") {
v = m_send_headers.getHeader("Content-Type");
if (v == "") {
m_socket->Send("Content-Type: text/plain\r\n",26);
//}else{
//s = snprintf(buff,1024,"Content-Type: %s\r\n",v.c_str());
//m_socket->Send(buff,s);
//}
}else{
s = snprintf(buff,1024,"Content-Type: %s\r\n",v.c_str());
m_socket->Send(buff,s);
}
s = m_send_headers.length();
s = snprintf(buff,1024,"Content-Length: %d\r\n",s);
m_socket->Send(buff,s);
//v = m_send_headers.cookie();
//if (v != "") {
//s = snprintf(buff,1024,"Set-Cookie: MTID=%s\r\n",v.c_str());
//m_socket->Send(buff,s);
//}
v = m_send_headers.getCookie();
if (v != "") {
s = snprintf(buff,1024,"Set-Cookie: MTID=%s\r\n",v.c_str());
m_socket->Send(buff,s);
}
v = m_send_headers.getHeader("Location");
if (v != "") {
s = snprintf(buff,1024,"Location: %s\r\n",v.c_str());
m_socket->Send(buff,s);
}
v = m_send_headers.getHeader("Refresh");
if (v != "") {
s = snprintf(buff,1024,"Refresh: %s\r\n",v.c_str());
m_socket->Send(buff,s);
}
m_socket->Send("\r\n",2);
}
@ -244,6 +582,7 @@ void HTTPRemoteClient::sendHeaders()
#ifndef SERVER
#include "client.h"
/* main loop for the client http fetcher */
void * HTTPClientThread::Thread()
{
ThreadStarted();
@ -272,6 +611,7 @@ void * HTTPClientThread::Thread()
* HTTPClient
*/
/* constructor */
HTTPClient::HTTPClient(Client *client):
m_cookie(""),
m_thread(this)
@ -280,10 +620,12 @@ HTTPClient::HTTPClient(Client *client):
m_req_mutex.Init();
}
/* destructor */
HTTPClient::~HTTPClient()
{
}
/* start the client http fetcher thread */
void HTTPClient::start(const Address &address)
{
DSTACK(__FUNCTION_NAME);
@ -301,6 +643,7 @@ void HTTPClient::start(const Address &address)
infostream<<"HTTPClient: Started"<<std::endl;
}
/* stop the client http fetcher thread */
void HTTPClient::stop()
{
DSTACK(__FUNCTION_NAME);
@ -311,11 +654,13 @@ void HTTPClient::stop()
infostream<<"HTTPClient: Threads stopped"<<std::endl;
}
/* the main function for the client loop */
void HTTPClient::step()
{
sleep(1);
}
/* add a request to the http client queue */
void HTTPClient::pushRequest(HTTPRequestType type, std::string &data)
{
switch (type) {
@ -354,12 +699,22 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data)
*/
case HTTPREQUEST_SKIN_HASH:
{
std::string tex = std::string("players/player_")+data+".png";
std::string tex = std::string("players") + DIR_DELIM + "player_" + data + ".png";
std::string ptex = getTexturePath(tex);
if (ptex == "") {
pushRequest(HTTPREQUEST_SKIN,data);
return;
}
char buff[100];
SHA1 s;
s.addFile(ptex.c_str());
s.getDigest(buff);
std::string url("/player/");
url += data + "/skin/" + buff;
HTTPRequest r(url);
m_req_mutex.Lock();
m_requests.push_back(r);
m_req_mutex.Unlock();
break;
}
/*
@ -373,12 +728,24 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data)
*/
case HTTPREQUEST_SKIN_SEND:
{
std::string tex = std::string("player.png");
std::string ptex = getTexturePath(tex);
if (ptex == "")
return;
std::string url("/player/");
url += data + "/skin";
HTTPRequest r(url,ptex);
m_req_mutex.Lock();
m_requests.push_back(r);
m_req_mutex.Unlock();
break;
}
default:;
}
}
/* add a request to the http client queue */
void HTTPClient::pushRequest(std::string &url, std::string &data)
{
HTTPRequest r(url,data);
@ -387,18 +754,22 @@ void HTTPClient::pushRequest(std::string &url, std::string &data)
m_req_mutex.Unlock();
}
/* send a http GET request to the server */
void HTTPClient::get(std::string &url)
{
}
/* send a http POST request to the server */
void HTTPClient::post(std::string &url, char* data)
{
}
void HTTPClient::postFile(std::string &url, std::string &file)
/* send a file to the server with a http PUT request */
void HTTPClient::put(std::string &url, std::string &file)
{
}
/* get a request from the client queue */
HTTPRequest HTTPClient::popRequest()
{
m_req_mutex.Lock();
@ -408,6 +779,7 @@ HTTPRequest HTTPClient::popRequest()
return r;
}
/* send http headers to the server */
void HTTPClient::sendHeaders()
{
}
@ -417,74 +789,61 @@ void HTTPClient::sendHeaders()
* HTTPHeaders
*/
int HTTPHeaders::read(char* buff, int length)
/* read in headers */
int HTTPRequestHeaders::read(char* buff, int length)
{
char nbuff[1024];
char vbuff[1024];
int n = 1;
int o = 0;
int c = m_url == "" ? 0 : 1;
int i = 0;
int c = getUrl() == "" ? 0 : 1;
for (int i=0; i<length; i++) {
for (i=0; i<length; i++) {
if (buff[i] == '\r' || (!o && buff[i] == ' '))
continue;
if (buff[i] == '\n') {
if (!c) {
nbuff[o] = 0;
printf("%s\n",nbuff);
char* u = strchr(nbuff,' ');
if (!u)
return 1;
return -1;
*u = 0;
setMethod(nbuff);
u++;
while (*u == ' ') {
u++;
}
printf("%s\n",u);
char* p = strchr(u,' ');
if (!p)
return 1;
return -1;
*p = 0;
p++;
while (*p == ' ') {
p++;
}
printf("%s\n",p);
if (!strcmp(p,"HTTP/1.1")) {
setKeepAlive(true);
setProtocol(p);
}else{
setKeepAlive(false);
setProtocol("HTTP/1.0");
}
setUrl(nbuff);
//size_t current;
//size_t next = -1;
//std::string s(u);
//do{
//current = next + 1;
//next = s.find_first_of("/", current);
//if (s.substr(current, next-current) != "")
//m_url_split.push_back(s.substr(current, next-current));
//} while (next != std::string::npos);
setUrl(u);
size_t current;
size_t next = -1;
std::string s(u);
do{
current = next + 1;
next = s.find_first_of("/", current);
if (s.substr(current, next-current) != "")
addUrl(s.substr(current, next-current));
} while (next != std::string::npos);
c++;
}else{
if (n)
return 0;
return i+1;
vbuff[o] = 0;
if (!strcmp(nbuff,"Content-Length")) {
setLength(strtoul(vbuff,NULL,10));
}else if (!strcmp(nbuff,"Cookie")) {
setCookie(vbuff);
}else if (!strcmp(nbuff,"Connection")) {
if (!strcmp(vbuff,"keep-alive") || !strcmp(vbuff,"Keep-Alive")) {
setKeepAlive(true);
}else if (!strcmp(vbuff,"close") || !strcmp(vbuff,"Close")) {
setKeepAlive(false);
}
}else if (!strcmp(nbuff,"Cookie") && !strncmp(vbuff,"MTID=",5)) {
printf("cookie: '%s'\n",vbuff+5);
setCookie(vbuff+5);
}else{
set(nbuff,vbuff);
setHeader(nbuff,vbuff);
}
}
o = 0;
@ -500,5 +859,64 @@ int HTTPHeaders::read(char* buff, int length)
}
}
return 2;
return -2;
}
/* read in headers */
int HTTPResponseHeaders::read(char* buff, int length)
{
char nbuff[1024];
char vbuff[1024];
int n = 1;
int o = 0;
int i = 0;
int c = getUrl() == "" ? 0 : 1;
for (i=0; i<length; i++) {
if (buff[i] == '\r' || (!o && buff[i] == ' '))
continue;
if (buff[i] == '\n') {
if (!c) {
nbuff[o] = 0;
char* r = strchr(nbuff,' ');
if (!r)
return -1;
*r = 0;
r++;
while (*r == ' ') {
r++;
}
char* s = strchr(r,' ');
if (!s)
return -1;
*s = 0;
setResponse(strtol(r,NULL,10));
c++;
}else{
if (n)
return i+1;
vbuff[o] = 0;
if (!strcmp(nbuff,"Content-Length")) {
setLength(strtoul(vbuff,NULL,10));
}else if (!strcmp(nbuff,"SetCookie") && !strncmp(vbuff,"MTID=",5)) {
printf("cookie: '%s'\n",vbuff+5);
setCookie(vbuff+5);
}else{
setHeader(nbuff,vbuff);
}
}
o = 0;
n = 1;
}else if (n && buff[i] == ':') {
nbuff[o] = 0;
o = 0;
n = 0;
}else if (n) {
nbuff[o++] = buff[i];
}else{
vbuff[o++] = buff[i];
}
}
return -2;
}

View File

@ -27,6 +27,7 @@
#include "common_irrlicht.h"
#include "utility.h"
#include "server.h"
#include "player.h"
#include <map>
class HTTPServer;
@ -57,34 +58,49 @@ public:
void clear()
{
m_contentLength = 0;
m_keepalive = false;
m_cookie = std::string("");
m_url = std::string("");
m_url_split.clear();
}
int read(char* buff, int length);
virtual int read(char* buff, int length) = 0;
u32 length() {return m_contentLength;}
bool keepAlive() {return m_keepalive;}
std::string &cookie() {return m_cookie;}
std::string &url() {return m_url;}
std::string &url(int index) {return m_url_split[index];}
std::string &get(std::string name) {return m_headers[name];}
void set(std::string name, std::string value) {m_headers[name] = value;}
void setLength(u32 length) {m_contentLength = length;}
void setKeepAlive(bool ka) {m_keepalive = ka;}
std::string getCookie() {return m_cookie;}
std::string getUrl() {return m_url;}
std::string getUrl(unsigned int index) { if (m_url_split.size() > index) return m_url_split[index]; return std::string("");}
std::string getHeader(std::string name) {return m_headers[name];}
std::string getMethod() {return m_method;}
u32 getLength() {return m_contentLength;}
void setCookie(std::string cookie) {std::string c(cookie.c_str()); m_cookie = c;}
void setUrl(std::string url) {std::string u(url); m_url = u;}
void addUrl(std::string url) {m_url_split.push_back(url);}
void setHeader(std::string name, std::string value) {m_headers[name] = value;}
void setMethod(std::string method) {std::string m(method); m_method = m;}
void setProtocol(std::string proto) {std::string p(proto); m_protocol = p;}
void setLength(u32 length) {m_contentLength = length;}
private:
std::map<std::string,std::string> m_headers;
u32 m_contentLength;
bool m_keepalive;
std::string m_cookie;
std::string m_url;
std::vector<std::string> m_url_split;
std::string m_method;
std::string m_protocol;
};
class HTTPRequestHeaders : public HTTPHeaders
{
public:
virtual int read(char* buff, int length);
private:
};
class HTTPResponseHeaders : public HTTPHeaders
{
public:
virtual int read(char* buff, int length);
void setResponse(int r) {m_response = r;}
int getResponse() {return m_response;}
private:
int m_response;
};
class HTTPRemoteClient
@ -96,19 +112,36 @@ public:
{
m_socket = sock;
m_server = server;
m_start = 0;
m_end = 0;
}
~HTTPRemoteClient();
int receive();
private:
int read(char* buff, int size);
int fillBuffer();
void sendHeaders();
int handlePlayer();
int handleTexture();
int handleModel();
int handleMap();
int handleIndex();
int handleSpecial(const char* response, std::string content);
int handleSpecial(const char* response) {return handleSpecial(response,"");}
void send(char* data);
void send(std::string &data) {send((char*)data.c_str());}
void sendHTML(char* data);
void sendHTML(std::string &data) {sendHTML((char*)data.c_str());}
void sendFile(std::string &file);
void setResponse(const char* response) {std::string r(response); m_response = r;}
private:
void sendHeaders();
HTTPHeaders m_recv_headers;
HTTPHeaders m_send_headers;
char m_buff[2048];
int m_start;
int m_end;
HTTPRequestHeaders m_recv_headers;
HTTPResponseHeaders m_send_headers;
std::string m_response;
bool m_auth;
TCPSocket *m_socket;
@ -123,7 +156,10 @@ public:
void start(u16 port);
void stop();
void step();
std::string getPlayerCookie(std::string &name) {return m_server->getPlayerCookie(name);}
std::string getPlayerCookie(std::string name) {return m_server->getPlayerCookie(name);}
std::string getPlayerFromCookie(std::string cookie) {return m_server->getPlayerFromCookie(cookie);}
std::string getPlayerPrivs(std::string name) {return privsToString(m_server->getPlayerAuthPrivs(name));}
Server *getGameServer() {return m_server;}
private:
TCPSocket *m_socket;
std::vector<HTTPRemoteClient*> m_peers;
@ -192,12 +228,12 @@ public:
private:
void get(std::string &url);
void post(std::string &url, char* data);
void postFile(std::string &url, std::string &file);
void put(std::string &url, std::string &file);
HTTPRequest popRequest();
void sendHeaders();
TCPSocket *m_socket;
HTTPHeaders m_recv_headers;
HTTPHeaders m_send_headers;
HTTPResponseHeaders m_recv_headers;
HTTPRequestHeaders m_send_headers;
std::string m_cookie;
std::vector<HTTPRequest> m_requests;
JMutex m_req_mutex;

View File

@ -439,6 +439,7 @@ Doing currently:
#include "settings.h"
#include "profiler.h"
#include "log.h"
#include "path.h"
// This makes textures
ITextureSource *g_texturesource = NULL;

191
src/path.cpp Normal file
View File

@ -0,0 +1,191 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "path.h"
#include "debug.h"
#include "main.h" // for g_settings
#include "filesys.h"
#include "utility.h"
#include "settings.h"
/*
A cache from texture name to texture path
*/
MutexedMap<std::string, std::string> g_texturename_to_path_cache;
MutexedMap<std::string, std::string> g_modelname_to_path_cache;
/*
Replaces the filename extension.
eg:
std::string image = "a/image.png"
replace_ext(image, "jpg")
-> image = "a/image.jpg"
Returns true on success.
*/
static bool replace_ext(std::string &path, const char *ext)
{
if(ext == NULL)
return false;
// Find place of last dot, fail if \ or / found.
s32 last_dot_i = -1;
for(s32 i=path.size()-1; i>=0; i--)
{
if(path[i] == '.')
{
last_dot_i = i;
break;
}
if(path[i] == '\\' || path[i] == '/')
break;
}
// If not found, return an empty string
if(last_dot_i == -1)
return false;
// Else make the new path
path = path.substr(0, last_dot_i+1) + ext;
return true;
}
/*
Find out the full path of an image by trying different filename
extensions.
If failed, return "".
*/
static std::string getImagePath(std::string path)
{
// A NULL-ended list of possible image extensions
const char *extensions[] = {
"png", "jpg", "bmp", "tga",
"pcx", "ppm", "psd", "wal", "rgb",
NULL
};
const char **ext = extensions;
do{
bool r = replace_ext(path, *ext);
if(r == false)
return "";
if(fs::PathExists(path))
return path;
}
while((++ext) != NULL);
return "";
}
/*
Gets the path to a texture by first checking if the texture exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getTexturePath(const std::string &filename)
{
std::string fullpath = "";
/*
Check from cache
*/
bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
if (incache && fullpath != "")
return fullpath;
std::string rel_path = std::string("textures")+DIR_DELIM+filename;
/*
Check from data_path /textures
*/
std::string data_path = g_settings->get("data_path");
if(data_path != "")
{
std::string testpath = data_path + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
/*
Check from default data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_data + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
// Add to cache (also an empty result is cached)
g_texturename_to_path_cache.set(filename, fullpath);
// Finally return it
return fullpath;
}
/*
Gets the path to a model by first checking if the model exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getModelPath(const std::string &filename)
{
std::string fullpath = "";
/*
Check from cache
*/
bool incache = g_modelname_to_path_cache.get(filename, &fullpath);
if(incache)
return fullpath;
std::string rel_path = std::string("models")+DIR_DELIM+filename;
/*
Check from data_path /models
*/
std::string data_path = g_settings->get("data_path");
if(data_path != "")
{
std::string testpath = data_path + DIR_DELIM + rel_path;
if(fs::PathExists(testpath))
fullpath = std::string(testpath);
}
/*
Check from default data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_data + DIR_DELIM + rel_path;
if(fs::PathExists(testpath))
fullpath = std::string(testpath);
}
// Add to cache (also an empty result is cached)
g_modelname_to_path_cache.set(filename, fullpath);
// Finally return it
return fullpath;
}

39
src/path.h Normal file
View File

@ -0,0 +1,39 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef PATH_HEADER
#define PATH_HEADER
#include "filesys.h"
#include <string>
/*
Gets the path to a texture/model by first checking if it exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getTexturePath(const std::string &filename);
std::string getModelPath(const std::string &filename);
#endif

View File

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mesh.h"
#endif
#include "settings.h"
#include "filesys.h"
#include "path.h"
Player::Player():
touching_ground(false),

View File

@ -455,6 +455,19 @@ public:
return "";
return p->getCookie();
}
std::string getPlayerFromCookie(std::string &cookie)
{
core::list<Player*> players = m_env.getPlayers();
for (core::list<Player*>::Iterator i = players.begin(); i != players.end(); i++) {
Player *player = *i;
if (player->getCookie() == cookie)
return player->getName();
}
return std::string("");
}
Player *getPlayer(std::string name) {return m_env.getPlayer(name.c_str());}
core::list<Player*> getPlayers() {return m_env.getPlayers();}
core::list<Player*> getPlayers(bool ign_disconnected) {return m_env.getPlayers(ign_disconnected);}
// Saves g_settings to configpath given at initialization
void saveConfig();

View File

@ -169,6 +169,20 @@ void SHA1::addBytes( const char* data, int num )
}
}
void SHA1::addFile(const char* file)
{
char buff[2048];
size_t l;
FILE *f;
f = fopen(file,"rb");
if (!f)
return;
while ((l = fread(buff,1,2048,f)) > 0) {
addBytes(buff,l);
}
fclose(f);
}
// digest ************************************************************
unsigned char* SHA1::getDigest()
{
@ -205,3 +219,16 @@ unsigned char* SHA1::getDigest()
// return the digest
return digest;
}
int SHA1::getDigest(char* buff)
{
int l;
int t = 0;
unsigned char* d = getDigest();
for (int i=0; i<20; i++) {
l = sprintf(buff,"%02x",d[i]);
buff += l;
t += l;
}
return t;
}

View File

@ -39,8 +39,10 @@ class SHA1
public:
SHA1();
~SHA1();
void addBytes( const char* data, int num );
void addBytes(const char* data, int num );
void addFile(const char* file);
unsigned char* getDigest();
int getDigest(char* buff);
// utility methods
static Uint32 lrot( Uint32 x, int bits );
static void storeBigEndianUint32( unsigned char* byte, Uint32 num );

View File

@ -28,193 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "mapnode.h" // For texture atlas making
#include "mineral.h" // For texture atlas making
/*
A cache from texture name to texture path
*/
MutexedMap<std::string, std::string> g_texturename_to_path_cache;
MutexedMap<std::string, std::string> g_modelname_to_path_cache;
/*
Replaces the filename extension.
eg:
std::string image = "a/image.png"
replace_ext(image, "jpg")
-> image = "a/image.jpg"
Returns true on success.
*/
static bool replace_ext(std::string &path, const char *ext)
{
if(ext == NULL)
return false;
// Find place of last dot, fail if \ or / found.
s32 last_dot_i = -1;
for(s32 i=path.size()-1; i>=0; i--)
{
if(path[i] == '.')
{
last_dot_i = i;
break;
}
if(path[i] == '\\' || path[i] == '/')
break;
}
// If not found, return an empty string
if(last_dot_i == -1)
return false;
// Else make the new path
path = path.substr(0, last_dot_i+1) + ext;
return true;
}
/*
Find out the full path of an image by trying different filename
extensions.
If failed, return "".
*/
static std::string getImagePath(std::string path)
{
// A NULL-ended list of possible image extensions
const char *extensions[] = {
"png", "jpg", "bmp", "tga",
"pcx", "ppm", "psd", "wal", "rgb",
NULL
};
const char **ext = extensions;
do{
bool r = replace_ext(path, *ext);
if(r == false)
return "";
if(fs::PathExists(path))
return path;
}
while((++ext) != NULL);
return "";
}
/*
Gets the path to a texture by first checking if the texture exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getTexturePath(const std::string &filename)
{
std::string fullpath = "";
/*
Check from cache
*/
bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
if (incache && fullpath != "")
return fullpath;
std::string rel_path = std::string("textures")+DIR_DELIM+filename;
/*
Check from user data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_userdata + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
/*
Check from data_path /textures
*/
std::string data_path = g_settings->get("data_path");
if(data_path != "")
{
std::string testpath = data_path + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
/*
Check from default data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_data + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
// Add to cache (also an empty result is cached)
g_texturename_to_path_cache.set(filename, fullpath);
// Finally return it
return fullpath;
}
/*
Gets the path to a model by first checking if the model exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getModelPath(const std::string &filename)
{
std::string fullpath = "";
/*
Check from cache
*/
bool incache = g_modelname_to_path_cache.get(filename, &fullpath);
if(incache)
return fullpath;
std::string rel_path = std::string("models")+DIR_DELIM+filename;
/*
Check from user data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_userdata + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
/*
Check from data_path /models
*/
std::string data_path = g_settings->get("data_path");
if(data_path != "")
{
std::string testpath = data_path + DIR_DELIM + rel_path;
if(fs::PathExists(testpath))
fullpath = std::string(testpath);
}
/*
Check from default data directory
*/
if(fullpath == "")
{
std::string testpath = porting::path_data + DIR_DELIM + rel_path;
if(fs::PathExists(testpath))
fullpath = std::string(testpath);
}
// Add to cache (also an empty result is cached)
g_modelname_to_path_cache.set(filename, fullpath);
// Finally return it
return fullpath;
}
#include "path.h"
/*
TextureSource

View File

@ -31,23 +31,6 @@ using namespace jthread;
tile.{h,cpp}: Texture handling stuff.
*/
/*
Gets the path to a texture/model by first checking if it exists
in data_path and if not, using the default data path.
Checks all supported extensions by replacing the original extension.
If not found, returns "".
Utilizes a thread-safe cache.
*/
std::string getTexturePath(const std::string &filename);
std::string getModelPath(const std::string &filename);
u32 parseImageTransform(const std::string& s);
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim);
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
/*
Specifies a texture in an atlas.