HTTP Server, using SD card and EthernetInterface.
Dependencies: EthernetInterface SDFileSystem mbed-rtos mbed
Revision 0:fbb29d9ea96b, committed 2013-04-07
- Comitter:
- azsymaivan
- Date:
- Sun Apr 07 11:23:03 2013 +0000
- Commit message:
- HTTP Server, using SD card and EthernetInterface. This code work, but sometimes mbed frizing. Always frizing occurs when mbed sent information to HTTP client. Exactly when call function tcpip_apimsg(struct api_msg *apimsg) in file "tcpip.c".
Changed in this revision
diff -r 000000000000 -r fbb29d9ea96b EthernetInterface.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetInterface.lib Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/EthernetInterface/#9b2d10dc0392
diff -r 000000000000 -r fbb29d9ea96b SDFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.lib Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/azsymaivan/code/SDFileSystem/#f242d7bdef28
diff -r 000000000000 -r fbb29d9ea96b filelib.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/filelib.h Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,127 @@ +#ifndef filelib +#define filelib + +#include "mbed.h" +#include <time.h> +#include <ff.h> //found in lib SDFileSystem->FATFileSystem/ChaN +#include "SDFileSystem.h" + + +/* +typedef enum { + FR_OK = 0, // (0) Succeeded + FR_DISK_ERR, // (1) A hard error occurred in the low level disk I/O layer + FR_INT_ERR, // (2) Assertion failed + FR_NOT_READY, // (3) The physical drive cannot work + FR_NO_FILE, // (4) Could not find the file + FR_NO_PATH, // (5) Could not find the path + FR_INVALID_NAME, // (6) The path name format is invalid + FR_DENIED, // (7) Access denied due to prohibited access or directory full + FR_EXIST, // (8) Access denied due to prohibited access + FR_INVALID_OBJECT, // (9) The file/directory object is invalid + FR_WRITE_PROTECTED, // (10) The physical drive is write protected + FR_INVALID_DRIVE, // (11) The logical drive number is invalid + FR_NOT_ENABLED, // (12) The volume has no work area + FR_NO_FILESYSTEM, // (13) There is no valid FAT volume + FR_MKFS_ABORTED, // (14) The f_mkfs() aborted due to any parameter error + FR_TIMEOUT, // (15) Could not get a grant to access the volume within defined period + FR_LOCKED, // (16) The operation is rejected according to the file sharing policy + FR_NOT_ENOUGH_CORE, // (17) LFN working buffer could not be allocated + FR_TOO_MANY_OPEN_FILES, // (18) Number of open files > _FS_SHARE + FR_INVALID_PARAMETER // (19) Given parameter is invalid +} FRESULT; + +*/ +/* +mode_t values in octal + S_IFREG 0100000 + S_IFDIR 040000 + S_IRUSR 0400 read permission, owner + S_IWUSR 0200 write permission, owner + S_IXUSR 0100 execute/search permission, owner + S_IRGRP 040 read permission, group + S_IWGRP 020 write permission, group + S_IXGRP 010 execute/search permission, group + S_IROTH 04 read permission, others + S_IWOTH 02 write permission, others + S_IXOTH 01 execute/search permission, others +*/ +struct sMystat { +// dev_t st_dev; /* ID of device containing file */ +// ino_t st_ino; /* inode number */ + mode_t st_mode; /* protection */ +// nlink_t st_nlink; /* number of hard links */ +// uid_t st_uid; /* user ID of owner */ +// gid_t st_gid; /* group ID of owner */ +// dev_t st_rdev; /* device ID (if special file) */ + // off_t st_size; /* total size, in bytes */ + DWORD st_size; /* total size, in bytes */ +// blksize_t st_blksize; /* blocksize for file system I/O */ +// blkcnt_t st_blocks; /* number of 512B blocks allocated */ +// time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last modification */ +// time_t st_ctime; /* time of last status change */ +}; + +sMystat myStatBuf; //store info for file +FILINFO finfo; //global file info struct see ff.h +FATFS_DIR dinfo; //global directoty info struct see ff.h + +FRESULT get_fileInfo(const char *path) //use finfo for get result fields +{ + FRESULT res = f_stat(path,&finfo); /* Get file status */ + if (EnDebugMSG) + if (res) + printf("\n-->get_fileInfo:%s ,res=%d ,Not Found!",path,res); + else + printf("\n-->get_fileInfo:%s ,res=%d ,Found!",path,res); + return res; +} + +FRESULT get_dirInfo(const char *path) +{ + FRESULT res= f_opendir (&dinfo,path); /* FR_OK(0): successful, !=0: error code */ + if (EnDebugMSG) + if (res) + printf("\n-->get_dirInfo :%s res=%d ,This is Not Directory!",path,res); + else + printf("\n-->get_dirInfo :%s res=%d ,This is Directory!",path,res); + return res; +} + +FRESULT Mystat(const char *path, struct sMystat *buf) +{ + FRESULT res = f_stat(path,&finfo); /* Get file status */ + if (res == FR_OK) { + buf->st_size = finfo.fsize; + buf->st_mtime = finfo.ftime; //fdate; + buf->st_mode = 4; //? + } + if (EnDebugMSG) + printf("\n--Mystat Path:%s ,filesize:%14lld ,res=%d",path, buf->st_size, res); + return res; +} + + +static char* get_mime_type( char* filename ) +{ + char* extension; + extension = strrchr( filename, '.' ); //get string after last . + if (EnDebugMSG) + printf("\n-->get_mime_tipe filename:%s, extension:%s",filename, extension); + if (extension !=NULL) { + if (strcasecmp(extension,".htm")==0 || strcasecmp(extension,".html") ==0) + return "text/html; charset=iso-8859-1"; + if (strcasecmp(extension,".png")==0) + return "image/png"; + if (strcasecmp(extension,".css")==0) + return "text/css"; + if (strcasecmp(extension,".gif")==0) + return "image/gif"; + if (strcasecmp(extension,".jpg")==0 || strcasecmp(extension,".jpeg" )==0) + return "image/jpeg"; + } + return "text/plain; charset=iso-8859-1"; +} + +#endif
diff -r 000000000000 -r fbb29d9ea96b main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,370 @@ +#include "mbed.h" +#include "EthernetInterface.h" +#include "SDFileSystem.h" + +#define EnDebugMSG false //true-> print debug message to PC USB terminal, false->not print +#include "filelib.h" + +#define IP "192.168.100.100" +#define MASK "255.255.255.0" +#define GATEWAY "192.168.100.1" +#define PORT 80 + +Serial pc (USBTX,USBRX); // tx, rx +SDFileSystem sd(p5, p6, p7, p8, "wfs"); // the pinout on the mbed + +char sMethod[7]; +char sURL[250]; +char sProtocol[8]; + +EthernetInterface eth; + +TCPSocketServer svr; +bool serverIsListened = false; + +TCPSocketConnection client; +bool clientIsConnected = false; + +char sentBuffer[1608] = {}; // 2*536=1072, 3*536=1608, 4*536=2144 !1500 +char line_response[256]= {0}; +char file_path[256] = {0}; + +DigitalOut led1(LED1); //server listning status +DigitalOut led2(LED2); //socket connecting status + +Ticker ledTick; + +void ledTickfunc() +{ + if(serverIsListened) { + led1 = !led1; + } else { + led1 = false; + } +} + +void send_HTTP_header(char* protocol, int code, char* title, char* mime_type, long long lengthBody) +{ + snprintf(line_response, sizeof(line_response),"%s %d %s\r\n", protocol, code, title ); + snprintf(sentBuffer, sizeof(sentBuffer),"%s",line_response); + + if ( mime_type != NULL ) { + snprintf(line_response, sizeof(line_response), "Content-Type: %s\r\n", mime_type ); + snprintf(sentBuffer, sizeof(sentBuffer), "%s%s",sentBuffer,line_response); //append to sentBuffer + } + if ( lengthBody >= 0 ) { + snprintf(line_response, sizeof(line_response), "Content-Length: %lld\r\n", lengthBody ); + snprintf(sentBuffer, sizeof(sentBuffer), "%s%s",sentBuffer,line_response); //append to sentBuffer + } + snprintf(line_response, sizeof(line_response), "Connection: close\r\n" ); + snprintf(sentBuffer, sizeof(sentBuffer),"%s%s\r\n",sentBuffer,line_response); //append to sentBuffer + + if (EnDebugMSG) + printf("\n-->sent Header--\n"); + + client.send_all(sentBuffer,strlen(sentBuffer)); + if (EnDebugMSG) { + printf(sentBuffer); + printf("\n--end Header-- bytes:%d",strlen(sentBuffer)); + } + Thread::wait(200); //200ms important for browser! +} + +void send_HTML_line(char* line, unsigned int length_line) +{ + client.send_all(line,length_line); + if (EnDebugMSG) + printf("\n-->send HTML line:\n%s ...Ok!",line); + Thread::wait(10); +} + +void send_HTML_error( int status_code, char* title, char* body_text) +{ + send_HTTP_header("HTTP/1.1", status_code, title, "text/html", -1); + if (EnDebugMSG) + printf("\n-->send_error...\n"); + sentBuffer[0]=NULL; //clear buffer + sprintf(line_response, "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<title>%d %s</title>\r\n</head>\r\n", status_code, title); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + sprintf(line_response, "<body><center><h2><center>%d %s</center></h2>\r\n",status_code, title ); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + sprintf(line_response, "%s\r\n", body_text ); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + sprintf(line_response, "<p>mbed HTTP File Server</p>\r\n</center></body></html>\r\n"); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + send_HTML_line(sentBuffer, strlen(sentBuffer)); +} + +int send_file(char *path_file) +{ + char *mime_type = {0}; + unsigned int bytes_for_send=0; + long long filesize, all_send_bytes = 0; + + mime_type = get_mime_type( path_file ); + snprintf(file_path, sizeof(file_path),"/wfs/%s",path_file); + if (EnDebugMSG) { + printf("\n-->from send_file:%s",file_path); + printf("\n-->from send_file mime type:%s",mime_type); + } + + if (Mystat(path_file, &myStatBuf)) { //fault with file + send_HTML_error( 403, "Forbidden", "403 - File access forbidden."); + return 403; + } + FILE* fp = NULL; + fp = fopen(file_path,"r"); + if (fp==NULL ) { + send_HTML_error( 403, "Forbidden", "403 - File access forbidden."); + return 403; + } + + filesize = myStatBuf.st_size; + send_HTTP_header("HTTP/1.1", 200, "Ok", mime_type, myStatBuf.st_size); + //binary send + all_send_bytes=0; + while(filesize) { //check for EOF !feof(fp) + bytes_for_send = filesize; + if (bytes_for_send > sizeof(sentBuffer)) { + bytes_for_send = sizeof(sentBuffer); + } + fread (sentBuffer,1,bytes_for_send,fp); + filesize -= bytes_for_send; + if (EnDebugMSG) + printf("\n---bytes_for_send...%d",bytes_for_send); + client.send_all(sentBuffer,bytes_for_send); + //Thread::wait(10); + all_send_bytes += bytes_for_send; + } + if (EnDebugMSG) + printf("\n---buffer fill end - all ...%lld", all_send_bytes); + //binary send + + sprintf(line_response, "\r\n"); + client.send_all(line_response,strlen(line_response)); + if ( fp != NULL ) + fclose(fp); + //Thread::wait(10); + return 0; +} + +int send_directory(char *path) +{ + char process_name[64]= {0}; + + char posOfLastSlash; + char *pLS; + + struct dirent *p; + struct sMystat sb; + struct tm *timeinfo; + char timeBuf[40]; + + if (EnDebugMSG) + printf("\n-->from send_directory:%s",path); + snprintf(file_path,sizeof(file_path),"/wfs%s",path); + DIR *d = opendir(file_path); + if (EnDebugMSG && d!=NULL) + printf("\n-->from send_directory:%s ...open OK",file_path); + if (d==NULL) { //error open dir + send_HTML_error( 403, "Forbidden", "403 - Directory access forbidden."); + return -1; + } + send_HTTP_header("HTTP/1.1", 200, "Ok",NULL, -1); + sentBuffer[0]=NULL; + sprintf(line_response,"<!DOCTYPE html>\r\n<html>\n<head><title>Index of %s</title>\n",path); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + + sprintf(line_response,"<meta content=\"text/html; charset=iso-8859-1\" http-equiv=\"Content-Type\"></head>\n"); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + + + sprintf(line_response,"<body><center>\n<h3>Index of %s</h3>\n", path); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + send_HTML_line(sentBuffer, strlen(sentBuffer)); +//begin table + sentBuffer[0]=NULL; //clear buffer + sprintf(line_response,"<table border=\"0\">\n"); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + sprintf(line_response,"<tr><th align=\"left\" width=\"200\">Name</th><th align=\"right\" width=\"100\">Size(bytes)</th><th align=\"right\" width=\"200\">Date/Time</th></tr>\n"); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer +//begin table + + pLS=strrchr(path,'/'); + posOfLastSlash=pLS-path+1; + if (EnDebugMSG) + printf("\r\n>>posOfLastSlash=%d",posOfLastSlash); + snprintf(process_name,posOfLastSlash+1,"%s",path); + if (EnDebugMSG) + printf("\r\n>>process_name=%s",process_name); + sprintf(line_response,"<tr><td align=\"left\"><a href=\"%s\">../</a></td></tr>\n",process_name); + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + while((p = readdir(d)) != NULL) { + if (EnDebugMSG) + printf("\n :%s",p->d_name); + sprintf(file_path,"%s/%s",path,p->d_name); + Mystat( file_path, &sb ); + if (get_dirInfo(file_path)==0 ) { //this is directory path + if (EnDebugMSG) + printf("\nDIR"); + sprintf(line_response, "<tr><td align=\"left\"><a href=\"%s\">%s</a><br></td></tr>\n",file_path,p->d_name); + if (strlen(line_response)>(sizeof(sentBuffer)-strlen(sentBuffer))) { //buffer must be sent + send_HTML_line(sentBuffer, strlen(sentBuffer)); + sentBuffer[0]=NULL; //clear buffer + } + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + + } else { //this is file + if (EnDebugMSG) + printf("\nFILE"); + timeinfo = localtime (&sb.st_mtime); + //strftime(timeBuf,40, "%I:%M:%S %p (%Y/%m/%d)\r\n", localtime(&sb.st_mtime)); + strftime(timeBuf, 40, "%c", timeinfo); + sprintf(line_response, "<tr><td align=\"left\"><a href=\"%s\">%s</a></td><td align=\"right\">%lld</td><td align=\"right\">%s</td></tr>\n", file_path, p->d_name,(long long) sb.st_size,timeBuf); // asctime(timeinfo) ); + + if (strlen(line_response)>(sizeof(sentBuffer)-strlen(sentBuffer))) { //buffer must be sent + send_HTML_line(sentBuffer, strlen(sentBuffer)); + sentBuffer[0]=NULL; //clear buffer + } + snprintf(&(sentBuffer[strlen(sentBuffer)]),sizeof(sentBuffer),"%s",line_response); //append to buffer + } + } + send_HTML_line(sentBuffer, strlen(sentBuffer)); + closedir(d); + + sprintf(line_response, "</table>\n<br><h4>mbed HTTP File Server</h4>\n</center></body></html>\n"); + send_HTML_line(line_response, strlen(line_response)); + + return 0; +} + +void parseHTTPRequest(char* buffer) +{ + char spacePos; + char *tmpBuffer; + spacePos = strcspn(buffer, " ") + 1; //position of first space character + snprintf(sMethod, spacePos,"%s", buffer); + + //get Protocol + tmpBuffer=&(buffer[spacePos]); //move pointer to buffer (delete Method) + spacePos = strcspn(tmpBuffer, "\r\n") + 1; + tmpBuffer[spacePos]='\0'; //set end of string ...cut + sprintf(sProtocol, "%s", strrchr(tmpBuffer,' ')); //get string after last (space ) + printf("\r\nsProtocol:%s", tmpBuffer); + buffer = &(sProtocol[1]); //cut first character (space) + sprintf(sProtocol, "%s", buffer); + + //get URL + snprintf(sURL,strlen(tmpBuffer)-strlen(sProtocol),"%s\r\n", tmpBuffer); //URL is between Method and Protocol + + printf("\nParse Method:%s",sMethod); + printf("\nParse URL:%s",sURL); + printf("\nParse PROTOCOL:%s",sProtocol); + printf("\n\r\n"); +} + +int processHTTP(char* sMethod, char* sURL, char* sProtocol) +{ + int gdi, gfi; //status of get_dir_info(xxx), and get_file_info(xxx) + + if (strcmp(sMethod,"GET")!=0) { + send_HTML_error( 501, "501 Not Implemented", "501 - The server either does not recognize the request method"); + return 501; + } + if (sURL[0]!= '/') { + send_HTML_error( 400, "Bad Request", "400 - The request cannot be fulfilled due to bad syntax."); + return 400; + } + if (sURL[strlen(sURL)-1]=='/') { + sURL[strlen(sURL)-1]=sURL[strlen(sURL)]; //delete last symbol + if (EnDebugMSG) + printf("\n delete last:%s",sURL); + } + gdi= get_dirInfo(sURL); + gfi= get_fileInfo(sURL); + if (gfi!=0) { //!=0 file not found + if (gdi==0) { //0-ok this is directory + return send_directory(sURL); + } + if (EnDebugMSG) + printf("\n404-br File not found or...(Fresult is:%d)",gfi); + send_HTML_error( 404, "Not Found","404 - The requested resource could not be found."); + return 404; + } else { //==0 found + if (gdi==0) //0-ok this is directory + return send_directory(sURL); + else + return send_file(sURL); + } +} + +int main() +{ + + + ledTick.attach(&ledTickfunc,0.5); + //ledTick.detach(); + //setup ethernet interface + //eth.init(); //Use DHCP + eth.init(IP,MASK,GATEWAY); //IP,mask,Gateway + eth.connect(); + printf("IP Address is %s\n\r", eth.getIPAddress()); + + //setup tcp socket + if(svr.bind(PORT)< 0) { + printf("tcp server bind failed.\n\r"); + return -1; + } else { + printf("tcp server bind successed.\n\r"); + serverIsListened = true; + } + + if(svr.listen(1) < 0) { + printf("tcp server listen failed.\n\r"); + return -1; + } else { + printf("tcp server is listening...\n\r"); + } + + //listening for http GET request + while (serverIsListened) { + //blocking mode(never timeout) + if(svr.accept(client)<0) { + printf("failed to accept connection.\n\r"); + } else { + //client.set_blocking(false,5000); //5000=5sec + printf("connection success!\n\rIP: %s\n\r",client.get_address()); + clientIsConnected = true; + led2 = true; + while(clientIsConnected) { + char buffer[1024] = {}; + switch(client.receive(buffer, 1023)) { + case 0: + printf("recieved buffer is empty.\n\r"); + clientIsConnected = false; + break; + case -1: + printf("failed to read data from client.\n\r"); + clientIsConnected = false; + break; + default: + printf("Recieved Data: %d\n\r\n\r%.*s\n\r",strlen(buffer),strlen(buffer),buffer); + parseHTTPRequest(buffer); + //if(buffer[0] == 'G' && buffer[1] == 'E' && buffer[2] == 'T' ) { + if (strcmp(sMethod, "GET" ) == 0 ) { + printf("GET request incomming.\n\r"); + processHTTP(sMethod, sURL, sProtocol); + clientIsConnected = false; + }//if get + break; + } //switch + //ledTick.attach(&ledTickfunc,0.5); + }//while + printf("close connection.\n\rHTTP server is listening...\n\r\n"); + client.close(); + Thread::wait(50); + led2 = false; + } + } + +}
diff -r 000000000000 -r fbb29d9ea96b mbed-rtos.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#53e6cccd8782
diff -r 000000000000 -r fbb29d9ea96b mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Apr 07 11:23:03 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/5e5da4a5990b \ No newline at end of file