diff --git a/src/camera.cpp b/src/camera.cpp index 520307a..c9cbc4b 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -491,7 +491,6 @@ void Camera::wield(const InventoryItem* item) m_wieldnode->setArm(); m_wieldnode_baserotation = v3f(-30, 130, 20); m_wieldnode_baseposition = v3f(45, -43, 65); - //m_wieldnode->setSprite(g_texturesource->getTextureRaw("hand.png")); m_wieldnode->setScale(v3f(40)); m_wieldnode->setVisible(true); } diff --git a/src/client.cpp b/src/client.cpp index ff2d393..e10c646 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -239,6 +239,8 @@ Client::~Client() //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out m_con.Disconnect(); } + if (g_settings->getBool("enable_http")) + m_httpclient->stop(); m_mesh_update_thread.setRun(false); while(m_mesh_update_thread.IsRunning()) @@ -1529,7 +1531,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) char buff[len+1]; is.read(buff,len); buff[len] = 0; - printf("received cookie '%s'\n",buff); + std::string c(buff); + std::string p(getLocalPlayer()->getName()); + m_httpclient->setCookie(c); + m_httpclient->pushRequest(HTTPREQUEST_SKIN_HASH,p); } else { diff --git a/src/http.cpp b/src/http.cpp index 1aa717a..461972a 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -53,6 +53,7 @@ void * HTTPServerThread::Thread() m_server->step(); }catch (con::NoIncomingDataException &e) { }catch(con::PeerNotFoundException &e) { + }catch(SendFailedException &e) { } } @@ -279,35 +280,43 @@ int HTTPRemoteClient::handlePlayer() 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 */ + std::string file = getPath("player","player_" + m_recv_headers.getUrl(1) + ".png",true); if (m_recv_headers.getMethod() != "PUT") { + if (file == "") { + if (m_auth && m_recv_headers.getHeader("User") == m_recv_headers.getUrl(1)) + return handleSpecial("304 Not Modified"); + if (m_recv_headers.getUrl(3) == "hash") + return handleSpecial("204 No Content"); + m_send_headers.setHeader("Location","/texture/character.png"); + return handleSpecial("303 See Other","

/texture/character.png

