public void handlePOSTRequest() { // this post data processing just reads everything into a memory stream. // this is fine for smallish things, but for large stuff we should really // hand an input stream to the request processor. However, the input stream // we hand him needs to let him see the "end of the stream" at this content // length, because otherwise he won't know when he's seen it all! ServerLog.LogInfo("get post data start"); int content_len = 0; MemoryStream ms = new MemoryStream(); if (this.httpHeaders.ContainsKey("Content-Length")) { content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]); if (content_len > MAX_POST_SIZE) { throw new Exception( String.Format("POST Content-Length({0}) too big for this simple server", content_len)); } byte[] buf = new byte[BUF_SIZE]; int to_read = content_len; while (to_read > 0) { ServerLog.LogInfo(String.Format("starting Read, to_read={0}", to_read)); int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read)); ServerLog.LogInfo(String.Format("read finished, numread={0}", numread)); if (numread == 0) { if (to_read == 0) { break; } else { throw new Exception("client disconnected during post"); } } to_read -= numread; ms.Write(buf, 0, numread); } ms.Seek(0, SeekOrigin.Begin); } ServerLog.LogInfo("get post data end"); srv.handlePOSTRequest(this, new StreamReader(ms)); }
public void parseRequest() { String request = streamReadLine(); if (request == null) { // Connection closed by browser throw new EndOfStreamException("EOS_BROWSER"); } string[] tokens = request.Split(' '); if (tokens.Length != 3) { throw new Exception("invalid http request line"); } http_method = tokens[0].ToUpper(); http_url = tokens[1]; http_protocol_versionstring = tokens[2]; ServerLog.LogInfo("starting: " + request); }
public void process() { // we can't use a StreamReader for input, because it buffers up extra data on us inside it's // "processed" view of the world, and we want the data raw after the headers inputStream = new BufferedStream(socket.GetStream()); // we probably shouldn't be using a streamwriter for all output from handlers either outputStream = new StreamWriter(new BufferedStream(socket.GetStream())); try { // Keep processing requests from the browser (keep alive) while (true) { parseRequest(); readHeaders(); if (http_method.Equals("GET")) { handleGETRequest(); } else if (http_method.Equals("POST")) { handlePOSTRequest(); } outputStream.Flush(); } } catch (EndOfStreamException eose) { if (eose.Message == "EOS_BROWSER") { return; } } catch (Exception e) { ServerLog.Log("Exception: " + e.ToString()); writeFailure(); outputStream.Flush(); } finally { // bs.Flush(); // flush any remaining output inputStream = null; outputStream = null; // bs = null; socket.Close(); } }
public void listen() { try{ listener = new TcpListener(address, port); listener.Start(); while (is_active) { ServerLog.LogInfo("Listening!"); TcpClient s = listener.AcceptTcpClient(); ServerLog.LogInfo("Client accepted!"); s.ReceiveTimeout = 1000; // After 1 seconds, time out the read operation!!! // Why? Because as long as the operation is waiting, this thread is in "native code" and Unity cannot go to "play" mode or reload the scripts! HttpProcessor processor = new HttpProcessor(s, this); Thread thread = new Thread(new ThreadStart(processor.process)); thread.Start(); Thread.Sleep(1); } } catch (Exception e) { ServerLog.Log("Server Listening Exception!"); ServerLog.Log(e); } }
/// <summary> /// HTTP POST => Implement to do API calls (saving/loading/deleting/listing Vubbi files) /// </summary> /// <param name="p">P.</param> /// <param name="inputData">Input data.</param> public override void handlePOSTRequest(HttpProcessor p, StreamReader inputData) { if (p.http_url.Equals("/api/save")) { // Save the file... api.Save(ParseQuery(inputData)); SendApiOk(p, ""); return; } if (p.http_url.Equals("/api/load")) { // Save the file... String content = api.Load(ParseQuery(inputData)); SendApiOk(p, content); return; } if (p.http_url.Equals("/api/lang")) { // Send back the language preference of the user... SendApiOk(p, api.GetLanguagePreference()); return; } if (p.http_url.StartsWith("/api/setlang/")) { // Send back the language preference of the user... api.SetLanguagePreference(p.http_url.Substring("/api/setlang/".Length)); SendApiOk(p, ""); return; } ServerLog.Log(p.http_url); String errorMessage = "<H2>Http Post not supported yet...</H2>"; SendHeader(config.DefaultMime, errorMessage.Length, ServerHttpStatusCode.ERR_404_FILENOTFOUND, p); p.outputStream.Write(errorMessage); }
/// <summary> /// /// This code is called when the Unity Editor starts. It starts Vubbi (installation + web server). /// /// </summary> static Init() { // // Check command line arguments... // string commandlinebuildkeyword = "+exportvubbiscriptunitypackage"; if (System.Environment.GetCommandLineArgs().Contains(commandlinebuildkeyword)) { // So, we need to do a build instead of running the code... string[] cargs = System.Environment.GetCommandLineArgs(); string outputdir = null; for (int i = 0; i < cargs.Length; i++) { if (cargs [i] == commandlinebuildkeyword) { outputdir = cargs [i + 1]; } } AssetDatabase.ExportPackage("Assets/Editor Default Resources/Editor/VubbiScript", outputdir, ExportPackageOptions.Recurse); return; // DO NOT CONTINUE... Exit Unity now... } // // Set the icon for Vubbi files // VubbiFileHandler.InitVubbiIcon(); // // Server Configuration // ServerConfig config = new ServerConfig(); #if UNITY_EDITOR // When running in development mode => the "web" code can be found in the folder "web" next to the actual unity project folder config.HostDirectory = System.IO.Path.Combine(UnityEngine.Application.dataPath, "../../web"); #else // When compiling for the release build, we do not define UNITY_EDITOR // For released code, the HTML & JavaScript can be found in: config.HostDirectory = System.IO.Path.Combine(UnityEngine.Application.dataPath, "../WebRoot"); #endif config.Port = 8040; // // Update Web directory // This is part of the "installer"... // Right after importing the unity package, we will unzip the data file and put it in the main project folder. // => Resulting in a "WebRoot" folder // string dataFile = System.IO.Path.Combine(UnityEngine.Application.dataPath, "Editor Default Resources/Editor/VubbiScript/Vubbi.data"); if (System.IO.File.Exists(dataFile)) { System.IO.Directory.CreateDirectory(config.HostDirectory + "/"); UnzipDataDir(dataFile, config.HostDirectory + "/"); System.IO.File.Delete(dataFile); AssetDatabase.Refresh(); ServerLog.Log("Installation successful!"); } // // Start Server // VubbiApi api = new VubbiApi(); new VubbiServer(config, api); // // Register update callback // EditorApplication.update += api.OnUpdate; }
/// <summary> /// HTTP GET => Implement to load actual files from the server... Returns the html/js/css/... files. /// </summary> /// <param name="p">P.</param> public override void handleGETRequest(HttpProcessor p) { String requestedUrl = p.http_url; ServerLog.Log(String.Format("request: {0}", requestedUrl)); if (requestedUrl.EndsWith("/")) { // We are looking in a directory... } //Extract the requested file name String directory = requestedUrl.Substring(requestedUrl.IndexOf("/"), requestedUrl.LastIndexOf("/") - requestedUrl.IndexOf("/")); String filename = requestedUrl.Substring(requestedUrl.LastIndexOf("/") + 1); ///////////////////////////////////////////////////////////////////// // Identify the Physical Directory ///////////////////////////////////////////////////////////////////// String physicalDirectory = config.GetPhysicalPath(directory); // TODO: check if directory exists... ///////////////////////////////////////////////////////////////////// // Identify the File Name ///////////////////////////////////////////////////////////////////// //If The file name is not supplied then look in the default file list if (filename.Length == 0) { // Get the default filename filename = config.GetDefaultFileInFolder(physicalDirectory); } // TODO: check if filename is no longer "" and check if file exists... String mimeHeader = config.GetMimeType(filename); String fullPath = Path.Combine(physicalDirectory, filename); ServerLog.LogInfo(" < " + fullPath); if (!File.Exists(fullPath)) { ServerLog.Log(" [!]" + ServerHttpStatusCode.ERR_404_FILENOTFOUND); String errorMessage = "<H2>404 Error! File Does Not Exists...</H2>"; SendHeader(config.DefaultMime, errorMessage.Length, ServerHttpStatusCode.ERR_404_FILENOTFOUND, p); p.outputStream.Write(errorMessage); } else { ServerLog.LogInfo(" [+]" + HttpStatusCode.OK); FileInfo f = new FileInfo(fullPath); Stream filecontent = new BufferedStream(f.OpenRead()); try{ SendHeader(mimeHeader, f.Length, ServerHttpStatusCode.OK, p); p.outputStream.Flush(); CopyStream(filecontent, p.socket.GetStream()); }finally{ filecontent.Close(); } } }