Example #1
0
        private void CheckValidParse(string input, RangeHeaderValue expectedResult)
        {
            RangeHeaderValue result = RangeHeaderValue.Parse(input);

            Assert.Equal(expectedResult, result);
        }
        /// <summary>
        /// Run a simple HTTP server that listens for a few test URIs.
        /// The server exits when a client requests "/Quit".
        /// </summary>
        /// <param name="prefix">Prefix at which the server should listen</param>
        private async Task RunTestServer(string prefix)
        {
            using (var httpListener = new HttpListener())
            {
                httpListener.Prefixes.Add(prefix);
                httpListener.Start();

                while (httpListener.IsListening)
                {
                    var context = await httpListener.GetContextAsync().ConfigureAwait(false);

                    var requestUri = context.Request.Url;
                    var response   = context.Response;

                    if (requestUri.AbsolutePath.EndsWith("/Quit"))
                    {
                        // Shut down the HTTP server.
                        response.Close();
                        httpListener.Stop();
                        continue;
                    }

                    // All downloader requests should include ?alt=media.
                    Assert.Equal("media", context.Request.QueryString["alt"]);

                    response.ContentType = "text/plain";
                    response.SendChunked = true;  // Avoid having to set Content-Length.

                    Stream outStream = new MemoryStream();

                    if (requestUri.AbsolutePath.EndsWith("/EchoUrl"))
                    {
                        // Return the URL that we saw.
                        byte[] uriBytes = Encoding.UTF8.GetBytes(requestUri.AbsoluteUri);
                        outStream.Write(uriBytes, 0, uriBytes.Length);
                    }
                    else if (requestUri.AbsolutePath.EndsWith("/BadRequestJson"))
                    {
                        // Return 400 with a JSON-encoded error.
                        var apiResponse = new StandardResponse <object> {
                            Error = BadRequestError
                        };
                        var    apiResponseText  = new NewtonsoftJsonSerializer().Serialize(apiResponse);
                        byte[] apiResponseBytes = Encoding.UTF8.GetBytes(apiResponseText);

                        response.StatusCode = (int)HttpStatusCode.BadRequest;
                        outStream.Write(apiResponseBytes, 0, apiResponseBytes.Length);
                    }
                    else if (requestUri.AbsolutePath.EndsWith("/NotFoundPlainText"))
                    {
                        // Return 404 with a plaintext error.
                        response.StatusCode = (int)HttpStatusCode.NotFound;
                        byte[] errorBytes = Encoding.UTF8.GetBytes(NotFoundError);
                        outStream.Write(errorBytes, 0, errorBytes.Length);
                    }
                    else if (requestUri.AbsolutePath.EndsWith("/GzipContent"))
                    {
                        // Return gzip-compressed content.
                        using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress, true))
                        {
                            gzipStream.Write(MediaContent, 0, MediaContent.Length);
                        }
                        response.AddHeader("Content-Encoding", "gzip");
                    }
                    else if (requestUri.AbsolutePath.EndsWith("/NoContent"))
                    {
                        // Return 206 and no content.
                        response.StatusCode = (int)HttpStatusCode.NoContent;
                    }
                    else
                    {
                        // Return plaintext content.
                        outStream.Write(MediaContent, 0, MediaContent.Length);
                    }

                    outStream.Position = 0;

                    // Provide rudimentary, non-robust support for Range.
                    string rangeHeader = context.Request.Headers["Range"];
                    if (rangeHeader != null && response.StatusCode == (int)HttpStatusCode.OK)
                    {
                        var range      = RangeHeaderValue.Parse(rangeHeader);
                        var firstRange = range.Ranges.First();

                        long from = firstRange.From ?? 0;
                        long to   = Math.Min(outStream.Length - 1, firstRange.To ?? long.MaxValue);

                        var contentRangeHeader = new ContentRangeHeaderValue(from, to, outStream.Length);
                        response.AddHeader("Content-Range", contentRangeHeader.ToString());

                        outStream.Position = from;
                        outStream.SetLength(to + 1);
                    }

                    await outStream.CopyToAsync(response.OutputStream).ConfigureAwait(false);

                    response.Close();
                }
            }
        }
        private HttpWebRequest CreateRequest(Request messageRequest)
        {
            var request = WebRequest.CreateHttp(messageRequest.Uri.ToUri());

            request.Method = messageRequest.Method.Method;
            request.Proxy  = _proxy;
            foreach (var messageRequestHeader in messageRequest.Headers)
            {
                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.ContentLength, StringComparison.OrdinalIgnoreCase))
                {
                    request.ContentLength = int.Parse(messageRequestHeader.Value, CultureInfo.InvariantCulture);
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Host, StringComparison.OrdinalIgnoreCase))
                {
                    request.Host = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Date, StringComparison.OrdinalIgnoreCase))
                {
                    request.Date = DateTime.Parse(messageRequestHeader.Value, CultureInfo.InvariantCulture);
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.ContentType, StringComparison.OrdinalIgnoreCase))
                {
                    request.ContentType = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.UserAgent, StringComparison.OrdinalIgnoreCase))
                {
                    request.UserAgent = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Accept, StringComparison.OrdinalIgnoreCase))
                {
                    request.Accept = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Referer, StringComparison.OrdinalIgnoreCase))
                {
                    request.Referer = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Range, StringComparison.OrdinalIgnoreCase))
                {
                    var value = RangeHeaderValue.Parse(messageRequestHeader.Value);
                    if (value.Unit != "bytes")
                    {
                        throw new InvalidOperationException("Only ranges with bytes unit supported.");
                    }

                    foreach (var rangeItem in value.Ranges)
                    {
                        if (rangeItem.From == null)
                        {
                            throw new InvalidOperationException("Only ranges with Offset supported.");
                        }

                        if (rangeItem.To == null)
                        {
                            request.AddRange(rangeItem.From.Value);
                        }
                        else
                        {
                            request.AddRange(rangeItem.From.Value, rangeItem.To.Value);
                        }
                    }
                    continue;
                }

                request.Headers.Add(messageRequestHeader.Name, messageRequestHeader.Value);
            }

            return(request);
        }
