Handle() public static method

public static Handle ( EndpointRegistration endpointRegistration, IRequestInfo info, CollectionSettings collectionSettings, Book currentBook ) : bool
endpointRegistration EndpointRegistration
info IRequestInfo
collectionSettings Bloom.Collection.CollectionSettings
currentBook Book
return bool
Example #1
0
        // Every path should return false or send a response.
        // Otherwise we can get a timeout error as the browser waits for a response.
        //
        // NOTE: this method gets called on different threads!
        protected override bool ProcessRequest(IRequestInfo info)
        {
            var localPath = GetLocalPathWithoutQuery(info);

            //enhance: something feeds back these branding logos with a weird URL, that shouldn't be.
            if (localPath.IndexOf("api/branding") > 20)            // this 20 is just arbitrary... the point is, if it doesn't start with api/branding, it is bogus
            {
                return(false);
            }

            if (localPath.ToLower().StartsWith("api/"))
            {
                var endpoint = localPath.Substring(3).ToLowerInvariant().Trim(new char[] { '/' });
                foreach (var pair in _endpointRegistrations.Where(pair =>
                                                                  Regex.Match(endpoint,
                                                                              "^" + //must match the beginning
                                                                              pair.Key.ToLower()
                                                                              ).Success))
                {
                    // A single synchronization object won't do, because when processing a request to create a thumbnail,
                    // we have to load the HTML page the thumbnail is based on. If the page content somehow includes
                    // an api request (api/branding/image is one example), that request will deadlock if the
                    // api/pageTemplateThumbnail request already has the main lock.
                    // To the best of my knowledge, there's no shared data between the thumbnailing process and any
                    // other api requests, so it seems safe to have one lock that prevents working on multiple
                    // thumbnails at the same time, and one that prevents working on other api requests at the same time.
                    var syncOn = SyncObj;
                    if (localPath.ToLowerInvariant().StartsWith("api/pagetemplatethumbnail"))
                    {
                        syncOn = ThumbnailSyncObj;
                    }
                    lock (syncOn)
                    {
                        return(ApiRequest.Handle(pair.Value, info, CurrentCollectionSettings, _bookSelection.CurrentSelection));
                    }
                }
            }

            //OK, no more obvious simple API requests, dive into the rat's nest of other possibilities
            if (base.ProcessRequest(info))
            {
                return(true);
            }

            if (localPath.Contains("CURRENTPAGE"))            //useful when debugging. E.g. http://localhost:8091/bloom/CURRENTPAGE.htm will always show the page we're on.
            {
                localPath = _keyToCurrentPage;
            }

            string content;
            bool   gotSimulatedPage;

            lock (_urlToSimulatedPageContent)
            {
                gotSimulatedPage = _urlToSimulatedPageContent.TryGetValue(localPath, out content);
            }
            if (gotSimulatedPage)
            {
                info.ContentType = "text/html";
                info.WriteCompleteOutput(content ?? "");
                return(true);
            }

            if (localPath.StartsWith(OriginalImageMarker) && IsImageTypeThatCanBeDegraded(localPath))
            {
                // Path relative to simulated page file, and we want the file contents without modification.
                // (Note that the simulated page file's own URL starts with this, so it's important to check
                // for that BEFORE we do this check.)
                localPath = localPath.Substring(OriginalImageMarker.Length + 1);
                return(ProcessAnyFileContent(info, localPath));
            }

            if (localPath.StartsWith("error", StringComparison.InvariantCulture))
            {
                ProcessError(info);
                return(true);
            }
            else if (localPath.StartsWith("i18n/", StringComparison.InvariantCulture))
            {
                if (ProcessI18N(localPath, info))
                {
                    return(true);
                }
            }
            else if (localPath.StartsWith("directoryWatcher/", StringComparison.InvariantCulture))
            {
                return(ProcessDirectoryWatcher(info));
            }
            else if (localPath.StartsWith("localhost/", StringComparison.InvariantCulture))
            {
                var temp = LocalHostPathToFilePath(localPath);
                if (RobustFile.Exists(temp))
                {
                    localPath = temp;
                }
            }
            // this is used only by the readium viewer
            else if (localPath.StartsWith("node_modules/jquery/dist/jquery.js"))
            {
                localPath = BloomFileLocator.GetBrowserFile("jquery.min.js");
                // Avoid having "output/browser/" removed on Linux developer machines.
                // GetBrowserFile adds output to the path on developer machines, but not user installs.
                return(ProcessContent(info, localPath));
            }
            //Firefox debugger, looking for a source map, was prefixing in this unexpected
            //way.
            localPath = localPath.Replace("output/browser/", "");

            return(ProcessContent(info, localPath));
        }
Example #2
0
        // Every path should return false or send a response.
        // Otherwise we can get a timeout error as the browser waits for a response.
        //
        // NOTE: this method gets called on different threads!
        public bool ProcessRequest(IRequestInfo info, string localPath)
        {
            var localPathLc = localPath.ToLowerInvariant();

            if (localPathLc.StartsWith("api/", StringComparison.InvariantCulture))
            {
                var endpointPath = localPath.Substring(3).ToLowerInvariant().Trim(new char[] { '/' });
                foreach (var pair in _endpointRegistrations.Where(pair =>
                                                                  Regex.Match(endpointPath,
                                                                              "^" + //must match the beginning
                                                                              pair.Key.ToLower()
                                                                              ).Success))
                {
                    var endpointRegistration = pair.Value;
                    if (endpointRegistration.RequiresSync)
                    {
                        // A single synchronization object won't do, because when processing a request to create a thumbnail or update a preview,
                        // we have to load the HTML page the thumbnail is based on, or other HTML pages (like one used to figure what's
                        // visible in a preview). If the page content somehow includes
                        // an api request (api/branding/image is one example), that request will deadlock if the
                        // api/pageTemplateThumbnail request already has the main lock.
                        // Another case is the Bloom Reader preview, where the whole UI is rebuilt at the same time as the preview.
                        // This leads to multiple api requests racing with the preview one, and it was possible for all
                        // the server threads to be processing these and waiting for SyncObject while the updatePreview
                        // request held the lock...and the request for the page that would free the lock was sitting in
                        // the queue, waiting for a thread.
                        // To the best of my knowledge, there's no shared data between the thumbnailing and preview processes and any
                        // other api requests, so it seems safe to have one lock that prevents working on multiple
                        // thumbnails/previews at the same time, and one that prevents working on other api requests at the same time.
                        var syncOn = SyncObj;
                        if (localPathLc.StartsWith("api/pagetemplatethumbnail", StringComparison.InvariantCulture) ||
                            localPathLc == "api/publish/android/thumbnail" ||
                            localPathLc == "api/publish/android/updatepreview")
                        {
                            syncOn = ThumbnailsAndPreviewsSyncObj;
                        }
                        else if (localPathLc.StartsWith("api/i18n/"))
                        {
                            syncOn = I18NLock;
                        }

                        // Basically what lock(syncObj) {} is syntactic sugar for (see its documentation),
                        // but we wrap RegisterThreadBlocking/Unblocked around acquiring the lock.
                        // We need the more complicated structure because we would like RegisterThreadUnblocked
                        // to be called immediately after acquiring the lock (notably, before Handle() is called),
                        // but we also want to handle the case where Monitor.Enter throws an exception.
                        bool lockAcquired = false;
                        try
                        {
                            // Try to acquire lock
                            BloomServer._theOneInstance.RegisterThreadBlocking();
                            try
                            {
                                // Blocks until it either succeeds (lockAcquired will then always be true) or throws (lockAcquired will stay false)
                                Monitor.Enter(syncOn, ref lockAcquired);
                            }
                            finally
                            {
                                BloomServer._theOneInstance.RegisterThreadUnblocked();
                            }

                            // Lock has been acquired.
                            ApiRequest.Handle(endpointRegistration, info, CurrentCollectionSettings,
                                              _bookSelection.CurrentSelection);

                            // Even if ApiRequest.Handle() fails, return true to indicate that the request was processed and there
                            // is no further need for the caller to continue trying to process the request as a filename.
                            // See https://issues.bloomlibrary.org/youtrack/issue/BL-6763.
                            return(true);
                        }
                        finally
                        {
                            if (lockAcquired)
                            {
                                Monitor.Exit(syncOn);
                            }
                        }
                    }
                    else
                    {
                        // Up to api's that request no sync to do things right!
                        ApiRequest.Handle(endpointRegistration, info, CurrentCollectionSettings, _bookSelection.CurrentSelection);
                        // Even if ApiRequest.Handle() fails, return true to indicate that the request was processed and there
                        // is no further need for the caller to continue trying to process the request as a filename.
                        // See https://issues.bloomlibrary.org/youtrack/issue/BL-6763.
                        return(true);
                    }
                }
            }
            return(false);
        }
        // Every path should return false or send a response.
        // Otherwise we can get a timeout error as the browser waits for a response.
        //
        // NOTE: this method gets called on different threads!
        public bool ProcessRequest(IRequestInfo info, string localPath)
        {
            var localPathLc = localPath.ToLowerInvariant();

            if (localPathLc.StartsWith("api/", StringComparison.InvariantCulture))
            {
                var endpoint = localPath.Substring(3).ToLowerInvariant().Trim(new char[] { '/' });
                foreach (var pair in _endpointRegistrations.Where(pair =>
                                                                  Regex.Match(endpoint,
                                                                              "^" + //must match the beginning
                                                                              pair.Key.ToLower()
                                                                              ).Success))
                {
                    if (pair.Value.RequiresSync)
                    {
                        // A single synchronization object won't do, because when processing a request to create a thumbnail or update a preview,
                        // we have to load the HTML page the thumbnail is based on, or other HTML pages (like one used to figure what's
                        // visible in a preview). If the page content somehow includes
                        // an api request (api/branding/image is one example), that request will deadlock if the
                        // api/pageTemplateThumbnail request already has the main lock.
                        // Another case is the Bloom Reader preview, where the whole UI is rebuilt at the same time as the preview.
                        // This leads to multiple api requests racing with the preview one, and it was possible for all
                        // the server threads to be processing these and waiting for SyncObject while the updatePreview
                        // request held the lock...and the request for the page that would free the lock was sitting in
                        // the queue, waiting for a thread.
                        // To the best of my knowledge, there's no shared data between the thumbnailing and preview processes and any
                        // other api requests, so it seems safe to have one lock that prevents working on multiple
                        // thumbnails/previews at the same time, and one that prevents working on other api requests at the same time.
                        var syncOn = SyncObj;
                        if (localPathLc.StartsWith("api/pagetemplatethumbnail", StringComparison.InvariantCulture) ||
                            localPathLc == "api/publish/android/thumbnail" ||
                            localPathLc == "api/publish/android/updatepreview")
                        {
                            syncOn = ThumbnailsAndPreviewsSyncObj;
                        }
                        else if (localPathLc.StartsWith("api/i18n/"))
                        {
                            syncOn = I18NLock;
                        }
                        lock (syncOn)
                        {
                            ApiRequest.Handle(pair.Value, info, CurrentCollectionSettings, _bookSelection.CurrentSelection);
                            // Even if ApiRequest.Handle() fails, return true to indicate that the request was processed and there
                            // is no further need for the caller to continue trying to process the request as a filename.
                            // See https://issues.bloomlibrary.org/youtrack/issue/BL-6763.
                            return(true);
                        }
                    }
                    else
                    {
                        // Up to api's that request no sync to do things right!
                        ApiRequest.Handle(pair.Value, info, CurrentCollectionSettings, _bookSelection.CurrentSelection);
                        // Even if ApiRequest.Handle() fails, return true to indicate that the request was processed and there
                        // is no further need for the caller to continue trying to process the request as a filename.
                        // See https://issues.bloomlibrary.org/youtrack/issue/BL-6763.
                        return(true);
                    }
                }
            }
            return(false);
        }