From f32212d160f5427a56b5b8e0219206930c518b64 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 7 Dec 2013 10:52:38 -0500 Subject: [PATCH] update to service stack v4 --- MediaBrowser.Api/AlbumsService.cs | 2 +- .../AuthorizationRequestFilterAttribute.cs | 19 +- MediaBrowser.Api/BaseApiService.cs | 21 +- .../DefaultTheme/DefaultThemeService.cs | 2 +- MediaBrowser.Api/DisplayPreferencesService.cs | 2 +- MediaBrowser.Api/EnvironmentService.cs | 2 +- MediaBrowser.Api/GamesService.cs | 2 +- MediaBrowser.Api/Images/ImageByNameService.cs | 2 +- MediaBrowser.Api/Images/ImageRequest.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 39 +- MediaBrowser.Api/Images/ImageWriter.cs | 4 +- MediaBrowser.Api/Images/RemoteImageService.cs | 10 +- MediaBrowser.Api/InstantMixService.cs | 2 +- MediaBrowser.Api/ItemRefreshService.cs | 2 +- MediaBrowser.Api/ItemUpdateService.cs | 2 +- MediaBrowser.Api/Library/LibraryService.cs | 2 +- .../Library/LibraryStructureService.cs | 2 +- MediaBrowser.Api/LibraryService.cs | 2 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 2 +- MediaBrowser.Api/LocalizationService.cs | 2 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 17 +- MediaBrowser.Api/MoviesService.cs | 2 +- MediaBrowser.Api/NotificationsService.cs | 2 +- MediaBrowser.Api/PackageReviewService.cs | 2 +- MediaBrowser.Api/PackageService.cs | 2 +- .../Playback/BaseStreamingService.cs | 2 +- .../Playback/Hls/AudioHlsService.cs | 2 +- .../Playback/Hls/HlsSegmentResponseFilter.cs | 4 +- .../Playback/Hls/HlsSegmentService.cs | 14 +- .../Playback/Hls/VideoHlsService.cs | 2 +- .../Playback/Progressive/AudioService.cs | 2 +- .../BaseProgressiveStreamingService.cs | 10 +- .../Progressive/ProgressiveStreamWriter.cs | 3 +- .../Playback/Progressive/VideoService.cs | 2 +- .../Playback/StaticRemoteStreamWriter.cs | 3 +- MediaBrowser.Api/Playback/StreamRequest.cs | 2 +- MediaBrowser.Api/PluginService.cs | 10 +- .../ScheduledTasks/ScheduledTaskService.cs | 6 +- MediaBrowser.Api/SearchService.cs | 2 +- MediaBrowser.Api/SessionsService.cs | 2 +- MediaBrowser.Api/SimilarItemsHelper.cs | 2 +- MediaBrowser.Api/SystemService.cs | 2 +- MediaBrowser.Api/TrailersService.cs | 2 +- MediaBrowser.Api/TvShowsService.cs | 2 +- .../UserLibrary/ArtistsService.cs | 2 +- .../UserLibrary/BaseItemsByNameService.cs | 2 +- .../UserLibrary/BaseItemsRequest.cs | 2 +- .../UserLibrary/GameGenresService.cs | 2 +- MediaBrowser.Api/UserLibrary/GenresService.cs | 2 +- .../UserLibrary/ItemByNameUserDataService.cs | 12 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 2 +- .../UserLibrary/MusicGenresService.cs | 2 +- .../UserLibrary/PersonsService.cs | 2 +- .../UserLibrary/StudiosService.cs | 2 +- .../UserLibrary/UserLibraryService.cs | 8 +- MediaBrowser.Api/UserLibrary/YearsService.cs | 2 +- MediaBrowser.Api/UserService.cs | 14 +- MediaBrowser.Api/VideosService.cs | 2 +- MediaBrowser.Api/packages.config | 2 - .../BaseApplicationHost.cs | 5 - ...MediaBrowser.Common.Implementations.csproj | 7 +- .../Serialization/JsonSerializer.cs | 2 +- .../packages.config | 1 - .../MediaBrowser.Common.csproj | 14 - MediaBrowser.Common/packages.config | 5 - .../MediaBrowser.Controller.csproj | 8 + .../Net/IHasResultFactory.cs | 7 +- .../Net/IHttpResultFactory.cs | 16 +- .../Net/IHttpServer.cs | 5 +- .../Net/IRestfulService.cs | 4 +- .../EntryPoints/UdpServerEntryPoint.cs | 1 + .../HttpServer/ContainerAdapter.cs | 53 + .../HttpServer/HttpListenerHost.cs | 533 +++++ .../HttpServer/HttpResultFactory.cs | 32 +- .../HttpServer/HttpServer.cs | 642 ------ .../HttpServer/LoggerUtils.cs | 48 + .../HttpServer/NativeWebSocket.cs | 36 + .../HttpServer/RangeRequestWriter.cs | 5 +- .../HttpServer/ResponseFilter.cs | 102 + .../HttpServer/ServerFactory.cs | 7 +- .../HttpServer/StreamWriter.cs | 3 +- .../HttpServer/SwaggerService.cs | 9 +- ...MediaBrowser.Server.Implementations.csproj | 114 +- .../ServerManager/ServerManager.cs | 3 +- .../Udp/UdpServer.cs | 70 +- .../packages.config | 10 - .../swagger-ui/css/hightlight.default.css | 135 -- .../swagger-ui/css/screen.css | 1759 -------------- .../swagger-ui/images/logo_small.png | Bin 770 -> 0 bytes .../swagger-ui/images/pet_store_api.png | Bin 824 -> 0 bytes .../swagger-ui/images/throbber.gif | Bin 9257 -> 0 bytes .../swagger-ui/images/wordnik_api.png | Bin 980 -> 0 bytes .../swagger-ui/lib/backbone-min.js | 38 - .../swagger-ui/lib/handlebars-1.0.rc.1.js | 1920 ---------------- .../swagger-ui/lib/highlight.7.3.pack.js | 1 - .../swagger-ui/lib/jquery-1.8.0.min.js | 2 - .../swagger-ui/lib/jquery.ba-bbq.min.js | 18 - .../swagger-ui/lib/jquery.slideto.min.js | 1 - .../swagger-ui/lib/jquery.wiggle.min.js | 8 - .../swagger-ui/lib/swagger.js | 772 ------- .../swagger-ui/lib/underscore-min.js | 32 - .../swagger-ui/swagger-ui.js | 2020 ----------------- .../swagger-ui/swagger-ui.min.js | 1 - .../ApplicationHost.cs | 3 +- MediaBrowser.ServerApplication/MainStartup.cs | 4 +- .../MediaBrowser.ServerApplication.csproj | 24 +- .../packages.config | 5 - .../Api/DashboardService.cs | 18 +- .../MediaBrowser.WebDashboard.csproj | 13 +- MediaBrowser.WebDashboard/packages.config | 2 - 110 files changed, 1048 insertions(+), 7750 deletions(-) delete mode 100644 MediaBrowser.Common/packages.config rename {MediaBrowser.Common => MediaBrowser.Controller}/Net/IHasResultFactory.cs (69%) rename {MediaBrowser.Common => MediaBrowser.Controller}/Net/IHttpResultFactory.cs (81%) rename {MediaBrowser.Common => MediaBrowser.Controller}/Net/IHttpServer.cs (93%) rename {MediaBrowser.Common => MediaBrowser.Controller}/Net/IRestfulService.cs (66%) create mode 100644 MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs create mode 100644 MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs create mode 100644 MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs create mode 100644 MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/css/hightlight.default.css delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/css/screen.css delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/images/logo_small.png delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/images/pet_store_api.png delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/images/throbber.gif delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/images/wordnik_api.png delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/backbone-min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/handlebars-1.0.rc.1.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/highlight.7.3.pack.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/jquery-1.8.0.min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/jquery.ba-bbq.min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/jquery.slideto.min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/jquery.wiggle.min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/swagger.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/lib/underscore-min.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/swagger-ui.js delete mode 100644 MediaBrowser.Server.Implementations/swagger-ui/swagger-ui.min.js diff --git a/MediaBrowser.Api/AlbumsService.cs b/MediaBrowser.Api/AlbumsService.cs index ffaa6139df..b8a830711a 100644 --- a/MediaBrowser.Api/AlbumsService.cs +++ b/MediaBrowser.Api/AlbumsService.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs index 9cc62a6dc1..a8b34b8bdf 100644 --- a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs +++ b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs @@ -2,10 +2,10 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Web; using System; using System.Collections.Generic; +using System.Net.Http.Headers; namespace MediaBrowser.Api { @@ -32,11 +32,10 @@ namespace MediaBrowser.Api /// The http request wrapper /// The http response wrapper /// The request DTO - public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto) + public void RequestFilter(IRequest request, IResponse response, object requestDto) { //This code is executed before the service - - var auth = GetAuthorization(request); + var auth = GetAuthorizationDictionary(request); if (auth != null) { @@ -74,9 +73,9 @@ namespace MediaBrowser.Api /// /// The HTTP req. /// Dictionary{System.StringSystem.String}. - public static Dictionary GetAuthorization(IHttpRequest httpReq) + private static Dictionary GetAuthorizationDictionary(IRequest httpReq) { - var auth = httpReq.Headers[HttpHeaders.Authorization]; + var auth = httpReq.Headers["Authorization"]; return GetAuthorization(auth); } @@ -86,11 +85,9 @@ namespace MediaBrowser.Api /// /// The HTTP req. /// Dictionary{System.StringSystem.String}. - public static AuthorizationInfo GetAuthorization(IRequestContext httpReq) + public static AuthorizationInfo GetAuthorization(IRequest httpReq) { - var header = httpReq.GetHeader("Authorization"); - - var auth = GetAuthorization(header); + var auth = GetAuthorizationDictionary(httpReq); string userId; string deviceId; diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index ee0721d5eb..ddce1ddcd1 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -1,12 +1,12 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; -using ServiceStack.ServiceHost; using System; using System.Collections.Generic; using System.Linq; +using ServiceStack.Web; namespace MediaBrowser.Api { @@ -32,7 +32,12 @@ namespace MediaBrowser.Api /// Gets or sets the request context. /// /// The request context. - public IRequestContext RequestContext { get; set; } + public IRequest Request { get; set; } + + public string GetHeader(string name) + { + return Request.Headers[name]; + } /// /// To the optimized result. @@ -43,7 +48,7 @@ namespace MediaBrowser.Api protected object ToOptimizedResult(T result) where T : class { - return ResultFactory.GetOptimizedResult(RequestContext, result); + return ResultFactory.GetOptimizedResult(Request, result); } /// @@ -59,7 +64,7 @@ namespace MediaBrowser.Api protected object ToOptimizedResultUsingCache(Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn) where T : class { - return ResultFactory.GetOptimizedResultUsingCache(RequestContext, cacheKey, lastDateModified, cacheDuration, factoryFn); + return ResultFactory.GetOptimizedResultUsingCache(Request, cacheKey, lastDateModified, cacheDuration, factoryFn); } /// @@ -76,7 +81,7 @@ namespace MediaBrowser.Api protected object ToCachedResult(Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType) where T : class { - return ResultFactory.GetCachedResult(RequestContext, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType); + return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType); } /// @@ -86,7 +91,7 @@ namespace MediaBrowser.Api /// System.Object. protected object ToStaticFileResult(string path) { - return ResultFactory.GetStaticFileResult(RequestContext, path); + return ResultFactory.GetStaticFileResult(Request, path); } private readonly char[] _dashReplaceChars = new[] { '?', '/' }; diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs index 4e8864644e..75ef7e54e4 100644 --- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs +++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs @@ -9,7 +9,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index b6c7434a16..39b335316b 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Serialization; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index 067da38534..dfdd0daf0a 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 799b9d7567..ef4fed3d36 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index b17cc81de6..44a69f6dea 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.IO; using System.Linq; diff --git a/MediaBrowser.Api/Images/ImageRequest.cs b/MediaBrowser.Api/Images/ImageRequest.cs index 288fd9ea63..0d4c1ff1be 100644 --- a/MediaBrowser.Api/Images/ImageRequest.cs +++ b/MediaBrowser.Api/Images/ImageRequest.cs @@ -1,6 +1,6 @@ using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; -using ServiceStack.ServiceHost; +using ServiceStack; namespace MediaBrowser.Api.Images { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 633d635141..2de78d75b2 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -11,8 +11,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Collections.Generic; using System.Drawing; @@ -20,6 +19,8 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ServiceStack.Text.Controller; +using ServiceStack.Web; namespace MediaBrowser.Api.Images { @@ -453,7 +454,7 @@ namespace MediaBrowser.Api.Images /// Task{List{ImageInfo}}. private List GetItemByNameImageInfos(GetItemByNameImageInfos request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -599,7 +600,7 @@ namespace MediaBrowser.Api.Images public object Get(GetItemByNameImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -613,21 +614,21 @@ namespace MediaBrowser.Api.Images /// The request. public void Post(PostUserImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(3), true); var item = _userManager.Users.First(i => i.Id == id); - var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType); + var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); Task.WaitAll(task); } public void Post(PostItemByNameImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var name = pathInfo.GetArgumentValue(1); @@ -635,7 +636,7 @@ namespace MediaBrowser.Api.Images var item = GetItemByName(name, type, _libraryManager); - var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType); + var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); Task.WaitAll(task); } @@ -646,28 +647,28 @@ namespace MediaBrowser.Api.Images /// The request. public void Post(PostItemImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(3), true); var item = _libraryManager.GetItemById(id); - var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType); + var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); Task.WaitAll(task); } public void Post(PostChannelImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = pathInfo.GetArgumentValue(2); request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(4), true); var item = _liveTv.GetChannel(id); - var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType); + var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); Task.WaitAll(task); } @@ -713,7 +714,7 @@ namespace MediaBrowser.Api.Images /// The request. public void Delete(DeleteItemByNameImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -742,7 +743,7 @@ namespace MediaBrowser.Api.Images /// The request. public void Post(UpdateItemByNameImageIndex request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -899,22 +900,22 @@ namespace MediaBrowser.Api.Images { if (format == ImageOutputFormat.Bmp) { - return MimeTypes.GetMimeType("i.bmp"); + return Common.Net.MimeTypes.GetMimeType("i.bmp"); } if (format == ImageOutputFormat.Gif) { - return MimeTypes.GetMimeType("i.gif"); + return Common.Net.MimeTypes.GetMimeType("i.gif"); } if (format == ImageOutputFormat.Jpg) { - return MimeTypes.GetMimeType("i.jpg"); + return Common.Net.MimeTypes.GetMimeType("i.jpg"); } if (format == ImageOutputFormat.Png) { - return MimeTypes.GetMimeType("i.png"); + return Common.Net.MimeTypes.GetMimeType("i.png"); } - return MimeTypes.GetMimeType(path); + return Common.Net.MimeTypes.GetMimeType(path); } /// diff --git a/MediaBrowser.Api/Images/ImageWriter.cs b/MediaBrowser.Api/Images/ImageWriter.cs index 4c61b68024..5d1ee140db 100644 --- a/MediaBrowser.Api/Images/ImageWriter.cs +++ b/MediaBrowser.Api/Images/ImageWriter.cs @@ -2,12 +2,12 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using ServiceStack.Web; namespace MediaBrowser.Api.Images { diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index 1084e99d07..c18954e500 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -8,14 +8,14 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ServiceStack.Text.Controller; namespace MediaBrowser.Api.Images { @@ -181,7 +181,7 @@ namespace MediaBrowser.Api.Images public object Get(GetItemByNameRemoteImageProviders request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -212,7 +212,7 @@ namespace MediaBrowser.Api.Images public object Get(GetItemByNameRemoteImages request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); @@ -264,7 +264,7 @@ namespace MediaBrowser.Api.Images public void Post(DownloadItemByNameRemoteImage request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(0); var item = GetItemByName(request.Name, type, _libraryManager); diff --git a/MediaBrowser.Api/InstantMixService.cs b/MediaBrowser.Api/InstantMixService.cs index 5a8c5a985c..c11f38123d 100644 --- a/MediaBrowser.Api/InstantMixService.cs +++ b/MediaBrowser.Api/InstantMixService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index 8fca3f338f..1b8b49f98a 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Linq; using System.Threading; diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 4483b74f94..9fc4bb3d04 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Linq; using System.Threading; diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index c7b4fae5f5..bef0ba1e19 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Common; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 198bec1a0d..c964b55171 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Api/LibraryService.cs b/MediaBrowser.Api/LibraryService.cs index 48037e8015..7dc8301fea 100644 --- a/MediaBrowser.Api/LibraryService.cs +++ b/MediaBrowser.Api/LibraryService.cs @@ -8,7 +8,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections; using System.Collections.Generic; diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 409b04b413..9e83a56de7 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs index d52f94b3c8..54ac8591ea 100644 --- a/MediaBrowser.Api/LocalizationService.cs +++ b/MediaBrowser.Api/LocalizationService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; -using ServiceStack.ServiceHost; +using ServiceStack; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index ffcc4b8383..1675929107 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -38,6 +38,14 @@ Always + + False + ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll + + + False + ..\ThirdParty\ServiceStack\ServiceStack.Text.dll + @@ -48,15 +56,6 @@ ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Common.dll - - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Interfaces.dll - - - ..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll - diff --git a/MediaBrowser.Api/MoviesService.cs b/MediaBrowser.Api/MoviesService.cs index 43fbe1f1b1..1b36ec8915 100644 --- a/MediaBrowser.Api/MoviesService.cs +++ b/MediaBrowser.Api/MoviesService.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using ServiceStack.ServiceHost; +using ServiceStack; namespace MediaBrowser.Api { diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs index 319cb996be..4f9ed729d9 100644 --- a/MediaBrowser.Api/NotificationsService.cs +++ b/MediaBrowser.Api/NotificationsService.cs @@ -1,10 +1,10 @@ using MediaBrowser.Controller.Notifications; using MediaBrowser.Model.Notifications; -using ServiceStack.ServiceHost; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ServiceStack; namespace MediaBrowser.Api { diff --git a/MediaBrowser.Api/PackageReviewService.cs b/MediaBrowser.Api/PackageReviewService.cs index e0d52ee8a8..b2de908d9f 100644 --- a/MediaBrowser.Api/PackageReviewService.cs +++ b/MediaBrowser.Api/PackageReviewService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Common.Constants; using MediaBrowser.Common.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Serialization; -using ServiceStack.ServiceHost; +using ServiceStack; namespace MediaBrowser.Api { diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index b152f02020..793b666ea0 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Updates; using MediaBrowser.Model.Updates; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e34f0888da..90996296d5 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -791,7 +791,7 @@ namespace MediaBrowser.Api.Playback var media = (IHasMediaStreams)item; - var url = RequestContext.PathInfo; + var url = Request.PathInfo; if (!request.AudioCodec.HasValue) { diff --git a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs index 073cd1b7fc..efcc3f07ab 100644 --- a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; -using ServiceStack.ServiceHost; +using ServiceStack; using System; namespace MediaBrowser.Api.Playback.Hls diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs index 44996c99f5..ed4ca86717 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs @@ -1,7 +1,7 @@ using MediaBrowser.Controller; using MediaBrowser.Model.Logging; -using ServiceStack.ServiceHost; using ServiceStack.Text.Controller; +using ServiceStack.Web; using System; using System.IO; using System.Linq; @@ -13,7 +13,7 @@ namespace MediaBrowser.Api.Playback.Hls public ILogger Logger { get; set; } public IServerApplicationPaths ApplicationPaths { get; set; } - public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response) + public void ResponseFilter(IRequest req, IResponse res, object response) { var pathInfo = PathInfo.Parse(req.PathInfo); var itemId = pathInfo.GetArgumentValue(1); diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index e9f7e48b19..02a6326945 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -1,5 +1,5 @@ using MediaBrowser.Controller; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.IO; using System.Linq; @@ -87,11 +87,11 @@ namespace MediaBrowser.Api.Playback.Hls { OnBeginRequest(request.PlaylistId); - var file = request.PlaylistId + Path.GetExtension(RequestContext.PathInfo); + var file = request.PlaylistId + Path.GetExtension(Request.PathInfo); file = Path.Combine(_appPaths.EncodedMediaCachePath, file); - return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); + return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } public void Delete(StopEncodingProcess request) @@ -106,13 +106,13 @@ namespace MediaBrowser.Api.Playback.Hls /// System.Object. public object Get(GetHlsVideoSegment request) { - var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); + var file = request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(_appPaths.EncodedMediaCachePath, file); OnBeginRequest(request.PlaylistId); - return ResultFactory.GetStaticFileResult(RequestContext, file); + return ResultFactory.GetStaticFileResult(Request, file); } /// @@ -122,11 +122,11 @@ namespace MediaBrowser.Api.Playback.Hls /// System.Object. public object Get(GetHlsAudioSegment request) { - var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); + var file = request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(_appPaths.EncodedMediaCachePath, file); - return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); + return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } /// diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index b194a47fe1..fe863c8629 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.IO; -using ServiceStack.ServiceHost; +using ServiceStack; using System; namespace MediaBrowser.Api.Playback.Hls diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 36a998c16d..86ab498f65 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.IO; -using ServiceStack.ServiceHost; +using ServiceStack; using System.Collections.Generic; namespace MediaBrowser.Api.Playback.Progressive diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 2447302f50..1fea322195 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// true if XXXX, false otherwise private void AddDlnaHeaders(StreamState state, IDictionary responseHeaders, bool isStaticallyStreamed) { - var timeSeek = RequestContext.GetHeader("TimeSeekRange.dlna.org"); + var timeSeek = GetHeader("TimeSeekRange.dlna.org"); if (!string.IsNullOrEmpty(timeSeek)) { @@ -110,7 +110,7 @@ namespace MediaBrowser.Api.Playback.Progressive return; } - var transferMode = RequestContext.GetHeader("transferMode.dlna.org"); + var transferMode = GetHeader("transferMode.dlna.org"); responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode; var contentFeatures = string.Empty; @@ -210,12 +210,12 @@ namespace MediaBrowser.Api.Playback.Progressive if (request.Static) { - return ResultFactory.GetStaticFileResult(RequestContext, state.Item.Path, FileShare.Read, responseHeaders, isHeadRequest); + return ResultFactory.GetStaticFileResult(Request, state.Item.Path, FileShare.Read, responseHeaders, isHeadRequest); } if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive)) { - return ResultFactory.GetStaticFileResult(RequestContext, outputPath, FileShare.Read, responseHeaders, isHeadRequest); + return ResultFactory.GetStaticFileResult(Request, outputPath, FileShare.Read, responseHeaders, isHeadRequest); } return GetStreamResult(state, responseHeaders, isHeadRequest).Result; @@ -307,7 +307,7 @@ namespace MediaBrowser.Api.Playback.Progressive return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor, null) { Logger = Logger, - RequestContext = RequestContext, + Request = Request, ResultFactory = ResultFactory }.Get(request); diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 816cab105d..58f36a06c1 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -1,7 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Model.Logging; -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using ServiceStack.Web; using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 97b808b867..40c7492ffb 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.IO; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.IO; diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs index 8c9815134a..7820a26d86 100644 --- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -1,5 +1,4 @@ -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using ServiceStack.Web; using System.Collections.Generic; using System.IO; using System.Net.Http; diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 339de0e6c6..1486c0de7a 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -1,5 +1,5 @@ using MediaBrowser.Model.Dto; -using ServiceStack.ServiceHost; +using ServiceStack; namespace MediaBrowser.Api.Playback { diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index 6c0face6b3..de9c89666c 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -5,12 +5,13 @@ using MediaBrowser.Common.Updates; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using ServiceStack.Text.Controller; +using ServiceStack.Web; namespace MediaBrowser.Api { @@ -79,7 +80,6 @@ namespace MediaBrowser.Api /// [Route("/Plugins/SecurityInfo", "GET")] [Api(("Gets plugin registration information"))] - [Restrict(VisibilityTo = EndpointAttributes.None)] public class GetPluginSecurityInfo : IReturn { } @@ -89,14 +89,12 @@ namespace MediaBrowser.Api /// [Route("/Plugins/SecurityInfo", "POST")] [Api("Updates plugin registration information")] - [Restrict(VisibilityTo = EndpointAttributes.None)] public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid { } [Route("/Plugins/RegistrationRecords/{Name}", "GET")] [Api("Gets registration status for a feature")] - [Restrict(VisibilityTo = EndpointAttributes.None)] public class GetRegistrationStatus { [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -224,7 +222,7 @@ namespace MediaBrowser.Api { // We need to parse this manually because we told service stack not to with IRequiresRequestStream // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); var plugin = _appHost.Plugins.First(p => p.Id == id); diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index d17a38e073..daa735fe53 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -1,11 +1,11 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Tasks; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; +using ServiceStack.Text.Controller; namespace MediaBrowser.Api.ScheduledTasks { @@ -205,7 +205,7 @@ namespace MediaBrowser.Api.ScheduledTasks { // We need to parse this manually because we told service stack not to with IRequiresRequestStream // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == id); diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 113df4e38c..25e22ab59b 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections; using System.Collections.Generic; diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index a3f7e3037c..2a979888b7 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index b0de3cf731..683e609d28 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index ae6c607954..dae603dc89 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.IO; using System.Threading.Tasks; diff --git a/MediaBrowser.Api/TrailersService.cs b/MediaBrowser.Api/TrailersService.cs index cc67c4036e..7d137646cc 100644 --- a/MediaBrowser.Api/TrailersService.cs +++ b/MediaBrowser.Api/TrailersService.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using ServiceStack.ServiceHost; +using ServiceStack; namespace MediaBrowser.Api { diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 68ebd60c54..b45d4dfb04 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs index 4dd3d744fa..5c1b104870 100644 --- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs +++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 3a0ecdf0d1..15926e9836 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 6aa87e499d..9c8157c9c0 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -2,7 +2,7 @@ using System.Linq; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; namespace MediaBrowser.Api.UserLibrary diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs index 84ab4bf9a5..54aeaeed35 100644 --- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index dac54e7c30..db3948976d 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs index 7913b8c8ac..1c32082164 100644 --- a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs @@ -2,11 +2,11 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Threading; using System.Threading.Tasks; +using ServiceStack.Text.Controller; namespace MediaBrowser.Api.UserLibrary { @@ -158,7 +158,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public object Post(MarkItemByNameFavorite request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(3); var task = MarkFavorite(request.UserId, type, request.Name, true); @@ -172,7 +172,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public object Post(UpdateItemByNameRating request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(3); var task = MarkLike(request.UserId, type, request.Name, request.Likes); @@ -186,7 +186,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public object Delete(UnmarkItemByNameFavorite request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(3); var task = MarkFavorite(request.UserId, type, request.Name, false); @@ -200,7 +200,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public object Delete(DeleteItemByNameRating request) { - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var type = pathInfo.GetArgumentValue(3); var task = MarkLike(request.UserId, type, request.Name, null); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 380e094633..6fcff545f6 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -10,7 +10,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs index 8ed280dc4d..59af94ef5b 100644 --- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs +++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs index 09b5ef09fe..48e486bb57 100644 --- a/MediaBrowser.Api/UserLibrary/PersonsService.cs +++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs index 9331916790..86f9394375 100644 --- a/MediaBrowser.Api/UserLibrary/StudiosService.cs +++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index e9fc524680..d3995ae2b2 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; @@ -8,9 +7,10 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -694,7 +694,7 @@ namespace MediaBrowser.Api.UserLibrary private SessionInfo GetSession() { - var auth = AuthorizationRequestFilterAttribute.GetAuthorization(RequestContext); + var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request); return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) && string.Equals(i.Client, auth.Client) && diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs index eda8e08c60..8f5178ac5c 100644 --- a/MediaBrowser.Api/UserLibrary/YearsService.cs +++ b/MediaBrowser.Api/UserLibrary/YearsService.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index ee8b6ff328..3b7808ba76 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -4,12 +4,12 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Users; -using ServiceStack.ServiceHost; -using ServiceStack.Text.Controller; +using ServiceStack; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using ServiceStack.Text.Controller; namespace MediaBrowser.Api { @@ -269,13 +269,13 @@ namespace MediaBrowser.Api /// Posts the specified request. /// /// The request. - public void Post(AuthenticateUser request) + public async Task Post(AuthenticateUser request) { // No response needed. Will throw an exception on failure. - var result = AuthenticateUser(request).Result; + await AuthenticateUser(request).ConfigureAwait(false); } - public object Post(AuthenticateUserByName request) + public async Task Post(AuthenticateUserByName request) { var user = _userManager.Users.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase)); @@ -284,7 +284,7 @@ namespace MediaBrowser.Api throw new ArgumentException(string.Format("User {0} not found.", request.Username)); } - var result = AuthenticateUser(new AuthenticateUser { Id = user.Id, Password = request.Password }).Result; + var result = await AuthenticateUser(new AuthenticateUser { Id = user.Id, Password = request.Password }).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -356,7 +356,7 @@ namespace MediaBrowser.Api { // We need to parse this manually because we told service stack not to with IRequiresRequestStream // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs - var pathInfo = PathInfo.Parse(RequestContext.PathInfo); + var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); var dtoUser = request; diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index 537b1ba932..d67c290229 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; -using ServiceStack.ServiceHost; +using ServiceStack; using System; using System.Linq; diff --git a/MediaBrowser.Api/packages.config b/MediaBrowser.Api/packages.config index e9a27e8ad8..f40bfae21f 100644 --- a/MediaBrowser.Api/packages.config +++ b/MediaBrowser.Api/packages.config @@ -1,6 +1,4 @@  - - \ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index e8f4d51eb1..e020b066ce 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -444,11 +444,6 @@ namespace MediaBrowser.Common.Implementations catch (Exception ex) { Logger.Error("Error creating {0}", ex, type.Name); - -#if DEBUG - throw; -#endif - // Don't blow up in release mode return null; } diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index f990db556a..0388fd38be 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -37,6 +37,10 @@ Always + + False + ..\ThirdParty\ServiceStack\ServiceStack.Text.dll + ..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll @@ -50,9 +54,6 @@ ..\packages\NLog.2.1.0\lib\net45\NLog.dll - - ..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll - ..\packages\SimpleInjector.2.3.6\lib\net40-client\SimpleInjector.dll diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs index 9c2412b227..130e21b6ef 100644 --- a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs @@ -166,7 +166,7 @@ namespace MediaBrowser.Common.Implementations.Serialization /// private void Configure() { - ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601; + ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.DateHandler.ISO8601; ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; ServiceStack.Text.JsConfig.IncludeNullValues = false; ServiceStack.Text.JsConfig.AlwaysUseUtc = true; diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index 269ac0e561..cf8bd48417 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,7 +1,6 @@  - \ No newline at end of file diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c7b3a65118..fce9c18cf9 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -38,15 +38,6 @@ - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Common.dll - - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Interfaces.dll - - - ..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll - @@ -69,15 +60,11 @@ - - - - @@ -105,7 +92,6 @@ - diff --git a/MediaBrowser.Common/packages.config b/MediaBrowser.Common/packages.config deleted file mode 100644 index 7411e313cd..0000000000 --- a/MediaBrowser.Common/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 21c9e39f19..f1f2aaf5ef 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -58,6 +58,10 @@ 4 + + False + ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll + @@ -123,6 +127,10 @@ + + + + diff --git a/MediaBrowser.Common/Net/IHasResultFactory.cs b/MediaBrowser.Controller/Net/IHasResultFactory.cs similarity index 69% rename from MediaBrowser.Common/Net/IHasResultFactory.cs rename to MediaBrowser.Controller/Net/IHasResultFactory.cs index d9da0c7e4e..a87113d1f4 100644 --- a/MediaBrowser.Common/Net/IHasResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHasResultFactory.cs @@ -1,12 +1,13 @@ -using ServiceStack.ServiceHost; +using MediaBrowser.Common.Net; +using ServiceStack.Web; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Controller.Net { /// /// Interface IHasResultFactory /// Services that require a ResultFactory should implement this /// - public interface IHasResultFactory : IRequiresRequestContext + public interface IHasResultFactory : IRequiresRequest { /// /// Gets or sets the result factory. diff --git a/MediaBrowser.Common/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs similarity index 81% rename from MediaBrowser.Common/Net/IHttpResultFactory.cs rename to MediaBrowser.Controller/Net/IHttpResultFactory.cs index 9f3d05d912..0614db12e6 100644 --- a/MediaBrowser.Common/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -1,10 +1,10 @@ -using ServiceStack.ServiceHost; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using ServiceStack.Web; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Controller.Net { /// /// Interface IHttpResultFactory @@ -36,7 +36,7 @@ namespace MediaBrowser.Common.Net /// The result. /// The response headers. /// System.Object. - object GetOptimizedResult(IRequestContext requestContext, T result, IDictionary responseHeaders = null) + object GetOptimizedResult(IRequest requestContext, T result, IDictionary responseHeaders = null) where T : class; /// @@ -50,7 +50,7 @@ namespace MediaBrowser.Common.Net /// The factory function that creates the response object. /// The response headers. /// System.Object. - object GetOptimizedResultUsingCache(IRequestContext requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, IDictionary responseHeaders = null) + object GetOptimizedResultUsingCache(IRequest requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, IDictionary responseHeaders = null) where T : class; /// @@ -65,7 +65,7 @@ namespace MediaBrowser.Common.Net /// Type of the content. /// The response headers. /// System.Object. - object GetCachedResult(IRequestContext requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) + object GetCachedResult(IRequest requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) where T : class; /// @@ -80,7 +80,7 @@ namespace MediaBrowser.Common.Net /// The response headers. /// if set to true [is head request]. /// System.Object. - object GetStaticResult(IRequestContext requestContext, Guid cacheKey, DateTime? lastDateModified, + object GetStaticResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType, Func> factoryFn, IDictionary responseHeaders = null, bool isHeadRequest = false); @@ -93,6 +93,6 @@ namespace MediaBrowser.Common.Net /// The response headers. /// if set to true [is head request]. /// System.Object. - object GetStaticFileResult(IRequestContext requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); + object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); } } diff --git a/MediaBrowser.Common/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs similarity index 93% rename from MediaBrowser.Common/Net/IHttpServer.cs rename to MediaBrowser.Controller/Net/IHttpServer.cs index 8bbaac0391..ba2cd0cccb 100644 --- a/MediaBrowser.Common/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -1,7 +1,8 @@ +using MediaBrowser.Common.Net; using System; using System.Collections.Generic; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Controller.Net { /// /// Interface IHttpServer @@ -18,7 +19,7 @@ namespace MediaBrowser.Common.Net /// Starts the specified server name. /// /// The URL. - void Start(string urlPrefix); + void StartServer(string urlPrefix); /// /// Gets a value indicating whether [supports web sockets]. diff --git a/MediaBrowser.Common/Net/IRestfulService.cs b/MediaBrowser.Controller/Net/IRestfulService.cs similarity index 66% rename from MediaBrowser.Common/Net/IRestfulService.cs rename to MediaBrowser.Controller/Net/IRestfulService.cs index 7a1b267951..f55012b734 100644 --- a/MediaBrowser.Common/Net/IRestfulService.cs +++ b/MediaBrowser.Controller/Net/IRestfulService.cs @@ -1,6 +1,6 @@ -using ServiceStack.ServiceHost; +using ServiceStack; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Controller.Net { /// /// Interface IRestfulService diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 9c1a953b11..7e5d5d3d83 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.Udp; diff --git a/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs b/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs new file mode 100644 index 0000000000..93d224b8db --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs @@ -0,0 +1,53 @@ +using MediaBrowser.Common; +using ServiceStack.Configuration; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + /// + /// Class ContainerAdapter + /// + class ContainerAdapter : IContainerAdapter, IRelease + { + /// + /// The _app host + /// + private readonly IApplicationHost _appHost; + + /// + /// Initializes a new instance of the class. + /// + /// The app host. + public ContainerAdapter(IApplicationHost appHost) + { + _appHost = appHost; + } + /// + /// Resolves this instance. + /// + /// + /// ``0. + public T Resolve() + { + return _appHost.Resolve(); + } + + /// + /// Tries the resolve. + /// + /// + /// ``0. + public T TryResolve() + { + return _appHost.TryResolve(); + } + + /// + /// Releases the specified instance. + /// + /// The instance. + public void Release(object instance) + { + // Leave this empty so SS doesn't try to dispose our objects + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs new file mode 100644 index 0000000000..c50588f95f --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -0,0 +1,533 @@ +using Funq; +using MediaBrowser.Common; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Logging; +using ServiceStack; +using ServiceStack.Configuration; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Host.HttpListener; +using ServiceStack.Logging; +using ServiceStack.Web; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + public delegate void DelReceiveWebRequest(HttpListenerContext context); + + public class HttpListenerHost : ServiceStackHost, IHttpServer + { + private string ServerName { get; set; } + private string HandlerPath { get; set; } + private string DefaultRedirectPath { get; set; } + + private readonly ILogger _logger; + public string UrlPrefix { get; private set; } + + private readonly List _restServices = new List(); + + private HttpListener Listener { get; set; } + protected bool IsStarted = false; + + private readonly List _autoResetEvents = new List(); + + private readonly ContainerAdapter _containerAdapter; + + private readonly ConcurrentDictionary _localEndPoints = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + public event EventHandler WebSocketConnected; + + /// + /// Gets the local end points. + /// + /// The local end points. + public IEnumerable LocalEndPoints + { + get { return _localEndPoints.Keys.ToList(); } + } + + public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, string serviceName, string handlerPath, string defaultRedirectPath, params Assembly[] assembliesWithServices) + : base(serviceName, assembliesWithServices) + { + // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4 + Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0="); + + DefaultRedirectPath = defaultRedirectPath; + ServerName = serviceName; + HandlerPath = handlerPath; + + _logger = logManager.GetLogger("HttpServer"); + + LogManager.LogFactory = new ServerLogFactory(logManager); + + _containerAdapter = new ContainerAdapter(applicationHost); + + for (var i = 0; i < 2; i++) + { + _autoResetEvents.Add(new AutoResetEvent(false)); + } + } + + public override void Configure(Container container) + { + HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath; + + HostConfig.Instance.MapExceptionToStatusCode = new Dictionary + { + {typeof (InvalidOperationException), 422}, + {typeof (ResourceNotFoundException), 404}, + {typeof (FileNotFoundException), 404}, + {typeof (DirectoryNotFoundException), 404} + }; + + HostConfig.Instance.DebugMode = true; + + HostConfig.Instance.LogFactory = LogManager.LogFactory; + + // The Markdown feature causes slow startup times (5 mins+) on cold boots for some users + // Custom format allows images + HostConfig.Instance.EnableFeatures = Feature.Csv | Feature.Html | Feature.Json | Feature.Jsv | Feature.Metadata | Feature.Xml | Feature.CustomFormat; + + container.Adapter = _containerAdapter; + + //Plugins.Add(new SwaggerFeature()); + Plugins.Add(new CorsFeature()); + HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); + } + + public override void OnAfterInit() + { + SetAppDomainData(); + + base.OnAfterInit(); + } + + public override void OnConfigLoad() + { + base.OnConfigLoad(); + + Config.HandlerFactoryPath = string.IsNullOrEmpty(HandlerPath) + ? null + : HandlerPath; + + Config.MetadataRedirectPath = string.IsNullOrEmpty(HandlerPath) + ? "metadata" + : PathUtils.CombinePaths(HandlerPath, "metadata"); + } + + protected override ServiceController CreateServiceController(params Assembly[] assembliesWithServices) + { + var types = _restServices.Select(r => r.GetType()).ToArray(); + + return new ServiceController(this, () => types); + } + + public virtual void SetAppDomainData() + { + //Required for Mono to resolve VirtualPathUtility and Url.Content urls + var domain = Thread.GetDomain(); // or AppDomain.Current + domain.SetData(".appDomain", "1"); + domain.SetData(".appVPath", "/"); + domain.SetData(".appPath", domain.BaseDirectory); + if (string.IsNullOrEmpty(domain.GetData(".appId") as string)) + { + domain.SetData(".appId", "1"); + } + if (string.IsNullOrEmpty(domain.GetData(".domainId") as string)) + { + domain.SetData(".domainId", "1"); + } + } + + public override ServiceStackHost Start(string listeningAtUrlBase) + { + StartListener(listeningAtUrlBase); + return this; + } + + /// + /// Starts the Web Service + /// + /// + /// A Uri that acts as the base that the server is listening on. + /// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/ + /// Note: the trailing slash is required! For more info see the + /// HttpListener.Prefixes property on MSDN. + /// + protected void StartListener(string listeningAtUrlBase) + { + // *** Already running - just leave it in place + if (IsStarted) + return; + + if (Listener == null) + Listener = new HttpListener(); + + HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(listeningAtUrlBase); + + UrlPrefix = listeningAtUrlBase; + + Listener.Prefixes.Add(listeningAtUrlBase); + + _logger.Info("Adding HttpListener Prefixes"); + Listener.Prefixes.Add(listeningAtUrlBase); + + IsStarted = true; + _logger.Info("Starting HttpListner"); + Listener.Start(); + + for (var i = 0; i < _autoResetEvents.Count; i++) + { + var index = i; + ThreadPool.QueueUserWorkItem(o => Listen(o, index)); + } + } + + private bool IsListening + { + get { return this.IsStarted && this.Listener != null && this.Listener.IsListening; } + } + + // Loop here to begin processing of new requests. + private void Listen(object state, int index) + { + while (IsListening) + { + if (Listener == null) return; + + try + { + Listener.BeginGetContext(c => ListenerCallback(c, index), Listener); + + _autoResetEvents[index].WaitOne(); + } + catch (Exception ex) + { + _logger.Error("Listen()", ex); + return; + } + if (Listener == null) return; + } + } + + // Handle the processing of a request in here. + private void ListenerCallback(IAsyncResult asyncResult, int index) + { + var listener = asyncResult.AsyncState as HttpListener; + HttpListenerContext context = null; + + if (listener == null) return; + + try + { + if (!IsListening) + { + _logger.Debug("Ignoring ListenerCallback() as HttpListener is no longer listening"); + return; + } + // The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework, + // blocks until there is a request to be processed or some type of data is available. + context = listener.EndGetContext(asyncResult); + } + catch (Exception ex) + { + // You will get an exception when httpListener.Stop() is called + // because there will be a thread stopped waiting on the .EndGetContext() + // method, and again, that is just the way most Begin/End asynchronous + // methods of the .NET Framework work. + var errMsg = ex + ": " + IsListening; + _logger.Warn(errMsg); + return; + } + finally + { + // Once we know we have a request (or exception), we signal the other thread + // so that it calls the BeginGetContext() (or possibly exits if we're not + // listening any more) method to start handling the next incoming request + // while we continue to process this request on a different thread. + _autoResetEvents[index].Set(); + } + + if (context == null) return; + + var date = DateTime.Now; + + Task.Factory.StartNew(async () => + { + try + { + LogHttpRequest(context, index); + + if (context.Request.IsWebSocketRequest) + { + ProcessWebSocketRequest(context); + return; + } + + var localPath = context.Request.Url.LocalPath; + + if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase)) + { + context.Response.Redirect(DefaultRedirectPath); + context.Response.Close(); + return; + } + if (string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase)) + { + context.Response.Redirect("mediabrowser/" + DefaultRedirectPath); + context.Response.Close(); + return; + } + if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)) + { + context.Response.Redirect("mediabrowser/" + DefaultRedirectPath); + context.Response.Close(); + return; + } + if (string.IsNullOrEmpty(localPath)) + { + context.Response.Redirect("/mediabrowser/" + DefaultRedirectPath); + context.Response.Close(); + return; + } + + var url = context.Request.Url.ToString(); + var endPoint = context.Request.RemoteEndPoint; + + await ProcessRequestAsync(context).ConfigureAwait(false); + + var duration = DateTime.Now - date; + + if (EnableHttpRequestLogging) + { + LoggerUtils.LogResponse(_logger, context, url, endPoint, duration); + } + } + catch (Exception ex) + { + _logger.ErrorException("ProcessRequest failure", ex); + + HandleError(ex, context, _logger); + } + + }); + } + + /// + /// Logs the HTTP request. + /// + /// The CTX. + private void LogHttpRequest(HttpListenerContext ctx, int index) + { + var endpoint = ctx.Request.LocalEndPoint; + + if (endpoint != null) + { + var address = endpoint.ToString(); + + _localEndPoints.GetOrAdd(address, address); + } + + if (EnableHttpRequestLogging) + { + LoggerUtils.LogRequest(_logger, ctx, index); + } + } + + /// + /// Processes the web socket request. + /// + /// The CTX. + /// Task. + private async Task ProcessWebSocketRequest(HttpListenerContext ctx) + { +#if !__MonoCS__ + try + { + var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); + if (WebSocketConnected != null) + { + WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint.ToString() }); + } + } + catch (Exception ex) + { + _logger.ErrorException("AcceptWebSocketAsync error", ex); + ctx.Response.StatusCode = 500; + ctx.Response.Close(); + } +#endif + } + + public static void HandleError(Exception ex, HttpListenerContext context, ILogger logger) + { + try + { + var errorResponse = new ErrorResponse + { + ResponseStatus = new ResponseStatus + { + ErrorCode = ex.GetType().GetOperationName(), + Message = ex.Message, + StackTrace = ex.StackTrace, + } + }; + + var operationName = context.Request.GetOperationName(); + var httpReq = context.ToRequest(operationName); + var httpRes = httpReq.Response; + var contentType = httpReq.ResponseContentType; + + var serializer = HostContext.ContentTypes.GetResponseSerializer(contentType); + if (serializer == null) + { + contentType = HostContext.Config.DefaultContentType; + serializer = HostContext.ContentTypes.GetResponseSerializer(contentType); + } + + var httpError = ex as IHttpError; + if (httpError != null) + { + httpRes.StatusCode = httpError.Status; + httpRes.StatusDescription = httpError.StatusDescription; + } + else + { + httpRes.StatusCode = 500; + } + + httpRes.ContentType = contentType; + + serializer(httpReq, errorResponse, httpRes); + + httpRes.Close(); + } + catch (Exception errorEx) + { + logger.ErrorException("Error this.ProcessRequest(context)(Exception while writing error to the response)", errorEx); + } + } + + /// + /// Shut down the Web Service + /// + public void Stop() + { + if (Listener != null) + { + Listener.Prefixes.Remove(UrlPrefix); + + Listener.Close(); + } + } + + /// + /// Overridable method that can be used to implement a custom hnandler + /// + /// + protected Task ProcessRequestAsync(HttpListenerContext context) + { + if (string.IsNullOrEmpty(context.Request.RawUrl)) + return ((object)null).AsTaskResult(); + + var operationName = context.Request.GetOperationName(); + + var httpReq = context.ToRequest(operationName); + var httpRes = httpReq.Response; + var handler = HttpHandlerFactory.GetHandler(httpReq); + + var serviceStackHandler = handler as IServiceStackHandler; + if (serviceStackHandler != null) + { + var restHandler = serviceStackHandler as RestHandler; + if (restHandler != null) + { + httpReq.OperationName = operationName = restHandler.RestPath.RequestType.GetOperationName(); + } + + var task = serviceStackHandler.ProcessRequestAsync(httpReq, httpRes, operationName); + task.ContinueWith(x => httpRes.Close()); + + return task; + } + + return new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo) + .AsTaskException(); + } + + /// + /// Gets or sets a value indicating whether [enable HTTP request logging]. + /// + /// true if [enable HTTP request logging]; otherwise, false. + public bool EnableHttpRequestLogging { get; set; } + + /// + /// Adds the rest handlers. + /// + /// The services. + public void Init(IEnumerable services) + { + _restServices.AddRange(services); + + ServiceController = CreateServiceController(); + + _logger.Info("Calling ServiceStack AppHost.Init"); + Init(); + } + + /// + /// Releases the specified instance. + /// + /// The instance. + public override void Release(object instance) + { + // Leave this empty so SS doesn't try to dispose our objects + } + + private bool _disposed; + private readonly object _disposeLock = new object(); + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + base.Dispose(); + + lock (_disposeLock) + { + if (_disposed) return; + + if (disposing) + { + Stop(); + } + + //release unmanaged resources here... + _disposed = true; + } + } + + public override void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void StartServer(string urlPrefix) + { + Start(urlPrefix); + } + + public bool SupportsWebSockets + { + get { return NativeWebSocket.IsSupported; } + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 5a5a2dd040..798632af7a 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -2,10 +2,8 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; using System; using System.Collections.Generic; using System.Globalization; @@ -13,6 +11,8 @@ using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; +using ServiceStack; +using ServiceStack.Web; using MimeTypes = MediaBrowser.Common.Net.MimeTypes; namespace MediaBrowser.Server.Implementations.HttpServer @@ -116,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The response headers. /// System.Object. /// result - public object GetOptimizedResult(IRequestContext requestContext, T result, IDictionary responseHeaders = null) + public object GetOptimizedResult(IRequest requestContext, T result, IDictionary responseHeaders = null) where T : class { if (result == null) @@ -156,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// or /// factoryFn /// - public object GetOptimizedResultUsingCache(IRequestContext requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, IDictionary responseHeaders = null) + public object GetOptimizedResultUsingCache(IRequest requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, IDictionary responseHeaders = null) where T : class { if (cacheKey == Guid.Empty) @@ -199,7 +199,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The response headers. /// System.Object. /// cacheKey - public object GetCachedResult(IRequestContext requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) + public object GetCachedResult(IRequest requestContext, Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) where T : class { if (cacheKey == Guid.Empty) @@ -256,7 +256,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// Duration of the cache. /// Type of the content. /// System.Object. - private object GetCachedResult(IRequestContext requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) + private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) { responseHeaders["ETag"] = cacheKeyString; @@ -287,7 +287,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// if set to true [is head request]. /// System.Object. /// path - public object GetStaticFileResult(IRequestContext requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false) + public object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false) { if (string.IsNullOrEmpty(path)) { @@ -332,7 +332,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// cacheKey /// or /// factoryFn - public object GetStaticResult(IRequestContext requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType, Func> factoryFn, IDictionary responseHeaders = null, bool isHeadRequest = false) + public object GetStaticResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType, Func> factoryFn, IDictionary responseHeaders = null, bool isHeadRequest = false) { if (cacheKey == Guid.Empty) { @@ -373,7 +373,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The request context. /// Type of the content. /// true if XXXX, false otherwise - private bool ShouldCompressResponse(IRequestContext requestContext, string contentType) + private bool ShouldCompressResponse(IRequest requestContext, string contentType) { // It will take some work to support compression with byte range requests if (!string.IsNullOrEmpty(requestContext.GetHeader("Range"))) @@ -428,9 +428,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// if set to true [compress]. /// if set to true [is head request]. /// Task{IHasOptions}. - private async Task GetStaticResult(IRequestContext requestContext, IDictionary responseHeaders, string contentType, Func> factoryFn, bool compress, bool isHeadRequest) + private async Task GetStaticResult(IRequest requestContext, IDictionary responseHeaders, string contentType, Func> factoryFn, bool compress, bool isHeadRequest) { - if (!compress || string.IsNullOrEmpty(requestContext.CompressionType)) + var requestedCompressionType = requestContext.GetCompressionType(); + + if (!compress || string.IsNullOrEmpty(requestedCompressionType)) { var stream = await factoryFn().ConfigureAwait(false); @@ -471,9 +473,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer return new HttpResult(content, contentType); } - var contents = content.Compress(requestContext.CompressionType); + var contents = content.Compress(requestedCompressionType); - return new CompressedResult(contents, requestContext.CompressionType, contentType); + return new CompressedResult(contents, requestedCompressionType, contentType); } /// @@ -548,7 +550,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The last date modified. /// Duration of the cache. /// true if [is not modified] [the specified cache key]; otherwise, false. - private bool IsNotModified(IRequestContext requestContext, Guid? cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) + private bool IsNotModified(IRequest requestContext, Guid? cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) { var isNotModified = true; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs deleted file mode 100644 index 7d049549b5..0000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs +++ /dev/null @@ -1,642 +0,0 @@ -using Funq; -using MediaBrowser.Common; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using ServiceStack.Api.Swagger; -using ServiceStack.Common.Web; -using ServiceStack.Configuration; -using ServiceStack.Logging; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Support; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.WebSockets; -using System.Reactive.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// - /// Class HttpServer - /// - public class HttpServer : HttpListenerBase, IHttpServer - { - /// - /// The logger - /// - private readonly ILogger _logger; - - /// - /// Gets the URL prefix. - /// - /// The URL prefix. - public string UrlPrefix { get; private set; } - - /// - /// The _rest services - /// - private readonly List _restServices = new List(); - - /// - /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it - /// - /// The HTTP listener. - private IDisposable HttpListener { get; set; } - - /// - /// Occurs when [web socket connected]. - /// - public event EventHandler WebSocketConnected; - - /// - /// Gets the default redirect path. - /// - /// The default redirect path. - private string DefaultRedirectPath { get; set; } - - /// - /// Gets or sets the name of the server. - /// - /// The name of the server. - private string ServerName { get; set; } - - /// - /// The _container adapter - /// - private readonly ContainerAdapter _containerAdapter; - - private readonly ConcurrentDictionary _localEndPoints = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Gets the local end points. - /// - /// The local end points. - public IEnumerable LocalEndPoints - { - get { return _localEndPoints.Keys.ToList(); } - } - - /// - /// Initializes a new instance of the class. - /// - /// The application host. - /// The log manager. - /// Name of the server. - /// The default redirectpath. - /// urlPrefix - public HttpServer(IApplicationHost applicationHost, ILogManager logManager, string serverName, string defaultRedirectpath) - : base() - { - if (logManager == null) - { - throw new ArgumentNullException("logManager"); - } - if (applicationHost == null) - { - throw new ArgumentNullException("applicationHost"); - } - if (string.IsNullOrEmpty(serverName)) - { - throw new ArgumentNullException("serverName"); - } - if (string.IsNullOrEmpty(defaultRedirectpath)) - { - throw new ArgumentNullException("defaultRedirectpath"); - } - - ServerName = serverName; - DefaultRedirectPath = defaultRedirectpath; - _logger = logManager.GetLogger("HttpServer"); - - LogManager.LogFactory = new ServerLogFactory(logManager); - - EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null; - EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; - - _containerAdapter = new ContainerAdapter(applicationHost); - } - - /// - /// The us culture - /// - protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Configures the specified container. - /// - /// The container. - public override void Configure(Container container) - { - JsConfig.DateHandler = JsonDateHandler.ISO8601; - JsConfig.ExcludeTypeInfo = true; - JsConfig.IncludeNullValues = false; - - SetConfig(new EndpointHostConfig - { - DefaultRedirectPath = DefaultRedirectPath, - - MapExceptionToStatusCode = { - { typeof(InvalidOperationException), 422 }, - { typeof(ResourceNotFoundException), 404 }, - { typeof(FileNotFoundException), 404 }, - { typeof(DirectoryNotFoundException), 404 } - }, - - DebugMode = true, - - ServiceName = ServerName, - - LogFactory = LogManager.LogFactory, - - // The Markdown feature causes slow startup times (5 mins+) on cold boots for some users - // Custom format allows images - EnableFeatures = Feature.Csv | Feature.Html | Feature.Json | Feature.Jsv | Feature.Metadata | Feature.Xml | Feature.CustomFormat - }); - - container.Adapter = _containerAdapter; - - Plugins.Add(new SwaggerFeature()); - Plugins.Add(new CorsFeature()); - - ResponseFilters.Add(FilterResponse); - } - - /// - /// Filters the response. - /// - /// The req. - /// The res. - /// The dto. - private void FilterResponse(IHttpRequest req, IHttpResponse res, object dto) - { - // Try to prevent compatibility view - res.AddHeader("X-UA-Compatible", "IE=Edge"); - - var exception = dto as Exception; - - if (exception != null) - { - _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl); - - if (!string.IsNullOrEmpty(exception.Message)) - { - var error = exception.Message.Replace(Environment.NewLine, " "); - error = RemoveControlCharacters(error); - - res.AddHeader("X-Application-Error-Code", error); - } - } - - if (dto is CompressedResult) - { - // Per Google PageSpeed - // This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed. - // The correct version of the resource is delivered based on the client request header. - // This is a good choice for applications that are singly homed and depend on public proxies for user locality. - res.AddHeader("Vary", "Accept-Encoding"); - } - - var hasOptions = dto as IHasOptions; - - if (hasOptions != null) - { - // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy - string contentLength; - - if (hasOptions.Options.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength)) - { - var length = long.Parse(contentLength, UsCulture); - - if (length > 0) - { - var response = (HttpListenerResponse)res.OriginalResponse; - - response.ContentLength64 = length; - - // Disable chunked encoding. Technically this is only needed when using Content-Range, but - // anytime we know the content length there's no need for it - response.SendChunked = false; - } - } - } - } - - /// - /// Removes the control characters. - /// - /// The in string. - /// System.String. - private static string RemoveControlCharacters(string inString) - { - if (inString == null) return null; - - var newString = new StringBuilder(); - - foreach (var ch in inString) - { - if (!char.IsControl(ch)) - { - newString.Append(ch); - } - } - return newString.ToString(); - } - - /// - /// Starts the Web Service - /// - /// A Uri that acts as the base that the server is listening on. - /// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/ - /// Note: the trailing slash is required! For more info see the - /// HttpListener.Prefixes property on MSDN. - /// urlBase - public override void Start(string urlBase) - { - if (string.IsNullOrEmpty(urlBase)) - { - throw new ArgumentNullException("urlBase"); - } - - // *** Already running - just leave it in place - if (IsStarted) - { - return; - } - - if (Listener == null) - { - _logger.Info("Creating HttpListner"); - Listener = new HttpListener(); - } - - EndpointHost.Config.ServiceStackHandlerFactoryPath = HttpListenerRequestWrapper.GetHandlerPathIfAny(urlBase); - - UrlPrefix = urlBase; - - _logger.Info("Adding HttpListener Prefixes"); - Listener.Prefixes.Add(urlBase); - - IsStarted = true; - _logger.Info("Starting HttpListner"); - Listener.Start(); - - _logger.Info("Creating HttpListner observable stream"); - HttpListener = CreateObservableStream().Subscribe(ProcessHttpRequestAsync); - } - - /// - /// Creates the observable stream. - /// - /// IObservable{HttpListenerContext}. - private IObservable CreateObservableStream() - { - return Observable.Create(obs => - Observable.FromAsync(() => Listener.GetContextAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// - /// Processes incoming http requests by routing them to the appropiate handler - /// - /// The CTX. - private async void ProcessHttpRequestAsync(HttpListenerContext context) - { - var date = DateTime.Now; - - LogHttpRequest(context); - - if (context.Request.IsWebSocketRequest) - { - await ProcessWebSocketRequest(context).ConfigureAwait(false); - return; - } - - var localPath = context.Request.Url.LocalPath; - - if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase)) - { - context.Response.Redirect(DefaultRedirectPath); - context.Response.Close(); - return; - } - if (string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase)) - { - context.Response.Redirect("mediabrowser/" + DefaultRedirectPath); - context.Response.Close(); - return; - } - if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)) - { - context.Response.Redirect("mediabrowser/" + DefaultRedirectPath); - context.Response.Close(); - return; - } - if (string.IsNullOrEmpty(localPath)) - { - context.Response.Redirect("/mediabrowser/" + DefaultRedirectPath); - context.Response.Close(); - return; - } - - RaiseReceiveWebRequest(context); - - await Task.Factory.StartNew(() => - { - try - { - var url = context.Request.Url.ToString(); - var endPoint = context.Request.RemoteEndPoint; - - ProcessRequest(context); - - var duration = DateTime.Now - date; - - LogResponse(context, url, endPoint, duration); - - } - catch (Exception ex) - { - _logger.ErrorException("ProcessRequest failure", ex); - } - - }).ConfigureAwait(false); - } - - /// - /// Processes the web socket request. - /// - /// The CTX. - /// Task. - private async Task ProcessWebSocketRequest(HttpListenerContext ctx) - { - #if __MonoCS__ - #else - try - { - var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); - if (WebSocketConnected != null) - { - WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint.ToString() }); - } - } - catch (Exception ex) - { - _logger.ErrorException("AcceptWebSocketAsync error", ex); - ctx.Response.StatusCode = 500; - ctx.Response.Close(); - } - #endif - } - - /// - /// Logs the HTTP request. - /// - /// The CTX. - private void LogHttpRequest(HttpListenerContext ctx) - { - var endpoint = ctx.Request.LocalEndPoint; - - if (endpoint != null) - { - var address = endpoint.ToString(); - - _localEndPoints.GetOrAdd(address, address); - } - - if (EnableHttpRequestLogging) - { - var log = new StringBuilder(); - - log.AppendLine("Url: " + ctx.Request.Url); - log.AppendLine("Headers: " + string.Join(",", ctx.Request.Headers.AllKeys.Select(k => k + "=" + ctx.Request.Headers[k]))); - - var type = ctx.Request.IsWebSocketRequest ? "Web Socket" : "HTTP " + ctx.Request.HttpMethod; - - _logger.LogMultiline(type + " request received from " + ctx.Request.RemoteEndPoint, LogSeverity.Debug, log); - } - } - - /// - /// Overridable method that can be used to implement a custom hnandler - /// - /// The context. - /// Cannot execute handler: + handler + at PathInfo: + httpReq.PathInfo - protected override void ProcessRequest(HttpListenerContext context) - { - if (string.IsNullOrEmpty(context.Request.RawUrl)) return; - - var operationName = context.Request.GetOperationName(); - - var httpReq = new HttpListenerRequestWrapper(operationName, context.Request); - var httpRes = new HttpListenerResponseWrapper(context.Response); - var handler = ServiceStackHttpHandlerFactory.GetHandler(httpReq); - - var serviceStackHandler = handler as IServiceStackHttpHandler; - - if (serviceStackHandler != null) - { - var restHandler = serviceStackHandler as RestHandler; - if (restHandler != null) - { - httpReq.OperationName = operationName = restHandler.RestPath.RequestType.Name; - } - serviceStackHandler.ProcessRequest(httpReq, httpRes, operationName); - return; - } - - throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo); - } - - /// - /// Logs the response. - /// - /// The CTX. - /// The URL. - /// The end point. - /// The duration. - private void LogResponse(HttpListenerContext ctx, string url, IPEndPoint endPoint, TimeSpan duration) - { - if (!EnableHttpRequestLogging) - { - return; - } - - var statusCode = ctx.Response.StatusCode; - - var log = new StringBuilder(); - - log.AppendLine(string.Format("Url: {0}", url)); - - log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); - - var responseTime = string.Format(". Response time: {0} ms", duration.TotalMilliseconds); - - var msg = "Response code " + statusCode + " sent to " + endPoint + responseTime; - - _logger.LogMultiline(msg, LogSeverity.Debug, log); - } - - /// - /// Creates the service manager. - /// - /// The assemblies with services. - /// ServiceManager. - protected override ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices) - { - var types = _restServices.Select(r => r.GetType()).ToArray(); - - return new ServiceManager(new Container(), new ServiceController(() => types)); - } - - /// - /// Shut down the Web Service - /// - public override void Stop() - { - if (HttpListener != null) - { - HttpListener.Dispose(); - HttpListener = null; - } - - if (Listener != null) - { - Listener.Prefixes.Remove(UrlPrefix); - } - - base.Stop(); - } - - /// - /// The _supports native web socket - /// - private bool? _supportsNativeWebSocket; - - /// - /// Gets a value indicating whether [supports web sockets]. - /// - /// true if [supports web sockets]; otherwise, false. - public bool SupportsWebSockets - { - get - { - #if __MonoCS__ - return false; - #else - #endif - - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } - } - - - /// - /// Gets or sets a value indicating whether [enable HTTP request logging]. - /// - /// true if [enable HTTP request logging]; otherwise, false. - public bool EnableHttpRequestLogging { get; set; } - - /// - /// Adds the rest handlers. - /// - /// The services. - public void Init(IEnumerable services) - { - _restServices.AddRange(services); - - _logger.Info("Calling EndpointHost.ConfigureHost"); - - EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager()); - - _logger.Info("Calling ServiceStack AppHost.Init"); - Init(); - } - - /// - /// Releases the specified instance. - /// - /// The instance. - public override void Release(object instance) - { - // Leave this empty so SS doesn't try to dispose our objects - } - } - - /// - /// Class ContainerAdapter - /// - class ContainerAdapter : IContainerAdapter, IRelease - { - /// - /// The _app host - /// - private readonly IApplicationHost _appHost; - - /// - /// Initializes a new instance of the class. - /// - /// The app host. - public ContainerAdapter(IApplicationHost appHost) - { - _appHost = appHost; - } - /// - /// Resolves this instance. - /// - /// - /// ``0. - public T Resolve() - { - return _appHost.Resolve(); - } - - /// - /// Tries the resolve. - /// - /// - /// ``0. - public T TryResolve() - { - return _appHost.TryResolve(); - } - - /// - /// Releases the specified instance. - /// - /// The instance. - public void Release(object instance) - { - // Leave this empty so SS doesn't try to dispose our objects - } - } -} \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs new file mode 100644 index 0000000000..8fe1297c72 --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs @@ -0,0 +1,48 @@ +using MediaBrowser.Model.Logging; +using System; +using System.Linq; +using System.Net; +using System.Text; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + public static class LoggerUtils + { + public static void LogRequest(ILogger logger, HttpListenerContext ctx, int workerIndex) + { + var log = new StringBuilder(); + + log.AppendLine("Url: " + ctx.Request.Url); + log.AppendLine("Headers: " + string.Join(",", ctx.Request.Headers.AllKeys.Select(k => k + "=" + ctx.Request.Headers[k]))); + + var type = ctx.Request.IsWebSocketRequest ? "Web Socket" : "HTTP " + ctx.Request.HttpMethod; + + logger.LogMultiline(type + " request received on worker " + workerIndex + " from " + ctx.Request.RemoteEndPoint, LogSeverity.Debug, log); + } + + /// + /// Logs the response. + /// + /// The logger. + /// The CTX. + /// The URL. + /// The end point. + /// The duration. + public static void LogResponse(ILogger logger, HttpListenerContext ctx, string url, IPEndPoint endPoint, TimeSpan duration) + { + var statusCode = ctx.Response.StatusCode; + + var log = new StringBuilder(); + + log.AppendLine(string.Format("Url: {0}", url)); + + log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); + + var responseTime = string.Format(". Response time: {0} ms", duration.TotalMilliseconds); + + var msg = "Response code " + statusCode + " sent to " + endPoint + responseTime; + + logger.LogMultiline(msg, LogSeverity.Debug, log); + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs index a40dff5a47..ff822a4e61 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs @@ -184,5 +184,41 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// /// The on receive. public Action OnReceive { get; set; } + + /// + /// The _supports native web socket + /// + private static bool? _supportsNativeWebSocket; + + /// + /// Gets a value indicating whether [supports web sockets]. + /// + /// true if [supports web sockets]; otherwise, false. + public static bool IsSupported + { + get + { +#if __MonoCS__ + return false; +#else +#endif + + if (!_supportsNativeWebSocket.HasValue) + { + try + { + new ClientWebSocket(); + + _supportsNativeWebSocket = true; + } + catch (PlatformNotSupportedException) + { + _supportsNativeWebSocket = false; + } + } + + return _supportsNativeWebSocket.Value; + } + } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 3956eb69d4..312e718e15 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -1,5 +1,4 @@ -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using ServiceStack.Web; using System; using System.Collections.Generic; using System.Globalization; @@ -197,7 +196,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public string ContentType { get; set; } - public IRequestContext RequestContext { get; set; } + public IRequest RequestContext { get; set; } public object Response { get; set; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs new file mode 100644 index 0000000000..520f035614 --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs @@ -0,0 +1,102 @@ +using MediaBrowser.Model.Logging; +using ServiceStack; +using ServiceStack.Web; +using System; +using System.Globalization; +using System.Net; +using System.Text; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + public class ResponseFilter + { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + private readonly ILogger _logger; + + public ResponseFilter(ILogger logger) + { + _logger = logger; + } + + /// + /// Filters the response. + /// + /// The req. + /// The res. + /// The dto. + public void FilterResponse(IRequest req, IResponse res, object dto) + { + // Try to prevent compatibility view + res.AddHeader("X-UA-Compatible", "IE=Edge"); + + var exception = dto as Exception; + + if (exception != null) + { + _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl); + + if (!string.IsNullOrEmpty(exception.Message)) + { + var error = exception.Message.Replace(Environment.NewLine, " "); + error = RemoveControlCharacters(error); + + res.AddHeader("X-Application-Error-Code", error); + } + } + + if (dto is CompressedResult) + { + // Per Google PageSpeed + // This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed. + // The correct version of the resource is delivered based on the client request header. + // This is a good choice for applications that are singly homed and depend on public proxies for user locality. + res.AddHeader("Vary", "Accept-Encoding"); + } + + var hasOptions = dto as IHasOptions; + + if (hasOptions != null) + { + // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy + string contentLength; + + if (hasOptions.Options.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength)) + { + var length = long.Parse(contentLength, UsCulture); + + if (length > 0) + { + var response = (HttpListenerResponse)res.OriginalResponse; + + response.ContentLength64 = length; + + // Disable chunked encoding. Technically this is only needed when using Content-Range, but + // anytime we know the content length there's no need for it + response.SendChunked = false; + } + } + } + } + + /// + /// Removes the control characters. + /// + /// The in string. + /// System.String. + private static string RemoveControlCharacters(string inString) + { + if (inString == null) return null; + + var newString = new StringBuilder(); + + foreach (var ch in inString) + { + if (!char.IsControl(ch)) + { + newString.Append(ch); + } + } + return newString.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs index e953a3c6d4..57acddc432 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs @@ -1,5 +1,5 @@ using MediaBrowser.Common; -using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; namespace MediaBrowser.Server.Implementations.HttpServer @@ -15,11 +15,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The application host. /// The log manager. /// Name of the server. + /// The handler path. /// The default redirectpath. /// IHttpServer. - public static IHttpServer CreateServer(IApplicationHost applicationHost, ILogManager logManager, string serverName, string defaultRedirectpath) + public static IHttpServer CreateServer(IApplicationHost applicationHost, ILogManager logManager, string serverName, string handlerPath, string defaultRedirectpath) { - return new HttpServer(applicationHost, logManager, serverName, defaultRedirectpath); + return new HttpListenerHost(applicationHost, logManager, serverName, handlerPath, defaultRedirectpath); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index 46d38ad148..a4e6f18bb7 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -1,6 +1,5 @@ using MediaBrowser.Model.Logging; -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using ServiceStack.Web; using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs b/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs index c7c6ad706b..8f85059336 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; -using ServiceStack.ServiceHost; +using MediaBrowser.Controller.Net; +using ServiceStack; +using ServiceStack.Web; using System.IO; namespace MediaBrowser.Server.Implementations.HttpServer @@ -40,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer var requestedFile = Path.Combine(swaggerDirectory, request.ResourceName.Replace('/', Path.DirectorySeparatorChar)); - return ResultFactory.GetStaticFileResult(RequestContext, requestedFile); + return ResultFactory.GetStaticFileResult(Request, requestedFile); } /// @@ -53,6 +54,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// Gets or sets the request context. /// /// The request context. - public IRequestContext RequestContext { get; set; } + public IRequest Request { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 4b30672d0a..3ce675d4fa 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -37,24 +37,28 @@ ..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll - - ..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.70\lib\net35\Mono.Data.Sqlite.dll + + False + ..\ThirdParty\ServiceStack\ServiceStack.dll - - ..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.70\lib\net35\ServiceStack.OrmLite.Sqlite.dll + + ..\ThirdParty\ServiceStack\ServiceStack.Client.dll - - - - - ..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll + + False + ..\ThirdParty\ServiceStack\ServiceStack.Common.dll - - ..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll + + False + ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll - - ..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll + + False + ..\ThirdParty\ServiceStack\ServiceStack.Text.dll + + + @@ -63,36 +67,9 @@ ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - - ..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll - - - ..\packages\ServiceStack.Redis.3.9.43\lib\net35\ServiceStack.Redis.dll - ..\packages\MediaBrowser.BdInfo.1.0.0.5\lib\net20\BDInfo.dll - - ..\packages\ServiceStack.3.9.70\lib\net35\ServiceStack.dll - - - ..\packages\ServiceStack.Api.Swagger.3.9.70\lib\net35\ServiceStack.Api.Swagger.dll - - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Common.dll - - - ..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Interfaces.dll - - - ..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.70\lib\net35\ServiceStack.OrmLite.dll - - - ..\packages\ServiceStack.3.9.70\lib\net35\ServiceStack.ServiceInterface.dll - - - ..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll - ..\packages\System.Data.SQLite.x86.1.0.89.0\lib\net45\System.Data.SQLite.dll @@ -119,10 +96,13 @@ + + - + + @@ -264,58 +244,6 @@ - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs index 84a40619c4..553aae285d 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -168,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager { HttpServer = _applicationHost.Resolve(); HttpServer.EnableHttpRequestLogging = enableHttpLogging; - HttpServer.Start(urlPrefix); + HttpServer.StartServer(urlPrefix); } catch (SocketException ex) { diff --git a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs index aca5461c85..9002996676 100644 --- a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs +++ b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs @@ -1,11 +1,12 @@ -using MediaBrowser.Common.Net; +using System.Threading; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using System; using System.Linq; using System.Net; using System.Net.Sockets; -using System.Reactive.Linq; using System.Text; using System.Threading.Tasks; @@ -35,6 +36,8 @@ namespace MediaBrowser.Server.Implementations.Udp /// private readonly IServerConfigurationManager _serverConfigurationManager; + private bool _isDisposed; + /// /// Initializes a new instance of the class. /// @@ -115,38 +118,41 @@ namespace MediaBrowser.Server.Implementations.Udp _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - CreateObservable().Subscribe(OnMessageReceived); + Task.Run(() => StartListening()); } - /// - /// Creates the observable. - /// - /// IObservable{UdpReceiveResult}. - private IObservable CreateObservable() + private async void StartListening() + { + while (!_isDisposed) + { + try + { + var result = await GetResult().ConfigureAwait(false); + + OnMessageReceived(result); + } + catch (ObjectDisposedException) + { + break; + } + } + } + + private Task GetResult() { - return Observable.Create(obs => - Observable.FromAsync(() => - { - try - { - return _udpClient.ReceiveAsync(); - } - catch (ObjectDisposedException) - { - return Task.FromResult(new UdpReceiveResult(new byte[]{}, new IPEndPoint(IPAddress.Any, 0))); - } - catch (Exception ex) - { - _logger.ErrorException("Error receiving udp message", ex); - return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0))); - } - }) - - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); + try + { + return _udpClient.ReceiveAsync(); + } + catch (ObjectDisposedException) + { + return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0))); + } + catch (Exception ex) + { + _logger.ErrorException("Error receiving udp message", ex); + return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0))); + } } /// @@ -182,6 +188,8 @@ namespace MediaBrowser.Server.Implementations.Udp /// public void Stop() { + _isDisposed = true; + if (_udpClient != null) { _udpClient.Close(); diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 488dbc1ae8..54c8c9f9d7 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -3,15 +3,5 @@ - - - - - - - - - - \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/swagger-ui/css/hightlight.default.css b/MediaBrowser.Server.Implementations/swagger-ui/css/hightlight.default.css deleted file mode 100644 index e417fc1799..0000000000 --- a/MediaBrowser.Server.Implementations/swagger-ui/css/hightlight.default.css +++ /dev/null @@ -1,135 +0,0 @@ -/* - -Original style from softwaremaniacs.org (c) Ivan Sagalaev - -*/ - -pre code { - display: block; padding: 0.5em; - background: #F0F0F0; -} - -pre code, -pre .subst, -pre .tag .title, -pre .lisp .title, -pre .clojure .built_in, -pre .nginx .title { - color: black; -} - -pre .string, -pre .title, -pre .constant, -pre .parent, -pre .tag .value, -pre .rules .value, -pre .rules .value .number, -pre .preprocessor, -pre .ruby .symbol, -pre .ruby .symbol .string, -pre .aggregate, -pre .template_tag, -pre .django .variable, -pre .smalltalk .class, -pre .addition, -pre .flow, -pre .stream, -pre .bash .variable, -pre .apache .tag, -pre .apache .cbracket, -pre .tex .command, -pre .tex .special, -pre .erlang_repl .function_or_atom, -pre .markdown .header { - color: #800; -} - -pre .comment, -pre .annotation, -pre .template_comment, -pre .diff .header, -pre .chunk, -pre .markdown .blockquote { - color: #888; -} - -pre .number, -pre .date, -pre .regexp, -pre .literal, -pre .smalltalk .symbol, -pre .smalltalk .char, -pre .go .constant, -pre .change, -pre .markdown .bullet, -pre .markdown .link_url { - color: #080; -} - -pre .label, -pre .javadoc, -pre .ruby .string, -pre .decorator, -pre .filter .argument, -pre .localvars, -pre .array, -pre .attr_selector, -pre .important, -pre .pseudo, -pre .pi, -pre .doctype, -pre .deletion, -pre .envvar, -pre .shebang, -pre .apache .sqbracket, -pre .nginx .built_in, -pre .tex .formula, -pre .erlang_repl .reserved, -pre .prompt, -pre .markdown .link_label, -pre .vhdl .attribute, -pre .clojure .attribute, -pre .coffeescript .property { - color: #88F -} - -pre .keyword, -pre .id, -pre .phpdoc, -pre .title, -pre .built_in, -pre .aggregate, -pre .css .tag, -pre .javadoctag, -pre .phpdoc, -pre .yardoctag, -pre .smalltalk .class, -pre .winutils, -pre .bash .variable, -pre .apache .tag, -pre .go .typename, -pre .tex .command, -pre .markdown .strong, -pre .request, -pre .status { - font-weight: bold; -} - -pre .markdown .emphasis { - font-style: italic; -} - -pre .nginx .built_in { - font-weight: normal; -} - -pre .coffeescript .javascript, -pre .javascript .xml, -pre .tex .formula, -pre .xml .javascript, -pre .xml .vbscript, -pre .xml .css, -pre .xml .cdata { - opacity: 0.5; -} diff --git a/MediaBrowser.Server.Implementations/swagger-ui/css/screen.css b/MediaBrowser.Server.Implementations/swagger-ui/css/screen.css deleted file mode 100644 index 06050e760d..0000000000 --- a/MediaBrowser.Server.Implementations/swagger-ui/css/screen.css +++ /dev/null @@ -1,1759 +0,0 @@ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -caption, th, td { - text-align: left; - font-weight: normal; - vertical-align: middle; -} - -q, blockquote { - quotes: none; -} - -q:before, q:after, blockquote:before, blockquote:after { - content: ""; - content: none; -} - -a img { - border: none; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { - display: block; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; -} - -h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { - text-decoration: underline; -} - -h1 span.divider, h2 span.divider, h3 span.divider, h4 span.divider, h5 span.divider, h6 span.divider { - color: #aaaaaa; -} - -h1 { - color: black; - font-size: 1.5em; - line-height: 1.3em; - padding: 10px 0 10px 0; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -h2 { - color: black; - font-size: 1.3em; - padding: 10px 0 10px 0; -} - -h2 a { - color: black; -} - -h2 span.sub { - font-size: 0.7em; - color: #999999; - font-style: italic; -} - -h2 span.sub a { - color: #777777; -} - -h3 { - color: black; - font-size: 1.1em; - padding: 10px 0 10px 0; -} - -.heading_with_menu { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -.heading_with_menu h1, .heading_with_menu h2, .heading_with_menu h3, .heading_with_menu h4, .heading_with_menu h5, .heading_with_menu h6 { - display: block; - clear: none; - float: left; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - width: 60%; -} - -.heading_with_menu ul { - display: block; - clear: none; - float: right; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - margin-top: 10px; -} - -input.parameter { - width: 300px; - border: 1px solid #aaa; -} - -.body-textarea { - width: 300px; - height: 100px; - border: 1px solid #aaa; -} - -p { - line-height: 1.4em; - padding: 0 0 10px; - color: #333333; -} - -ol { - margin: 0px 0 10px; - padding: 0 0 0 18px; - list-style-type: decimal; -} - -ol li { - padding: 5px 0px; - font-size: 0.9em; - color: #333333; -} - -.markdown h3 { - color: #547f00; -} - -.markdown h4 { - color: #666666; -} - -.markdown pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; - margin: 0 0 10px 0; -} - -.markdown pre code { - line-height: 1.6em; -} - -.markdown p code, .markdown li code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #f0f0f0; - color: black; - padding: 1px 3px; -} - -.markdown ol, .markdown ul { - font-family: "Droid Sans", sans-serif; - margin: 5px 0 10px; - padding: 0 0 0 18px; - list-style-type: disc; -} - -.markdown ol li, .markdown ul li { - padding: 3px 0px; - line-height: 1.4em; - color: #333333; -} - -div.gist { - margin: 20px 0 25px 0 !important; -} - -p.big, div.big p { - font-size: 1em; - margin-bottom: 10px; -} - -span.weak { - color: #666666; -} - -span.blank, span.empty { - color: #888888; - font-style: italic; -} - -a { - color: #547f00; -} - -b, strong { - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -.code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; -} - -pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; -} - -pre code { - line-height: 1.6em; -} - -.required { - font-weight: bold; -} - -table.fullwidth { - width: 100%; -} - -table thead tr th { - padding: 5px; - font-size: 0.9em; - color: #666666; - border-bottom: 1px solid #999999; -} - -table tbody tr.offset { - background-color: #f5f5f5; -} - -table tbody tr td { - padding: 6px; - font-size: 0.9em; - border-bottom: 1px solid #cccccc; - vertical-align: top; - line-height: 1.3em; -} - -table tbody tr:last-child td { - border-bottom: none; -} - -table tbody tr.offset { - background-color: #f0f0f0; -} - -form.form_box { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - padding: 10px; -} - -form.form_box label { - color: #0f6ab4 !important; -} - -form.form_box input[type=submit] { - display: block; - padding: 10px; -} - -form.form_box p { - font-size: 0.9em; - padding: 0 0 15px; - color: #7e7b6d; -} - -form.form_box p a { - color: #646257; -} - -form.form_box p strong { - color: black; -} - -form.form_box p.weak { - font-size: 0.8em; -} - -form.formtastic fieldset.inputs ol li p.inline-hints { - margin-left: 0; - font-style: italic; - font-size: 0.9em; - margin: 0; -} - -form.formtastic fieldset.inputs ol li label { - display: block; - clear: both; - width: auto; - padding: 0 0 3px; - color: #666666; -} - -form.formtastic fieldset.inputs ol li label abbr { - padding-left: 3px; - color: #888888; -} - -form.formtastic fieldset.inputs ol li.required label { - color: black; -} - -form.formtastic fieldset.inputs ol li.string input, form.formtastic fieldset.inputs ol li.url input, form.formtastic fieldset.inputs ol li.numeric input { - display: block; - padding: 4px; - width: auto; - clear: both; -} - -form.formtastic fieldset.inputs ol li.string input.title, form.formtastic fieldset.inputs ol li.url input.title, form.formtastic fieldset.inputs ol li.numeric input.title { - font-size: 1.3em; -} - -form.formtastic fieldset.inputs ol li.text textarea { - font-family: "Droid Sans", sans-serif; - height: 250px; - padding: 4px; - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.select select { - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.boolean { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -form.formtastic fieldset.inputs ol li.boolean input { - display: block; - float: left; - clear: none; - margin: 0 5px 0 0; -} - -form.formtastic fieldset.inputs ol li.boolean label { - display: block; - float: left; - clear: none; - margin: 0; - padding: 0; -} - -form.formtastic fieldset.buttons { - margin: 0; - padding: 0; -} - -form.fullwidth ol li.string input, form.fullwidth ol li.url input, form.fullwidth ol li.text textarea, form.fullwidth ol li.numeric input { - width: 500px !important; -} - -body { - font-family: "Droid Sans", sans-serif; -} - -body #content_message { - margin: 10px 15px; - font-style: italic; - color: #999999; -} - -body #header { - background-color: #89bf04; - padding: 14px; -} - -body #header a#logo { - font-size: 1.5em; - font-weight: bold; - text-decoration: none; - background: transparent url(../images/logo_small.png) no-repeat left center; - padding: 20px 0 20px 40px; - color: white; -} - -body #header form#api_selector { - display: block; - clear: none; - float: right; -} - -body #header form#api_selector .input { - display: block; - clear: none; - float: left; - margin: 0 10px 0 0; -} - -body #header form#api_selector .input input { - font-size: 0.9em; - padding: 3px; - margin: 0; -} - -body #header form#api_selector .input input#input_baseUrl { - width: 400px; -} - -body #header form#api_selector .input input#input_apiKey { - width: 200px; -} - -body #header form#api_selector .input a#explore { - display: block; - text-decoration: none; - font-weight: bold; - padding: 6px 8px; - font-size: 0.9em; - color: white; - background-color: #547f00; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -o-border-radius: 4px; - -ms-border-radius: 4px; - -khtml-border-radius: 4px; - border-radius: 4px; -} - -body #header form#api_selector .input a#explore:hover { - background-color: #547f00; -} - -body p#colophon { - margin: 0 15px 40px 15px; - padding: 10px 0; - font-size: 0.8em; - border-top: 1px solid #dddddd; - font-family: "Droid Sans", sans-serif; - color: #999999; - font-style: italic; -} - -body p#colophon a { - text-decoration: none; - color: #547f00; -} - -body ul#resources { - font-family: "Droid Sans", sans-serif; - font-size: 0.9em; -} - -body ul#resources li.resource { - border-bottom: 1px solid #dddddd; -} - -body ul#resources li.resource:last-child { - border-bottom: none; -} - -body ul#resources li.resource div.heading { - border: 1px solid transparent; - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource div.heading h2 { - color: #999999; - padding-left: 0; - display: block; - clear: none; - float: left; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -body ul#resources li.resource div.heading h2 a { - color: #999999; -} - -body ul#resources li.resource div.heading h2 a:hover { - color: black; -} - -body ul#resources li.resource div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 14px 10px 0 0; -} - -body ul#resources li.resource div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource div.heading ul.options li:first-child, body ul#resources li.resource div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource div.heading ul.options li:last-child, body ul#resources li.resource div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource div.heading ul.options li { - color: #666666; - font-size: 0.9em; -} - -body ul#resources li.resource div.heading ul.options li a { - color: #aaaaaa; - text-decoration: none; -} - -body ul#resources li.resource div.heading ul.options li a:hover { - text-decoration: underline; - color: black; -} - -body ul#resources li.resource:hover div.heading h2 a, body ul#resources li.resource.active div.heading h2 a { - color: black; -} - -body ul#resources li.resource:hover div.heading ul.options li a, body ul#resources li.resource.active div.heading ul.options li a { - color: #555555; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f0f7; - border: 1px solid #c3d9ec; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #0f6ab4; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - border-right-color: #c3d9ec; - color: #0f6ab4; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { - color: #0f6ab4; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { - color: #0f6ab4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fa5d2; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f6ec; - border: 1px solid #c3e8d1; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #10a54a; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - border-right-color: #c3e8d1; - color: #10a54a; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { - color: #10a54a; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { - background-color: #ebf7f0; - border: 1px solid #c3e8d1; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { - color: #10a54a; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f9f2e9; - border: 1px solid #f0e0ca; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #c5862b; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - border-right-color: #f0e0ca; - color: #c5862b; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { - color: #c5862b; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { - background-color: #faf5ee; - border: 1px solid #f0e0ca; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { - color: #c5862b; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #FCE9E3; - border: 1px solid #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #D38042; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - border-right-color: #f0cecb; - color: #D38042; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { - color: #D38042; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { - background-color: #faf0ef; - border: 1px solid #f0cecb; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { - color: #D38042; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px 0; - padding: 0 0 0 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 0 0; - padding: 0; - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #ffd20f; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options { - float: none; - clear: both; - overflow: hidden; - margin: 0; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - border-right-color: #ffd20f; - color: #ffd20f; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { - color: #ffd20f; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { - color: #ffd20f; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header img { - display: block; - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block { - background-color: #fcf6db; - border: 1px solid black; - border-color: #e5e0c6; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f5e8e8; - border: 1px solid #e8c6c7; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #a41e22; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - border-right-color: #e8c6c7; - color: #a41e22; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { - color: #a41e22; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { - background-color: #f7eded; - border: 1px solid #e8c6c7; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { - color: #a41e22; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #c8787a; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - - -.model-signature { - font-family: "Droid Sans", sans-serif; - font-size: 1em; - line-height: 1.5em; -} - -.model-signature .description div { - font-size: 0.9em; - line-height: 1.5em; - margin-left: 1em; -} - -.model-signature .description .strong { - font-weight: bold; - color: #000; - font-size: .9em; -} - -.model-signature .description .stronger { - font-weight: bold; - color: #000; -} - -.model-signature .signature-nav a { - text-decoration: none; - color: #AAA; -} - -.model-signature pre { - font-size: .85em; - line-height: 1.2em; - overflow: auto; - max-height: 200px; - cursor: pointer; -} - -.model-signature pre:hover { - background-color: #ffffdd; -} - -.model-signature .snippet small { - font-size: 0.75em; -} - -.model-signature .signature-container { - clear: both; -} - -.model-signature .signature-nav a:hover { - text-decoration: underline; - color: black; -} - -.model-signature .signature-nav .selected { - color: black; - text-decoration: none; -} - -.model-signature ul.signature-nav { - display: block; - margin: 0; - padding: 0; -} - -.model-signature ul.signature-nav li { - float: left; - margin: 0 5px 5px 0; - padding: 2px 5px 2px 0; - border-right: 1px solid #ddd; -} - -.model-signature ul.signature-nav li:last-child { - padding-right: 0; - border-right: none; -} - -.model-signature .propName { - font-weight: bold; -} -.model-signature .propType { - color: #5555aa; -} -.model-signature .propOptKey { - font-style: italic; -} -.model-signature .propOpt { - color: #555; -} - -pre code { - background: none; -} - -.content pre { - font-size: 12px; - margin-top: 5px; - padding: 5px; -} - -.content > .content-type > div > label { - clear: both; - display: block; - color: #0F6AB4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -.swagger-ui-wrap { - max-width: 960px; - margin-left: auto; - margin-right: auto; -} - -.icon-btn { - cursor: pointer; -} - -#message-bar { - min-height: 30px; - text-align: center; - padding-top: 10px; -} - -.message-success { - color: #89BF04; -} - -.message-fail { - color: #cc0000; -} \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/swagger-ui/images/logo_small.png b/MediaBrowser.Server.Implementations/swagger-ui/images/logo_small.png deleted file mode 100644 index 5496a65579ae903d4008f9d268fac422ef9d3679..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 770 zcmV+d1O5DoP)K11rQipnJ)eVnTSzHNF zN8ab&RhE5cC$$4FI-PZXx$pga@8yN)KS}L2Us~^y$(x-xioWbnFcV+~b9ig=!ft8Q z0RD+rpA8910Smyc0GviVUOPGiY6YM@-r6Nn8S&~cxHl27$l)-R$1(!Xx045RDy;_& zeXkG{;_#i9rz0B6149#Ddj=KM6MV^rTD%ylzGdCBX<^=^@I0X3SCR7OMbn}sUKdeF zKO-flaJa%@kJ27@Rod?J9=+Qx5|=PtG8n> zy~9rIu}+48M}FW5Bbqw3t#po?c?kmG!FX32W(dOjzTb+U@64MzHItoeB!M0Jcd}|E z>ekW`<~FjR_ZVVJkF|_htH&v!({Oad?xax?0K0sLwBY%nr46DpCmIIaa?@|Y&?n0q z@kJlMy`pE2HtEgASNd~xNzt$Kn7w#^Fy5oi`e$bUE*+f>Vk5z7=-2pj68afrqli$_ zvqe##5V?a)QU_-s9+s?mJYT5m`MQDRH4cYs^L1lCW;Dua5Ln9lG0BC@9DJQHA(}y&Z}$apb{kU zbezR}b^|O%6i+$BFsT3zqAe8wg9`vfiRp#{)z2bsJw`vBQL7Bt!IexM3$Hsf0tHK3 z+R=x{lR$K`s;7__?ASPW=3?*xgCpGaiadSEpoi0pw-_V#OXM8Ap{4qlG08x0ig9IY z3Ijqh(t1_=g#jocuqyJO=729e9OSiNDSrhR0Gc5G)(QGH?*IS*07*qoM6N<$f<~fU A82|tP diff --git a/MediaBrowser.Server.Implementations/swagger-ui/images/pet_store_api.png b/MediaBrowser.Server.Implementations/swagger-ui/images/pet_store_api.png deleted file mode 100644 index f9f9cd4aeb35a108c4b2f1dddb59977d56c595d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 824 zcmV-81IPS{P)n=Rd;8mVwQNY4k4xJQ%YT}s;WA7;r!W@XgqjG_4og} z8w>{OB9REiMa8-B85td+y}bji^~2KA`Md4j-u{zw=H%Da@83%_8qEnl9k1WK;pWX- zb-lg)pQYAreK@>)*5Clqni{IZVYGG+NY67Bp-^bn;L{Nbh44I6CIK+n7p8#U?;fCA zYMFcy%UEjup4fgnli%NyzSe*@419QuU9lJ|T$?f9w?HIQ$RwEJGK7^!y7LhxIgVJp z9c!kB{0aydM1epU1NJ=h(}2X?Y{qn70yEN$dwm~favs=VbQ+T?!AvSl{P~PE zS&zsJbTQttne>kdM4$jBhLMFy@I1)3u-4cAzrY*l!o9eK^w%+jqY!oi(Ri8sMauvK zwnCP#%3hEH#FtNqq{iT(?=_JA_8XC>5Y8Y@!wmxKb|A87ZbpHA`+%v~0pt{5Nko1L zLKR^25YExt1lH7L1{t{|P z@n)yHyZf~3>LZ@#&CNw1rA#OlY^|)UJQKUrlKKO&x%wPhH}6&e0000K^a6u zQ3;5MiU^7p6*M3qDk!2=YEcHMQ>nzEYP;R`e2C@r+U+?#XaC*&gKPcB#k$`o&;7mu zYNhYYXe|Uo84#4ZIko#rcU5K8*yFL{qT47O&^5fZH$ zVZ@%(l~vVHjnm;H@KL8@r%yUHoo;rbHI_4lIH(_nsTT>S2`DFOD~uCb9_dF4`#QgI zy7ldMcLs+A_s%|e1pRPrbX-tpeNP!9(IpMFTce`t_5U%lP99z%&i6`1d~ zWeM!Rxc50<+d$e^9LT`?B+aMK~apR zHm?q;p<7{wN2g|I^aGlSws;VP84j(z%aQwvAWv83Z$}p(% zZ^?2;gxg(ey_`V5J7{;!o;o;KslW@z5EP~JGs|U)J7dF&(ff#A=6vU?cGQ$-4+;Jf z-ggJEa!yStn`_EWvl)#yhm6XVs}UUbsi;+agri;mCfjH^Uy;lH+Zw^h)4N?oZgZz4 zJk(fTZ|Bi^;+s_M=~+d#vyoxEPzTlOS=mX@sbl*uRj>=MaMr}cFIY8i?UM61>86uB zV$DlOUCiUJwbzJMP@D$urzK|lL2-PC!p1l47V-ZG<5Ev0Z5h~Kx?`KOp7gkAjV93A z-Gc7MrlxTf?wF;CbNc@tCHJH{TB3c;#{SVu%97}tyAM2n&|9W_?qv}$*Jt*%7Yxb# zV0;d;7|lDEltJYS+U)#aiJO};?_Jyy_4%syQ(uy?-J-Yx-9O5nKRk@@XSS~X<(2u~ zV-LamWm~!iqtH9wkpf8mAXZhOD&L#aA_%)4h2M;1M5jt zIR>Us+%W-GXa_f^opKg=DSrAs)AXeRa;Hp0aC1OgbxQ%Qr_QvTleM1jkR!2mkcX$3 ztsR8~G9iqh(-FJ@F_rQBIYDXV_6s7G9SxaVF^laZqcx$!D97m|7t16j6@Jt6UdDRy49Qyvs|c>RuA|@b%}`*wU}2^7q;&Vtc6@lb zcXl)T!6nYDzmMJ~%n$KNXyNlCG)GkJ4!82;v6@d3>s5r~E+3!O?049JDr14Y^PeMI02R`0lJ^=oJ zYd|*u9|SU(j7hY?+<=(?fP*mtV*zFhOrz6%{VA?ozdm&(Jf^V zMfPZ?>l`mS3{Uq8IM;e!+1YjJy2!mzK$O|wPeU{*QSbs9m+@`f5KxO3PBnQ=%RsZg%go*fJ`*w9TL{-WgZVIA$!YV}3BRcfeXaR$x#b zW)Tpd#8E4)^MyYdkH;4_;ChJuw%n+Be7Ko4;w-nHvyo$d_0e-YiF78Df&)_)(}fcr_r0mPH(4RRYWIu+d@t0&Ss@O^s! zOKyX&13)%N@83r^;QsgN{rl(!0|RF1FA)b1{CRXAy&1ySz@>olPiR4r$aMdq&_=nK zq|cFs8phWJ1@%dZ-gXd{zDbTILD>)qEvH-NU*Rf1b2J1Ri79`rBFl@ z8E^0I)OqEi{pH(a24b9YPG;Kz@t-qZW;3Mpe`MRlmYx{7bH-XZ&`RQ7Rb^%}gc&X| zd}Q-FZf|RWxHU?PR!(C?80zu(^l>*h{#ulSiid(O!J(8P-41bNM3tnX@U6NS5yo0? zdcF)~xFE&+&|gZ$23dV5t~?$$&ymZ;F8j7GGMncGSsDo%>J`26=&l=X#rSKv_64;0 zr;k6no@=gV`P)K!=kaHl>q?!`X>(A;84tg^Md<`zA%qbRLby1Z=fn*ZRdNqs%Tq|3 zOt}lZu0q9oKJhgz&+^7PCt$=UFW=R*w?a1)ePoL*`R$Gxj?TU@12tTHsT$giHQU+sqf;fS0FpT!< z z#UR4L_rT;lfRLVo8|3$7cmuxwjY5rmYs&kR6z_LRhf9-=4QalKQYEWw^4-EBI3j$& zA>$Im_{ZA>0`)E_&m%x6a)BThkx=e|aMkOrK9zb1YzqpQ&WZ^$)2T>CwTCuYRn5y) z3fVXg-@R5&Bf4?WUTyD|hBDe2>xEh|o-y}o5Se~+Ob!5xN>CaAN!<4)F zwNh!Y7B?@AigokFYNJL`0Vz&-ekrY95-n3M<%GR<;SzXRmO7(zd+gf|$Thb%;pby2 zyd{5TJ?|JYUgpSlJ0=LB@k6#d&opuPGq^qJAIumfhigC2qAX0OEnYnT@O;bA?X1O5 zpLe9|%_H+Yki!Rv$7Kvjv8r7Z?$<>G)g*%D*V#s&kz>Z3V1 z3!ZKh9H8Nl9IdhEW_rY#oYdDCLTe+nQ{(d2pBX8%CmxL+1`|b#Vb!?IY!kT7$PDWAP9$FY=e9KSK{DEH|408! zl-$lv)U8$EB{~es&j>rYg%{{JRvIl8@NK}L=xDAEVv(o#W@3LUDc*m?yKSPR0O|nY zAh;*QuBdpja8HzP8Uw`ce-r*LrUA47ZvZ)ff3k4^>;dFcof}9eXeeM<0OVj&CKDVK zpUKKIF%hSmry!pwK68UX>zOF@dv}B4Gg)^2GQmN7@A?zG!xO6dT*Cq0+r{eY6}AfU zf`|~y!?^R*nB0!iTcg|CgM}ou^H*s~5)%h;Xh;PYOM!|Yhfk$w;@`1Dx1y!EZrM&^zMat!^Wz# z=Z{;Pa0w21oA1X3*9=`*c7o3ePa^k%Vzu>2C_7DaZJ8FW5GJv|t>`Ym;_S>7g_3XI zdRb!Ppd`ErK`pUDHRsJd9@)bu>}s1)nKsyAR7h21<1u{DX1gd_Vf;^zdUpFPeSHHR z7AMgw^{FlFlK91CGMafKt`$FLhq#^=->@Uok7pqW6&#Zs4*E(i5-jog43A*qC@!(8 z8&F}pofRcMVmcJd=f;fvlfAR!ZqeaTE?#TQ^jQM0ioaJf8m^!Kdv^`f5kEsD0=gX#4={QE1$3A4K~V$ITKEd){XVLx?i6K*D>JF6E=i znqF^X#&UX}rfB|#A9%y|sR5i6B5gyk>8@Q+xHg|^5iz7C2}YkGF)nuP4LX#k2tRBP z=!VnWnXea(K#Wvg2&0f{!mXuuWaPpsoZ)3TSaEp;i|_)CvP=4wjI; zH%7tcLM8dQXsHW*#|}%TG9yiGpyjBltpcpXkpl8zg~x zD{QG)2Z8x$vfjgDc(J6i|OHoLX&!<+m^<$S3DtA8Mf!{ z7;g1}0uqJ0Mxuy%=#BFX5;Xh9JkrA$d}neS9T;$F$kXn}ss zF{Jn}9EDk=>h)sMy$YXfhKIDxr7U@3xl+uI|N5y!>?{aVn703L1Qgb$ql%JT^lsGD%)~)(H?Spj$zNt)h)Raob z@KyVB@&ngE0rtMW4!UTqGX>{&KHJAWqb)oYq9O)e)nmN0jVa;LNbKXx04a+8&O;q) zHBzGejrqt7Dk$Z2VR%%K#`!((pXE*MR{jGtv|q$p5#v9N0f^6B9IB!Q6(y$TmHRLM zsYXm2jn3f{9T)KVVzotDx=Ng8q0Z*VDZOkd5C!p0PRoFt>NyVEc9*%YR&2>Nq~$AI zXOQfjJ&wpGMe~I8y=cC(QR4=W2GWccFK(3`d&gN+)qWtW-`*}mZI%KDRl4@rUv1%d zxFO82lhW$xQyYxJg8tOZyXm1As%kEFNn)eW{R61M>af@wr(YW{R@+eL2 zx?SovK+867$F%T;Dfeajw|kiQ81GcOnS$Y4+hp8g_w1P8_~79d9p$*M1_Ei81$H$Ti6oi?ZW)&tmsJa7RV1LKddm7R*qL54L7j zvCr1Mrb;l!=m^TbJun-C_6$7w81E1eAQC^6s4>rZ4&I5+yyu$kha%Z&d+|S7Ki#{2 zy}%Giz|eR|G?ychX%%=eL`W(aLarb(L4jd>J+wlX;xMV9H8J!l&i?~Mw7)jlIuLD% zyq+AK92j#kC`ycv$SJ|E7!FBParx#v<3_rZ-DLQ@>`#sdl5}immok8&`{YgF|+< z`tB>e%6G{=B4?V-be>`&*}0d*f?$yBX@w+rJht@O+=^zttqB2p=IiA17#YD$4-fih z@$gJ95mGmFhN!d;3Ag4#>3o`>%L{G=9<}qOJ$wDN)%)MN6bVsAPG4oKB3+8r6!Qf9 z3m8?jIpWcEJbt6|f?Y4nMXK(--YZ|GA2_aRS!do%J9S7?Q&4FYL@sPilq}e4tlYa& z?f+we^=FH^Z9|dnXZghblW!IYGIAT{``58&7vZBybh+GuIPP{h*J?&vf7i8rv6qgx zab9~l+K`tvC7pWtlS!5lt(n#Yl}PAR(v01oXjc0F?T0w>+*p#PtE?Tf_hMrEaZ!^V zbv_>=4xibc0TUxg^I>TS?HR4fdiWl`@6{7|WU9G68l7tOz2p>oIe~NNr!>Q&PHm`4 z98R?g(IT*nl#{_|*WO_h0X78;WwMp?A^Zi)W@BX5q==TdOl?~J6HK(0b(xD6?m3e3 z#+zMaSJb(W$h5+d+6vujSjyi_R80c9>7h;0YlUFDvN`iNGu&5HQ5^e>6x?&JSc4V$6_I1jJ4vnCVbkU`Gz=Uy#~OI( zlL-$UAE$pVCsD_rICM#Q!ltzcqDphp5L|ZrqUm>=H%x!RjMrF#*?BN2shvUg=H;)& zy~_xWl*k$~9Hl6PIq({dELPE-r4*YNs7?5{>dlC`EcK~lPKB_8V)G@H)UZFF8$tXT z@^raW#Hq4OJGFL2Aye|HU&_NL%dYans6?ltqEBz`Q|m=@Zh4=-p2r;}q(Nbsk$fUI zP|(Ns2>MDvZi1H7<55frlQn#%?`WY3g`+fRuC#UJx%#d!zxEu3=}zF514S=6f@?~$ zeuSB=6E7r3ya|; z@K7M3VBrls6c{M*M_{AB_fVjgQ|F(FuK(@=1eWeVMSpLglllqV6Rg-L_46;?^IskS z)x6|SR1^gGl6amWjkb1dX}^8DumNXNmhsfxKA#;bBBIZE@0gma5yQY(FX>|N~Y^mgq`xc zdxOf6r{9u#_e0gV3(fdBTdV2Sc4SN5ZmP?cB4?KRdvj&>@zN_HP5m0E=+A=efDBI*IG*Gy%%< zz@yc%2XvGm)QQv5k^ZC6!9MwX8BCmQ{3eAX|GTwn#>(PS6PoB=$Pwn*?wz?%Tx2gwJ4apoy`A15D=>?%}hj`fV*p=6XW=YR(sp))`dxTnqHE&{&; zPdeO}SVkf*6_$c45W3Z}u|Z&a8{r!6ZNY62S>5{jAd)Hkjg@h%@c)c#BvZK2lmGw| z`Vh+%ECkF{t=)XpF3Z1bj=Pe9LpHbnQwjeTU#=4hB76#52DU2P2Ouj~^lRWwRd%eN zBw_z%FL0CUlk!`s2!`>QG&H__i_)I9=AuA=jn40z>;@hRsg)>J(58cx;l;h_zE*-R7Wbz6Ff#1Mss*)zTImU4`2@?a7y;v4 zH=lJ_PM5Rkw*AU`Cmq6aa>chASJ&Z3Ebj`y;w$MM!fa6`13VU7Kc|T5Xl#7ecj?mp zREV-nBJ6C)`?&}QDe_(KM>BrlN|iF{7-90j+J>N0^vY=LK;8!^9Y_m*aRPX{!S6ag zgRw(13pJvt`;{^S-vgUk?8pV_Vh4a4P7~}uHT)ENFMqd71QIOl8Q6+24TM_+158z) z54U-*C{M)S&!2Bfu&`?Ti6;WojY;%6+I;uCof+*T2iUMz!7Eg<{}#DJSx)C$5f zP(oSf>_s1t06cJ-U3?<9poS4O{Go>H>hro^ks;r3mm1Ehfq?m(_YE8UiVUgG%W9ZY z!@O^}KR%JW*0e=66rUYj5BP~=x%$^x92-m_=b))this.iframe=i('