Example #4
0
 private void CheckInvalidParse(string?input)
 {
     Assert.Throws <FormatException>(() => RangeHeaderValue.Parse(input));
 }
        /// <summary>
        /// Insert a request HTTP header
        /// </summary>
        /// <param name="header">A <see cref="System.Net.Http.Headers.HttpRequestHeaders"/> object on wich the request header will be recorded.</param>
        /// <param name="name">The header attribute name.</param>
        /// <param name="value">The header attribute value.</param>
        public void AddRequestHeader(HttpRequestHeaders header, string name, string value)
        {
            if (name.Equals("Authorization", StringComparison.OrdinalIgnoreCase))
            {
                header.Authorization = new AuthenticationHeaderValue(value);
            }

            else if (name.Equals("Cache-Control", StringComparison.OrdinalIgnoreCase))
            {
                header.CacheControl = CacheControlHeaderValue.Parse(value);
            }

            else if (name.Equals("Date", StringComparison.OrdinalIgnoreCase))
            {
                header.Date = DateTimeOffset.Parse(value);
            }

            else if (name.Equals("If-Modified-Since", StringComparison.OrdinalIgnoreCase))
            {
                header.IfModifiedSince = DateTimeOffset.Parse(value);
            }

            else if (name.Equals("If-Range", StringComparison.OrdinalIgnoreCase))
            {
                header.IfRange = RangeConditionHeaderValue.Parse(value);
            }

            else if (name.Equals("If-Unmodified-Since", StringComparison.OrdinalIgnoreCase))
            {
                header.IfUnmodifiedSince = DateTimeOffset.Parse(value);
            }

            else if (name.Equals("Max-Forwards", StringComparison.OrdinalIgnoreCase))
            {
                header.MaxForwards = int.Parse(value);
            }

            else if (name.Equals("Proxy-Authorization", StringComparison.OrdinalIgnoreCase))
            {
                header.ProxyAuthorization = AuthenticationHeaderValue.Parse(value);
            }

            else if (name.Equals("Range", StringComparison.OrdinalIgnoreCase))
            {
                header.Range = RangeHeaderValue.Parse(value);
            }

            else if (name.Equals("Referrer", StringComparison.OrdinalIgnoreCase))
            {
                header.Referrer = new Uri(value);
            }

            else
            {
                try{
                    header.Add(name, value);
                }catch (ArgumentException) {
                    if (header.GetType().GetProperty(name.Replace("-", "")) != null)
                    {
                        header.GetType().GetProperty(name.Replace("-", "")).SetValue(header, value);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
Example #6
0
        private HttpWebRequest CreateRequest(Request messageRequest)
        {
            var request = WebRequest.CreateHttp(messageRequest.Uri.ToUri());

            // Don't disable the default proxy when there is no environment proxy configured
            if (_environmentProxy != null)
            {
                request.Proxy = _environmentProxy;
            }

            _configureRequest(request);

            request.Method = messageRequest.Method.Method;
            foreach (var messageRequestHeader in messageRequest.Headers)
            {
                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.ContentLength, StringComparison.OrdinalIgnoreCase))
                {
                    request.ContentLength = long.Parse(messageRequestHeader.Value, CultureInfo.InvariantCulture);
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Host, StringComparison.OrdinalIgnoreCase))
                {
                    request.Host = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Date, StringComparison.OrdinalIgnoreCase))
                {
                    request.Date = DateTime.Parse(messageRequestHeader.Value, CultureInfo.InvariantCulture);
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.ContentType, StringComparison.OrdinalIgnoreCase))
                {
                    request.ContentType = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.UserAgent, StringComparison.OrdinalIgnoreCase))
                {
                    request.UserAgent = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Accept, StringComparison.OrdinalIgnoreCase))
                {
                    request.Accept = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Referer, StringComparison.OrdinalIgnoreCase))
                {
                    request.Referer = messageRequestHeader.Value;
                    continue;
                }

                if (string.Equals(messageRequestHeader.Name, HttpHeader.Names.Range, StringComparison.OrdinalIgnoreCase))
                {
                    var value = RangeHeaderValue.Parse(messageRequestHeader.Value);
                    if (value.Unit != "bytes")
                    {
                        throw new InvalidOperationException("Only ranges with bytes unit supported.");
                    }

                    foreach (var rangeItem in value.Ranges)
                    {
                        if (rangeItem.From == null)
                        {
                            throw new InvalidOperationException("Only ranges with Offset supported.");
                        }

                        if (rangeItem.To == null)
                        {
                            request.AddRange(rangeItem.From.Value);
                        }
                        else
                        {
                            request.AddRange(rangeItem.From.Value, rangeItem.To.Value);
                        }
                    }
                    continue;
                }

                request.Headers.Add(messageRequestHeader.Name, messageRequestHeader.Value);
            }

            if (request.ContentLength == -1 &&
                messageRequest.Content != null &&
                messageRequest.Content.TryComputeLength(out var length))
            {
                request.ContentLength = length;
            }

            if (request.ContentLength != -1)
            {
                // disable buffering when the content length is known
                // as the content stream is re-playable and we don't want to allocate extra buffers
                request.AllowWriteStreamBuffering = false;
            }
            return(request);
        }
