diff --git a/DemoWeb/DemoWeb.csproj b/DemoWeb/DemoWeb.csproj index 510a8b1..51b28a0 100644 --- a/DemoWeb/DemoWeb.csproj +++ b/DemoWeb/DemoWeb.csproj @@ -40,6 +40,7 @@ + @@ -49,6 +50,7 @@ + @@ -60,8 +62,14 @@ + + + + {66F7DA1E-2931-4E24-81F7-471B08488B96} + NetduinoSDCard + {6BFC7545-24EF-4C5B-9EDE-3EC99CDB86E4} Rinsen.WebServer diff --git a/DemoWeb/FilesController.cs b/DemoWeb/FilesController.cs new file mode 100644 index 0000000..727afa2 --- /dev/null +++ b/DemoWeb/FilesController.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.SPOT; + +using Rinsen.WebServer.FileAndDirectoryServer; +using Rinsen.WebServer; + +namespace DemoWeb +{ + public class FilesController : FileController + { + public void Index() + { + this.SDCardManager = new SDCardManager(Program.WORKINGDIRECTORY); + string strHTML = string.Empty; + + + try + { + strHTML = SDCardManager.ReadTextFile(SDCardManager.GetWorkingDirectoryPath() + "filemanager.html"); + strHTML = strHTML.Substring(1, strHTML.Length - 2); //If I don't remove the first character then the page doesn't get rendered as html... + } + catch (Exception objEx) + { + Debug.Print("Exception caught in FilesController:\r\n" + objEx.Message); + } + + SetHtmlResult(strHTML); + } + + public void Upload() + { + this.SDCardManager = new SDCardManager(Program.WORKINGDIRECTORY); + + if (HttpContext.Request.Method == HTTPMethod.Post) + { + var doFileUpload = RecieveFiles(); + + SetJsonResult(new Result { Success = true, Message = "Files Recieved!" }); + } + } + } +} diff --git a/DemoWeb/Program.cs b/DemoWeb/Program.cs index f60a9d0..6cee87a 100644 --- a/DemoWeb/Program.cs +++ b/DemoWeb/Program.cs @@ -4,14 +4,20 @@ namespace DemoWeb { public class Program { + public const string WORKINGDIRECTORY = @"\WWW"; + public static void Main() { // write your code here var webServer = new WebServer(); webServer.AddRequestFilter(new RequestFilter()); + var fileAndDirectoryService = new FileAndDirectoryService(); + fileAndDirectoryService.SetSDCardManager(new SDCardManager(WORKINGDIRECTORY)); webServer.SetFileAndDirectoryService(new FileAndDirectoryService()); - webServer.RouteTable.DefaultControllerName = "Default"; - webServer.StartServer(); + /*By not setting a default Controller, the root web directory (set with WORKINGDIRECTORY) will have it's contents listed + * with the FileAndDirectoryServer library */ + //webServer.RouteTable.DefaultControllerName = "Default"; + webServer.StartServer(80); } } } \ No newline at end of file diff --git a/DemoWeb/SDCardManager.cs b/DemoWeb/SDCardManager.cs new file mode 100644 index 0000000..49b2b00 --- /dev/null +++ b/DemoWeb/SDCardManager.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.SPOT; + +using Rinsen.WebServer.FileAndDirectoryServer; + +namespace DemoWeb +{ + public class SDCardManager : NetduinoSDCard.SDCard, ISDCardManager + { + public SDCardManager(string WorkingDirectory) + : base(WorkingDirectory) {} + } +} diff --git a/NetduinoSDCard/ConsoleWrite.cs b/NetduinoSDCard/ConsoleWrite.cs new file mode 100644 index 0000000..8e89f6b --- /dev/null +++ b/NetduinoSDCard/ConsoleWrite.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.SPOT; + +namespace NetduinoSDCard +{ + public class ConsoleWrite // todo this should be moved to a general library. + { + public static Object _PrintLock = new Object(); + public static Object _GCLock = new Object(); + + public static void Print(string message) + { + lock (_PrintLock) + { + Debug.Print(message); + } + } + + public static uint MemoryCollect(bool force) + { + uint freeMemory = 0; + lock (_GCLock) + { + freeMemory = Microsoft.SPOT.Debug.GC(force); + } + return freeMemory; + } + + public static void CollectMemoryAndPrint(bool force, int id) + { + uint freeMemory = MemoryCollect(force); + Print("Memory: " + freeMemory.ToString() + ", release workerid: " + id.ToString()); + + } + } +} diff --git a/NetduinoSDCard/NetduinoSDCard.csproj b/NetduinoSDCard/NetduinoSDCard.csproj new file mode 100644 index 0000000..f9c1024 --- /dev/null +++ b/NetduinoSDCard/NetduinoSDCard.csproj @@ -0,0 +1,47 @@ + + + + NetduinoSDCard + Exe + NetduinoSDCard + {b69e3092-b931-443c-abe7-7e7b65f2a37f};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 9.0.21022 + 2.0 + {66F7DA1E-2931-4E24-81F7-471B08488B96} + v4.3 + $(MSBuildExtensionsPath32)\Microsoft\.NET Micro Framework\ + Netduino + USB + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetduinoSDCard/Program.cs b/NetduinoSDCard/Program.cs new file mode 100644 index 0000000..51fc6ce --- /dev/null +++ b/NetduinoSDCard/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Microsoft.SPOT; +using Microsoft.SPOT.Hardware; +using SecretLabs.NETMF.Hardware; +using SecretLabs.NETMF.Hardware.Netduino; + +namespace NetduinoSDCard +{ + public class Program + { + public static void Main() + { + // write your code here + + + } + + } +} diff --git a/NetduinoSDCard/Properties/AssemblyInfo.cs b/NetduinoSDCard/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..00e30ca --- /dev/null +++ b/NetduinoSDCard/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NetduinoSDCard")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NetduinoSDCard")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NetduinoSDCard/SDCard.cs b/NetduinoSDCard/SDCard.cs new file mode 100644 index 0000000..789d93c --- /dev/null +++ b/NetduinoSDCard/SDCard.cs @@ -0,0 +1,261 @@ +using System; +using System.Net; +using System.IO; +using System.Net.Sockets; +using System.Text; + +namespace NetduinoSDCard +{ + public delegate void BytesDelegate(byte[] data); + + + public class SDCard // todo web log and error log + { + const int READ_CHUNK_SIZE = 1500;// + const int WRITE_CHUNK_SIZE = 1500;// + + public static Object SDCardLock = new Object(); + public const string MountDirectoryPath = @"\SD"; + + public SDCard() + { + } + public SDCard(string WorkingDirectory) + { + SetWorkingDirectoryInfo(WorkingDirectory); + } + + public DirectoryInfo WorkingDirectoryInfo { get; set; } + public void SetWorkingDirectoryInfo(string WorkingDirectory) + { + string strPath = string.Empty; + + + if (WorkingDirectory.LastIndexOf("\\") == WorkingDirectory.Length - 1) + strPath = MountDirectoryPath + WorkingDirectory; + else + strPath = MountDirectoryPath + WorkingDirectory + "\\"; + + CreateDirectory(strPath); + WorkingDirectoryInfo = new DirectoryInfo(strPath); + } + + public string GetWorkingDirectoryPath() + { + if (WorkingDirectoryInfo == null) + return MountDirectoryPath; + else + return WorkingDirectoryInfo.FullName + "\\"; + } + + public static string GetFullDirectoryPath(string folderName) + { + return MountDirectoryPath + folderName; + } + + public static string GetFileFullPath(string fileName)// todo allow for trailing slash on f + { + return MountDirectoryPath + "\\" + fileName; + } + + public static string GetFileFullPath(string directoryPath, string fileName) + { + if (directoryPath.LastIndexOf('\\') == directoryPath.Length - 1) + { + return MountDirectoryPath + fileName; + } + else + { + return directoryPath + "\\" + fileName; + } + } + + public static string GetFullPathFromUri(string uri) + { + return MountDirectoryPath + PathToBackSlash(uri); + } + + public void CreateFile(string path, string fileName)// needs trailing slash + { + string fileFullPath = path + fileName; + CreateDirectory(path); + lock (SDCardLock) + { + if (!File.Exists(path + fileName)) + { + FileStream fs = File.Create(fileFullPath); + fs.Close(); + } + } + } + + public void CreateDirectory(string fullPath) + { + lock (SDCardLock) + { + if (!Directory.Exists(fullPath)) + { + DirectoryInfo directoryInfo = Directory.CreateDirectory(fullPath); + } + } + } + + public bool WriteLine(string path, string fileName, FileMode fileMode, string text) + { + return Write(path, fileName, fileMode, text + "\n");// todo \r\n?? + } + + public bool Write(string path, string fileName, FileMode fileMode, string text) + { + byte[] buffer = Encoding.UTF8.GetBytes(text); + return Write(path, fileName, fileMode, buffer, buffer.Length); + } + + public bool Write(string path, string fileName, FileMode fileMode, byte[] bytes, int length) + { + string fileFullPath = path + fileName; + CreateFile(path, fileName); + lock (SDCardLock) + { + FileStream fs = new FileStream(fileFullPath, fileMode, FileAccess.Write, FileShare.None, length);// todo make buffersize a constant somewhere + fs.Write(bytes, 0, length); + fs.Close(); + } + return true; + } + + public bool WriteLines(string path, string fileName, string[] lines) + { + string fileFullPath = path + fileName; + CreateFile(path, fileName); + lock (SDCardLock) + { + FileStream fs = new FileStream(fileFullPath, FileMode.Append, FileAccess.Write, FileShare.None, WRITE_CHUNK_SIZE); + for (int i = 0; i < lines.Length - 1; i++) + { + var buf = Encoding.UTF8.GetBytes(lines[i] + "\r\n"); + fs.Write(buf, 0, buf.Length); + } + fs.Close(); + } + return true; + } + //http://forums.netduino.com/index.php?/topic/2394-memory-efficient-way-to-enumerate-an-array-of-fileinfo/page__p__16985__hl__%2Bsdcard+%2Benumerate__fromsearch__1#entry16985 + + public string ReadLine(string fullPath) + { + var FileContents = string.Empty; + + ConsoleWrite.Print("Reading file: " + fullPath); + lock (SDCardLock) + { + if (File.Exists(fullPath)) + using (StreamReader objStreamReader = new StreamReader(fullPath)) + FileContents = objStreamReader.ReadLine(); + else + throw new IOException("File Not Found!"); + } + return FileContents; + + } + + public string ReadTextFile(string fullPath) + { + var FileContents = string.Empty; + + ConsoleWrite.Print("Reading file: " + fullPath); + lock (SDCardLock) + { + if (File.Exists(fullPath)) + using (StreamReader objStreamReader = new StreamReader(fullPath)) + FileContents = objStreamReader.ReadToEnd(); + else + throw new IOException("File Not Found!"); + } + return FileContents; + } + + public void SendFile(string fullPath, Socket socket) + { + ConsoleWrite.Print("Reading file: " + fullPath); + bool chunkHasBeenRead = false; + int totalBytesRead = 0; + lock (SDCardLock) + { + if (File.Exists(fullPath)) + { + using (FileStream inputStream = new FileStream(fullPath, FileMode.Open)) + { + byte[] readBuffer = new byte[READ_CHUNK_SIZE]; + while (true) + { + // Send the file a few bytes at a time + int bytesRead = inputStream.Read(readBuffer, 0, readBuffer.Length); + if (bytesRead == 0) + break; + socket.Send(readBuffer, 0, bytesRead, SocketFlags.None); + //sendDataCallback(readBuffer); + totalBytesRead += bytesRead; + } + } + chunkHasBeenRead = true; + } + else + { + chunkHasBeenRead = false; + } + } + if (chunkHasBeenRead == true) + ConsoleWrite.Print("Sending " + totalBytesRead.ToString() + " bytes..."); + else + ConsoleWrite.Print("Failed to read chunk, full path: " + fullPath); + } + + public static string Replace(string input, char[] oldText, string newText) + { + string result = ""; + string[] split = input.Split(oldText); + for (int i = 0; i < split.Length - 1; i++) + { + result += split[i] + newText; + } + result += split[split.Length - 1]; + return result; + } + + public static string PathToBackSlash(string input) + { + string result = Replace(input, new char[] { '/' }, "\\"); + return result; + } + + public long GetFileSize(string directoryPath, string fileName) + { + long result = 0; + // ConsoleWrite.Print("Get File Size: " + fileNameAndPath); + lock (SDCardLock) + { + string fileNameAndPath = GetFileFullPath(directoryPath, fileName); + if (Directory.Exists(directoryPath)) + { + if (File.Exists(fileNameAndPath)) + { + using (FileStream inputStream = new FileStream(fileNameAndPath, FileMode.Open)) + { + result = inputStream.Length; + } + } + } + } + return result; + } + public long GetFileSize(string fileNameAndPath) + { + int lastIndexOf = fileNameAndPath.LastIndexOf('\\'); + string directoryName = fileNameAndPath.Substring(0, lastIndexOf); + string fileName = fileNameAndPath.Substring(lastIndexOf + 1); + return GetFileSize(directoryName, fileName); + } + + } +} diff --git a/Rinsen.WebServer.FileAndDirectoryServer/BoundaryHeaderCollection.cs b/Rinsen.WebServer.FileAndDirectoryServer/BoundaryHeaderCollection.cs new file mode 100644 index 0000000..bc4a8c9 --- /dev/null +++ b/Rinsen.WebServer.FileAndDirectoryServer/BoundaryHeaderCollection.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.SPOT; + +using System.Collections; + + +namespace Rinsen.WebServer.FileAndDirectoryServer +{ + public class BoundaryHeaderCollection : Hashtable + { + public BoundaryHeaderCollection():base(){} + + public BoundaryHeaderCollection(string HeaderData) + : base() + { + var arrHeaders = HeaderData.Trim().Split('\n'); + foreach (var strLine in arrHeaders) + { + var arrHeaderKeyValue = strLine.Split(':'); + Add(arrHeaderKeyValue[0].Trim().ToLower(), arrHeaderKeyValue[1]); + } + } + + //public BoundaryHeaderCollection(string HeaderData) + // : base() + //{ + // var arrHeaders = HeaderData.Trim().Split('\n'); + // foreach (var strLine in arrHeaders) + // { + // Debug.Print("Header: " + strLine); + // var arrHeaderKeyValue = strLine.Split(':'); + // var arrSubKeys = arrHeaderKeyValue[1].Split(';'); + // var arrSubKeyKeyValues = new Hashtable(); + // foreach (var strValue in arrSubKeys) + // { + // Debug.Print("Subkey: " + strValue); + // if (strValue.IndexOf(';') != -1) + // { + // var arrTemp = strValue.Split(';'); + // arrSubKeyKeyValues.Add(arrTemp[0].Trim(), arrTemp[1]); + // } + // else + // arrSubKeyKeyValues.Add(strValue.Trim(), string.Empty); + // } + // Add(arrHeaderKeyValue[0].Trim(), arrSubKeyKeyValues); + // } + //} + } +} diff --git a/Rinsen.WebServer.FileAndDirectoryServer/FileAndDirectoryService.cs b/Rinsen.WebServer.FileAndDirectoryServer/FileAndDirectoryService.cs index 0e1b468..0ef727b 100644 --- a/Rinsen.WebServer.FileAndDirectoryServer/FileAndDirectoryService.cs +++ b/Rinsen.WebServer.FileAndDirectoryServer/FileAndDirectoryService.cs @@ -1,48 +1,56 @@ using Rinsen.WebServer.Http; using System.IO; using System.Net.Sockets; + +using System.Collections; +using Microsoft.SPOT; + namespace Rinsen.WebServer.FileAndDirectoryServer { public class FileAndDirectoryService : IFileAndDirectoryService { + private static ISDCardManager SDCardManager { get; set; } + public void SetFileNameAndPathIfFileExists(ServerContext serverContext, HttpContext httpContext) { + var contentType = httpContext.Response.ContentType; var fileFullName = serverContext.FileServerBasePath + httpContext.Request.Uri.LocalPath; - string contentType = string.Empty; - - if (fileFullName.IndexOf(".htm") != -1 || fileFullName.IndexOf(".HTM") != -1 || fileFullName.IndexOf(".html") != -1 || fileFullName.IndexOf(".HTML") != -1) + if (fileFullName.ToUpper().IndexOf(".HTM") != -1 || fileFullName.ToUpper().IndexOf(".HTML") != -1) { - contentType = "text/html"; + contentType = new ContentType { MainContentType = EnumMainContentType.Text, SubContentType = EnumSubContentType.Html }; } - else if (fileFullName.IndexOf(".css") != -1 || fileFullName.IndexOf(".CSS") != -1) + else if (fileFullName.ToUpper().IndexOf(".CSS") != -1) { - contentType = "text/css"; + contentType = new ContentType { MainContentType = EnumMainContentType.Text, SubContentType = EnumSubContentType.Css }; } - else if (fileFullName.IndexOf(".txt") != -1 || fileFullName.IndexOf(".TXT") != -1) + else if (fileFullName.ToUpper().IndexOf(".TXT") != -1) { - contentType = "text/plain"; + contentType = new ContentType { MainContentType = EnumMainContentType.Text, SubContentType = EnumSubContentType.Plain }; } - else if (fileFullName.IndexOf(".jpg") != -1 || fileFullName.IndexOf(".JPG") != -1 || - fileFullName.IndexOf(".bmp") != -1 || fileFullName.IndexOf(".BMP") != -1 || - fileFullName.IndexOf(".jpeg") != -1 || fileFullName.IndexOf(".JPEG") != -1) + else if (fileFullName.ToUpper().IndexOf(".JPG") != -1 || + fileFullName.ToUpper().IndexOf(".BMP") != -1 || + fileFullName.ToUpper().IndexOf(".JPEG") != -1) { - contentType = "image/jpeg"; + contentType = new ContentType { MainContentType = EnumMainContentType.Image, SubContentType = EnumSubContentType.Jpeg }; } - else if (fileFullName.IndexOf(".js") != -1 || fileFullName.IndexOf(".JS") != -1) + else if (fileFullName.ToUpper().IndexOf(".JS") != -1) { - contentType = "text/javascript"; + //note this was text/javascript; I updated because it was obsoleted in favor of application/javascript + contentType = new ContentType { MainContentType = EnumMainContentType.Application, SubContentType = EnumSubContentType.JavaScript }; } - if (contentType != string.Empty) + if (contentType != null) { + Debug.Print("Set Content Type: " + contentType); httpContext.Response.ContentType = contentType; } else { + Debug.Print("No Matching Content Type set... " + contentType); return; } - + if (File.Exists(fileFullName)) { var files = new DirectoryInfo(fileFullName.Substring(0, fileFullName.LastIndexOf('\\'))).GetFiles(); @@ -60,24 +68,7 @@ public void SetFileNameAndPathIfFileExists(ServerContext serverContext, HttpCont public void SendFile(ServerContext serverContext, HttpContext httpContext) { - using (var fileStream = new FileStream(httpContext.Response.FileFullName, FileMode.Open, FileAccess.Read, FileShare.None)) - { - var fileLength = fileStream.Length; - byte[] buf = new byte[2048]; - for (long bytesSent = 0; bytesSent < fileLength; ) - { - // Determines amount of data left. - long bytesToRead = fileLength - bytesSent; - bytesToRead = bytesToRead < 2048 ? bytesToRead : 2048; - // Reads the data. - fileStream.Read(buf, 0, (int)bytesToRead); - // Writes data to browser - httpContext.Socket.Send(buf, 0, (int)bytesToRead, SocketFlags.None); - - // Updates bytes read. - bytesSent += bytesToRead; - } - } + SDCardManager.SendFile(httpContext.Response.FileFullName, httpContext.Socket); } public bool TryGetDirectoryResultIfDirectoryExists(ServerContext serverContext, HttpContext httpContext) @@ -90,30 +81,49 @@ public bool TryGetDirectoryResultIfDirectoryExists(ServerContext serverContext, DirectoryInfo[] directories = rootDirectory.GetDirectories(); FileInfo[] files = rootDirectory.GetFiles(); httpContext.Response.Data = new DirectoryListBuilder().GenerateSimpleDirectoryList(httpContext.Request.Uri.RawPath, directories, files, serverContext.HostName); - httpContext.Response.ContentType = "text/html"; + httpContext.Response.ContentType = new ContentType { MainContentType = EnumMainContentType.Text, SubContentType = EnumSubContentType.Html }; return true; } return false; } - public string GetFileServiceBasePath() { - string basePath = "\\SD\\WWW"; + string basePath = string.Empty; + + Debug.Print("Setting File Services Base Path..." + "\r\nHas an SDCard Manager: " + HasSDCardManager); + if (HasSDCardManager) + { + basePath = SDCardManager.GetWorkingDirectoryPath().TrimEnd(new char[] { '\\' }); + Debug.Print("Base path is: " + basePath); + return basePath; + } + + basePath = "\\SD\\WWW"; var directory = new DirectoryInfo(basePath); if (directory.Exists) { + Microsoft.SPOT.Debug.Print("Base path is: " + basePath); return basePath; } - + basePath = "\\WINFS\\WWW"; directory = new DirectoryInfo(basePath); if (directory.Exists) { + Debug.Print("Base path is: " + basePath); return basePath; } + Debug.Print("No Base Path Set..."); return string.Empty; } + + public void SetSDCardManager(ISDCardManager sdCardManager) + { + SDCardManager = sdCardManager; + } + + public bool HasSDCardManager { get { return SDCardManager != null; } } } } diff --git a/Rinsen.WebServer.FileAndDirectoryServer/FileController.cs b/Rinsen.WebServer.FileAndDirectoryServer/FileController.cs new file mode 100644 index 0000000..b3c5053 --- /dev/null +++ b/Rinsen.WebServer.FileAndDirectoryServer/FileController.cs @@ -0,0 +1,171 @@ +using System; +using Microsoft.SPOT; + +using System.Collections; +using System.Text.RegularExpressions; +using System.Text; +using Rinsen.WebServer.Collections; +using Rinsen.WebServer.Extensions; + + +namespace Rinsen.WebServer.FileAndDirectoryServer +{ + public class FileController : Controller + { + public ISDCardManager SDCardManager { get; set; } + //private const int _PostRxBufferSize = 1500; + + public FormCollection RecieveFiles() + { + var request = HttpContext.Request; + + + + if (request.Method == HTTPMethod.Post && + request.ContentType.MainContentType == EnumMainContentType.MultiPart && + request.ContentType.SubContentType == EnumSubContentType.FormData) + { + var contentLengthFromHeader = int.Parse(request.Headers["Content-Length"].ToString()); + var contentLengthReceived = 0; + var PostedData = new FormCollection(); + var socket = HttpContext.Socket; + var allDataRecieved = false; + var receivedByteCount = 0; + var buffer = new byte[2048]; //The size of this array essentially sets the read rate... + var fileDirectoryPath = SDCardManager.GetWorkingDirectoryPath(); + var boundaryBytes = Encoding.UTF8.GetBytes(request.Boundary); + var BeginningboundaryBytes = Encoding.UTF8.GetBytes("\r\n-----"); + var strBldrBoundaryHeader = new StringBuilder(); + var strBldrBoundaryData = new StringBuilder(); + StringBuilder strBldr = new StringBuilder(); + var BoundaryDataSeparator = Encoding.UTF8.GetBytes("\r\n\r\n"); //a double newline delimits Boundary Headers from Boundary Data... + var BoundaryDataIndex = 0; + Regex rx = new Regex("([^=\\s]+)=\"([^\"]*)\""); //matches key value pairs like the below... + //var Value = "key1=\"value1\" key2=\"value 2\" key3=\"value3\" key4=\"value4\" key5=\"5555\" key6=\"xxx666\""; + + + Debug.Print("Boundary is: " + request.Boundary); //The Boundary property will be populated if it is multipart/form-data + Debug.Print("Reading Bytes..."); + socket.ReceiveUntil(buffer, boundaryBytes, out receivedByteCount, true); //Discard the first Boundary Read... + + while (!allDataRecieved) + { + contentLengthReceived += receivedByteCount; + Debug.Print("Bytes Read: " + receivedByteCount + + "\r\nTotal Bytes Read: " + contentLengthReceived + + "\r\nTotal Bytes To Read: " + contentLengthFromHeader); + + if (contentLengthReceived < contentLengthFromHeader) + { + Debug.Print("Reading Bytes..."); + socket.ReceiveUntil(buffer, boundaryBytes, out receivedByteCount, true); + BoundaryDataIndex = buffer.IndexOf(BoundaryDataSeparator); + //Debug.Print("Boundary Data Index: " + BoundaryDataIndex); + + /*The end of the multipart form is denoted by the boundary data followed by -- and a Carriage Return Line Feed (ex -----------------------------42291685921978--) + * Since I read until the the Boundary Data, I loop until only those characters are found; I do a check for null bytes just to make sure.*/ + if (buffer.IndexOf(Encoding.UTF8.GetBytes("--\r\n")) == 0 && buffer[5] == default(byte)) + { + Debug.Print("You've reached the end of the multipart form! "); + continue; + } + + strBldrBoundaryHeader.Clear(); + strBldrBoundaryHeader.Append(Encoding.UTF8.GetChars(buffer.SubArray(0, BoundaryDataIndex + 1))); + //Debug.Print("Boundary Header: \r\n" + strBldrBoundaryHeader.ToString().ToString().Trim()); + + var objBoundaryHeaderCollection = new BoundaryHeaderCollection(strBldrBoundaryHeader.ToString()); + + strBldr.Clear(); + strBldr.Append(objBoundaryHeaderCollection["Content-Disposition".ToLower()]); //I store all keys in lowercase... + //Debug.Print("Content-Disposition Value: " + strBldr); + var KeyValuePairs = new Hashtable(); + foreach (Match m in rx.Matches(strBldr.ToString())) + { + Debug.Print("Found KeyValue Pair:" + + "\r\n\tKey: " + m.Groups[1] + + "\r\n\tValue: " + m.Groups[2]); + KeyValuePairs.Add(m.Groups[1].ToString().ToLower(), m.Groups[2]); + + } + + + if (objBoundaryHeaderCollection.Contains("Content-Type".ToLower()))//write Boundary Data to File... + { + strBldr.Clear();//Get the value portion of the Content-Type Boundary Header + strBldr.Append(objBoundaryHeaderCollection["Content-Type".ToLower()]); //I store all keys in lowercase... + Debug.Print("I've got a file and the Content-Type is: " + strBldr.ToString()); + + //Get the file's name from the KeyValuePairs... + string fileName = string.Empty; + if (KeyValuePairs.Contains("filename")) //JQuery ajax post (from ) sends filename parameter containing file's name; the name property is left as defined in the html. + fileName = KeyValuePairs["filename"].ToString(); + else if (KeyValuePairs.Contains("name")) //Form Post sends name parameter containing file's name (no filename parameter is sent) + fileName = KeyValuePairs["name"].ToString(); + else + fileName = "Unknown.txt"; + Debug.Print("File name is set to: " + fileName); + + + + if (buffer.IndexOf(boundaryBytes) == -1) //Write to file, loop to get remaining file data + { + var BoundaryData = buffer.SubArray(BoundaryDataIndex + BoundaryDataSeparator.Length, receivedByteCount - BoundaryDataIndex - BoundaryDataSeparator.Length); + var intTemp = receivedByteCount; + SDCardManager.Write(fileDirectoryPath, fileName, System.IO.FileMode.Create, BoundaryData, BoundaryData.Length); + while (buffer.IndexOf(boundaryBytes) == -1) //boundary hasn't been reached, get more data... + { + Debug.Print("Getting more File data..."); + socket.ReceiveUntil(buffer, boundaryBytes, out receivedByteCount, true); + if (buffer.IndexOf(boundaryBytes) != -1)//remove boundary string here before you have written to a file... + { + var intBeginningBoundaryBytesIndex = buffer.IndexOf(BeginningboundaryBytes); + var Data = buffer.SubArray(0, intBeginningBoundaryBytesIndex); + SDCardManager.Write(fileDirectoryPath, fileName, System.IO.FileMode.Append, Data, Data.Length); + } + else + SDCardManager.Write(fileDirectoryPath, fileName, System.IO.FileMode.Append, buffer, receivedByteCount); + intTemp += receivedByteCount; + Debug.Print("Iterated a loop and Recieved: " + receivedByteCount + " Bytes..."); + } + + receivedByteCount = intTemp; + } + else //remove boundary string, write to file and exit... + { + var BoundaryData = buffer.SubArray(BoundaryDataIndex + BoundaryDataSeparator.Length, receivedByteCount - BoundaryDataIndex - BoundaryDataSeparator.Length + 1); + var intBeginningBoundaryBytesIndex = BoundaryData.IndexOf(BeginningboundaryBytes); + var Data = BoundaryData.SubArray(0, intBeginningBoundaryBytesIndex); + SDCardManager.Write(fileDirectoryPath, fileName, System.IO.FileMode.Append, Data, Data.Length); + } + } + else //add the 'name' value and BoundaryData to the PostedData FormCollection object... + { + strBldrBoundaryData.Clear(); + strBldrBoundaryData.Append(Encoding.UTF8.GetChars(buffer.SubArray(BoundaryDataIndex + BoundaryDataSeparator.Length, buffer.Length - BoundaryDataIndex - BoundaryDataSeparator.Length))); + //Debug.Print("Boundary Data: \r\n" + strBldrBoundaryData.ToString()); + + var strBoundaryData = strBldrBoundaryData.ToString(); + if (KeyValuePairs.Contains("name")) + PostedData.AddValue(KeyValuePairs["name"].ToString(), strBoundaryData.Substring(0, strBoundaryData.IndexOf('\n'))); + Debug.Print("Added Key/Value Pair to PostedData FormCollection..."); + } + + + + + //var data = socket.GetMoreBytes(2048, out receivedByteCount); + //SDCardManager.Write(fileDirectoryPath, "Test.txt", System.IO.FileMode.Append, data, receivedByteCount); + + } + else + allDataRecieved = true; + } + + return PostedData; + } + + throw new NotSupportedException("Only POST is supported"); + } + } +} diff --git a/Rinsen.WebServer.FileAndDirectoryServer/ISDCardManager.cs b/Rinsen.WebServer.FileAndDirectoryServer/ISDCardManager.cs new file mode 100644 index 0000000..5618fde --- /dev/null +++ b/Rinsen.WebServer.FileAndDirectoryServer/ISDCardManager.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.SPOT; + +using System.Net.Sockets; +using System.IO; + +namespace Rinsen.WebServer.FileAndDirectoryServer +{ + public interface ISDCardManager + { + string GetWorkingDirectoryPath(); + + void SendFile(string fullPath, Socket socket); + + bool Write(string path, string fileName, FileMode fileMode, string text); + + bool Write(string path, string fileName, FileMode fileMode, byte[] bytes, int length); + + string ReadTextFile(string fullPath); + } +} diff --git a/Rinsen.WebServer.FileAndDirectoryServer/Rinsen.WebServer.FileAndDirectoryServer.csproj b/Rinsen.WebServer.FileAndDirectoryServer/Rinsen.WebServer.FileAndDirectoryServer.csproj index f1b0a8a..cd45444 100644 --- a/Rinsen.WebServer.FileAndDirectoryServer/Rinsen.WebServer.FileAndDirectoryServer.csproj +++ b/Rinsen.WebServer.FileAndDirectoryServer/Rinsen.WebServer.FileAndDirectoryServer.csproj @@ -34,15 +34,18 @@ + + + - - + + diff --git a/Rinsen.WebServer.UnitTests/Rinsen.WebServer.UnitTests.csproj b/Rinsen.WebServer.UnitTests/Rinsen.WebServer.UnitTests.csproj index ae4e967..34e5696 100644 --- a/Rinsen.WebServer.UnitTests/Rinsen.WebServer.UnitTests.csproj +++ b/Rinsen.WebServer.UnitTests/Rinsen.WebServer.UnitTests.csproj @@ -48,6 +48,10 @@ + + ..\packages\Json.NetMF.1.3.0.0\lib\netmf43\Json.NetMF.dll + True + ..\packages\MFUnit.0.4\lib\netmf43\MFUnit.dll diff --git a/Rinsen.WebServer.UnitTests/packages.config b/Rinsen.WebServer.UnitTests/packages.config index 9d0705a..8ac6c1b 100644 --- a/Rinsen.WebServer.UnitTests/packages.config +++ b/Rinsen.WebServer.UnitTests/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/Rinsen.WebServer/ContentType.cs b/Rinsen.WebServer/ContentType.cs new file mode 100644 index 0000000..a270af3 --- /dev/null +++ b/Rinsen.WebServer/ContentType.cs @@ -0,0 +1,46 @@ +using System; +using Microsoft.SPOT; + +using Rinsen.WebServer.Extensions; + + +namespace Rinsen.WebServer +{ + public enum EnumMainContentType + { + Application, + Audio, + Example, + Image, + Message, + Model, + MultiPart, + Text, + Video, + Undefined + } + + public enum EnumSubContentType + { + FormData, + Json, + Html, + Css, + Plain, + Jpeg, + JavaScript, + Undefined + } + + //per http://www.iana.org/assignments/media-types/media-types.xhtml + public class ContentType + { + public EnumMainContentType MainContentType { get; set; } + public EnumSubContentType SubContentType { get; set; } + + public override string ToString() + { + return MainContentType.GetName() + "/" + SubContentType.GetName(); + } + } +} diff --git a/Rinsen.WebServer/Controller.cs b/Rinsen.WebServer/Controller.cs index b66cd17..aa0c864 100644 --- a/Rinsen.WebServer/Controller.cs +++ b/Rinsen.WebServer/Controller.cs @@ -24,13 +24,13 @@ public void InitializeController(HttpContext httpContext, IJsonSerializer jsonSe public void SetHtmlResult(string data) { - HttpContext.Response.ContentType = "text/html"; + HttpContext.Response.ContentType = new ContentType { MainContentType = EnumMainContentType.Text, SubContentType = EnumSubContentType.Html }; HttpContext.Response.Data = data; } public void SetJsonResult(object objectToSerialize) { - HttpContext.Response.ContentType = "application/json"; + HttpContext.Response.ContentType = new ContentType { MainContentType = EnumMainContentType.Application, SubContentType = EnumSubContentType.Json }; HttpContext.Response.Data = JsonSerializer.Serialize(objectToSerialize); } @@ -40,11 +40,11 @@ public void SetJsonResult(object objectToSerialize) /// public FormCollection GetFormCollection() { - if (HttpContext.Request.Method == "GET") + if (HttpContext.Request.Method == HTTPMethod.Get) { return new FormCollection(HttpContext.Request.Uri.QueryString); } - else if (HttpContext.Request.Method == "POST") + else if (HttpContext.Request.Method == HTTPMethod.Post) { var socket = HttpContext.Socket; var buffer = new byte[2048]; diff --git a/Rinsen.WebServer/Extensions/ExtensionMethods.cs b/Rinsen.WebServer/Extensions/ExtensionMethods.cs index 491d9df..ec8aa18 100644 --- a/Rinsen.WebServer/Extensions/ExtensionMethods.cs +++ b/Rinsen.WebServer/Extensions/ExtensionMethods.cs @@ -32,20 +32,30 @@ public static void ReceiveUntil(this Socket socket, byte[] buffer, string readUn } public static void ReceiveUntil(this Socket socket, byte[] buffer, byte[] readUntil) + { + var bytesReceived = 0; + + ReceiveUntil(socket, buffer, readUntil, out bytesReceived); + } + + public static void ReceiveUntil(this Socket socket, byte[] buffer, byte[] readUntil, out int bytesRecieved, bool leaveDelimeter = false) { // Clear buffer always to remove old junk if buffer is reused Array.Clear(buffer, 0, buffer.Length); var count = 0; var matchCounter = 0; + + bytesRecieved = 0; while (socket.Available > 0 && count < buffer.Length) { - socket.Receive(buffer, count, 1, SocketFlags.None); + bytesRecieved += socket.Receive(buffer, count, 1, SocketFlags.None); if (buffer[count] == readUntil[matchCounter]) { matchCounter++; if (matchCounter == readUntil.Length) { - Array.Clear(buffer, count - readUntil.Length + 1, readUntil.Length); + if (!leaveDelimeter) + Array.Clear(buffer, count - readUntil.Length + 1, readUntil.Length); break; } } @@ -57,6 +67,14 @@ public static void ReceiveUntil(this Socket socket, byte[] buffer, byte[] readUn } } + public static byte[] GetMoreBytes(this Socket socket, int rxBufferSize, out int bytesRecieved) + { + byte[] result = new byte[rxBufferSize]; + SocketFlags socketFlags = new SocketFlags(); + bytesRecieved = socket.Receive(result, result.Length, socketFlags); + return result; + } + public static int Count(this IEnumerable collection) { var count = 0; @@ -66,5 +84,171 @@ public static int Count(this IEnumerable collection) } return count; } + + public static string ToHexString(this byte[] value, int index = 0) + { + return ToHexString(value, index, value.Length - index); + } + + public static string ToHexString(this byte[] value, int index, int length) + { + char[] c = new char[length * 3]; + byte b; + + for (int y = 0, x = 0; y < length; ++y, ++x) + { + b = (byte)(value[index + y] >> 4); + c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); + b = (byte)(value[index + y] & 0xF); + c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); + c[++x] = '-'; + } + return new string(c, 0, c.Length - 1); + } + + public static string GetName(this HTTPMethod source) + { + switch (source) + { + case HTTPMethod.Get: + return "GET"; + case HTTPMethod.Post: + return "POST"; + case HTTPMethod.Put: + return "PUT"; + case HTTPMethod.Delete: + return "DELETE"; + default: + return "Undefined"; + } + } + + public static string GetName(this EnumMainContentType source) + { + switch (source) + { + case EnumMainContentType.Application: + return "application"; + case EnumMainContentType.Audio: + return "audio"; + case EnumMainContentType.Example: + return "example"; + case EnumMainContentType.Image: + return "image"; + case EnumMainContentType.Message: + return "message"; + case EnumMainContentType.Model: + return "model"; + case EnumMainContentType.MultiPart: + return "multipart"; + case EnumMainContentType.Text: + return "text"; + case EnumMainContentType.Video: + return "video"; + default: + return "Undefined"; + } + } + + public static EnumMainContentType GetContentTypeMain(this string source) + { + switch (source.Trim().ToLower()) + { + case "application": + return EnumMainContentType.Application; + case "audio": + return EnumMainContentType.Audio; + case "example": + return EnumMainContentType.Example; + case "image": + return EnumMainContentType.Image; + case "message": + return EnumMainContentType.Message; + case "model": + return EnumMainContentType.Model; + case "multipart": + return EnumMainContentType.MultiPart; + case "text": + return EnumMainContentType.Text; + case "video": + return EnumMainContentType.Video; + default: + return EnumMainContentType.Undefined; + } + } + + public static string GetName(this EnumSubContentType source) + { + switch (source) + { + case EnumSubContentType.FormData: + return "form-data"; + case EnumSubContentType.Json: + return "json"; + case EnumSubContentType.Html: + return "html"; + case EnumSubContentType.Css: + return "css"; + case EnumSubContentType.Plain: + return "plain"; + case EnumSubContentType.Jpeg: + return "jpeg"; + case EnumSubContentType.JavaScript: + return "javascript"; + default: + return "Undefined"; + } + } + + public static EnumSubContentType GetContentTypeSub(this string source) + { + switch (source.Trim().ToLower()) + { + case "form-data": + return EnumSubContentType.FormData; + case "json": + return EnumSubContentType.Json; + case "html": + return EnumSubContentType.Html; + case "css": + return EnumSubContentType.Css; + case "plain": + return EnumSubContentType.Plain; + case "javascript": + return EnumSubContentType.JavaScript; + default: + return EnumSubContentType.Undefined; + } + } + + public static int IndexOf(this byte[] source, byte[] patternToFind) + { + if (patternToFind.Length > source.Length) + return -1; + for (int i = 0; i < source.Length - patternToFind.Length; i++) + { + bool found = true; + for (int j = 0; j < patternToFind.Length; j++) + { + if (source[i + j] != patternToFind[j]) + { + found = false; + break; + } + } + if (found) + { + return i; + } + } + return -1; + } + + public static byte[] SubArray(this byte[] source, int index, int length) + { + byte[] result = new byte[length]; + Array.Copy(source, index, result, 0, length); + return result; + } } } diff --git a/Rinsen.WebServer/NetworkInterfaceLocator.cs b/Rinsen.WebServer/NetworkInterfaceLocator.cs index f3efe17..257a74f 100644 --- a/Rinsen.WebServer/NetworkInterfaceLocator.cs +++ b/Rinsen.WebServer/NetworkInterfaceLocator.cs @@ -2,7 +2,7 @@ using Microsoft.SPOT; using System.Net; using Microsoft.SPOT.Net.NetworkInformation; -using System.Text; +using Rinsen.WebServer.Extensions; namespace Rinsen.WebServer { @@ -22,16 +22,7 @@ public IPAddress Locate() { Debug.Print("Dns address: " + dnsAddress); } - var sb = new StringBuilder("Physical address: "); - var parts = 1; - foreach (var physicalAddress in networkInterface.PhysicalAddress) - { - sb.Append(physicalAddress); - if (parts < networkInterface.PhysicalAddress.Length) - sb.Append("-"); - parts++; - } - Debug.Print(sb.ToString()); + Debug.Print("Physical address: " + networkInterface.PhysicalAddress.ToHexString()); Debug.Print("Subnet mask: " + networkInterface.SubnetMask); count++; diff --git a/Rinsen.WebServer/RequestContext.cs b/Rinsen.WebServer/RequestContext.cs index c039c06..9ac2e36 100644 --- a/Rinsen.WebServer/RequestContext.cs +++ b/Rinsen.WebServer/RequestContext.cs @@ -2,16 +2,28 @@ using System.Collections; using Rinsen.WebServer.Routing; using Rinsen.WebServer.Collections; - +using Rinsen.WebServer.Extensions; namespace Rinsen.WebServer { + public enum HTTPMethod { Get, Post, Put, Delete, Undefined } //add as neccessary + + public class RequestContext { - public string RequestLine { get { return Method + " " + Uri.RawPath + " " + HttpVersion; } } + public RequestContext() + { + Headers = new HeaderCollection(); + } + + public string RequestLine { get { return Method.GetName() + " " + Uri.RawPath + " " + HttpVersion; } } public HeaderCollection Headers { get; private set; } - public string Method { get; private set;} + public HTTPMethod Method { get; private set; } + + public ContentType ContentType { get; private set; } + + public string Boundary { get; set; } public string HttpVersion { get; private set; } @@ -21,7 +33,7 @@ public class RequestContext public RequestRoute RequestedRoute { get; set; } - public string Information { get; set; } + public string Data { get; set; } public void SetHeaders(ArrayList headers) { @@ -35,13 +47,53 @@ public void SetHeaders(ArrayList headers) public void SetHeader(string header) { var splitIndex = header.IndexOf(':'); - Headers.AddValue(header.Substring(0, splitIndex), header.Substring(splitIndex + 1).TrimStart(' ')); + var headerKey = header.Substring(0, splitIndex); + var headerValue = header.Substring(splitIndex + 1).TrimStart(' '); + + if (headerKey.Trim().ToLower().Equals("content-type")) + { + ContentType = new ContentType(); + var contentTypes = headerValue.Split('/'); //sample data "multipart/form-data; boundary=---------------------------2261521032598" + + ContentType.MainContentType = contentTypes[0].GetContentTypeMain(); + if (ContentType.MainContentType == EnumMainContentType.MultiPart) + { + var subcontentData = contentTypes[1].Split(';'); + ContentType.SubContentType = subcontentData[0].GetContentTypeSub(); + + var boundaryData = subcontentData[1].Split('='); + Boundary = boundaryData[1].TrimStart('-');//only remove the --'s because there is a \r\n on the other side of the number that is needed... + } + else + { + ContentType.SubContentType = contentTypes[1].GetContentTypeSub(); + } + } + Headers.AddValue(headerKey, headerValue); } public void SetRequestLineAndUri(string requestLine) { var parts = requestLine.Split(' '); - Method = parts[0]; + + switch (parts[0].Trim().ToUpper()) + { + case "POST": + Method = HTTPMethod.Post; + break; + case "GET": + Method = HTTPMethod.Get; + break; + case "PUT": + Method = HTTPMethod.Put; + break; + case "DELETE": + Method = HTTPMethod.Delete; + break; + default: + Method = HTTPMethod.Undefined; + break; + } var host = Headers["Host"].Split(':'); if (host.Length > 1) { diff --git a/Rinsen.WebServer/RequestContextBuilder.cs b/Rinsen.WebServer/RequestContextBuilder.cs index 5e0415d..10b43e5 100644 --- a/Rinsen.WebServer/RequestContextBuilder.cs +++ b/Rinsen.WebServer/RequestContextBuilder.cs @@ -28,6 +28,8 @@ private void GetHeaderPartsFromSocket(Socket socket, RequestContext requestConte var headerSize = 0; byte[] buffer = new byte[_serverContext.BufferSize]; var requestLineSet = false; + var RequestLineHeader = string.Empty; + while (socket.Available > 0) { @@ -55,13 +57,14 @@ private void GetHeaderPartsFromSocket(Socket socket, RequestContext requestConte } requestLineSet = true; - requestContext.SetRequestLineAndUri(headerString); + RequestLineHeader = headerString; } else { requestContext.SetHeader(headerString); } } + requestContext.SetRequestLineAndUri(RequestLineHeader); } } } diff --git a/Rinsen.WebServer/ResponseContext.cs b/Rinsen.WebServer/ResponseContext.cs index aa66bad..bde2100 100644 --- a/Rinsen.WebServer/ResponseContext.cs +++ b/Rinsen.WebServer/ResponseContext.cs @@ -37,7 +37,7 @@ public string DataLength } } - public string ContentType { get; set; } + public ContentType ContentType { get; set; } public HttpStatusCode HttpStatusCode { get; set; } diff --git a/Rinsen.WebServer/ResponseHeaderBuilder.cs b/Rinsen.WebServer/ResponseHeaderBuilder.cs index e438d00..fa162d3 100644 --- a/Rinsen.WebServer/ResponseHeaderBuilder.cs +++ b/Rinsen.WebServer/ResponseHeaderBuilder.cs @@ -22,7 +22,7 @@ public string BuildResponseLineAndHeaders(ResponseContext responseContext) private void SetContentLength(ResponseContext response) { response.Headers["Content-Length"] = response.DataLength; - response.Headers["ContentType"] = response.ContentType; + response.Headers["ContentType"] = response.ContentType.ToString(); } } } diff --git a/Rinsen.WebServer/Result.cs b/Rinsen.WebServer/Result.cs index bc65aea..57e069d 100644 --- a/Rinsen.WebServer/Result.cs +++ b/Rinsen.WebServer/Result.cs @@ -5,6 +5,7 @@ namespace Rinsen.WebServer { public class Result { - public string Data { get; set; } + public bool Success { get; set; } + public string Message { get; set; } } } diff --git a/Rinsen.WebServer/Rinsen.WebServer.csproj b/Rinsen.WebServer/Rinsen.WebServer.csproj index 8952b7e..35e182b 100644 --- a/Rinsen.WebServer/Rinsen.WebServer.csproj +++ b/Rinsen.WebServer/Rinsen.WebServer.csproj @@ -36,6 +36,7 @@ + @@ -78,6 +79,10 @@ + + ..\packages\Json.NetMF.1.3.0.0\lib\netmf43\Json.NetMF.dll + True + diff --git a/Rinsen.WebServer/Serializers/JsonSerializer.cs b/Rinsen.WebServer/Serializers/JsonSerializer.cs index 06f075f..fa2e34c 100644 --- a/Rinsen.WebServer/Serializers/JsonSerializer.cs +++ b/Rinsen.WebServer/Serializers/JsonSerializer.cs @@ -5,144 +5,8 @@ namespace Rinsen.WebServer.Serializers { - public class JsonSerializer : IJsonSerializer + public class JsonSerializer : Json.NETMF.JsonSerializer, IJsonSerializer { - public virtual string Serialize(object obj) - { - var jsonStringBuilder = new StringBuilder("{"); - var properties = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); - var first = true; - foreach (var property in properties) - { - // Skip if no return value - if (property.ReturnType == typeof(void)) - continue; - - var propertyName = property.Name.Substring(4); - propertyName = propertyName[0].ToLower() + propertyName.Substring(1); - if (first) - { - jsonStringBuilder.Append("\"" + propertyName + "\": "); - first = false; - } - else - { - jsonStringBuilder.Append(",\"" + propertyName + "\": "); - } - - var value = property.Invoke(obj, new object[] { }); - - if (!AppendValueToJsonBuilder(value, jsonStringBuilder)) - { - // If unknown object in value try to serialize object content and add as value - jsonStringBuilder.Append(Serialize(value)); - } - } - jsonStringBuilder.Append("}"); - - return jsonStringBuilder.ToString(); - } - - private bool AppendValueToJsonBuilder(object value, StringBuilder jsonStringBuilder) - { - var type = value.GetType(); - - if (type == typeof(ArrayList)) - { - SerializeArray((ArrayList)value, jsonStringBuilder); - return true; - } - if (type == typeof(bool)) - { - jsonStringBuilder.Append(value.ToString().ToLower()); - return true; - } - if (type == typeof(byte)) - { - jsonStringBuilder.Append((byte)value); - return true; - } - if (type == typeof(sbyte)) - { - jsonStringBuilder.Append((sbyte)value); - return true; - } - if (type == typeof(char)) - { - jsonStringBuilder.Append("\"" + (char)value + "\""); - return true; - } - if (type == typeof(double)) - { - jsonStringBuilder.Append((double)value); - return true; - } - if (type == typeof(float)) - { - jsonStringBuilder.Append((float)value); - return true; - } - if (type == typeof(int)) - { - jsonStringBuilder.Append((int)value); - return true; - } - if (type == typeof(uint)) - { - jsonStringBuilder.Append((uint)value); - return true; - } - if (type == typeof(long)) - { - jsonStringBuilder.Append((long)value); - return true; - } - if (type == typeof(ulong)) - { - jsonStringBuilder.Append((ulong)value); - return true; - } - if (type == typeof(short)) - { - jsonStringBuilder.Append((short)value); - return true; - } - if (type == typeof(ushort)) - { - jsonStringBuilder.Append((ushort)value); - return true; - } - if (type == typeof(string)) - { - jsonStringBuilder.Append("\"" + (string)value + "\""); - return true; - } - - return false; - } - - private void SerializeArray(ArrayList valueArray, StringBuilder jsonStringBuilder) - { - if (valueArray.Count == 0) - return; - - jsonStringBuilder.Append("["); - var first = true; - foreach (var value in valueArray) - { - if (!first) - jsonStringBuilder.Append(", "); - else - first = false; - - if (!AppendValueToJsonBuilder(value, jsonStringBuilder)) - { - // If unknown object in value try to serialize object content and add as value - jsonStringBuilder.Append(Serialize(value)); - } - } - jsonStringBuilder.Append("]"); - } } } diff --git a/Rinsen.WebServer/ServerBase.cs b/Rinsen.WebServer/ServerBase.cs index add3f00..1dd77b5 100644 --- a/Rinsen.WebServer/ServerBase.cs +++ b/Rinsen.WebServer/ServerBase.cs @@ -68,6 +68,11 @@ public void SetFileAndDirectoryService(IFileAndDirectoryService fileAndDirectory _serverContext.FileServerBasePath = fileAndDirectoryService.GetFileServiceBasePath(); } + public void SetHostName(string hostName) + { + _serverContext.HostName = hostName; + } + public bool ThreadedResponses { get diff --git a/Rinsen.WebServer/packages.config b/Rinsen.WebServer/packages.config new file mode 100644 index 0000000..8acc6ab --- /dev/null +++ b/Rinsen.WebServer/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/RinsenWebServer.sln b/RinsenWebServer.sln index e37d7d5..36e2d5c 100644 --- a/RinsenWebServer.sln +++ b/RinsenWebServer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoWeb", "DemoWeb\DemoWeb.csproj", "{72EE43DE-970A-443F-851F-CA89A061CC1E}" EndProject @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rinsen.WebServer", "Rinsen. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rinsen.WebServer.UnitTests", "Rinsen.WebServer.UnitTests\Rinsen.WebServer.UnitTests.csproj", "{A08D703F-165F-4605-8DC1-05743A113D9E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetduinoSDCard", "NetduinoSDCard\NetduinoSDCard.csproj", "{66F7DA1E-2931-4E24-81F7-471B08488B96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -37,6 +39,12 @@ Global {A08D703F-165F-4605-8DC1-05743A113D9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A08D703F-165F-4605-8DC1-05743A113D9E}.Release|Any CPU.Build.0 = Release|Any CPU {A08D703F-165F-4605-8DC1-05743A113D9E}.Release|Any CPU.Deploy.0 = Release|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Release|Any CPU.Build.0 = Release|Any CPU + {66F7DA1E-2931-4E24-81F7-471B08488B96}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SDCardContens/WWW/filemanager.html b/SDCardContens/WWW/filemanager.html new file mode 100644 index 0000000..bb4959d --- /dev/null +++ b/SDCardContens/WWW/filemanager.html @@ -0,0 +1,55 @@ + + + + + + Cart Scale File Manager + + + + + + + + + +
+
+ +

Cart Scale File Manager

+
+
+
+
+
+ Network Information +
+ + +
+ +
+ +
+
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/SDCardContens/WWW/images/img01.jpg b/SDCardContens/WWW/images/img01.jpg new file mode 100644 index 0000000..985a40a Binary files /dev/null and b/SDCardContens/WWW/images/img01.jpg differ diff --git a/SDCardContens/WWW/images/img02.gif b/SDCardContens/WWW/images/img02.gif new file mode 100644 index 0000000..070011a Binary files /dev/null and b/SDCardContens/WWW/images/img02.gif differ diff --git a/SDCardContens/WWW/images/img03.jpg b/SDCardContens/WWW/images/img03.jpg new file mode 100644 index 0000000..916a157 Binary files /dev/null and b/SDCardContens/WWW/images/img03.jpg differ diff --git a/SDCardContens/WWW/js/filemanager.js b/SDCardContens/WWW/js/filemanager.js new file mode 100644 index 0000000..79e0d03 --- /dev/null +++ b/SDCardContens/WWW/js/filemanager.js @@ -0,0 +1,30 @@ +var intMessageFadeTimeout = 10000; +var sFileUploadURL = 'Files/Upload'; + + +//Prevent forms from submitting so that I can use the jquery button click method with an ajax call instead... +$(".preventsubmit").submit(function (event) { + event.preventDefault(); +}); + +$("#btnUpload").button().click(function () { + + //var data = new FormData(); + //jQuery.each(jQuery('#file')[0].files, function (i, file) { + // data.append('file-' + i, file); + //}); + var formData = new FormData($("#frmFileUpload")[0]); + + $.ajax({ + url: sFileUploadURL, + type: 'POST', + data: formData, + async: false, + cache: false, + contentType: false, + processData: false, + success: function (returndata) { + alert(returndata); + } + }); +}); \ No newline at end of file diff --git a/SDCardContens/WWW/style/style.css b/SDCardContens/WWW/style/style.css new file mode 100644 index 0000000..ef6b25c --- /dev/null +++ b/SDCardContens/WWW/style/style.css @@ -0,0 +1,56 @@ +body { + background: #0C1114 url(/images/img01.jpg) no-repeat top center; + color: #8EA2AD; + line-height: 1.75em; + font-size: 12pt; +} + +input.form-submit { + color: #FFFFFF; + font-family: Oswald, sans-serif; + padding: 5px; + margin-left: 1em; + background: #CC7F5C; + border: 0; +} + +input.form-text { + padding: 10px; + border: dotted 1px #26333D; +} + +h1.Title { + color: cornflowerblue; +} + +span.Messages { + color: red; +} + +.float-left { + float: left; +} + +.float-right { + float: right; +} + +.clear-fix { + clear: both; +} + +.clear-left { + clear: left; +} + +.clear-right { + clear: right; +} + +input.stretch { + width: 100%; +} + +input.stretch3Quarters { + width: 75%; +} \ No newline at end of file diff --git a/packages/repositories.config b/packages/repositories.config index 5124ce9..e329769 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -1,4 +1,5 @@  + \ No newline at end of file