This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088

Dependents:   MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ModLocalFileSystem.cpp Source File

ModLocalFileSystem.cpp

00001 #include "ModLocalFileSystem.h"
00002 #include "HttpdConnection.h"
00003 #include "UrlReader.h"
00004 #include "Http.h"
00005 #include "Httpd.h"
00006 #include "NyLPC_net.h"
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <typeinfo>
00010 #include "mbed.h"
00011 #include "FATDirHandle.h"
00012 
00013 
00014 using namespace MiMic;
00015 
00016 static void write_path(HttpdConnection& i_connection,const char* i_buf,const char* i_root_alias,const char* i_f_path)
00017 {
00018     if(i_root_alias==NULL){
00019         i_connection.sendBodyF("%s",i_buf);
00020     }else{
00021         i_connection.sendBodyF("%.*s%s",strlen(i_root_alias)-1,i_root_alias,i_buf+strlen(i_f_path)+1);
00022     }
00023 }
00024 
00025 void ModLocalFileSystem::retDirJson(const char* i_buf,HttpdConnection& i_connection,unsigned char i_fs_type)
00026 {
00027    //assert(HEAD or GET)
00028    //directory-list json
00029     if(!NyLPC_cHttpdUtils_sendJsonHeader((i_connection._ref_inst))){
00030         return;
00031     }
00032     if(!i_connection.isMethodType(Http::MT_GET)){
00033         return;
00034     }
00035       
00036     DIR* d=opendir(i_buf);
00037     if ( d == NULL )
00038     {
00039         i_connection.sendBodyF("{\"dir\":\"");
00040         write_path(i_connection,i_buf,this->_root_alias,this->_path);
00041         i_connection.sendBodyF("\",\"status\":404,\"list\":[]}");
00042         return;
00043     }
00044     if(!i_connection.isMethodType(Http::MT_GET)){
00045         //nothing to do
00046     }else{
00047         i_connection.sendBodyF("{\"dir\":\"");
00048         write_path(i_connection,i_buf,this->_root_alias,this->_path);
00049         i_connection.sendBodyF("\",\"status\":200,\"list\":[");
00050         switch(i_fs_type){
00051         case ModLocalFileSystem::FST_DEFAULT:
00052             for(struct dirent *p= readdir(d);;)
00053             {
00054                 i_connection.sendBodyF("{\"name\":\"%s\",\"mtype\":\"%s\",\"size\":undefined}",
00055                 p->d_name,NyLPC_cMiMeType_getFileName2MimeType(p->d_name));
00056                 p = readdir(d);
00057                 if(p==NULL){
00058                     break;
00059                 }
00060                 i_connection.sendBodyF(",");                        
00061             }
00062             break;
00063         case ModLocalFileSystem::FST_SDFATFS:
00064             for(struct dirent *p= readdir(d);;)
00065             {
00066                 bool isdir=(((struct direntFAT*)(p))->fattrib & AM_DIR)!=0;
00067                 i_connection.sendBodyF("{\"name\":\"%s\",\"mtype\":\"%s\",\"size\":%u}",
00068                 p->d_name,isdir?"directory":NyLPC_cMiMeType_getFileName2MimeType(p->d_name),
00069                 isdir?0:((struct direntFAT*)(p))->fsize);
00070                 p = readdir(d);
00071                 if(p==NULL){
00072                     break;
00073                 }
00074                 i_connection.sendBodyF(",");                        
00075             }
00076             break;
00077         default:
00078             break;
00079         }
00080         i_connection.sendBodyF("]}");
00081     }
00082     closedir(d);
00083 }
00084 void ModLocalFileSystem::retDirHtml(const char* i_buf,HttpdConnection& i_connection,unsigned char i_fs_type)
00085 {
00086     //assert(HEAD or GET)
00087     DIR* d=opendir(i_buf);
00088     if(d==NULL){
00089         i_connection.sendError(403);
00090         return;
00091     }        
00092     if(!i_connection.sendHeader(200,"text/html",NULL)){
00093         //nothing to do
00094     }else{
00095         if(!i_connection.isMethodType(Http::MT_GET)){
00096             //nothing to do.
00097         }else{
00098             i_connection.sendBodyF(
00099                 "<!DOCTYPE html><html><body><h1>Index of ");
00100             write_path(i_connection,i_buf,this->_root_alias,this->_path);
00101             i_connection.sendBodyF("</h1><hr/>\n"
00102                 "<ul>\n");
00103             switch(i_fs_type){
00104             case ModLocalFileSystem::FST_DEFAULT:
00105                 for(struct dirent *p = readdir(d);p!=NULL;p = readdir(d))
00106                 {
00107                     i_connection.sendBodyF("<li><a href=\"./%s\">%s</a></li>\n",
00108                     p->d_name,p->d_name);
00109                 }
00110                 break;
00111             case ModLocalFileSystem::FST_SDFATFS:
00112                 for(struct dirent *p = readdir(d);p!=NULL;p = readdir(d))
00113                 {
00114                     if((((struct direntFAT*)(p))->fattrib & AM_DIR)!=0){
00115                         //dir
00116                         i_connection.sendBodyF("<li><a href=\"./%s/\">[DIR]%s</a></li>\n",p->d_name,p->d_name);
00117                     }else{
00118                         //file
00119                         i_connection.sendBodyF("<li><a href=\"./%s\">%s</a></li>\n",p->d_name,p->d_name);
00120                     }
00121                 }
00122                 break;
00123             default:
00124                 break;
00125             }
00126             i_connection.sendBodyF("</ul></body></html>");
00127         }
00128     }
00129     closedir(d);
00130 }
00131 /**
00132  * @param i_path
00133  * i_pathにはnull終端ファイルパスを入れてください。
00134  */
00135 void ModLocalFileSystem::retFile(char* i_buf,HttpdConnection& i_connection)
00136 {
00137     //return content
00138     FILE *fp = fopen(i_buf, "r"); 
00139     if(fp==NULL){
00140         i_connection.sendError(404);
00141         return;
00142     }
00143     
00144     fseek(fp, 0, SEEK_END); // seek to end of file
00145     size_t sz = ftell(fp);       // get current file pointer
00146     fseek(fp, 0, SEEK_SET); // seek back to beginning of file
00147     if(i_connection.sendHeader(200,NyLPC_cMiMeType_getFileName2MimeType(i_buf),NULL,sz)){
00148         if(!i_connection.isMethodType(Http::MT_GET)){
00149             //nothing to do
00150         }else{
00151             Timer t;
00152             t.start();
00153             for(;;){
00154                 sz=fread(i_buf,1,Httpd::SIZE_OF_HTTP_BUF,fp);
00155                 if(sz<1){
00156                     break;
00157                 }
00158                 if(!i_connection.sendBody(i_buf,sz)){
00159                     break;
00160                 }
00161                 //switch other session
00162                 if(t.read_ms()>500){
00163                     //switch transport thread
00164                     i_connection.unlockHttpd();
00165                     NyLPC_cThread_sleep(50);
00166                     i_connection.lockHttpd();
00167                     t.reset();
00168                 }
00169             }
00170         }
00171     }
00172     fclose(fp);
00173 }    
00174 
00175 NyLPC_TBool flip_url_prefix(char* buf, int buf_len, const char* url_prefix, const char* file_path)
00176 {
00177     size_t bl = strlen(url_prefix);
00178     size_t al = strlen(file_path)+2;
00179     if (al - bl + strlen(buf) + 1 > buf_len){
00180         return NyLPC_TBool_FALSE;
00181     }
00182     if (strncmp(buf, url_prefix, bl) == 0){
00183         memmove(buf + al, buf + bl, strlen(buf) - bl + 1);
00184         memcpy(buf + 1, file_path, al - 1);
00185         *(buf + al - 1) = '/';
00186     }
00187     return NyLPC_TBool_TRUE;
00188 }
00189 
00190 namespace MiMic
00191 {
00192     ModLocalFileSystem::ModLocalFileSystem(const char* i_path,const char* i_root_alias,unsigned char i_fs_type):ModBaseClass()
00193     {
00194         this->setParam(i_path,i_root_alias,i_fs_type);
00195     }
00196     ModLocalFileSystem::ModLocalFileSystem(const char* i_path,unsigned char i_fs_type):ModBaseClass()
00197     {
00198         this->setParam(i_path,NULL,i_fs_type);
00199     }
00200     ModLocalFileSystem::ModLocalFileSystem():ModBaseClass()
00201     {
00202         this->_root_alias=NULL;
00203     }
00204     ModLocalFileSystem::~ModLocalFileSystem()
00205     {
00206     }
00207     void ModLocalFileSystem::setParam(const char* i_path,const char* i_root_alias,unsigned char i_fs_type)
00208     {
00209         NyLPC_Assert(strlen(i_root_alias)>0);
00210         ModBaseClass::setParam(i_path);
00211         this->_root_alias=i_root_alias;
00212         this->_fs_type=i_fs_type;
00213     }
00214     void ModLocalFileSystem::setParam(const char* i_path,unsigned char i_fs_type)
00215     {
00216         this->setParam(i_path,NULL,i_fs_type);
00217     }
00218     bool ModLocalFileSystem::canHandle(HttpdConnection& i_connection)
00219     {
00220         if(this->_root_alias==NULL){
00221             return ModBaseClass::canHandle(i_connection);
00222         }
00223         //root alias指定がある場合
00224         if(!NyLPC_cHttpdConnection_getReqStatus(i_connection._ref_inst)==NyLPC_cHttpdConnection_ReqStatus_REQPARSE)
00225         {
00226             return NyLPC_TBool_FALSE;
00227         }        
00228         const NyLPC_TChar* in_url;
00229         in_url=NyLPC_cHttpdConnection_getUrlPrefix(i_connection._ref_inst);
00230         size_t base_url_len=strlen(this->_root_alias);
00231         if(strncmp(this->_root_alias,in_url,base_url_len)!=0){
00232             return false;
00233         }
00234         return true;
00235     }  
00236     bool ModLocalFileSystem::execute(HttpdConnection& i_connection)
00237     {
00238         //check platform
00239         //<write here! />
00240         
00241         //check prefix
00242         if(!this->canHandle(i_connection)){
00243             return false;
00244         }
00245         
00246         //check Method type
00247         {
00248             int mt=i_connection.getMethodType();
00249             if(mt!=Http::MT_GET && mt!=Http::MT_HEAD){
00250                 //method not allowed.
00251                 i_connection.sendError(405);
00252                 return true;
00253             }
00254         }
00255         //Httpd lock
00256         i_connection.lockHttpd();
00257         char* buf=Httpd::_shared_buf;
00258         
00259         //set file path
00260         {
00261             //call ModUrl
00262             NyLPC_TcModUrl_t mod;
00263             NyLPC_cModUrl_initialize(&mod);
00264             if(!NyLPC_cModUrl_execute2(&mod,i_connection._ref_inst,buf,Httpd::SIZE_OF_HTTP_BUF,0,NyLPC_cModUrl_ParseMode_ALL)){
00265                 NyLPC_cModUrl_finalize(&mod);
00266                 i_connection.unlockHttpd();
00267                 return true;
00268             }
00269             NyLPC_cModUrl_finalize(&mod);
00270         }
00271         //パスのエイリアスがあるときはここで編集
00272         if(this->_root_alias!=NULL){
00273             flip_url_prefix(buf,Httpd::SIZE_OF_HTTP_BUF,this->_root_alias,this->_path);
00274         }
00275         UrlReader url(buf);
00276         if(url.hasQueryKey("list")){
00277             // if path has '/?list' query key,return directory information
00278             const char* t;
00279             int l;
00280             url.getPath(t,l);
00281             buf[l]='\0';//split path
00282             //remove '/'
00283             if(buf[l-1]=='/'){
00284                 buf[l-1]='\0';
00285             }
00286             retDirJson(buf,i_connection,this->_fs_type);
00287         }else if(strchr(buf,'?')==NULL && strchr(buf,'#')==NULL && buf[strlen(buf)-1]=='/'){
00288             //return directory html when URL has not bookmark and URL query and terminated by '/'.
00289             buf[strlen(buf)-1]='\0';//convert to dir path
00290             retDirHtml(buf,i_connection,this->_fs_type);
00291         }else{
00292             //split URL path and query
00293             const char* t;
00294             int l;
00295             url.getPath(t,l);
00296             buf[l]='\0';
00297             retFile(buf,i_connection);
00298         }
00299         //Httpd unlock
00300         i_connection.unlockHttpd();
00301         return true;
00302         
00303     }
00304 }