diff --git a/tests/common/MonoTouch.Dialog/Elements.cs b/tests/common/MonoTouch.Dialog/Elements.cs index 6bd56b5b7897..f528d3e48111 100644 --- a/tests/common/MonoTouch.Dialog/Elements.cs +++ b/tests/common/MonoTouch.Dialog/Elements.cs @@ -765,7 +765,7 @@ public override bool Matches (string text) /// options and can render images or background images either from UIImage parameters /// or by downloading them from the net. /// - public partial class StyledStringElement : StringElement, IImageUpdated, IColorizeBackground { + public partial class StyledStringElement : StringElement, IColorizeBackground { static NSString [] skey = { new NSString (".1"), new NSString (".2"), new NSString (".3"), new NSString (".4") }; public StyledStringElement (string caption) : base (caption) { } @@ -793,9 +793,7 @@ public StyledStringElement (string caption, string value, UITableViewCellStyle s ExtraInfo extraInfo; class ExtraInfo { - public UIImage Image; // Maybe add BackgroundImage? public UIColor BackgroundColor, DetailColor; - public Uri Uri, BackgroundUri; } ExtraInfo OnImageInfo () @@ -805,36 +803,12 @@ ExtraInfo OnImageInfo () return extraInfo; } - // Uses the specified image (use this or ImageUri) - public UIImage Image { - get { - return extraInfo is null ? null : extraInfo.Image; - } - set { - OnImageInfo ().Image = value; - extraInfo.Uri = null; - } - } - - // Loads the image from the specified uri (use this or Image) - public Uri ImageUri { - get { - return extraInfo is null ? null : extraInfo.Uri; - } - set { - OnImageInfo ().Uri = value; - extraInfo.Image = null; - } - } - - // Background color for the cell (alternative: BackgroundUri) public UIColor BackgroundColor { get { return extraInfo is null ? null : extraInfo.BackgroundColor; } set { OnImageInfo ().BackgroundColor = value; - extraInfo.BackgroundUri = null; } } @@ -847,17 +821,6 @@ public UIColor DetailColor { } } - // Uri for a Background image (alternatiev: BackgroundColor) - public Uri BackgroundUri { - get { - return extraInfo is null ? null : extraInfo.BackgroundUri; - } - set { - OnImageInfo ().BackgroundUri = value; - extraInfo.BackgroundColor = null; - } - } - protected virtual string GetKey (int style) { return skey [style]; @@ -893,19 +856,6 @@ protected void PrepareCell (UITableViewCell cell) if (extraInfo is null) { ClearBackground (cell); } else { - var imgView = cell.ImageView; - UIImage img; - - if (imgView is not null) { - if (extraInfo.Uri is not null) - img = ImageLoader.DefaultRequestImage (extraInfo.Uri, this); - else if (extraInfo.Image is not null) - img = extraInfo.Image; - else - img = null; - imgView.Image = img; - } - if (cell.DetailTextLabel is not null) cell.DetailTextLabel.TextColor = extraInfo.DetailColor ?? UIColor.Gray; } @@ -934,24 +884,10 @@ void IColorizeBackground.WillDisplay (UITableView tableView, UITableViewCell cel if (extraInfo.BackgroundColor is not null) { cell.TextLabel.BackgroundColor = UIColor.Clear; cell.BackgroundColor = extraInfo.BackgroundColor; - } else if (extraInfo.BackgroundUri is not null) { - var img = ImageLoader.DefaultRequestImage (extraInfo.BackgroundUri, this); - cell.TextLabel.BackgroundColor = UIColor.Clear; - cell.BackgroundColor = img is null ? UIColor.White : UIColor.FromPatternImage (img); } else ClearBackground (cell); } - void IImageUpdated.UpdatedImage (Uri uri) - { - if (uri is null || extraInfo is null) - return; - var root = GetImmediateRootElement (); - if (root is null || root.TableView is null) - return; - root.TableView.ReloadRows (new NSIndexPath [] { IndexPath }, UITableViewRowAnimation.None); - } - internal void AccessoryTap () { NSAction tapped = AccessoryTapped; @@ -1079,57 +1015,6 @@ public virtual nfloat GetHeight (UITableView tableView, NSIndexPath indexPath) } } - public partial class ImageStringElement : StringElement { - static NSString skey = new NSString ("ImageStringElement"); - UIImage image; - public UITableViewCellAccessory Accessory { get; set; } - - public ImageStringElement (string caption, UIImage image) : base (caption) - { - this.image = image; - this.Accessory = UITableViewCellAccessory.None; - } - - public ImageStringElement (string caption, string value, UIImage image) : base (caption, value) - { - this.image = image; - this.Accessory = UITableViewCellAccessory.None; - } - - public ImageStringElement (string caption, NSAction tapped, UIImage image) : base (caption, tapped) - { - this.image = image; - this.Accessory = UITableViewCellAccessory.None; - } - - protected override NSString CellKey { - get { - return skey; - } - } - public override UITableViewCell GetCell (UITableView tv) - { - var cell = tv.DequeueReusableCell (CellKey); - if (cell is null) { - cell = new UITableViewCell (Value is null ? UITableViewCellStyle.Default : UITableViewCellStyle.Subtitle, CellKey); - cell.SelectionStyle = UITableViewCellSelectionStyle.Blue; - } - - cell.Accessory = Accessory; - cell.TextLabel.Text = Caption; - cell.TextLabel.TextAlignment = Alignment; - - cell.ImageView.Image = image; - - // The check is needed because the cell might have been recycled. - if (cell.DetailTextLabel is not null) - cell.DetailTextLabel.Text = Value is null ? "" : Value; - - return cell; - } - - } - /// /// This interface is implemented by Element classes that will have /// different heights @@ -1268,194 +1153,6 @@ public override void Selected (DialogViewController dvc, UITableView tableView, } - public partial class ImageElement : Element { - public UIImage Value; - static CGRect rect = new CGRect (0, 0, dimx, dimy); - static NSString ikey = new NSString ("ImageElement"); - UIImage scaled; - - // There's no UIImagePickerController in tvOS (and I couldn't find any suitable replacement either). -#if !__TVOS__ - UIPopoverController popover; - - // Apple leaks this one, so share across all. - static UIImagePickerController picker; -#endif // !__TVOS__ - - // Height for rows - const int dimx = 48; - const int dimy = 43; - - // radius for rounding - const int rad = 10; - - static UIImage MakeEmpty () - { - using (var cs = CGColorSpace.CreateDeviceRGB ()) { - using (var bit = new CGBitmapContext (IntPtr.Zero, dimx, dimy, 8, 0, cs, CGImageAlphaInfo.PremultipliedFirst)) { - bit.SetStrokeColor (1, 0, 0, 0.5f); - bit.FillRect (new CGRect (0, 0, dimx, dimy)); - - return UIImage.FromImage (bit.ToImage ()); - } - } - } - - UIImage Scale (UIImage source) - { - UIGraphics.BeginImageContext (new CGSize (dimx, dimy)); - var ctx = UIGraphics.GetCurrentContext (); - - var img = source.CGImage; - ctx.TranslateCTM (0, dimy); - if (img.Width > img.Height) - ctx.ScaleCTM (1, (nfloat) (-img.Width / dimy)); - else - ctx.ScaleCTM ((nfloat) img.Height / dimx, -1); - - ctx.DrawImage (rect, source.CGImage); - - var ret = UIGraphics.GetImageFromCurrentImageContext (); - UIGraphics.EndImageContext (); - return ret; - } - - public ImageElement (UIImage image) : base ("") - { - if (image is null) { - Value = MakeEmpty (); - scaled = Value; - } else { - Value = image; - scaled = Scale (Value); - } - } - - protected override NSString CellKey { - get { - return ikey; - } - } - - public override UITableViewCell GetCell (UITableView tv) - { - var cell = tv.DequeueReusableCell (CellKey); - if (cell is null) { - cell = new UITableViewCell (UITableViewCellStyle.Default, CellKey); - } - - if (scaled is null) - return cell; - - Section psection = Parent as Section; - bool roundTop = psection.Elements [0] == this; - bool roundBottom = psection.Elements [psection.Elements.Count - 1] == this; - - using (var cs = CGColorSpace.CreateDeviceRGB ()) { - using (var bit = new CGBitmapContext (IntPtr.Zero, dimx, dimy, 8, 0, cs, CGImageAlphaInfo.PremultipliedFirst)) { - // Clipping path for the image, different on top, middle and bottom. - if (roundBottom) { - bit.AddArc (rad, rad, rad, (float) Math.PI, (float) (3 * Math.PI / 2), false); - } else { - bit.MoveTo (0, rad); - bit.AddLineToPoint (0, 0); - } - bit.AddLineToPoint (dimx, 0); - bit.AddLineToPoint (dimx, dimy); - - if (roundTop) { - bit.AddArc (rad, dimy - rad, rad, (float) (Math.PI / 2), (float) Math.PI, false); - bit.AddLineToPoint (0, rad); - } else { - bit.AddLineToPoint (0, dimy); - } - bit.Clip (); - bit.DrawImage (rect, scaled.CGImage); - - cell.ImageView.Image = UIImage.FromImage (bit.ToImage ()); - } - } - return cell; - } - - protected override void Dispose (bool disposing) - { - if (disposing) { - if (scaled is not null) { - scaled.Dispose (); - Value.Dispose (); - scaled = null; - Value = null; - } - } - base.Dispose (disposing); - } - -#if !__TVOS__ - class MyDelegate : UIImagePickerControllerDelegate { - ImageElement container; - UITableView table; - NSIndexPath path; - - public MyDelegate (ImageElement container, UITableView table, NSIndexPath path) - { - this.container = container; - this.table = table; - this.path = path; - } - -#if !NET - public override void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo) - { - container.Picked (image); - table.ReloadRows (new NSIndexPath [] { path }, UITableViewRowAnimation.None); - } -#else - public override void FinishedPickingMedia (UIImagePickerController picker, NSDictionary info) - { - var image = (UIImage) (info [UIImagePickerController.OriginalImage] ?? info [UIImagePickerController.EditedImage]); - container.Picked (image); - table.ReloadRows (new NSIndexPath [] { path }, UITableViewRowAnimation.None); - } -#endif - } - - void Picked (UIImage image) - { - Value = image; - scaled = Scale (image); - currentController.DismissModalViewController (true); - } - - UIViewController currentController; - public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path) - { - if (picker is null) - picker = new UIImagePickerController (); - picker.Delegate = new MyDelegate (this, tableView, path); - - switch (UIDevice.CurrentDevice.UserInterfaceIdiom) { - case UIUserInterfaceIdiom.Pad: - CGRect useRect; - popover = new UIPopoverController (picker); - var cell = tableView.CellAt (path); - if (cell is null) - useRect = rect; - else - useRect = cell.Frame; - popover.PresentFromRect (useRect, dvc.View, UIPopoverArrowDirection.Any, true); - break; - - default: - case UIUserInterfaceIdiom.Phone: - dvc.ActivateController (picker); - break; - } - currentController = dvc; - } -#endif // !__TVOS__ - } - /// /// An element that can be used to enter text. /// diff --git a/tests/common/MonoTouch.Dialog/Elements/ElementBadge.cs b/tests/common/MonoTouch.Dialog/Elements/ElementBadge.cs deleted file mode 100644 index acf1a26976b4..000000000000 --- a/tests/common/MonoTouch.Dialog/Elements/ElementBadge.cs +++ /dev/null @@ -1,156 +0,0 @@ -// -// ElementBadge.cs: defines the Badge Element. -// -// Author: -// Miguel de Icaza (miguel@gnome.org) -// -// Copyright 2010, Novell, Inc. -// -// Code licensed under the MIT X11 license -// -using System; -using System.Collections; -using System.Collections.Generic; -using System.Drawing; - -using UIKit; -using CoreGraphics; -using Foundation; -using ObjCRuntime; - -using NSAction = global::System.Action; - -namespace MonoTouch.Dialog { - /// - /// This element can be used to show an image with some text - /// - /// - /// The font can be configured after the element has been created - /// by assignign to the Font property; If you want to render - /// multiple lines of text, set the MultiLine property to true. - /// - /// If no font is specified, it will default to Helvetica 17. - /// - /// A static method MakeCalendarBadge is provided that can - /// render a calendar badge like the iPhone OS. It will compose - /// the text on top of the image which is expected to be 57x57 - /// - public partial class BadgeElement : Element, IElementSizing { - static NSString ckey = new NSString ("badgeKey"); - public event NSAction Tapped; - public UILineBreakMode LineBreakMode = UILineBreakMode.TailTruncation; - public UIViewContentMode ContentMode = UIViewContentMode.Left; - public int Lines = 1; - public UITableViewCellAccessory Accessory = UITableViewCellAccessory.None; - UIImage image; - UIFont font; - - public BadgeElement (UIImage badgeImage, string cellText) - : this (badgeImage, cellText, null) - { - } - - public BadgeElement (UIImage badgeImage, string cellText, NSAction tapped) : base (cellText) - { - if (badgeImage is null) - throw new ArgumentNullException ("badgeImage"); - - image = badgeImage; - if (tapped is not null) - Tapped += tapped; - } - - public UIFont Font { - get { - if (font is null) - font = UIFont.FromName ("Helvetica", 17f); - return font; - } - set { - if (font is not null) - font.Dispose (); - font = value; - } - } - - public override UITableViewCell GetCell (UITableView tv) - { - var cell = tv.DequeueReusableCell (ckey); - if (cell is null) { - cell = new UITableViewCell (UITableViewCellStyle.Default, ckey) { - SelectionStyle = UITableViewCellSelectionStyle.Blue - }; - } - cell.Accessory = Accessory; - var tl = cell.TextLabel; - tl.Text = Caption; - tl.Font = Font; - tl.LineBreakMode = LineBreakMode; - tl.Lines = Lines; - tl.ContentMode = ContentMode; - - cell.ImageView.Image = image; - - return cell; - } - - protected override void Dispose (bool disposing) - { - base.Dispose (disposing); - } - - public nfloat GetHeight (UITableView tableView, NSIndexPath indexPath) - { - CGSize size = new CGSize (tableView.Bounds.Width - 40, nfloat.MaxValue); - nfloat height = Caption.StringSize (Font, size, LineBreakMode).Height + 10; - - // Image is 57 pixels tall, add some padding - return (nfloat) Math.Max (height, 63); - } - - public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path) - { - if (Tapped is not null) - Tapped (); - tableView.DeselectRow (path, true); - } - - public static UIImage MakeCalendarBadge (UIImage template, string smallText, string bigText) - { - using (var cs = CGColorSpace.CreateDeviceRGB ()) { - using (var context = new CGBitmapContext (IntPtr.Zero, 57, 57, 8, 57 * 4, cs, CGImageAlphaInfo.PremultipliedLast)) { - //context.ScaleCTM (0.5f, -1); - context.TranslateCTM (0, 0); - context.DrawImage (new CGRect (0, 0, 57, 57), template.CGImage); - context.SetFillColor (1, 1, 1, 1); - - context.SelectFont ("Helvetica", 10f, CGTextEncoding.MacRoman); - - // Pretty lame way of measuring strings, as documented: - var start = context.TextPosition.X; - context.SetTextDrawingMode (CGTextDrawingMode.Invisible); - context.ShowText (smallText); - var width = context.TextPosition.X - start; - - context.SetTextDrawingMode (CGTextDrawingMode.Fill); - context.ShowTextAtPoint ((57 - width) / 2, 46, smallText); - - // The big string - context.SelectFont ("Helvetica-Bold", 32, CGTextEncoding.MacRoman); - start = context.TextPosition.X; - context.SetTextDrawingMode (CGTextDrawingMode.Invisible); - context.ShowText (bigText); - width = context.TextPosition.X - start; - - context.SetFillColor (0, 0, 0, 1); - context.SetTextDrawingMode (CGTextDrawingMode.Fill); - context.ShowTextAtPoint ((57 - width) / 2, 9, bigText); - - context.StrokePath (); - - return UIImage.FromImage (context.ToImage ()); - } - } - } - } -} diff --git a/tests/common/MonoTouch.Dialog/Utilities/ImageLoader.cs b/tests/common/MonoTouch.Dialog/Utilities/ImageLoader.cs deleted file mode 100644 index 55c4a2511ea1..000000000000 --- a/tests/common/MonoTouch.Dialog/Utilities/ImageLoader.cs +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2010-2011 Miguel de Icaza -// -// Based on the TweetStation specific ImageStore -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using System.Security.Cryptography; - -using Foundation; -using UIKit; -using CoreGraphics; - -using MonoTouch.Dialog.Utilities; - -namespace MonoTouch.Dialog.Utilities { - /// - /// This interface needs to be implemented to be notified when an image - /// has been downloaded. The notification will happen on the UI thread. - /// Upon notification, the code should call RequestImage again, this time - /// the image will be loaded from the on-disk cache or the in-memory cache. - /// - public interface IImageUpdated { - void UpdatedImage (Uri uri); - } - - /// - /// Network image loader, with local file system cache and in-memory cache - /// - /// - /// By default, using the static public methods will use an in-memory cache - /// for 50 images and 4 megs total. The behavior of the static methods - /// can be modified by setting the public DefaultLoader property to a value - /// that the user configured. - /// - /// The instance methods can be used to create different imageloader with - /// different properties. - /// - /// Keep in mind that the phone does not have a lot of memory, and using - /// the cache with the unlimited value (0) even with a number of items in - /// the cache can consume memory very quickly. - /// - /// Use the Purge method to release all the memory kept in the caches on - /// low memory conditions, or when the application is sent to the background. - /// - - public class ImageLoader { - public readonly static string BaseDir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".."); - const int MaxRequests = 6; - static string PicDir; - - // Cache of recently used images - LRUCache cache; - - // A list of requests that have been issues, with a list of objects to notify. - static Dictionary> pendingRequests; - - // A list of updates that have completed, we must notify the main thread about them. - static HashSet queuedUpdates; - - // A queue used to avoid flooding the network stack with HTTP requests - static Stack requestQueue; - - static NSString nsDispatcher = new NSString ("x"); - - static MD5 checksum = MD5.Create (); - - /// - /// This contains the default loader which is configured to be 50 images - /// up to 4 megs of memory. Assigning to this property a new value will - /// change the behavior. This property is lazyly computed, the first time - /// an image is requested. - /// - public static ImageLoader DefaultLoader; - - static ImageLoader () - { - PicDir = Path.Combine (BaseDir, "Library/Caches/Pictures.MonoTouch.Dialog/"); - - if (!Directory.Exists (PicDir)) - Directory.CreateDirectory (PicDir); - - pendingRequests = new Dictionary> (); - queuedUpdates = new HashSet (); - requestQueue = new Stack (); - } - - /// - /// Creates a new instance of the image loader - /// - /// - /// The maximum number of entries in the LRU cache - /// - /// - /// The maximum number of bytes to consume by the image loader cache. - /// - public ImageLoader (int cacheSize, int memoryLimit) - { - cache = new LRUCache (cacheSize, memoryLimit, sizer); - } - - static int sizer (UIImage img) - { - var cg = img.CGImage; - return (int) (cg.BytesPerRow * cg.Height); - } - - /// - /// Purges the contents of the DefaultLoader - /// - public static void Purge () - { - if (DefaultLoader is not null) - DefaultLoader.PurgeCache (); - } - - /// - /// Purges the cache of this instance of the ImageLoader, releasing - /// all the memory used by the images in the caches. - /// - public void PurgeCache () - { - lock (cache) - cache.Purge (); - } - - static int hex (int v) - { - if (v < 10) - return '0' + v; - return 'a' + v - 10; - } - - static string md5 (string input) - { - var bytes = checksum.ComputeHash (Encoding.UTF8.GetBytes (input)); - var ret = new char [32]; - for (int i = 0; i < 16; i++) { - ret [i * 2] = (char) hex (bytes [i] >> 4); - ret [i * 2 + 1] = (char) hex (bytes [i] & 0xf); - } - return new string (ret); - } - - /// - /// Requests an image to be loaded using the default image loader - /// - /// - /// The URI for the image to load - /// - /// - /// A class implementing the IImageUpdated interface that will be invoked when the image has been loaded - /// - /// - /// If the image has already been downloaded, or is in the cache, this will return the image as a UIImage. - /// - public static UIImage DefaultRequestImage (Uri uri, IImageUpdated notify) - { - if (DefaultLoader is null) - DefaultLoader = new ImageLoader (50, 4 * 1024 * 1024); - return DefaultLoader.RequestImage (uri, notify); - } - - /// - /// Requests an image to be loaded from the network - /// - /// - /// The URI for the image to load - /// - /// - /// A class implementing the IImageUpdated interface that will be invoked when the image has been loaded - /// - /// - /// If the image has already been downloaded, or is in the cache, this will return the image as a UIImage. - /// - public UIImage RequestImage (Uri uri, IImageUpdated notify) - { - UIImage ret; - - lock (cache) { - ret = cache [uri]; - if (ret is not null) - return ret; - } - - lock (requestQueue) { - if (pendingRequests.ContainsKey (uri)) { - if (!pendingRequests [uri].Contains (notify)) - pendingRequests [uri].Add (notify); - return null; - } - } - - string picfile = uri.IsFile ? uri.LocalPath : PicDir + md5 (uri.AbsoluteUri); - if (File.Exists (picfile)) { - ret = UIImage.FromFile (picfile); - if (ret is not null) { - lock (cache) - cache [uri] = ret; - return ret; - } - } - if (uri.IsFile) - return null; - QueueRequest (uri, notify); - return null; - } - - static void QueueRequest (Uri uri, IImageUpdated notify) - { - if (notify is null) - throw new ArgumentNullException ("notify"); - - lock (requestQueue) { - if (pendingRequests.ContainsKey (uri)) { - //Util.Log ("pendingRequest: added new listener for {0}", id); - pendingRequests [uri].Add (notify); - return; - } - var slot = new List (4); - slot.Add (notify); - pendingRequests [uri] = slot; - - if (picDownloaders >= MaxRequests) - requestQueue.Push (uri); - else { - ThreadPool.QueueUserWorkItem (delegate - { - try { - StartPicDownload (uri); - } catch (Exception e) { - Console.WriteLine (e); - } - }); - } - } - } - - static bool Download (Uri uri) - { - try { - NSUrlResponse response; - NSError error; - - var target = PicDir + md5 (uri.AbsoluteUri); - var req = new NSUrlRequest (new NSUrl (uri.AbsoluteUri.ToString ()), NSUrlRequestCachePolicy.UseProtocolCachePolicy, 120); - var data = NSUrlConnection.SendSynchronousRequest (req, out response, out error); - return data.Save (target, true, out error); - } catch (Exception e) { - Console.WriteLine ("Problem with {0} {1}", uri, e); - return false; - } - } - - static long picDownloaders; - - static void StartPicDownload (Uri uri) - { - Interlocked.Increment (ref picDownloaders); - try { - _StartPicDownload (uri); - } catch (Exception e) { - Console.Error.WriteLine ("CRITICAL: should have never happened {0}", e); - } - //Util.Log ("Leaving StartPicDownload {0}", picDownloaders); - Interlocked.Decrement (ref picDownloaders); - } - - static void _StartPicDownload (Uri uri) - { - do { - bool downloaded = false; - - //System.Threading.Thread.Sleep (5000); - downloaded = Download (uri); - //if (!downloaded) - // Console.WriteLine ("Error fetching picture for {0} to {1}", uri, target); - - // Cluster all updates together - bool doInvoke = false; - - lock (requestQueue) { - if (downloaded) { - queuedUpdates.Add (uri); - - // If this is the first queued update, must notify - if (queuedUpdates.Count == 1) - doInvoke = true; - } else - pendingRequests.Remove (uri); - - // Try to get more jobs. - if (requestQueue.Count > 0) { - uri = requestQueue.Pop (); - if (uri is null) { - Console.Error.WriteLine ("Dropping request {0} because url is null", uri); - pendingRequests.Remove (uri); - uri = null; - } - } else { - //Util.Log ("Leaving because requestQueue.Count = {0} NOTE: {1}", requestQueue.Count, pendingRequests.Count); - uri = null; - } - } - if (doInvoke) - nsDispatcher.BeginInvokeOnMainThread (NotifyImageListeners); - - } while (uri is not null); - } - - // Runs on the main thread - static void NotifyImageListeners () - { - lock (requestQueue) { - foreach (var quri in queuedUpdates) { - var list = pendingRequests [quri]; - pendingRequests.Remove (quri); - foreach (var pr in list) { - try { - pr.UpdatedImage (quri); - } catch (Exception e) { - Console.WriteLine (e); - } - } - } - queuedUpdates.Clear (); - } - } - } -} diff --git a/tests/monotouch-test/Foundation/CookieTest.cs b/tests/monotouch-test/Foundation/CookieTest.cs index 58b5cc95a7f4..32f1804d4a77 100644 --- a/tests/monotouch-test/Foundation/CookieTest.cs +++ b/tests/monotouch-test/Foundation/CookieTest.cs @@ -174,7 +174,9 @@ public void DotNetInterop_NonSession () c.CommentUri = new Uri ("http://comment.uri"); c.Discard = false; c.Expires = DateTime.Now.AddDays (1); +#pragma warning disable SM02360 // "Websites must specify the HttpOnly attribute on sensitive cookies" - this is a cookie test, we're not sending any requests, so it's safe to ignore c.HttpOnly = false; +#pragma warning restore SM02360 c.Port = "\"80\""; c.Secure = true; c.Version = 1; diff --git a/tests/xharness/Jenkins/TestServer.cs b/tests/xharness/Jenkins/TestServer.cs index 0c1609be8102..d739cdccfd96 100644 --- a/tests/xharness/Jenkins/TestServer.cs +++ b/tests/xharness/Jenkins/TestServer.cs @@ -95,7 +95,17 @@ IEnumerable find_tasks (StreamWriter writer, string ids) } string serveFile = null; - switch (request.Url.LocalPath) { + var localPath = request.Url.LocalPath; + if (localPath.Contains ("..") || localPath.Contains ("/") || localPath.Contains ("\\")) { + // Validate that we're not requested to serve any file on the file system. + // Ref: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2351243 + response.StatusCode = 400; + response.StatusDescription = "Bad Request"; + response.OutputStream.Write (System.Text.Encoding.UTF8.GetBytes ("Invalid local path")); + return; + } + + switch (localPath) { case "/": response.ContentType = System.Net.Mime.MediaTypeNames.Text.Html; using (var writer = new StreamWriter (response.OutputStream)) { @@ -188,10 +198,10 @@ IEnumerable find_tasks (StreamWriter writer, string ids) writer.WriteLine ("unknown query: {0}", request.Url.Query); break; } - if (request.Url.LocalPath == "/select") { + if (localPath == "/select") { if (is_match.HasValue && is_match.Value) task.Ignored = false; - } else if (request.Url.LocalPath == "/deselect") { + } else if (localPath == "/deselect") { if (is_match.HasValue && is_match.Value) task.Ignored = true; } @@ -273,17 +283,17 @@ IEnumerable find_tasks (StreamWriter writer, string ids) response.Redirect (redirect_to); break; default: - var filename = Path.GetFileName (request.Url.LocalPath); - if (filename == "index.html" && Path.GetFileName (jenkins.LogDirectory) == Path.GetFileName (Path.GetDirectoryName (request.Url.LocalPath))) { + var filename = Path.GetFileName (localPath); + if (filename == "index.html" && Path.GetFileName (jenkins.LogDirectory) == Path.GetFileName (Path.GetDirectoryName (localPath))) { // We're asked for the report for the current test run, so re-generate it. jenkins.GenerateReport (); } if (serveFile is null) { - serveFile = Path.Combine (Path.GetDirectoryName (jenkins.LogDirectory), request.Url.LocalPath.Substring (1)); + serveFile = Path.Combine (Path.GetDirectoryName (jenkins.LogDirectory), localPath.Substring (1)); serveFile = Path.GetFullPath (serveFile); if (!serveFile.StartsWith (Path.GetDirectoryName (Path.GetFullPath (jenkins.LogDirectory)) + Path.DirectorySeparatorChar)) { - Console.WriteLine ($"400: {request.Url.LocalPath}"); + Console.WriteLine ($"400: {localPath}"); response.StatusCode = 400; response.OutputStream.WriteByte ((byte) '?'); break; @@ -316,7 +326,7 @@ IEnumerable find_tasks (StreamWriter writer, string ids) response.OutputStream.Write (buffer, 0, read); } } else { - Console.WriteLine ($"404: {request.Url.LocalPath}"); + Console.WriteLine ($"404: {localPath}"); response.StatusCode = 404; response.OutputStream.WriteByte ((byte) '?'); }