mirror of
https://github.com/apache/cordova-plugin-file-transfer.git
synced 2026-02-02 00:00:05 +08:00
CB-8761 [wp8]: Copy cookies from WebBrowser
On other platforms, the cookies from the browser that apply to the request are automatically included. On WP8, that's not the case. This commit will copy the cookies from the WebBrowser control, if the scheme and host of the WebBrowser match that of the HttpWebRequest. For users who host their web components remotely, and perform uploads/downloads from the same server using cookie based authentication, this fix enables that scenario on WP8, and brings it up to parity with iOS, Android, and others. Fixes https://issues.apache.org/jira/browse/CB-8761 CB-8761 [wp8]: Cleanup per comments github close #74
This commit is contained in:
@@ -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<string, DownloadRequestState> InProcDownloads = new Dictionary<string,DownloadRequestState>();
|
||||
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Uploading response info
|
||||
/// </summary>
|
||||
@@ -209,6 +215,80 @@ namespace WPCordovaClassLib.Cordova.Commands
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to copy all relevant cookies from the WebBrowser control into a header on
|
||||
/// the HttpWebRequest
|
||||
/// </summary>
|
||||
/// <param name="browser">The source browser to copy the cookies from</param>
|
||||
/// <param name="webRequest">The destination HttpWebRequest to add the cookie header to</param>
|
||||
/// <returns>Nothing</returns>
|
||||
private async Task CopyCookiesFromWebBrowser(HttpWebRequest webRequest)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload options
|
||||
/// </summary>
|
||||
@@ -224,7 +304,7 @@ namespace WPCordovaClassLib.Cordova.Commands
|
||||
/// </summary>
|
||||
/// <param name="options">Upload options</param>
|
||||
/// 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<string, string> 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<string, string> headers = parseHeaders(downloadOptions.Headers);
|
||||
|
||||
Reference in New Issue
Block a user