private void ExecCommand(HttpListenerContext context, ICommand cmd) { TextWriter stdOut; TextWriter stdErr = new StringWriter(); string tempdir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N").Substring(0, 16)); SwitchedOutputStream output = new SwitchedOutputStream(context.Response.OutputStream, ushort.MaxValue); try { string contentType = "text/plain"; IArgument reqFile = null; IArgument resFile = null; foreach (IArgument argument in cmd.Arguments) { HttpRequestFileAttribute reqFileAttr = null; HttpResponseFileAttribute resFileAttr = null; if (argument.TryGetAttribute(out reqFileAttr)) { Check.Assert <ArgumentException>(null == Interlocked.Exchange(ref reqFile, argument)); } if (argument.TryGetAttribute(out resFileAttr)) { Check.Assert <ArgumentException>(null == Interlocked.Exchange(ref resFile, argument)); } } if (reqFile != null && reqFile.Required && ( context.Request.HttpMethod.ToUpperInvariant() != "POST" || !context.Request.ContentType.StartsWith( "multipart/form-data", StringComparison.OrdinalIgnoreCase))) { throw new InvalidOperationException(); } List <string> args = new List <string>(); args.Add(cmd.DisplayName); HttpResponseTypeAttribute ctypeAttr; if (cmd.TryGetAttribute(out ctypeAttr) && !String.IsNullOrEmpty(ctypeAttr.MimeType)) { contentType = ctypeAttr.MimeType; } GetArguments(context, cmd, tempdir, ref contentType, args); if (resFile != null) { HttpResponseFileAttribute fattr; resFile.TryGetAttribute(out fattr); Directory.CreateDirectory(tempdir); string tempPath = Path.Combine(tempdir, cmd.DisplayName + fattr.Extension); args.Add(String.Format("/{0}={1}", resFile.DisplayName, tempPath)); using (stdOut = new StreamWriter(output, Encoding.UTF8)) Run(args.ToArray(), stdOut, stdErr, TextReader.Null); if (output.OutputSent) { throw new ApplicationException("Headers already sent."); } context.Response.ContentType = fattr.MimeType ?? "application/binary"; context.Response.Headers.Add("Content-Disposition", String.Format("attachment; filename=\"{0}{1}\"", cmd.DisplayName, fattr.Extension)); using (Stream ostream = context.Response.OutputStream) using (Stream istream = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.None)) { int len; byte[] buffer = new byte[ushort.MaxValue]; while (0 != (len = istream.Read(buffer, 0, buffer.Length))) { ostream.Write(buffer, 0, len); } } } else { context.Response.ContentType = contentType + (contentType.Contains("text") || contentType.Contains("xml") || contentType.Contains("json") ? "; charset=utf-8" : ""); using (stdOut = new StreamWriter(output, Encoding.UTF8)) Run(args.ToArray(), stdOut, stdErr, TextReader.Null); } if (!output.OutputSent) { context.Response.ContentLength64 = output.BufferPosition; } output.Commit(); } catch (InterpreterException) { throw; } catch (Exception e) { if (output.OutputSent) { using (stdOut = new StreamWriter(output, Encoding.UTF8)) { stdOut.Write("EXCEPTION: "); stdOut.WriteLine(e.Message); stdOut.WriteLine(stdErr.ToString()); } output.Commit(); } else { WriteErrorPage(context, 500, "Internal Server Error", e.Message, stdErr.ToString(), output.ToString()); } } finally { if (Directory.Exists(tempdir)) { try { Directory.Delete(tempdir, true); } catch { } } } }
private void ServerOnProcessRequest(object sender, HttpContextEventArgs eventArg) { HttpListenerContext context = eventArg.Context; try { context.Response.Headers["Server"] = "C0D3"; context.Response.Headers["Expires"] = "0"; context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; string applicationPath = context.Request.Url.AbsolutePath.TrimEnd('/', '\\') + '/'; if (applicationPath.StartsWith(eventArg.Host.ApplicationPath, StringComparison.OrdinalIgnoreCase)) { applicationPath = applicationPath.Substring(eventArg.Host.ApplicationPath.Length - 1); } string[] segments = applicationPath.TrimEnd('/', '\\').Split('/', '\\'); HttpIgnoreAttribute ignore; ICommand cmd; bool execute = _commands.TryGetValue(context.Request.Url.AbsolutePath, out cmd); if (cmd == null && segments.Length == 2) { if (_commands.TryGetValue(segments[1], out cmd)) { execute = (!String.IsNullOrEmpty(context.Request.Url.Query) || context.Request.HttpMethod.ToUpperInvariant() != "GET"); } } if (cmd != null && cmd.TryGetAttribute(out ignore)) { throw new UnauthorizedAccessException("The command is not available."); } else if (cmd != null && execute) { ExecCommand(context, cmd); return; } else if (cmd != null || (cmd == null && segments.Length == 1)) { context.Response.ContentType = "text/html; charset=utf-8"; using (SwitchedOutputStream output = new SwitchedOutputStream(context.Response.OutputStream, ushort.MaxValue)) using (StreamWriter wtr = new StreamWriter(output)) { GenerateHtmlPage(wtr, eventArg.Host.ApplicationPath, cmd != null ? cmd.DisplayName : null); if (!output.OutputSent) { context.Response.ContentLength64 = output.BufferPosition; } output.Commit(); } return; } WriteErrorPage(context, 404, "Not Found", "The url is malformed or the command name is incorrect."); } catch (InterpreterException e) { try { WriteErrorPage(context, 400, "Bad Request", e.Message); } catch { } } catch (UnauthorizedAccessException e) { try { WriteErrorPage(context, 403, "Forbidden", e.Message); } catch { } } catch (Exception e) { try { WriteErrorPage(context, 500, "Internal Server Error", e.Message); } catch { } } }