Example #7
0
        public async Task <StreamingResult> GetContents(FileIdentifier identifier, CancellationToken cancellationToken)
        {
            if (!ModelState.IsValid)
            {
                throw new ModelValidationException(ModelState);
            }
            if (identifier == null)
            {
                throw new ArgumentNullException(nameof(identifier));
            }
            if (!identifier.IsValid)
            {
                throw new InvalidIdentifierException();
            }

            var fileModel = await FileStore.GetOneAsync(identifier);

            if (fileModel == null)
            {
                throw new ObjectDoesNotExistException();
            }

            long from = 0;
            long to   = fileModel.Length - 1;

            if (Request.Headers["Range"].Any())
            {
                var range = RangeHeaderValue.Parse(Request.Headers["Range"].ToString()).Ranges.FirstOrDefault();
                if (range.From.HasValue)
                {
                    from = range.From.Value;
                }
                if (range.To.HasValue)
                {
                    to = Math.Min(range.To.Value, to);
                }

                Response.StatusCode = (int)HttpStatusCode.PartialContent;
                Response.Headers.Add("Content-Range", new ContentRangeHeaderValue(
                                         from,
                                         to,
                                         fileModel.Length
                                         ).ToString());
            }

            long rangeLength = to - from + 1;

            var contentDisposition = new ContentDispositionHeaderValue("attachment");

            contentDisposition.SetHttpFileName(fileModel.Name);
            Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();

            // tell the base class not to screw with our result
            SuppressWrapper = true;
            return(new StreamingResult(async response =>
            {
                Response.ContentLength = rangeLength;
                Response.ContentType = fileModel.MimeType ?? "application/octet-stream";

                await FileContentsService.DownloadAsync(fileModel, Response.Body, from, to, cancellationToken);
            }));
        }
