예제 #1
0
        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);
        }
예제 #2
0
        /** 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);
        }
예제 #4
0
        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);
        }