<commit_before>﻿using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using NuGet.Repositories;

namespace NuGet {   
    public class GalleryServer {
        public const string DefaultGalleryServerUrl = "http://go.microsoft.com/fwlink/?LinkID=207106";
        private const string CreatePackageService = "PackageFiles";
        private const string PackageService = "Packages";
        private const string PublishPackageService = "PublishedPackages/Publish";

        private const string _UserAgentPattern = "NuGet Package Explorer/{0} ({1})";
        
        private string _baseGalleryServerUrl;
        private string _userAgent;

        IProxyService _proxyService;

        public GalleryServer()
            : this(DefaultGalleryServerUrl,new ProxyService()) {
        }

        public GalleryServer(string galleryServerSource, IProxyService proxyService) {
            _baseGalleryServerUrl = GetSafeRedirectedUri(galleryServerSource);
            var version = typeof(GalleryServer).Assembly.GetNameSafe().Version;
            _userAgent = String.Format(CultureInfo.InvariantCulture, _UserAgentPattern, version, Environment.OSVersion);

            _proxyService = proxyService;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Reliability", 
            "CA2000:Dispose objects before losing scope",
            Justification="We dispose it in the Completed event handler.")]
        public void CreatePackage(string apiKey, Stream packageStream, IObserver<int> progressObserver, IPackageMetadata metadata = null) {

            var state = new PublishState {
                PublishKey = apiKey,
                PackageMetadata = metadata, 
                ProgressObserver = progressObserver
            };

            var url = new Uri(String.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}/nupkg", _baseGalleryServerUrl, CreatePackageService, apiKey));

            WebClient client = new WebClient();
            client.Proxy = _proxyService.GetProxy(url);
            client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
            client.Headers[HttpRequestHeader.UserAgent] = _userAgent;
            client.UploadProgressChanged += OnUploadProgressChanged;
            client.UploadDataCompleted += OnCreatePackageCompleted;
            client.UploadDataAsync(url, "POST", packageStream.ReadAllBytes(), state);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Reliability",
            "CA2000:Dispose objects before losing scope",
            Justification = "We dispose it in the Completed event handler.")]
        private void PublishPackage(PublishState state) {
            var url = new Uri(String.Format(CultureInfo.InvariantCulture, "{0}/{1}", _baseGalleryServerUrl, PublishPackageService));

            using (Stream requestStream = new MemoryStream()) {
                var data = new PublishData {
                    Key = state.PublishKey,
                    Id = state.PackageMetadata.Id,
                    Version = state.PackageMetadata.Version.ToString()
                };

                var jsonSerializer = new DataContractJsonSerializer(typeof(PublishData));
                jsonSerializer.WriteObject(requestStream, data);
                requestStream.Seek(0, SeekOrigin.Begin);

                WebClient client = new WebClient();
                client.Proxy = _proxyService.GetProxy(url);
                client.Headers[HttpRequestHeader.ContentType] = "application/json";
                client.Headers[HttpRequestHeader.UserAgent] = _userAgent;
                client.UploadProgressChanged += OnUploadProgressChanged;
                client.UploadDataCompleted += OnPublishPackageCompleted;
                client.UploadDataAsync(url, "POST", requestStream.ReadAllBytes(), state);
            }
        }

        private void OnCreatePackageCompleted(object sender, UploadDataCompletedEventArgs e) {
            var state = (PublishState) e.UserState;
            if (e.Error != null) {
                Exception error = e.Error;

                WebException webException = e.Error as WebException;
                if (webException != null) {
                    var response = (HttpWebResponse) webException.Response;
                    if (response.StatusCode == HttpStatusCode.InternalServerError) {
                        // real error message is contained inside the response body
                        using (Stream stream = response.GetResponseStream()) {
                            string errorMessage = stream.ReadToEnd();
                            error = new WebException(errorMessage, webException, webException.Status,
                                                     webException.Response);
                        }
                    }
                }
                
                state.ProgressObserver.OnError(error);
            }
            else if (!e.Cancelled) {
                if (state.PackageMetadata != null) {
                    PublishPackage(state);
                }
                else {
                    state.ProgressObserver.OnCompleted();
                }
            }

            var client = (WebClient)sender;
            client.Dispose();
        }

        private void OnPublishPackageCompleted(object sender, UploadDataCompletedEventArgs e) {
            var state = (PublishState)e.UserState;
            if (e.Error != null) {
                Exception error = e.Error;

                WebException webException = e.Error as WebException;
                if (webException != null) {
                    // real error message is contained inside the response body
                    using (Stream stream = webException.Response.GetResponseStream()) {
                        string errorMessage = stream.ReadToEnd();
                        error = new WebException(errorMessage, webException, webException.Status, webException.Response);
                    }
                }

                state.ProgressObserver.OnError(error);
            }
            else if (!e.Cancelled) {
                state.ProgressObserver.OnCompleted();
            }

            var client = (WebClient)sender;
            client.Dispose();
        }

        private void OnUploadProgressChanged(object sender, UploadProgressChangedEventArgs e) {
            var state = (PublishState)e.UserState;
            // Hack: the UploadDataAsync only reports up to 50 percent. multiply by 2 to simulate 100. LOL
            state.ProgressObserver.OnNext(Math.Min(100, 2*e.ProgressPercentage));
        }

        private static string GetSafeRedirectedUri(string uri) {
            WebRequest request = WebRequest.Create(uri);
            try {
                WebResponse response = request.GetResponse();
                if (response == null) {
                    return null;
                }
                return response.ResponseUri.ToString();
            }
            catch (WebException e) {
                return e.Response.ResponseUri.ToString(); ;
            }
        }

        private class PublishState {
            public string PublishKey { get; set; }
            public IObserver<int> ProgressObserver { get; set; }
            public IPackageMetadata PackageMetadata { get; set; }
        }
    }

    [DataContract]
    public class PublishData {<commit_msg>GetSafeRedirectedUri method in the GalleryServer class was creating a request using WebRequest.Create and the proxy was not being set for it so it was failing under the BasicAuth scenario. Updated to use the RedirectedHttpClient class that accepts a  Proxy object and automatically discovers the redirected URL that we should be using.<commit_after>﻿using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using NuGet.Repositories;
using NuGet.Utility;

namespace NuGet {   
    public class GalleryServer {
        public const string DefaultGalleryServerUrl = "http://go.microsoft.com/fwlink/?LinkID=207106";
        private const string CreatePackageService = "PackageFiles";
        private const string PackageService = "Packages";
        private const string PublishPackageService = "PublishedPackages/Publish";

        private const string _UserAgentPattern = "NuGet Package Explorer/{0 }({1})";
        
        private string _baseGalleryServerUrl;
        private string _userAgent;

        IProxyService _proxyService;

        public GalleryServer()
            : this(DefaultGalleryServerUrl,new ProxyService()) {
        }

        public GalleryServer(string galleryServerSource, IProxyService proxyService) {
            if (string.IsNullOrEmpty(galleryServerSource))
            {
                throw new ArgumentNullException("galleryServerSource");
            }
            if (null == proxyService)
            {
                throw new ArgumentNullException("proxyService");
            }
            _proxyService = proxyService;

            _baseGalleryServerUrl = GetSafeRedirectedUri(galleryServerSource);
            var version = typeof(GalleryServer).Assembly.GetNameSafe().Version;
            _userAgent = String.Format(CultureInfo.InvariantCulture, _UserAgentPattern, version, Environment.OSVersion);

        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Reliability", 
            "CA2000:Dispose objects before losing scope",
            Justification="We dispose it in the Completed event handler.")]
        public void CreatePackage(string apiKey, Stream packageStream, IObserver<int> progressObserver, IPackageMetadata metadata = null) {

            var state = new PublishState {
                PublishKey = apiKey,
                PackageMetadata = metadata, 
                ProgressObserver = progressObserver
            };

            var url = new Uri(String.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}/nupkg", _baseGalleryServerUrl, CreatePackageService, apiKey));

            WebClient client = new WebClient();
            client.Proxy = _proxyService.GetProxy(url);
            client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
            client.Headers[HttpRequestHeader.UserAgent] = _userAgent;
            client.UploadProgressChanged += OnUploadProgressChanged;
            client.UploadDataCompleted += OnCreatePackageCompleted;
            client.UploadDataAsync(url, "POST", packageStream.ReadAllBytes(), state);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Reliability",
            "CA2000:Dispose objects before losing scope",
            Justification = "We dispose it in the Completed event handler.")]
        private void PublishPackage(PublishState state) {
            var url = new Uri(String.Format(CultureInfo.InvariantCulture, "{0}/{1}", _baseGalleryServerUrl, PublishPackageService));

            using (Stream requestStream = new MemoryStream()) {
                var data = new PublishData {
                    Key = state.PublishKey,
                    Id = state.PackageMetadata.Id,
                    Version = state.PackageMetadata.Version.ToString()
                };

                var jsonSerializer = new DataContractJsonSerializer(typeof(PublishData));
                jsonSerializer.WriteObject(requestStream, data);
                requestStream.Seek(0, SeekOrigin.Begin);

                WebClient client = new WebClient();
                client.Proxy = _proxyService.GetProxy(url);
                client.Headers[HttpRequestHeader.ContentType] = "application/json";
                client.Headers[HttpRequestHeader.UserAgent] = _userAgent;
                client.UploadProgressChanged += OnUploadProgressChanged;
                client.UploadDataCompleted += OnPublishPackageCompleted;
                client.UploadDataAsync(url, "POST", requestStream.ReadAllBytes(), state);
            }
        }

        private void OnCreatePackageCompleted(object sender, UploadDataCompletedEventArgs e) {
            var state = (PublishState) e.UserState;
            if (e.Error != null) {
                Exception error = e.Error;

                WebException webException = e.Error as WebException;
                if (webException != null) {
                    var response = (HttpWebResponse) webException.Response;
                    if (response.StatusCode == HttpStatusCode.InternalServerError) {
                        // real error message is contained inside the response body
                        using (Stream stream = response.GetResponseStream()) {
                            string errorMessage = stream.ReadToEnd();
                            error = new WebException(errorMessage, webException, webException.Status,
                                                     webException.Response);
                        }
                    }
                }
                
                state.ProgressObserver.OnError(error);
            }
            else if (!e.Cancelled) {
                if (state.PackageMetadata != null) {
                    PublishPackage(state);
                }
                else {
                    state.ProgressObserver.OnCompleted();
                }
            }

            var client = (WebClient)sender;
            client.Dispose();
        }

        private void OnPublishPackageCompleted(object sender, UploadDataCompletedEventArgs e) {
            var state = (PublishState)e.UserState;
            if (e.Error != null) {
                Exception error = e.Error;

                WebException webException = e.Error as WebException;
                if (webException != null) {
                    // real error message is contained inside the response body
                    using (Stream stream = webException.Response.GetResponseStream()) {
                        string errorMessage = stream.ReadToEnd();
                        error = new WebException(errorMessage, webException, webException.Status, webException.Response);
                    }
                }

                state.ProgressObserver.OnError(error);
            }
            else if (!e.Cancelled) {
                state.ProgressObserver.OnCompleted();
            }

            var client = (WebClient)sender;
            client.Dispose();
        }

        private void OnUploadProgressChanged(object sender, UploadProgressChangedEventArgs e) {
            var state = (PublishState)e.UserState;
            // Hack: the UploadDataAsync only reports up to 50 percent. multiply by 2 to simulate 100. LOL
            state.ProgressObserver.OnNext(Math.Min(100, 2*e.ProgressPercentage));
        }

        private string GetSafeRedirectedUri(string uri) {
            try {
                Uri originalUri = new Uri(uri);
                IWebProxy proxy = _proxyService.GetProxy(originalUri);
                RedirectedHttpClient client = new RedirectedHttpClient(originalUri,proxy);
                return client.Uri.ToString();
            }
            catch (WebException e) {
                return e.Response.ResponseUri.ToString(); ;
            }
        }

        private class PublishState {
            public string PublishKey { get; set; }
            public IObserver<int> ProgressObserver { get; set; }
            public IPackageMetadata PackageMetadata { get; set; }
        }
    }

    [DataContract]
    public class PublishData {
{'fraction_non_alphanumeric': 0.07839754648265286, 'fraction_numerical': 0.0040891955785572805, 'mean_word_length': 1.9677664012135, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '676955', 'n_tokens_mistral': 3696, 'n_tokens_neox': 3500, 'n_words': 862}