Open danielbarrosamorim opened 6 years ago
Same here
Java.IO.IOException: stream was reset: PROTOCOL_ERROR
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in
Any way to fix @danielbarrosamorim ?
With a fast search i found that:
Maybe the bug occurs because ModernHttpClient dependency?
After disable HTTP/2 from my server all work.
I will wait a fix to enable again.
Any news on this? We are experiencing the same error and need the security etc from okhttp 2+
Are this plug-in maintained? I have held off on upgrading my services to http2 but now the decision was out of my hands. Anyone know a workaround?
On Rendy Del Rosario's twitter he mentions these two alternatives:
https://github.com/Redth/HttpTwo
https://github.com/Matthias247/http2dotnet
I haven't used them though :)
thanks mate, i will look into these
For anyone who might get this error in the future. Ok, big a hack this is. But one "can" download the code from here and change the ModernHttpClient dependency to an updated one. then change the .net target to 2.0 for the android, abstractions projects and build a .dll. then remove the nuget from your xamarin project and use the new dlls insted.
i do not recommend this to anyone.
i will do not have the time to create a PR on this change as there is some problem with the mac and UWP implementations in this hack.
The new android FileUploadManager
using Android.Webkit;
using Java.Util.Concurrent;
using Plugin.FileUploader.Abstractions;
using Square.OkHttp3;
using Square.OkIO;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace Plugin.FileUploader
{
/// <summary>
/// Implementation for Feature
/// </summary>
public class FileUploadManager : IFileUploader, ICountProgressListener
{
public static TimeUnit UploadTimeoutUnit { get; set; } = TimeUnit.Minutes;
public static long SocketUploadTimeout { get; set; } = 5;
public static long ConnectUploadTimeout { get; set; } = 5;
TaskCompletionSource<FileUploadResponse> uploadCompletionSource;
public event EventHandler<FileUploadResponse> FileUploadCompleted = delegate { };
public event EventHandler<FileUploadResponse> FileUploadError = delegate { };
public event EventHandler<FileUploadProgress> FileUploadProgress = delegate { };
public async Task<FileUploadResponse> UploadFileAsync(string url, FileBytesItem fileItem, IDictionary<string, string> headers = null, IDictionary<string, string> parameters = null, string boundary = null)
{
return await UploadFileAsync(url, new FileBytesItem[] { fileItem }, fileItem.Name, headers, parameters, boundary);
}
public async Task<FileUploadResponse> UploadFileAsync(string url, FileBytesItem[] fileItems, string tag, IDictionary<string, string> headers = null, IDictionary<string, string> parameters = null, string boundary = null)
{
uploadCompletionSource = new TaskCompletionSource<FileUploadResponse>();
if (fileItems == null || fileItems.Length == 0)
{
var fileUploadResponse = new FileUploadResponse("There are no items to upload", -1, tag, null);
FileUploadError(this, fileUploadResponse);
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
else
{
Task.Run(() =>
{
try
{
var requestBodyBuilder = PrepareRequest(parameters, boundary);
foreach (var fileItem in fileItems)
{
var mediaType = MediaType.Parse(GetMimeType(fileItem.Name));
if (mediaType == null)
mediaType = MediaType.Parse("*/*");
RequestBody fileBody = RequestBody.Create(mediaType, fileItem.Bytes);
requestBodyBuilder.AddFormDataPart(fileItem.FieldName, fileItem.Name, fileBody);
}
var resp = MakeRequest(url, tag, requestBodyBuilder, headers);
if (!uploadCompletionSource.Task.IsCompleted)
{
uploadCompletionSource.TrySetResult(resp);
}
}
catch (Java.Net.UnknownHostException ex)
{
var fileUploadResponse = new FileUploadResponse("Host not reachable", -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
catch (Java.IO.IOException ex)
{
var fileUploadResponse = new FileUploadResponse(ex.ToString(), -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
catch (Exception ex)
{
var fileUploadResponse = new FileUploadResponse(ex.ToString(), -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
});
}
return await uploadCompletionSource.Task;
}
string GetMimeType(string url)
{
string type = "*/*";
try
{
string extension = MimeTypeMap.GetFileExtensionFromUrl(url);
if (!string.IsNullOrEmpty(extension))
{
type = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension.ToLower());
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
return type;
}
public async Task<FileUploadResponse> UploadFileAsync(string url, FilePathItem fileItem, IDictionary<string, string> headers = null, IDictionary<string, string> parameters = null, string boundary = null)
{
return await UploadFileAsync(url, new FilePathItem[] { fileItem }, fileItem.Path, headers, parameters, boundary);
}
public async Task<FileUploadResponse> UploadFileAsync(string url, FilePathItem[] fileItems, string tag, IDictionary<string, string> headers = null, IDictionary<string, string> parameters = null, string boundary = null)
{
uploadCompletionSource = new TaskCompletionSource<FileUploadResponse>();
if (fileItems == null || fileItems.Length == 0)
{
var fileUploadResponse = new FileUploadResponse("There are no items to upload", -1, tag, null);
FileUploadError(this, fileUploadResponse);
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
else
{
Task.Run(() =>
{
try
{
var requestBodyBuilder = PrepareRequest(parameters, boundary);
foreach (var fileItem in fileItems)
{
Java.IO.File f = new Java.IO.File(fileItem.Path);
string fileAbsolutePath = f.AbsolutePath;
RequestBody file_body = RequestBody.Create(MediaType.Parse(GetMimeType(fileItem.Path)), f);
var fileName = fileAbsolutePath.Substring(fileAbsolutePath.LastIndexOf("/") + 1);
requestBodyBuilder.AddFormDataPart(fileItem.FieldName, fileName, file_body);
}
var resp = MakeRequest(url, tag, requestBodyBuilder, headers);
if (!uploadCompletionSource.Task.IsCompleted)
{
uploadCompletionSource.TrySetResult(resp);
}
}
catch (Java.Net.UnknownHostException ex)
{
var fileUploadResponse = new FileUploadResponse("Host not reachable", -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
catch (Java.IO.IOException ex)
{
var fileUploadResponse = new FileUploadResponse(ex.ToString(), -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
catch (Exception ex)
{
var fileUploadResponse = new FileUploadResponse(ex.ToString(), -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(ex.ToString());
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
});
}
return await uploadCompletionSource.Task;
}
MultipartBody.Builder PrepareRequest(IDictionary<string, string> parameters = null, string boundary = null)
{
MultipartBody.Builder requestBodyBuilder = null;
if (string.IsNullOrEmpty(boundary))
{
requestBodyBuilder = new MultipartBody.Builder().SetType(MultipartBody.Form);
}
else
{
requestBodyBuilder = new MultipartBody.Builder(boundary).SetType(MultipartBody.Form);
}
if (parameters != null)
{
foreach (string key in parameters.Keys)
{
if (parameters[key] != null)
{
requestBodyBuilder.AddFormDataPart(key, parameters[key]);
}
}
}
return requestBodyBuilder;
}
FileUploadResponse MakeRequest(string url, string tag, MultipartBody.Builder requestBodyBuilder, IDictionary<string, string> headers = null)
{
//RequestBody requestBody = requestBodyBuilder.Build();
CountingRequestBody requestBody = new CountingRequestBody(requestBodyBuilder.Build(), tag, this);
var requestBuilder = new Request.Builder();
if (headers != null)
{
foreach (string key in headers.Keys)
{
if (!string.IsNullOrEmpty(headers[key]))
{
requestBuilder = requestBuilder.AddHeader(key, headers[key]);
}
}
}
Request request = requestBuilder
.Url(url)
.Post(requestBody)
.Build();
OkHttpClient client = new OkHttpClient.Builder()
.ConnectTimeout(ConnectUploadTimeout, UploadTimeoutUnit)
.ReadTimeout(SocketUploadTimeout, UploadTimeoutUnit)
.Build();
//client.SetConnectTimeout(ConnectUploadTimeout, UploadTimeoutUnit); // connect timeout
//client.SetReadTimeout(SocketUploadTimeout, UploadTimeoutUnit); // socket timeout
Response response = client.NewCall(request).Execute();
var responseString = response.Body().String();
var code = response.Code();
IDictionary<string, string> responseHeaders = new Dictionary<string, string>();
var rHeaders = response.Headers();
if (rHeaders != null)
{
var names = rHeaders.Names();
foreach (string name in names)
{
if (!string.IsNullOrEmpty(rHeaders.Get(name)))
{
responseHeaders.Add(name, rHeaders.Get(name));
}
}
}
FileUploadResponse fileUploadResponse = new FileUploadResponse(responseString, code, tag, new ReadOnlyDictionary<string, string>(responseHeaders));
if (response.IsSuccessful)
{
FileUploadCompleted(this, fileUploadResponse);
}
else
{
FileUploadError(this, fileUploadResponse);
}
return fileUploadResponse;
}
public void OnProgress(string tag, long bytesWritten, long contentLength)
{
var fileUploadProgress = new FileUploadProgress(bytesWritten, contentLength, tag);
FileUploadProgress(this, fileUploadProgress);
}
public void OnError(string tag, string error)
{
var fileUploadResponse = new FileUploadResponse(error, -1, tag, null);
FileUploadError(this, fileUploadResponse);
System.Diagnostics.Debug.WriteLine(error);
uploadCompletionSource.TrySetResult(fileUploadResponse);
}
}
}
the new android CountingRequestBody
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Square.OkHttp3;
using Square.OkIO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.FileUploader
{
public class CountingRequestBody : RequestBody
{
protected RequestBody _body;
protected ICountProgressListener _listener;
protected string _tag;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody body, string tag, ICountProgressListener listener)
{
_body = body;
_tag = tag;
_listener = listener;
}
public override MediaType ContentType()
{
return _body.ContentType();
}
public override long ContentLength()
{
return _body.ContentLength();
}
public override void WriteTo(IBufferedSink p0)
{
try
{
IBufferedSink bufferedSink;
countingSink = new CountingSink(this, p0);
bufferedSink = OkIO.Buffer(countingSink);
_body.WriteTo(bufferedSink);
bufferedSink.Flush();
}
catch (Java.IO.IOException ex)
{
_listener?.OnError(_tag, ex.ToString());
}
}
public class CountingSink : ForwardingSink
{
private long bytesWritten = 0;
CountingRequestBody _parent;
public CountingSink(CountingRequestBody parent, ISink sink) : base(sink)
{
_parent = parent;
}
public override void Write(OkBuffer p0, long p1)
{
try
{
base.Write(p0, p1);
bytesWritten += p1;
_parent?._listener.OnProgress(_parent._tag, bytesWritten, _parent.ContentLength());
}
catch (Java.IO.IOException ex)
{
_parent?._listener?.OnError(_parent._tag, ex.ToString());
}
}
}
}
}
Bug Information
Java.IO.IOException: stream was reset: PROTOCOL_ERROR at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in
Detailed error at: https://gist.github.com/danielbarrosamorim/b92faa78c4ae27b6b62cb6eda7a069d5
Version Number of Plugin: 1.4.0 Device Tested On: Android Moto G Play Version 7.1.1 Simulator Tested On: Not tested Version of VS: 7.4.2 (Build 12) Stable Version of Xamarin: Xamarin Forms 2.5.1.444934 Versions of other things you are using: .Net Standard 1.6
Steps to reproduce the Behavior
Create a new Xamarin.Forms + .NetStandard 1.6 Create a Method to Post an Image to a server On Android just post an Image from local path to an URL
Expected Behavior
Save the image on the server.
Actual Behavior
Java error as described above.
Code snippet
var result = await CrossFileUploader.Current.UploadFileAsync(url, new FilePathItem("filePayload", path), new Dictionary<string, string>(){ {"Authorization" , $"Bearer {Settings.AccessToken}"} } , new Dictionary<string, string>(){ { uploadType , Id } } ); ApiResult apiResult = new ApiResult();
apiResult.code = result.StatusCode.ToString();
apiResult.data = result.Message;
Screenshotst