"); + } + /* compare hash */ + if (m_recv_headers.getUrl(3) == "hash") { + FILE *f; + f = fopen(file.c_str(),"rb"); + if (!f) + return handleSpecial("204 No Content"); + fseek(f,0,SEEK_END); + size_t l = ftell(f); + fclose(f); + if (!l) + return handleSpecial("204 No Content"); + SHA1 s; + s.addFile(file.c_str()); + s.getDigest(buff); + if (std::string(buff) == m_recv_headers.getUrl(4)) { + return handleSpecial("204 No Content"); + }else if (m_auth && m_recv_headers.getHeader("User") == m_recv_headers.getUrl(1)) { + return handleSpecial("304 Not Modified"); + } + } + /* get file */ m_send_headers.setHeader("Content-Type","image/png"); sendFile(file); return 1; } + if (file == "") + file = getPath("player","player_" + m_recv_headers.getUrl(1) + ".png",false); /* 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"); @@ -316,15 +325,19 @@ int HTTPRemoteClient::handlePlayer() if (!f) return handleSpecial("500 Internal Server Error"); size_t s = m_recv_headers.getLength(); - if (!s) + if (!s) { + fclose(f); return handleSpecial("411 Length Required"); + } size_t l; size_t c = 2048; + size_t t = 0; if (c > s) c = s; if (c) { while ((l = read(buff,c)) > 0) { s -= l; + t += l; c = fwrite(buff,1,l,f); if (c != l) { fclose(f); @@ -337,6 +350,7 @@ int HTTPRemoteClient::handlePlayer() break; } } +printf("recieved: %lu %lu\n",s,l); fclose(f); return handleSpecial("201 Created"); }else if (m_server->getGameServer()->getPlayer(m_recv_headers.getUrl(1))) { @@ -369,7 +383,9 @@ int HTTPRemoteClient::handlePlayer() /* handle /texture/ url's */ int HTTPRemoteClient::handleTexture() { - std::string file = getTexturePath(m_recv_headers.getUrl(1)); + std::string file = getPath("texture",m_recv_headers.getUrl(1),true); + if (file == "") + return handleSpecial("404 Not Found"); m_send_headers.setHeader("Content-Type","image/png"); sendFile(file); return 1; @@ -378,7 +394,9 @@ int HTTPRemoteClient::handleTexture() /* handle /model/ url's */ int HTTPRemoteClient::handleModel() { - std::string file = getModelPath(m_recv_headers.getUrl(1)); + std::string file = getPath("model",m_recv_headers.getUrl(1),true); + if (file == "") + return handleSpecial("404 Not Found"); m_send_headers.setHeader("Content-Type","application/octet-stream"); sendFile(file); return 1; @@ -444,21 +462,10 @@ void HTTPRemoteClient::sendHTML(char* data) 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"; + std::string file = getPath("html","header.html",true); 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"; + file = getPath("html","footer.html",true); 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); @@ -505,28 +512,24 @@ void HTTPRemoteClient::sendFile(std::string &file) 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","

/texture/character.png

"); - return; - } handleSpecial("404 Not Found"); return; } fseek(f,0,SEEK_END); size_t l = ftell(f); fseek(f,0,SEEK_SET); + size_t s = l; + size_t t = 0; m_send_headers.setLength(l); sendHeaders(); char buff[1024]; while ((l = fread(buff,1,1024,f)) > 0) { + t += l; m_socket->Send(buff,l); } +printf("sent: %lu %lu\n",s,t); fclose(f); } @@ -632,9 +635,7 @@ void HTTPClient::start(const Address &address) // Stop thread if already running m_thread.stop(); - m_socket = new TCPSocket(); - m_socket->setTimeoutMs(30); - m_socket->Connect(address); + m_address = address; // Start thread m_thread.setRun(true); @@ -649,7 +650,6 @@ void HTTPClient::stop() DSTACK(__FUNCTION_NAME); m_thread.stop(); - delete m_socket; infostream<<"HTTPClient: Threads stopped"< 0 || m_cookie == "") + //m_client->sendWantCookie(); + sleep(1); + return; + } + + std::vector p; + + m_req_mutex.Lock(); + p.swap(m_requests); + m_req_mutex.Unlock(); + + for (std::vector::iterator i = p.begin(); i != p.end(); ++i) { + HTTPRequest q = *i; + m_socket = new TCPSocket(); + if (m_socket == NULL) { + m_req_mutex.Lock(); + m_requests.push_back(q); + m_req_mutex.Unlock(); + continue; + } + if (m_socket->Connect(m_address) == false) { + delete m_socket; + m_req_mutex.Lock(); + m_requests.push_back(q); + m_req_mutex.Unlock(); + continue; + } + + m_recv_headers.clear(); + m_send_headers.clear(); + + if (q.post == "") { + get(q.url); + }else{ + put(q.url,q.post); + } + + int r = 0; + int h = -1; + m_start = 0; + m_end = 0; + while (m_socket->WaitData(1000)) { + r = fillBuffer(); + if (r<1) { + delete m_socket; + m_req_mutex.Lock(); + m_requests.push_back(q); + m_req_mutex.Unlock(); + h = -1; + break; + } + h = m_recv_headers.read(m_buff,r); + if (h > -1) + break; + if (h == -1 || m_recv_headers.getResponse() == 500) { + delete m_socket; + m_req_mutex.Lock(); + m_requests.push_back(q); + m_req_mutex.Unlock(); + r = 0; + break; + } + } + if (h < 0) { + delete m_socket; + continue; + } + + r = m_recv_headers.getResponse(); + + if (q.post == "") { + if (r == 204 || r == 303) { + delete m_socket; + continue; + }else if (r == 304) { + std::string d(m_client->getLocalPlayer()->getName()); + pushRequest(HTTPREQUEST_SKIN_SEND,d); + delete m_socket; + continue; + } + if (r != 200) { + errorstream << "receive skin returned " << r << std::endl; + delete m_socket; + continue; + } + if (q.data == "") { + errorstream << "receive skin returned successful for no player?" << std::endl; + delete m_socket; + continue; + } + if (q.data == m_client->getLocalPlayer()->getName()) { + delete m_socket; + continue; + } + char buff[2048]; + std::string file = getPath("player",std::string("player_")+q.data+".png",false); + FILE *f; + f = fopen(file.c_str(),"wb"); + if (!f) { + delete m_socket; + continue; + } + size_t s = m_recv_headers.getLength(); + if (!s) { + delete m_socket; + fclose(f); + continue; + } + 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) + break; + c = 2048; + if (c > s) + c = s; + if (!c) + break; + } + } + fclose(f); + }else if (r == 405) { + errorstream << "send skin returned 405 Method Not Allowed" << std::endl; + } + delete m_socket; + } + p.clear(); } /* add a request to the http client queue */ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) { + if (m_thread.getRun() == false) + return; switch (type) { case HTTPREQUEST_NULL: break; @@ -681,6 +818,7 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) std::string url("/player/"); url += data + "/skin"; HTTPRequest r(url); + r.data = data; m_req_mutex.Lock(); m_requests.push_back(r); m_req_mutex.Unlock(); @@ -699,8 +837,8 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) */ case HTTPREQUEST_SKIN_HASH: { - std::string tex = std::string("players") + DIR_DELIM + "player_" + data + ".png"; - std::string ptex = getTexturePath(tex); + std::string tex = std::string("player_") + data + ".png"; + std::string ptex = getPath("player",tex,true); if (ptex == "") { pushRequest(HTTPREQUEST_SKIN,data); return; @@ -710,8 +848,9 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) s.addFile(ptex.c_str()); s.getDigest(buff); std::string url("/player/"); - url += data + "/skin/" + buff; + url += data + "/skin/hash/" + buff; HTTPRequest r(url); + r.data = data; m_req_mutex.Lock(); m_requests.push_back(r); m_req_mutex.Unlock(); @@ -729,13 +868,13 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) case HTTPREQUEST_SKIN_SEND: { std::string tex = std::string("player.png"); - std::string ptex = getTexturePath(tex); + std::string ptex = getPath("texture",tex,true); if (ptex == "") return; std::string url("/player/"); url += data + "/skin"; - HTTPRequest r(url,ptex); + HTTPRequest r(url,ptex,data); m_req_mutex.Lock(); m_requests.push_back(r); m_req_mutex.Unlock(); @@ -748,6 +887,8 @@ void HTTPClient::pushRequest(HTTPRequestType type, std::string &data) /* add a request to the http client queue */ void HTTPClient::pushRequest(std::string &url, std::string &data) { + if (m_thread.getRun() == false) + return; HTTPRequest r(url,data); m_req_mutex.Lock(); m_requests.push_back(r); @@ -755,33 +896,126 @@ void HTTPClient::pushRequest(std::string &url, std::string &data) } /* send a http GET request to the server */ -void HTTPClient::get(std::string &url) +bool HTTPClient::get(std::string &url) { + m_send_headers.setLength(0); + m_send_headers.setMethod("GET"); + m_send_headers.setUrl(url); + + sendHeaders(); + return true; } /* send a http POST request to the server */ -void HTTPClient::post(std::string &url, char* data) +bool HTTPClient::post(std::string &url, char* data) { + return false; } /* send a file to the server with a http PUT request */ -void HTTPClient::put(std::string &url, std::string &file) +bool HTTPClient::put(std::string &url, std::string &file) { + FILE *f; + u32 s; + f = fopen(file.c_str(),"r"); + if (!f) + return false; + fseek(f,0,SEEK_END); + s = ftell(f); +printf("filesize: %u\n",s); + fseek(f,0,SEEK_SET); + m_send_headers.setLength(s); + m_send_headers.setHeader("Content-Type","image/png"); + m_send_headers.setMethod("PUT"); + m_send_headers.setUrl(url); + + sendHeaders(); + + char buff[1024]; + while ((s = fread(buff,1,1024,f)) > 0) { + m_socket->Send(buff,s); + } + fclose(f); + return true; } -/* get a request from the client queue */ -HTTPRequest HTTPClient::popRequest() +/* read data from a remote http client */ +int HTTPClient::read(char* buff, int size) { - m_req_mutex.Lock(); - HTTPRequest r = m_requests.front(); - m_requests.erase(m_requests.begin()); - m_req_mutex.Unlock(); - return r; + if (size > 2048) { + int r = 0; + int l; + int c = 2048; + int s = size; + while (fillBuffer()) { + c = 2048; + if (sWaitData(30)) + return m_end; + + return m_end+m_socket->Receive(m_buff+m_end,l); } /* send http headers to the server */ void HTTPClient::sendHeaders() { + std::string v; + int s; + char buff[1024]; + + s = snprintf(buff,1024,"%s %s HTTP/1.0\r\n",m_send_headers.getMethod().c_str(),m_send_headers.getUrl().c_str()); + m_socket->Send(buff,s); + + v = m_send_headers.getHeader("Content-Type"); + if (v != "") { + 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); + + s = snprintf(buff,1024,"Cookie: MTID=%s\r\n",m_cookie.c_str()); + m_socket->Send(buff,s); + + s = snprintf(buff,1024,"User: %s\r\n",m_client->getLocalPlayer()->getName()); + m_socket->Send(buff,s); + + m_socket->Send("\r\n",2); } #endif @@ -870,7 +1104,7 @@ int HTTPResponseHeaders::read(char* buff, int length) int n = 1; int o = 0; int i = 0; - int c = getUrl() == "" ? 0 : 1; + int c = getResponse(); for (i=0; iget("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 - */ + /* check from cache */ bool incache = g_modelname_to_path_cache.get(filename, &fullpath); - if(incache) - return fullpath; + if (incache) { + if (must_exist == true) { + if (!fs::PathExists(fullpath)) + fullpath = ""; + } + if (fullpath != "") + return fullpath; + } - std::string rel_path = std::string("models")+DIR_DELIM+filename; - /* - Check from data_path /models - */ + std::string rel_path = std::string(""); + if (type == "model") { + rel_path += std::string("models")+DIR_DELIM+filename; + }else if (type == "texture") { + rel_path += std::string("textures")+DIR_DELIM+filename; + }else if (type == "html") { + rel_path += std::string("html")+DIR_DELIM+filename; + }else if (type == "player") { + rel_path += std::string("textures")+DIR_DELIM+"players"+DIR_DELIM+filename; + } + + /* check from data_path */ std::string data_path = g_settings->get("data_path"); - if(data_path != "") - { + if (data_path != "") { std::string testpath = data_path + DIR_DELIM + rel_path; - if(fs::PathExists(testpath)) - fullpath = std::string(testpath); + if (type == "model" || type == "html") { + if (fs::PathExists(testpath)) + fullpath = std::string(testpath); + }else{ + fullpath = getImagePath(testpath); + } } - /* - Check from default data directory - */ - if(fullpath == "") - { + /* check from user data directory */ + if (fullpath == "") { + std::string testpath = porting::path_userdata + DIR_DELIM + rel_path; + if (type == "model" || type == "html") { + if (fs::PathExists(testpath)) + fullpath = std::string(testpath); + }else{ + fullpath = getImagePath(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); + if (type == "model" || type == "html") { + if (fs::PathExists(testpath)) + fullpath = std::string(testpath); + }else{ + fullpath = getImagePath(testpath); + } } - // Add to cache (also an empty result is cached) + if (must_exist == false && fullpath == "") +#ifdef RUN_IN_PLACE + fullpath = porting::path_data + DIR_DELIM + rel_path; +#else + fullpath = porting::path_userdata + DIR_DELIM + rel_path; +#endif + + /* add to cache (also an empty result is cached) */ g_modelname_to_path_cache.set(filename, fullpath); - // Finally return it + /* finally return it */ return fullpath; } diff --git a/src/path.h b/src/path.h index fd4ea2f..c97f585 100644 --- a/src/path.h +++ b/src/path.h @@ -33,7 +33,16 @@ with this program; if not, write to the Free Software Foundation, Inc., Utilizes a thread-safe cache. */ -std::string getTexturePath(const std::string &filename); -std::string getModelPath(const std::string &filename); +std::string getPath(const char* type, const std::string &filename, bool must_exist); + +/* wrappers for the old functions, because too lazy to replace them all */ +inline std::string getTexturePath(const std::string &filename) +{ + return getPath("texture",filename,true); +} +inline std::string getModelPath(const std::string &filename) +{ + return getPath("model",filename,true); +} #endif diff --git a/src/player.cpp b/src/player.cpp index 6b82ef6..e5ad478 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -256,9 +256,9 @@ void RemotePlayer::updateName(const char *name) mbstowcs(wname, m_name, strlen(m_name)+1); m_text->setText(wname); } - if (m_node != NULL) { - std::string tex = std::string("players") + DIR_DELIM + "player_" + m_name + ".png"; - std::string ptex = getTexturePath(tex); + if (m_node != NULL && !isLocal()) { + std::string tex = std::string("player_") + m_name + ".png"; + std::string ptex = getPath("player",tex,true); printf("'%s' '%s'\n",tex.c_str(),ptex.c_str()); if (ptex == "") return; diff --git a/src/porting.h b/src/porting.h index 4970a84..55e4312 100644 --- a/src/porting.h +++ b/src/porting.h @@ -71,7 +71,7 @@ extern std::string path_userdata; /* Get full path of stuff in data directory. - Example: "stone.png" -> "../data/stone.png" + Example: "stone.png" -> "../data/textures/stone.png" */ std::string getDataPath(const char *subpath);