diff --git a/src/wp/FileTransfer.cs b/src/wp/FileTransfer.cs index 1ddfc28..e1f9fb0 100644 --- a/src/wp/FileTransfer.cs +++ b/src/wp/FileTransfer.cs @@ -12,6 +12,7 @@ limitations under the License. */ +using Microsoft.Phone.Controls; using System; using System.Collections.Generic; using System.IO; @@ -21,6 +22,7 @@ using System.Runtime.Serialization; using System.Windows; using System.Security; using System.Diagnostics; +using System.Threading.Tasks; namespace WPCordovaClassLib.Cordova.Commands { @@ -86,6 +88,10 @@ namespace WPCordovaClassLib.Cordova.Commands private static Dictionary InProcDownloads = new Dictionary(); + // Private instance of the main WebBrowser instance + // NOTE: Any access to this object needs to occur on the UI thread via the Dispatcher + private WebBrowser browser; + /// /// Uploading response info /// @@ -209,6 +215,80 @@ namespace WPCordovaClassLib.Cordova.Commands } } + /// + /// Helper method to copy all relevant cookies from the WebBrowser control into a header on + /// the HttpWebRequest + /// + /// The source browser to copy the cookies from + /// The destination HttpWebRequest to add the cookie header to + /// Nothing + private async Task CopyCookiesFromWebBrowser(HttpWebRequest webRequest) + { + var tcs = new TaskCompletionSource(); + + // Accessing WebBrowser needs to happen on the UI thread + Deployment.Current.Dispatcher.BeginInvoke(() => + { + // Get the WebBrowser control + if (this.browser == null) + { + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + if (page != null) + { + CordovaView cView = page.FindName("CordovaView") as CordovaView; + if (cView != null) + { + this.browser = cView.Browser; + } + } + } + } + + try + { + // Only copy the cookies if the scheme and host match (to avoid any issues with secure/insecure cookies) + // NOTE: since the returned CookieCollection appears to munge the original cookie's domain value in favor of the actual Source domain, + // we can't know for sure whether the cookies would be applicable to any other hosts, so best to play it safe and skip for now. + if (this.browser != null && this.browser.Source.IsAbsoluteUri == true && + this.browser.Source.Scheme == webRequest.RequestUri.Scheme && this.browser.Source.Host == webRequest.RequestUri.Host) + { + string cookieHeader = ""; + string requestPath = webRequest.RequestUri.PathAndQuery; + CookieCollection cookies = this.browser.GetCookies(); + + // Iterate over the cookies and add to the header + foreach (Cookie cookie in cookies) + { + // Check that the path is allowed, first + // NOTE: Path always seems to be empty for now, even if the cookie has a path set by the server. + if (cookie.Path.Length == 0 || requestPath.IndexOf(cookie.Path, StringComparison.InvariantCultureIgnoreCase) == 0) + { + cookieHeader += cookie.Name + "=" + cookie.Value + "; "; + } + } + + // Finally, set the header if we found any cookies + if (cookieHeader.Length > 0) + { + webRequest.Headers["Cookie"] = cookieHeader; + } + } + } + catch (Exception) + { + // Swallow the exception + } + + // Complete the task + tcs.SetResult(Type.Missing); + }); + + await tcs.Task; + } + /// /// Upload options /// @@ -224,7 +304,7 @@ namespace WPCordovaClassLib.Cordova.Commands /// /// Upload options /// exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]); - public void upload(string options) + public async void upload(string options) { options = options.Replace("{}", ""); // empty objects screw up the Deserializer string callbackId = ""; @@ -283,6 +363,10 @@ namespace WPCordovaClassLib.Cordova.Commands webRequest.ContentType = "multipart/form-data; boundary=" + Boundary; webRequest.Method = uploadOptions.Method; + // Associate cookies with the request + // This is an async call, so we need to await it in order to preserve proper control flow + await CopyCookiesFromWebBrowser(webRequest); + if (!string.IsNullOrEmpty(uploadOptions.Headers)) { Dictionary headers = parseHeaders(uploadOptions.Headers); @@ -341,7 +425,7 @@ namespace WPCordovaClassLib.Cordova.Commands return null; } - public void download(string options) + public async void download(string options) { TransferOptions downloadOptions = null; HttpWebRequest webRequest = null; @@ -475,6 +559,10 @@ namespace WPCordovaClassLib.Cordova.Commands state.request = webRequest; InProcDownloads[downloadOptions.Id] = state; + // Associate cookies with the request + // This is an async call, so we need to await it in order to preserve proper control flow + await CopyCookiesFromWebBrowser(webRequest); + if (!string.IsNullOrEmpty(downloadOptions.Headers)) { Dictionary headers = parseHeaders(downloadOptions.Headers);