forked from oerkki/voxelands
http part 3
This commit is contained in:
parent
c6cd8c8619
commit
f13cf01980
|
@ -0,0 +1,4 @@
|
|||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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">
|
|
@ -129,6 +129,7 @@ set(common_SRCS
|
|||
base64.cpp
|
||||
ban.cpp
|
||||
http.cpp
|
||||
path.cpp
|
||||
)
|
||||
|
||||
# This gives us the icon
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
618
src/http.cpp
618
src/http.cpp
|
@ -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;
|
||||
}
|
||||
|
|
78
src/http.h
78
src/http.h
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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),
|
||||
|
|
13
src/server.h
13
src/server.h
|
@ -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();
|
||||
|
|
27
src/sha1.cpp
27
src/sha1.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
188
src/tile.cpp
188
src/tile.cpp
|
@ -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
|
||||
|
|
17
src/tile.h
17
src/tile.h
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue