Example #1
0
        /// <summary>
        /// Handles the request for a cached tile.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="pathParts">The path parts from the request.</param>
        /// <param name="fileName">The filename from the request.</param>
        /// <param name="clientEndpoint"></param>
        /// <param name="headers">The request headers.</param>
        /// <returns></returns>
        public WebRequestOutcome ProcessRequest(Options options, IEnumerable <string> pathParts, string fileName, IPAddress clientEndpoint, RequestHeadersDictionary headers)
        {
            var result         = new WebRequestOutcome();
            var displayOutcome = new RequestOutcome()
            {
                ID          = Interlocked.Increment(ref _NextID),
                ReceivedUtc = DateTime.UtcNow,
            };

            RecentRequestOutcomes.Add(displayOutcome);

            try {
                var urlValues = _TileServerUrlTranslator.ExtractEncodedValuesFromUrlParts(pathParts, fileName);
                displayOutcome.CopyUrlValues(urlValues);

                if (urlValues != null)
                {
                    var cachedContent = TileCache.GetCachedTile(urlValues);

                    if (cachedContent != null)
                    {
                        result.ImageBytes = cachedContent.Content;
                        displayOutcome.ServedFromCache = true;
                        Interlocked.Increment(ref _CountServedFromCache);
                        Plugin.Singleton?.RefreshStatusDescription();
                    }
                    else
                    {
                        if (options.IsOfflineModeEnabled)
                        {
                            displayOutcome.MissingFromCache = true;
                            result.StatusCode = HttpStatusCode.NotFound;
                        }
                        else
                        {
                            FetchTileServerImage(options, urlValues, clientEndpoint, headers, result, displayOutcome);

                            if (result.ImageBytes?.Length > 0)
                            {
                                TileCache.SaveTile(urlValues, result.ImageBytes);
                            }
                        }
                    }

                    if (result.ImageBytes != null)
                    {
                        result.StatusCode     = HttpStatusCode.OK;
                        result.ImageExtension = urlValues.TileImageExtension;
                    }
                }
            } catch (ThreadAbortException) {
                displayOutcome.Abandoned = true;
                ; // .NET will rethrow this automatically
            } catch {
                displayOutcome.ExceptionEncountered = true;
                throw;
            } finally {
                try {
                    displayOutcome.CompletedUtc = DateTime.UtcNow;
                } catch {
                    ; // Don't want to confuse the issue with exceptions when trying to update the outcome display
                }
            }

            return(result);
        }
Example #2
0
        /// <summary>
        /// Downloads the tile image using the URL values passed across.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="urlValues"></param>
        /// <param name="clientEndpoint"></param>
        /// <param name="headers"></param>
        /// <param name="outcome"></param>
        /// <param name="displayOutcome"></param>
        /// <returns></returns>
        private void FetchTileServerImage(Options options, FakeUrlEncodedValues urlValues, IPAddress clientEndpoint, HeadersDictionary headers, WebRequestOutcome outcome, RequestOutcome displayOutcome)
        {
            var tileServerSettings = Plugin.TileServerSettingsManagerWrapper.GetRealTileServerSettings(
                urlValues.MapProvider,
                urlValues.Name
                );

            if (tileServerSettings != null)
            {
                var tileImageUrl = _TileServerUrlTranslator.ExpandUrlParameters(
                    tileServerSettings.Url,
                    urlValues,
                    tileServerSettings.Subdomains
                    );

                var request = (HttpWebRequest)HttpWebRequest.Create(tileImageUrl);
                request.Method = "GET";
                request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
                foreach (var headerKey in headers.Keys)
                {
                    var value = headers[headerKey];
                    switch (headerKey.ToLower())
                    {
                    case "accept":              request.Accept = value; break;

                    case "accept-encoding":     break;

                    case "connection":          break;

                    case "content-length":      break;

                    case "content-type":        request.ContentType = value; break;

                    case "date":                break;

                    case "expect":              request.Expect = value; break;

                    case "host":                break;

                    case "if-modified-since":   break;

                    case "proxy-connection":    break;

                    case "range":               break;

                    case "referer":             request.Referer = value; break;

                    case "transfer-encoding":   request.TransferEncoding = value; break;

                    case "user-agent":          request.UserAgent = value; break;

                    default:
                        request.Headers[headerKey] = value;
                        break;
                    }
                }
                request.AuthenticationLevel   = AuthenticationLevel.None;
                request.Credentials           = null;
                request.UseDefaultCredentials = false;
                request.KeepAlive             = true;
                request.Timeout = 1000 * options.TileServerTimeoutSeconds;

                lock (_SyncLock) {
                    if (!_TileServerNameToCookieCollection.TryGetValue(urlValues.Name, out var cookies))
                    {
                        cookies = new CookieCollection();
                        _TileServerNameToCookieCollection.Add(urlValues.Name, cookies);
                    }
                    foreach (Cookie cookie in cookies)
                    {
                        request.CookieContainer.Add(cookie);
                    }
                }

                var forwarded = request.Headers["Forwarded"] ?? "";
                if (forwarded.Length > 0)
                {
                    forwarded = $"{forwarded}, ";
                }
                forwarded = $"{forwarded}for={clientEndpoint}";
                request.Headers["Forwarded"] = forwarded;

                try {
                    using (var response = (HttpWebResponse)request.GetResponse()) {
                        using (var memoryStream = new MemoryStream()) {
                            using (var responseStream = response.GetResponseStream()) {
                                var buffer    = new byte[1024];
                                var bytesRead = 0;
                                do
                                {
                                    bytesRead = responseStream.Read(buffer, 0, buffer.Length);
                                    if (bytesRead > 0)
                                    {
                                        memoryStream.Write(buffer, 0, bytesRead);
                                    }
                                } while(bytesRead > 0);
                            }

                            outcome.ImageBytes = memoryStream.ToArray();
                            displayOutcome.FetchedFromTileServer        = true;
                            displayOutcome.TileServerResponseStatusCode = (int)response.StatusCode;
                        }

                        var cookies = new CookieCollection();
                        foreach (Cookie cookie in response.Cookies)
                        {
                            cookies.Add(cookie);
                        }
                        lock (_SyncLock) {
                            _TileServerNameToCookieCollection[urlValues.Name] = cookies;
                        }
                    }
                } catch (WebException ex) {
                    if (ex.Status == WebExceptionStatus.Timeout)
                    {
                        displayOutcome.TimedOut = true;
                    }
                    else
                    {
                        displayOutcome.WebExceptionErrorMessage = ex.Message;

                        outcome.StatusCode = HttpStatusCode.InternalServerError;
                        if (ex.Response is HttpWebResponse httpResponse)
                        {
                            if (httpResponse.StatusCode != HttpStatusCode.OK)
                            {
                                outcome.StatusCode = httpResponse.StatusCode;
                                displayOutcome.TileServerResponseStatusCode = (int)httpResponse.StatusCode;
                            }
                        }
                    }
                }
            }
        }