public static RSResponse StoreFile(RSRequest rsRequest, Stream entity) { string extensionToAdd = ""; //If file extension was not specified, make a good guess if (Path.GetExtension(rsRequest.LocalPath) == String.Empty) { extensionToAdd = rsRequest.ContentType.GetFileExtensionCandidates()[0]; } //Add extension to the target file name (or don't) string newFileName = rsRequest.LocalPath + extensionToAdd; try { using (FileStream fs = File.OpenWrite(newFileName)) { entity.CopyTo(fs); } } catch (Exception ex) { return new StatusCodeResponse(HttpStatusCode.InternalServerError, ex.Message); } return new StatusCodeResponse(HttpStatusCode.Created); }
/// <summary> /// Construct new ServerThread, using HttpListenerContext to populate request and response objects /// </summary> /// <param name="context">The HttpListenerContext of the current request</param> public HttpServerThread(HttpListenerContext context) { _request = context.Request; _response = context.Response; rsRequest = new RSRequest(context); Output.Write(Name + " initialised"); }
/// <summary> /// Pass the user through an authentication gate. /// If the correct auth cookie is present, returns null /// otherwise returns a 401 login prompt /// </summary> /// <param name="rsRequest"></param> /// <returns>null if authenticated, StatusCodeResponse(401) if not</returns> public static RSResponse RequireAuthentication(RSRequest rsRequest) { if (CookiePresent(rsRequest)) { return null; } else { var loginResponse = new StatusCodeResponse(HttpStatusCode.Unauthorized, "Log in"); loginResponse.AdditionalHeaders.Add("WWW-Authenticate", "Basic realm=\"Log in to " + rsRequest.Website.Name + "\""); return loginResponse; } }
/// <summary> /// Based on request URI, method, and headers; form an appropriate response and carry out necessary actions on the server /// </summary> public void HandleRequest() { Output.Write(Name + " handling '" + _request.Url.AbsoluteUri + "'"); rsRequest = new RSRequest(_request.Url); //ReServer (RS) response object // Class used to build the raw output // which will be fed into the HttpResponse OutputStream RSResponse rsResponse = new RSResponse(); // Check first whether it is a dir if (Directory.Exists(rsRequest.LocalPath)) { Output.Write("Directory"); // localPath is a directory: // Check it ends with a slash if (rsRequest.PathEndsInSlash()) { Output.Write("Getting default file"); // Folder root requested: // Search configured list of default pages rsResponse = new DefaultFileResponse(rsRequest.LocalPath, rsRequest.AcceptTypes); } else { // Re-target the request to the directory itself // to give correct behaviour when child files are requested Output.Write(" Lacks terminating slash; redirecting..."); _response.Redirect(_request.Url.AbsoluteUri + '/'); rsResponse = new RedirectionResponse(); } } else { //Return the requested file rsResponse = new FileResponse(rsRequest.LocalPath, rsRequest.AcceptTypes); } //If not found, return error or debug info if (!rsResponse.Satisfied) { //This is kind of temporary rsResponse = new TextResponse(rsRequest.Website.Local, _request, HttpStatusCode.NotFound); } //Convert the response to a client-preferred Content-Type // UNLESS this is a redirect scenario if (rsResponse.Type != RSResponse.RSResponseType.Redirect) { rsResponse = TryConvertToAcceptableContentType(rsResponse); } //Set headers // Logical headers like content type _response.ContentType = rsResponse.ContentType.ToString(); // Additional headers added by the RSResponse foreach (var h in rsResponse.AdditionalHeaders) { _response.Headers.Add(h); } // Feed the bytes using outputstream and close _response.ContentLength64 = rsResponse.Bytes.Length; Stream output = _response.OutputStream; output.Write(rsResponse.Bytes, 0, rsResponse.Bytes.Length); output.Close(); }
/// <summary> /// Retrieve or perform an action on the specified file /// </summary> /// <param name="rsRequest">The original request object</param> /// <param name="entityStream">The request body stream (for storage with PUT if necessary)</param> /// <returns>RSResponse for the server thread to feed to the client</returns> public RSResponse HandleFileRoute(RSRequest rsRequest, Stream entityStream) { switch (Method) { case GET: //Retrieve the file return new FileResponse(rsRequest.LocalPath, rsRequest.AcceptTypes); case POST: //TODO Decide behaviour for post to file; Append resource?? //return new StatusCodeResponse(HttpStatusCode.Created); case PUT: //Store the file at the specified path return DocumentHandler.StoreFile(rsRequest, entityStream); case DELETE: //Delete the file return DocumentHandler.DeleteFile(rsRequest.LocalPath, rsRequest.ContentType); default: //Return error if not handled InvalidHttpMethod(Method); break; } //(Defensive) return error if not handled return new StatusCodeResponse(HttpStatusCode.MethodNotAllowed); }
private static bool CookiePresent(RSRequest rsRequest) { string requiredCookie = CookieName(rsRequest); return (rsRequest.Cookies[requiredCookie] != null); }
private static string CookieName(RSRequest rsRequest) { return "rs-collab-" + rsRequest.Website.Name; }