public void GetFileContent() { // GET:files/{fileid} // http://developer.mindtouch.com/Deki/API_Reference/GET%3afiles%2f%2f%7bfileid%7d Plug p = Utils.BuildPlugForAdmin(); string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); byte[] content = FileUtils.GenerateRandomContent(); string fileid = null; string filename = null; msg = FileUtils.UploadRandomFile(p, id, content, string.Empty, out fileid, out filename); msg = p.At("files", fileid).Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes())); // GET:files/{fileid}/{filename} // http://developer.mindtouch.com/Deki/API_Reference/GET%3afiles%2f%2f%7bfileid%7d%2f%2f%7bfilename%7d msg = p.At("files", fileid, "=" + filename).Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes())); PageUtils.DeletePageByID(p, id, true); }
public void GetFileFromAnonymous() { //Assumptions: // //Actions: // create page // upload file to page // try get file from anonymous account //Expected result: // ok Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id); byte[] content = FileUtils.GenerateRandomContent(); string fileid = null; string filename = null; msg = FileUtils.UploadRandomFile(p, id, content, string.Empty, out fileid, out filename); p = Utils.BuildPlugForAnonymous(); msg = p.At("files", fileid).Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes())); p = Utils.BuildPlugForAdmin(); PageUtils.DeletePageByID(p, id, true); }
public void UploadFileWithZeroSize() { // Acquire ADMIN permissions Plug p = Utils.BuildPlugForAdmin(); /// Create a random page string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); // Create a file with zero size and upload it to page byte[] content = new byte[0]; string fileid = null; string filename = null; msg = FileUtils.UploadRandomFile(p, id, content, string.Empty, out fileid, out filename); // Retrieve file msg = p.At("files", fileid).Get(); // Assert OK HTTP status returned Assert.AreEqual(DreamStatus.Ok, msg.Status); // Assert uploaded file content equals retrieved file content Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes())); // Delete the page PageUtils.DeletePageByID(p, id, true); }
public void UploadFileWithConfigExtension() { // Acquire ADMIN permissions Plug p = Utils.BuildPlugForAdmin(); // Create a random page string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); // Create a file with random content and a .config extension byte[] content = FileUtils.GenerateRandomContent(); string fileid = null; string filename = System.IO.Path.GetTempPath() + "/=file" + Utils.GenerateUniqueName() + ".config"; FileUtils.CreateFile(content, filename); // Upload the file and assert it uploaded successfully msg = FileUtils.UploadFile(p, id, string.Empty, out fileid, filename); Assert.AreEqual(DreamStatus.Ok, msg.Status, "File upload failed!"); // Assert uploaded file has only 1 revision msg = p.At("pages", id, "files").Get(); Assert.AreEqual(1, msg.ToDocument()["file/revisions/@count"].AsInt, "File revision count does not equal 1!"); // Retrieve file, assert retrieval is successful, and assert retrieved content matches generated content msg = p.At("files", fileid).Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "File retrieval failed!"); Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes()), "Retrieved content does not match generated content!"); // Delete the page PageUtils.DeletePageByID(p, id, true); }
public object Fetch( [DekiExtParam("document id")] string id ) { // fetch response from cache CacheEntry result; lock (_cacheLookup) { _cacheLookup.TryGetValue(id, out result); } // check if we have a cached entry XDoc document = null; if (result != null) { _log.DebugFormat("cache hit for '{0}'", result.Id); result.ResetMemoryExpiration(); if (result.Cache != null) { _log.DebugFormat("cache data in memory '{0}'", result.Id); document = XDocFactory.From(result.Cache, MimeType.XML); } else { // we have the result on disk, so let's fetch it DreamMessage msg = Storage.At(CACHE_DATA, result.Guid + ".bin").GetAsync().Wait(); if (msg.IsSuccessful) { _log.DebugFormat("cache data pulled from disk"); result.Cache = Encoding.UTF8.GetString(msg.AsBytes()); document = XDocFactory.From(result.Cache, MimeType.XML); } else { _log.DebugFormat("unable to fetch cache data from disk: {0}", msg.Status); } } } // check if we have a document to convert if (document != null) { try { DekiScriptList list = (DekiScriptList)DekiScriptLiteral.FromXml(document); return(list[0]); } catch { // the cached entry is corrupted, remove it Clear(id); } } return(null); }
public void UploadFileWithLongName() { // Acquire ADMIN permissions Plug p = Utils.BuildPlugForAdmin(); // Create a random page string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); // Create a file with random content and with a long name string fileid = null; string filename = System.IO.Path.GetTempPath() + "file" + Utils.GenerateUniqueName(); filename = filename.PadRight(250, 'a'); byte[] content = FileUtils.GenerateRandomContent(); FileUtils.CreateFile(content, filename); // Upload the file, assert it uploaded successfully, and store filename returned in document msg = FileUtils.UploadFile(p, id, string.Empty, out fileid, filename); Assert.AreEqual(DreamStatus.Ok, msg.Status, "File upload failed"); string savedFileName = msg.ToDocument()["filename"].AsText; // Retrieve the file and assert it retrieved successfully. msg = p.At("files", fileid).Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "File content retrieval failed"); // Assert retrieved file content matches generated content Assert.IsTrue(Utils.ByteArraysAreEqual(content, msg.AsBytes()), "Retrieved file content does not match generated content!"); // Retrieve page files and assert file is present msg = p.At("pages", id, "files").Get(); Assert.AreEqual(savedFileName, msg.ToDocument()["file/filename"].AsText, "File is not attached to page!"); // Delete the page PageUtils.DeletePageByID(p, id, true); }
public static DekiScriptMap GetImplicitEnvironment(DreamMessage message, DSACryptoServiceProvider publicDigitalSignature) { DekiScriptMap env = new DekiScriptMap(); // retrieve implicit arguments string[] headers = message.Headers.GetValues(IMPLICIT_ENVIRONMENT_HEADER); if (!ArrayUtil.IsNullOrEmpty(headers)) { env.AddAt("__implicit", new DekiScriptList(new ArrayList(headers))); foreach (string implicitArg in headers) { foreach (KeyValuePair <string, string> arg in HttpUtil.ParseNameValuePairs(implicitArg)) { env.AddNativeValueAt(arg.Key, arg.Value); } } } if (publicDigitalSignature != null) { bool valid = false; try { Dictionary <string, string> values = HttpUtil.ParseNameValuePairs(message.Headers[IMPLICIT_SIGNATURE_HEADER]); // verify date DateTime date = DateTime.Parse(values["date"]).ToUniversalTime(); double delta = DateTime.UtcNow.Subtract(date).TotalSeconds; if ((delta < -60) || (delta > 60)) { throw new DreamAbortException(DreamMessage.Forbidden("date in message signature is too far apart from server date")); } // verify message MemoryStream data = new MemoryStream(); byte[] bytes = null; // get message bytes bytes = message.AsBytes(); data.Write(bytes, 0, bytes.Length); // retrieve headers to verify if (!ArrayUtil.IsNullOrEmpty(headers)) { Array.Sort(headers, StringComparer.Ordinal); bytes = Encoding.UTF8.GetBytes(string.Join(",", headers)); data.Write(bytes, 0, bytes.Length); } // add request date bytes = Encoding.UTF8.GetBytes(values["date"]); data.Write(bytes, 0, bytes.Length); // verify signature byte[] signature = Convert.FromBase64String(values["dsig"]); valid = publicDigitalSignature.VerifyData(data.GetBuffer(), signature); } catch (Exception e) { if (e is DreamAbortException) { throw; } } if (!valid) { throw new DreamAbortException(DreamMessage.Forbidden("invalid or missing digital signature")); } } return(env); }
private string CachedWebGet(XUri uri, double?ttl, bool?nilIfMissing) { string id = uri.ToString(); // fetch message from cache or from the web CacheEntry result; bool isNew = true; lock (_cacheLookup) { _cacheLookup.TryGetValue(id, out result); } // check if we have a cached entry if (result != null) { _log.DebugFormat("cache hit for '{0}'", result.Id); isNew = false; result.ResetMemoryExpiration(); if (result.Cache != null) { _log.DebugFormat("cache data in memory '{0}'", result.Id); return(result.Cache); } // we have the result on disk, so let's fetch it DreamMessage msg = Storage.At(CACHE_DATA, result.Guid + ".bin").GetAsync().Wait(); if (msg.IsSuccessful) { _log.DebugFormat("cache data pulled from disk"); result.Cache = Encoding.UTF8.GetString(msg.AsBytes()); return(result.Cache); } _log.DebugFormat("unable to fetch cache data from disk: {0}", msg.Status); } else { _log.DebugFormat("new cache item for '{0}'", id); result = new CacheEntry(id, ttl); } // do the web request Result <DreamMessage> response = new Result <DreamMessage>(); Plug.New(uri).WithTimeout(DEFAULT_WEB_TIMEOUT).InvokeEx("GET", DreamMessage.Ok(), response); DreamMessage message = response.Wait(); try { // check message status if (!message.IsSuccessful) { if (nilIfMissing.GetValueOrDefault()) { return(null); } return(message.Status == DreamStatus.UnableToConnect ? string.Format("(unable to fetch text document from uri [status: {0} ({1}), message: \"{2}\"])", (int)message.Status, message.Status, message.ToDocument()["message"].AsText) : string.Format("(unable to fetch text document from uri [status: {0} ({1})])", (int)message.Status, message.Status)); } // check message size Result resMemorize = message.Memorize(_insertTextLimit, new Result()).Block(); if (resMemorize.HasException) { return(nilIfMissing.GetValueOrDefault() ? null : "(text document is too large)"); } // detect encoding and decode response var stream = message.ToStream(); var encoding = stream.DetectEncoding() ?? message.ContentType.CharSet; result.Cache = encoding.GetString(stream.ReadBytes(-1)); } finally { message.Close(); } // start timer to clean-up cached result if (result.Cache != null) { XDoc infoDoc = new XDoc("cache-entry") .Elem("guid", result.Guid) .Elem("id", result.Id) .Elem("expires", result.Expires); lock (result) { Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait(); Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait(); } if (isNew) { lock (_cacheLookup) { _cacheLookup[id] = result; } // this timer removes the cache entry from disk SetupCacheTimer(result); } } return(result.Cache); }
private DreamMessage PreProcessRequest(string verb, XUri uri, XUri normalizedUri, DreamMessage message) { DreamContext current = DreamContext.Current; DekiContext deki = DekiContext.Current; DekiInstance instance = deki.Instance; // set preferred culture message.Headers.AcceptLanguage = string.Format("{0}, *;q=0.5", current.Culture.Name); // add the 'deki' header message.Headers[DekiExtService.DEKI_HEADER] = instance.Token; // convert implicit environment into a message headers DekiScriptMap implicitEnv = DreamContext.Current.GetState <DekiScriptMap>(); if (implicitEnv != null) { foreach (KeyValuePair <string, DekiScriptLiteral> outer in implicitEnv.Value) { DekiScriptMap map = outer.Value as DekiScriptMap; if ((map != null) && !map.IsEmpty) { StringBuilder header = new StringBuilder(); foreach (KeyValuePair <string, DekiScriptLiteral> inner in map.Value) { string value = inner.Value.AsString(); if (value != null) { if (header.Length > 0) { header.Append(", "); } header.AppendFormat("{0}.{1}={2}", outer.Key, inner.Key, value.QuoteString()); } } // add header string headerValue = header.ToString(); message.Headers.Add(DekiExtService.IMPLICIT_ENVIRONMENT_HEADER, headerValue); } } } // add digital signature DSACryptoServiceProvider dsa = instance.PrivateDigitalSignature; if (dsa != null) { MemoryStream data = new MemoryStream(); // get message bytes byte[] bytes = message.AsBytes(); data.Write(bytes, 0, bytes.Length); // retrieve headers to sign string[] headers = message.Headers.GetValues(DekiExtService.IMPLICIT_ENVIRONMENT_HEADER); if (!ArrayUtil.IsNullOrEmpty(headers)) { Array.Sort(headers, StringComparer.Ordinal); bytes = Encoding.UTF8.GetBytes(string.Join(",", headers)); data.Write(bytes, 0, bytes.Length); } // add request date string date = DateTime.UtcNow.ToString(XDoc.RFC_DATETIME_FORMAT); bytes = Encoding.UTF8.GetBytes(date); data.Write(bytes, 0, bytes.Length); // sign data byte[] signature = dsa.SignData(data.GetBuffer()); message.Headers.Add(DekiExtService.IMPLICIT_SIGNATURE_HEADER, string.Format("dsig=\"{0}\", date=\"{1}\"", Convert.ToBase64String(signature), date)); } return(message); }
public void LogoTest() // TODO: split { // GET:logo.png // ... // 1. Retrieve logo // (2) Assert logo retrieved successfully (200 OK HTTP response) // 3. Generate a PNG image // 4. Upload as logo // (5) Assert logo uploaded successfully (200 OK HTTP response) // 6. Retrieve logo once again // (7) Assert retrieved logo matches uploaded logo // 8. Delete logo // (9) Assert logo delete was successful (200 OK HTTP response) // 10. Retrieve logo once more // (11) Assert 404 Not Found HTTP response Plug p = Utils.BuildPlugForAdmin(); DreamMessage msg = p.At("site", "logo.png").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Logo retrieval failed"); // PUT:site/logo // ... byte[] imageData = null; System.Drawing.Bitmap pic = new System.Drawing.Bitmap(100, 100); using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(pic)) g.DrawRectangle(System.Drawing.Pens.Blue, 10, 10, 80, 80); System.IO.MemoryStream stream = new System.IO.MemoryStream(); pic.Save(stream, System.Drawing.Imaging.ImageFormat.Png); imageData = stream.ToArray(); msg = p.At("site", "logo").Put(DreamMessage.Ok(MimeType.PNG, imageData)); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Logo upload (PUT) failed"); // GET:site/logo // ... msg = p.At("site", "logo").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Utils.ByteArraysAreEqual(msg.AsBytes(), imageData); // GET:site/logo.png // ... msg = p.At("site", "logo.png").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Logo retrieval failed"); Utils.ByteArraysAreEqual(msg.AsBytes(), imageData); // DELETE:site/logo // ... msg = p.At("site", "logo").Delete(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Logo deletion failed"); msg = p.At("site", "logo").GetAsync().Wait(); Assert.AreEqual(DreamStatus.NotFound, msg.Status, "Logo successfully retrieved after deletion?!"); }