async Task <HttpResponseMessage> DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"{this}.DoProcessRequest ()"); } try { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $" connecting"); } await httpConnection.ConnectAsync().ConfigureAwait(false); if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $" connected"); } } catch (Java.Net.ConnectException ex) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Connection exception {ex}"); } // Wrap it nicely in a "standard" exception so that it's compatible with HttpClientHandler throw new WebException(ex.Message, ex, WebExceptionStatus.ConnectFailure, null); } if (httpConnection.DoOutput) { await request.Content.CopyToAsync(httpConnection.OutputStream).ConfigureAwait(false); } var statusCode = (HttpStatusCode)httpConnection.ResponseCode; var connectionUri = new Uri(httpConnection.URL.ToString()); // If the request was redirected we need to put the new URL in the request request.RequestUri = connectionUri; var ret = new AndroidHttpResponseMessage(javaUrl, httpConnection) { RequestMessage = request, ReasonPhrase = httpConnection.ResponseMessage, StatusCode = statusCode, }; if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Status code: {statusCode}"); } if (statusCode == HttpStatusCode.Unauthorized || statusCode == HttpStatusCode.ProxyAuthenticationRequired) { // We don't resend the request since that would require new set of credentials if the // ones provided in Credentials are invalid (or null) and that, in turn, may require asking the // user which is not something that should be taken care of by us and in this // context. The application should be responsible for this. // HttpClientHandler throws an exception in this instance, but I think it's not a good // idea. We'll return the response message with all the information required by the // application to fill in the blanks and provide the requested credentials instead. // // We should return the body of the response too but, alas, the Java client will throw // a, wait for it, FileNotFound exception if we attempt to access the input stream. So // no body, just a dummy. Java FTW! ret.Content = new StringContent("Unauthorized", Encoding.ASCII); CopyHeaders(httpConnection, ret); if (ret.Headers.WwwAuthenticate != null) { ProxyAuthenticationRequested = false; CollectAuthInfo(ret.Headers.WwwAuthenticate); } else if (ret.Headers.ProxyAuthenticate != null) { ProxyAuthenticationRequested = true; CollectAuthInfo(ret.Headers.ProxyAuthenticate); } ret.RequestedAuthentication = RequestedAuthentication; return(ret); } if (!IsErrorStatusCode(statusCode)) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Reading..."); } Stream inputStream = new BufferedStream(httpConnection.InputStream); if (decompress_here) { string[] encodings = httpConnection.ContentEncoding?.Split(','); if (encodings != null) { if (encodings.Contains(GZIP_ENCODING, StringComparer.OrdinalIgnoreCase)) { inputStream = new GZipStream(inputStream, CompressionMode.Decompress); } else if (encodings.Contains(DEFLATE_ENCODING, StringComparer.OrdinalIgnoreCase)) { inputStream = new DeflateStream(inputStream, CompressionMode.Decompress); } } } ret.Content = new StreamContent(inputStream); } else { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Status code is {statusCode}, returning empty content"); } // For 400 >= response code <= 599 the Java client throws the FileNotFound exeption when attempting to read from the connection // Client tests require we return no content here ret.Content = new StringContent(String.Empty, Encoding.ASCII); } CopyHeaders(httpConnection, ret); IEnumerable <string> cookieHeaderValue; if (!UseCookies || CookieContainer == null || !ret.Headers.TryGetValues("Set-Cookie", out cookieHeaderValue) || cookieHeaderValue == null) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"No cookies"); } return(ret); } try { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Parsing cookies"); } CookieContainer.SetCookies(connectionUri, String.Join(",", cookieHeaderValue)); } catch (Exception ex) { // We don't want to terminate the response because of a bad cookie, hence just reporting // the issue. We might consider adding a virtual method to let the user handle the // issue, but not sure if it's really needed. Set-Cookie header will be part of the // header collection so the user can always examine it if they spot an error. if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Failed to parse cookies in the server response. {ex.GetType ()}: {ex.Message}"); } } if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Returning"); } return(ret); }
/** Called when the activity is first created. */ protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); if (APP_ID == null) { Util.ShowAlert(this, "Warning", "Facebook Applicaton ID must be " + "specified before running this example: see Example.java"); } SetContentView(Resource.Layout.main); mLoginButton = (LoginButton)FindViewById(Resource.Id.login); mText = (TextView)FindViewById(Resource.Id.txt); mRequestButton = (Button)FindViewById(Resource.Id.requestButton); mPostButton = (Button)FindViewById(Resource.Id.postButton); mDeleteButton = (Button)FindViewById(Resource.Id.deletePostButton); mUploadButton = (Button)FindViewById(Resource.Id.uploadButton); mFacebook = new Facebook(APP_ID); mAsyncRunner = new AsyncFacebookRunner(mFacebook); SessionStore.Restore(mFacebook, this); SessionEvents.AddAuthListener(new SampleAuthListener(this)); SessionEvents.AddLogoutListener(new SampleLogoutListener(this)); mLoginButton.Init(this, mFacebook); mRequestButton.Click += delegate { mAsyncRunner.Request("me", new SampleRequestListener(this)); }; mRequestButton.Visibility = mFacebook.IsSessionValid ? ViewStates.Visible : ViewStates.Invisible; mUploadButton.Click += async delegate { Bundle parameters = new Bundle(); parameters.PutString("method", "photos.upload"); URL uploadFileUrl = null; try { uploadFileUrl = new URL( "http://www.facebook.com/images/devsite/iphone_connect_btn.jpg"); } catch (MalformedURLException e) { e.PrintStackTrace(); } try { HttpURLConnection conn = (HttpURLConnection)uploadFileUrl.OpenConnection(); conn.DoInput = true; await conn.ConnectAsync(); int length = conn.ContentLength; byte[] imgData = new byte[length]; var ins = conn.InputStream; await ins.ReadAsync(imgData, 0, imgData.Length); parameters.PutByteArray("picture", imgData); } catch (IOException e) { e.PrintStackTrace(); } mAsyncRunner.Request(null, parameters, "POST", new SampleUploadListener(this), null); }; mUploadButton.Visibility = mFacebook.IsSessionValid ? ViewStates.Visible : ViewStates.Invisible; mPostButton.Click += delegate { mFacebook.Dialog(this, "feed", new SampleDialogListener(this)); }; mPostButton.Visibility = mFacebook.IsSessionValid ? ViewStates.Visible : ViewStates.Invisible; }
async Task <HttpResponseMessage> DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"{this}.DoProcessRequest ()"); } if (cancellationToken.IsCancellationRequested) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, " cancelled"); } cancellationToken.ThrowIfCancellationRequested(); } CancellationTokenSource waitHandleSource = new CancellationTokenSource(); try { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $" connecting"); } CancellationToken linkedToken = CancellationTokenSource.CreateLinkedTokenSource(waitHandleSource.Token, cancellationToken).Token; await Task.WhenAny( httpConnection.ConnectAsync(), Task.Run(() => { linkedToken.WaitHandle.WaitOne(); if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Wait handle task finished"); } })) .ConfigureAwait(false); if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $" connected"); } } catch (Java.Net.ConnectException ex) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Connection exception {ex}"); } // Wrap it nicely in a "standard" exception so that it's compatible with HttpClientHandler throw new WebException(ex.Message, ex, WebExceptionStatus.ConnectFailure, null); } finally{ //If not already cancelled, cancel the WaitOne through the waitHandleSource to prevent an orphaned thread waitHandleSource.Cancel(); } if (cancellationToken.IsCancellationRequested) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, " cancelled"); } await DisconnectAsync(httpConnection).ConfigureAwait(continueOnCapturedContext: false); cancellationToken.ThrowIfCancellationRequested(); } CancellationTokenRegistration cancelRegistration = default(CancellationTokenRegistration); HttpStatusCode statusCode = HttpStatusCode.OK; Uri connectionUri = null; try { cancelRegistration = cancellationToken.Register(() => { DisconnectAsync(httpConnection).ContinueWith(t => { if (t.Exception != null) { Logger.Log(LogLevel.Info, LOG_APP, $"Disconnection exception: {t.Exception}"); } }, TaskScheduler.Default); }, useSynchronizationContext: false); if (httpConnection.DoOutput) { using (var stream = await request.Content.ReadAsStreamAsync().ConfigureAwait(false)) { await stream.CopyToAsync(httpConnection.OutputStream, 4096, cancellationToken) .ConfigureAwait(false); } } statusCode = await Task.Run(() => (HttpStatusCode)httpConnection.ResponseCode).ConfigureAwait(false); connectionUri = new Uri(httpConnection.URL.ToString()); } finally { cancelRegistration.Dispose(); } if (cancellationToken.IsCancellationRequested) { await DisconnectAsync(httpConnection).ConfigureAwait(continueOnCapturedContext: false); cancellationToken.ThrowIfCancellationRequested(); } // If the request was redirected we need to put the new URL in the request request.RequestUri = connectionUri; var ret = new AndroidHttpResponseMessage(javaUrl, httpConnection) { RequestMessage = request, ReasonPhrase = httpConnection.ResponseMessage, StatusCode = statusCode, }; if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Status code: {statusCode}"); } bool disposeRet; if (HandleRedirect(statusCode, httpConnection, redirectState, out disposeRet)) { if (disposeRet) { ret.Dispose(); ret = null; } return(ret); } switch (statusCode) { case HttpStatusCode.Unauthorized: case HttpStatusCode.ProxyAuthenticationRequired: // We don't resend the request since that would require new set of credentials if the // ones provided in Credentials are invalid (or null) and that, in turn, may require asking the // user which is not something that should be taken care of by us and in this // context. The application should be responsible for this. // HttpClientHandler throws an exception in this instance, but I think it's not a good // idea. We'll return the response message with all the information required by the // application to fill in the blanks and provide the requested credentials instead. // // We return the body of the response too, but the Java client will throw // a FileNotFound exception if we attempt to access the input stream. // Instead we try to read the error stream and return an default message if the error stream isn't readable. ret.Content = GetErrorContent(httpConnection, new StringContent("Unauthorized", Encoding.ASCII)); CopyHeaders(httpConnection, ret); if (ret.Headers.WwwAuthenticate != null) { ProxyAuthenticationRequested = false; CollectAuthInfo(ret.Headers.WwwAuthenticate); } else if (ret.Headers.ProxyAuthenticate != null) { ProxyAuthenticationRequested = true; CollectAuthInfo(ret.Headers.ProxyAuthenticate); } ret.RequestedAuthentication = RequestedAuthentication; return(ret); } if (!IsErrorStatusCode(statusCode)) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Reading..."); } ret.Content = GetContent(httpConnection, httpConnection.InputStream); } else { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Status code is {statusCode}, reading..."); } // For 400 >= response code <= 599 the Java client throws the FileNotFound exception when attempting to read from the input stream. // Instead we try to read the error stream and return an empty string if the error stream isn't readable. ret.Content = GetErrorContent(httpConnection, new StringContent(String.Empty, Encoding.ASCII)); } CopyHeaders(httpConnection, ret); IEnumerable <string> cookieHeaderValue; if (!UseCookies || CookieContainer == null || !ret.Headers.TryGetValues("Set-Cookie", out cookieHeaderValue) || cookieHeaderValue == null) { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"No cookies"); } return(ret); } try { if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Parsing cookies"); } CookieContainer.SetCookies(connectionUri, String.Join(",", cookieHeaderValue)); } catch (Exception ex) { // We don't want to terminate the response because of a bad cookie, hence just reporting // the issue. We might consider adding a virtual method to let the user handle the // issue, but not sure if it's really needed. Set-Cookie header will be part of the // header collection so the user can always examine it if they spot an error. if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Failed to parse cookies in the server response. {ex.GetType ()}: {ex.Message}"); } } if (Logger.LogNet) { Logger.Log(LogLevel.Info, LOG_APP, $"Returning"); } return(ret); }
async Task <HttpResponseMessage> DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) { if (cancellationToken.IsCancellationRequested) { cancellationToken.ThrowIfCancellationRequested(); } try { await Task.WhenAny( httpConnection.ConnectAsync(), Task.Run(() => { cancellationToken.WaitHandle.WaitOne(); })) .ConfigureAwait(false); } catch (Java.Net.ConnectException ex) { // Wrap it nicely in a "standard" exception so that it's compatible with HttpClientHandler throw new WebException(ex.Message, ex, WebExceptionStatus.ConnectFailure, null); } if (cancellationToken.IsCancellationRequested) { httpConnection.Disconnect(); cancellationToken.ThrowIfCancellationRequested(); } cancellationToken.Register(httpConnection.Disconnect); if (httpConnection.DoOutput) { using (var stream = await request.Content.ReadAsStreamAsync()) { await stream.CopyToAsync(httpConnection.OutputStream, 4096, cancellationToken) .ConfigureAwait(false); } } if (cancellationToken.IsCancellationRequested) { httpConnection.Disconnect(); cancellationToken.ThrowIfCancellationRequested(); } var statusCode = await Task.Run(() => (HttpStatusCode)httpConnection.ResponseCode).ConfigureAwait(false); var connectionUri = new Uri(httpConnection.URL.ToString()); // If the request was redirected we need to put the new URL in the request request.RequestUri = connectionUri; var ret = new AndroidHttpResponseMessage(javaUrl, httpConnection) { RequestMessage = request, ReasonPhrase = httpConnection.ResponseMessage, StatusCode = statusCode, }; bool disposeRet; if (HandleRedirect(statusCode, httpConnection, redirectState, out disposeRet)) { if (disposeRet) { ret.Dispose(); ret = null; } return(ret); } switch (statusCode) { case HttpStatusCode.Unauthorized: case HttpStatusCode.ProxyAuthenticationRequired: // We don't resend the request since that would require new set of credentials if the // ones provided in Credentials are invalid (or null) and that, in turn, may require asking the // user which is not something that should be taken care of by us and in this // context. The application should be responsible for this. // HttpClientHandler throws an exception in this instance, but I think it's not a good // idea. We'll return the response message with all the information required by the // application to fill in the blanks and provide the requested credentials instead. // // We return the body of the response too, but the Java client will throw // a FileNotFound exception if we attempt to access the input stream. // Instead we try to read the error stream and return an default message if the error stream isn't readable. ret.Content = GetErrorContent(httpConnection, new StringContent("Unauthorized", Encoding.ASCII)); CopyHeaders(httpConnection, ret); if (ret.Headers.WwwAuthenticate != null) { ProxyAuthenticationRequested = false; CollectAuthInfo(ret.Headers.WwwAuthenticate); } else if (ret.Headers.ProxyAuthenticate != null) { ProxyAuthenticationRequested = true; CollectAuthInfo(ret.Headers.ProxyAuthenticate); } // COMMENTED OUT: Kyle //ret.RequestedAuthentication = RequestedAuthentication; return(ret); } if (!IsErrorStatusCode(statusCode)) { ret.Content = GetContent(httpConnection, httpConnection.InputStream); } else { // For 400 >= response code <= 599 the Java client throws the FileNotFound exception when attempting to read from the input stream. // Instead we try to read the error stream and return an empty string if the error stream isn't readable. ret.Content = GetErrorContent(httpConnection, new StringContent(String.Empty, Encoding.ASCII)); } CopyHeaders(httpConnection, ret); IEnumerable <string> cookieHeaderValue; if (!UseCookies || CookieContainer == null || !ret.Headers.TryGetValues("Set-Cookie", out cookieHeaderValue) || cookieHeaderValue == null) { return(ret); } try { CookieContainer.SetCookies(connectionUri, String.Join(",", cookieHeaderValue)); } catch (Exception ex) { // We don't want to terminate the response because of a bad cookie, hence just reporting // the issue. We might consider adding a virtual method to let the user handle the // issue, but not sure if it's really needed. Set-Cookie header will be part of the // header collection so the user can always examine it if they spot an error. } return(ret); }