Example #8
0
        async Task DoDownloadPackage(PackageDef package, FileStream fileStream, CancellationToken cancellationToken)
        {
            bool finished = false;

            try
            {
                using (HttpClientHandler hch = new HttpClientHandler()
                {
                    UseProxy = true, Proxy = WebRequest.GetSystemWebProxy()
                })
                    using (HttpClient hc = new HttpClient(hch)
                    {
                        Timeout = Timeout.InfiniteTimeSpan
                    })
                    {
                        HttpResponseMessage response = null;
                        hc.DefaultRequestHeaders.Add("OpenTAP", PluginManager.GetOpenTapAssembly().SemanticVersion.ToString());
                        var retries         = 60;
                        var downloadedBytes = 0;
                        var totalSize       = -1L;

                        while (retries > 0)
                        {
                            if (retries < 60)
                            {
                                log.Debug($"Retrying {61 - retries}/60");
                            }

                            hc.DefaultRequestHeaders.Range = RangeHeaderValue.Parse($"bytes={downloadedBytes}-");

                            try
                            {
                                if (package.PackageSource is HttpRepositoryPackageDefSource httpSource && string.IsNullOrEmpty(httpSource.DirectUrl) == false)
                                {
                                    log.Info($"Downloading package directly from: '{httpSource.DirectUrl}'.");
                                    var message = new HttpRequestMessage(HttpMethod.Get, new Uri(httpSource.DirectUrl));

                                    try
                                    {
                                        response = await hc.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

                                        if (response.IsSuccessStatusCode == false)
                                        {
                                            throw new Exception($"Request to '{httpSource.DirectUrl}' failed with status code: {response.StatusCode}.");
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        log.Warning($"Could not download package directly from: '{httpSource.DirectUrl}'. Downloading package normally.");
                                        log.Debug(e);
                                        response = await hc.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
                                    }
                                }
                                else
                                {
                                    var message = new HttpRequestMessage(HttpMethod.Get,
                                                                         new Uri(Url + "/" + ApiVersion + "/DownloadPackage" +
                                                                                 $"/{Uri.EscapeDataString(package.Name)}" +
                                                                                 $"?version={Uri.EscapeDataString(package.Version.ToString())}" +
                                                                                 $"&os={Uri.EscapeDataString(package.OS)}" +
                                                                                 $"&architecture={Uri.EscapeDataString(package.Architecture.ToString())}"));
                                    response = await hc.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
                                }

                                if (totalSize < 0)
                                {
                                    totalSize = response.Content.Headers.ContentLength ?? 1;
                                }

                                // Download the package
                                using (var responseStream = await response.Content.ReadAsStreamAsync())
                                {
                                    if (response.IsSuccessStatusCode == false)
                                    {
                                        throw new HttpRequestException($"The download request failed with {response.StatusCode}.");
                                    }

                                    var buffer = new byte[4096];
                                    int read   = 0;

                                    var task = Task.Run(() =>
                                    {
                                        do
                                        {
                                            read = responseStream.Read(buffer, 0, 4096);
                                            fileStream.Write(buffer, 0, read);
                                            downloadedBytes += read;
                                        } while (read > 0);

                                        finished = true;
                                    }, cancellationToken);
                                    ConsoleUtils.PrintProgressTillEnd(task, "Downloading", () => fileStream.Position, () => totalSize);
                                }

                                if (finished)
                                {
                                    break;
                                }
                            }
                            catch (Exception e)
                            {
                                response.Dispose();
                                retries--;
                                if (retries <= 0 || cancellationToken.IsCancellationRequested)
                                {
                                    throw;
                                }
                                log.Debug("Failed to download package.");
                                log.Debug(e);
                                Thread.Sleep(TimeSpan.FromSeconds(1));
                            }
                        }