public void ProcessRequest(HttpContext context, string httpMethod, Stream inputStream) { ODataRequest odataReq = null; ODataFormatter formatter = null; var portalContext = (PortalContext)context.Items[PortalContext.CONTEXT_ITEM_KEY]; try { Content content; odataReq = portalContext.ODataRequest; if (odataReq == null) { formatter = ODataFormatter.Create("json", portalContext); throw new ODataException("The Request is not an OData request.", ODataExceptionCode.RequestError); } this.ODataRequest = portalContext.ODataRequest; Exception requestError = this.ODataRequest.RequestError; formatter = ODataFormatter.Create(portalContext, odataReq); if (formatter == null) { formatter = ODataFormatter.Create("json", portalContext); throw new ODataException(ODataExceptionCode.InvalidFormatParameter); } if (requestError != null) { var innerOdataError = requestError as ODataException; var message = "An error occured during request parsing. " + requestError.Message + " See inner exception for details."; var code = innerOdataError?.ODataExceptionCode ?? ODataExceptionCode.RequestError; throw new ODataException(message, code, requestError); } odataReq.Format = formatter.FormatName; formatter.Initialize(odataReq); // Cross-Origin Resource Sharing (CORS) // Do this after the formatter was initialized to be able to provide a proper error message. if (!HttpHeaderTools.IsOriginHeaderAllowed()) { throw new ODataException(ODataExceptionCode.Forbidden); } var exists = Node.Exists(odataReq.RepositoryPath); if (!exists && !odataReq.IsServiceDocumentRequest && !odataReq.IsMetadataRequest && !AllowedMethodNamesWithoutContent.Contains(httpMethod)) { ContentNotFound(context, odataReq.RepositoryPath); return; } JObject model = null; switch (httpMethod) { case "GET": if (odataReq.IsServiceDocumentRequest) { formatter.WriteServiceDocument(portalContext, odataReq); } else if (odataReq.IsMetadataRequest) { formatter.WriteMetadata(context, odataReq); } else { if (!Node.Exists(odataReq.RepositoryPath)) { ContentNotFound(context, odataReq.RepositoryPath); } else if (odataReq.IsCollection) { formatter.WriteChildrenCollection(odataReq.RepositoryPath, portalContext, odataReq); } else if (odataReq.IsMemberRequest) { formatter.WriteContentProperty(odataReq.RepositoryPath, odataReq.PropertyName, odataReq.IsRawValueRequest, portalContext, odataReq); } else { formatter.WriteSingleContent(odataReq.RepositoryPath, portalContext); } } break; case "PUT": // update if (odataReq.IsMemberRequest) { throw new ODataException("Cannot access a member with HTTP PUT.", ODataExceptionCode.IllegalInvoke); } else { model = Read(inputStream); content = LoadContentOrVirtualChild(odataReq); if (content == null) { ContentNotFound(context, odataReq.RepositoryPath); return; } ResetContent(content); UpdateContent(content, model, odataReq); formatter.WriteSingleContent(content, portalContext); } break; case "MERGE": case "PATCH": // update if (odataReq.IsMemberRequest) { throw new ODataException( String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke); } else { model = Read(inputStream); content = LoadContentOrVirtualChild(odataReq); if (content == null) { ContentNotFound(context, odataReq.RepositoryPath); return; } UpdateContent(content, model, odataReq); formatter.WriteSingleContent(content, portalContext); } break; case "POST": // invoke an action, create content if (odataReq.IsMemberRequest) { formatter.WriteOperationResult(inputStream, portalContext, odataReq); } else { // parent must exist if (!Node.Exists(odataReq.RepositoryPath)) { ContentNotFound(context, odataReq.RepositoryPath); return; } model = Read(inputStream); content = CreateContent(model, odataReq); formatter.WriteSingleContent(content, portalContext); } break; case "DELETE": if (odataReq.IsMemberRequest) { throw new ODataException( String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke); } else { content = LoadContentOrVirtualChild(odataReq); if (content != null) { content.Delete(); } } break; case "OPTIONS": // set allowed methods and headers HttpHeaderTools.SetPreflightResponse(); break; } } catch (ContentNotFoundException e) { var oe = new ODataException(ODataExceptionCode.ResourceNotFound, e); formatter.WriteErrorResponse(context, oe); } catch (ODataException e) { if (e.HttpStatusCode == 500) { SnLog.WriteException(e); } formatter.WriteErrorResponse(context, e); } catch (SenseNetSecurityException e) { // In case of a visitor we should not expose the information that this content actually exists. We return // a simple 404 instead to provide exactly the same response as the regular 404, where the content // really does not exist. But do this only if the visitor really does not have permission for the // requested content (because security exception could be thrown by an action or something else too). if (odataReq != null && User.Current.Id == User.Visitor.Id) { var head = NodeHead.Get(odataReq.RepositoryPath); if (head != null && !SecurityHandler.HasPermission(head, PermissionType.Open)) { ContentNotFound(context, odataReq.RepositoryPath); return; } } var oe = new ODataException(ODataExceptionCode.NotSpecified, e); SnLog.WriteException(oe); formatter.WriteErrorResponse(context, oe); } catch (InvalidContentActionException ex) { var oe = new ODataException(ODataExceptionCode.NotSpecified, ex); if (ex.Reason != InvalidContentActionReason.NotSpecified) { oe.ErrorCode = Enum.GetName(typeof(InvalidContentActionReason), ex.Reason); } // it is unnecessary to log this exception as this is not a real error formatter.WriteErrorResponse(context, oe); } catch (ContentRepository.Storage.Data.NodeAlreadyExistsException nae) { var oe = new ODataException(ODataExceptionCode.ContentAlreadyExists, nae); formatter.WriteErrorResponse(context, oe); } catch (System.Threading.ThreadAbortException tae) { if (!context.Response.IsRequestBeingRedirected) { var oe = new ODataException(ODataExceptionCode.RequestError, tae); formatter.WriteErrorResponse(context, oe); } // specific redirect response so do nothing } catch (Exception ex) { var oe = new ODataException(ODataExceptionCode.NotSpecified, ex); SnLog.WriteException(oe); formatter.WriteErrorResponse(context, oe); } finally { context.Response.End(); } }
//================================================================================= IHttpHandler public void ProcessRequest(HttpContext context) { // Handling If-Modified-Since var modifiedSinceHeader = HttpContext.Current.Request.Headers["If-Modified-Since"]; if (modifiedSinceHeader != null) { DateTime ifModifiedSince = DateTime.MinValue; DateTime.TryParse(modifiedSinceHeader, out ifModifiedSince); if (ifModifiedSince != DateTime.MinValue) { // TODO: Once you can query properly in text files, only take into account the // resource files which contain the resource class in question. var lastModificationDate = GetLastResourceModificationDate(ifModifiedSince); if (lastModificationDate != null && lastModificationDate <= ifModifiedSince) { context.Response.Clear(); context.Response.StatusCode = 304; context.Response.Flush(); context.Response.End(); } } } // Handling the rest of the request var shouldDeny = true; try { var parsedUrl = ParseUrl(context.Request.RawUrl); if (parsedUrl != null) { var cultureName = parsedUrl.Item1; var className = parsedUrl.Item2; CultureInfo culture = null; if (!string.IsNullOrEmpty(cultureName)) { culture = CultureInfo.GetCultureInfo(cultureName); } if (culture != null && !string.IsNullOrEmpty(className)) { var script = ResourceScripter.RenderResourceScript(className, culture); var lastModificationDate = GetLastResourceModificationDate(null); HttpHeaderTools.SetCacheControlHeaders(lastModified: lastModificationDate); // TODO: add an expires header when appropriate, but without clashing with the resource editor context.Response.ContentType = "text/javascript"; context.Response.Write(script); context.Response.Flush(); shouldDeny = false; } } } catch { shouldDeny = true; } // If it failed for some reason, deny it if (shouldDeny) { DenyRequest(context); } }
/// <summary> /// Processes the request. /// </summary> public virtual void ProcessRequestCore(HttpContextBase context) { var propertyName = PropertyName; var requestedNode = RequestedNode; if (string.IsNullOrEmpty(propertyName) || requestedNode == null) { context.Response.StatusCode = 404; return; } // Get the stream through our provider to let 3rd party developers serve custom data string contentType; BinaryFileName fileName; var binaryStream = DocumentBinaryProvider.Current.GetStream(requestedNode, propertyName, out contentType, out fileName); if (binaryStream == null) { return; } Stream resizedStream; // If this is an image and we need to resize it if (Width.HasValue && Height.HasValue) { resizedStream = Image.CreateResizedImageFile(binaryStream, string.Empty, Width.Value, Height.Value, 0, contentType); } else { resizedStream = binaryStream; } // We need to Flush the headers before // We start to stream the actual binary. context.Response.ContentType = contentType; context.Response.AppendHeader("Content-Length", resizedStream.Length.ToString()); HttpHeaderTools.SetContentDispositionHeader(fileName); HttpHeaderTools.SetCacheControlHeaders(lastModified: requestedNode.ModificationDate); if (this.MaxAge.HasValue) { HttpHeaderTools.SetCacheControlHeaders(maxAge: this.MaxAge); } context.Response.StatusCode = 200; context.Response.Flush(); resizedStream.Position = 0; var buffer = new byte[Math.Min(resizedStream.Length, RepositoryConfiguration.BinaryChunkSize)]; int bytesRead; //while (bytesRead > 0) while ((bytesRead = resizedStream.Read(buffer, 0, buffer.Length)) > 0) { context.Response.OutputStream.Write(buffer, 0, bytesRead); context.Response.Flush(); } // Let the client code log file downloads var file = requestedNode as ContentRepository.File; if (file != null) { ContentRepository.File.Downloaded(file.Id); } }
//========================================================================================= Overrides protected override void CreateChildControls() { Controls.Clear(); var node = GetContextNode(); if (node == null) { if (this.RenderException != null) { this.Controls.Clear(); this.Controls.Add(new LiteralControl(String.Concat("Portlet Error: ", this.RenderException.Message))); } return; } try { if (!string.IsNullOrEmpty(this.Renderer)) { var viewControl = Page.LoadControl(this.Renderer); if (viewControl != null) { this.Controls.Add(viewControl); } if (UrlListView == null) { throw new Exception("UrlListView is missing from the view: " + this.Renderer); } if (PortalContext.ProxyIPs.Count == 0) { UrlListView.Visible = true; if (this.ErrorPlaceholder != null) { var errorLabel = new Label(); errorLabel.Text = HttpContext.GetGlobalResourceObject("Portal", "NoProxyServers") as string; errorLabel.CssClass = "sn-purge-error"; this.ErrorPlaceholder.Visible = true; this.ErrorPlaceholder.Controls.Add(errorLabel); } return; } var urlCollector = TypeHandler.ResolveProvider <PurgeUrlCollector>(); if (urlCollector == null) { throw new Exception("UrlCollector type is missing"); } var urlList = urlCollector.GetUrls(node); var purgeResult = HttpHeaderTools.PurgeUrlsFromProxy(urlList); var resultList = from url in urlList where !string.IsNullOrEmpty(url) && purgeResult.ContainsKey(url) select new ProxyPurgeResult { Url = url, Result = purgeResult[url] }; UrlListView.ItemDataBound += UrlListView_ItemDataBound; UrlListView.DataSource = resultList; UrlListView.DataBind(); } } catch (Exception ex) { Logger.WriteException(ex); Controls.Add(new LiteralControl(ex.Message)); } ChildControlsCreated = true; }